feat: packages and a signed repository for Debian and Fedora
The code works on those distributions now; there was still nothing to install. This adds the two packages and, more to the point, somewhere for them to live that hands out updates - a package a user has to notice a new version of and download again is not much better than a checkout. Both are built from `make install` and nothing else. A packaging script that lists the installed files a second time is a second description of the layout, and the two drift the first time a file moves; here the Makefile stays the only place that says where anything goes. The .deb is staged and wrapped with dpkg-deb, the .rpm goes through a spec whose %install is the same make invocation. Both are architecture-independent, so one file each covers Debian, Ubuntu and their derivatives on one side and Fedora, RHEL and openSUSE on the other. The version is not written down twice either. The Makefile has it, the control file and the spec take it as a placeholder, and check-version.sh refuses a tag that disagrees - otherwise a v1.0.4 release quietly ships a program that reports 1.0.3. The release workflow builds both in a Debian and a Fedora container, signs the RPM where there is a native rpm-sign, attaches both to the GitHub release, and then adds them to an APT and a DNF repository on gh-pages, regenerating the indexes over every version ever published so that pinning and going back to one still work. Missing the signing key is not an error: it builds, it says in the log that the repositories were left alone, and the packages are still on the release. There is also a check workflow, which is the first time shellcheck actually runs on this. Neither package carries a maintainer script. The units are enabled per user by the program itself, so there is nothing for a package to do as root - and nothing it could do about the changes in a user's home either, which is why both descriptions say to run `disable` before removing. packaging/README.md has the two things that cannot be automated: making the signing key, and pointing Pages at the branch.
This commit is contained in:
1 parent
36498f2acf
commit
a053b4e555
15 files changed
+764
-4
No files matched your search
@@ -0,0 +1,28 @@
|
||||
name: check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: syntax and shellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# The Makefile skips whatever is missing rather than failing, so the
|
||||
# tools it looks for have to be here or the check checks less than it
|
||||
# appears to.
|
||||
- name: Install the tools the Makefile looks for
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
shellcheck gettext scdoc
|
||||
|
||||
- run: make check
|
||||
|
||||
- name: Build the catalogs and the man page
|
||||
run: make build
|
||||
@@ -0,0 +1,156 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
deb:
|
||||
name: Debian package
|
||||
runs-on: ubuntu-latest
|
||||
container: debian:stable
|
||||
steps:
|
||||
- name: Install the build tools
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates git make gettext scdoc dpkg-dev
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check the tag against the Makefile
|
||||
run: packaging/check-version.sh "${{ github.ref_name }}"
|
||||
|
||||
- run: packaging/build-deb.sh
|
||||
|
||||
- name: Look inside what was built
|
||||
run: |
|
||||
dpkg-deb --info dist/*.deb
|
||||
dpkg-deb --contents dist/*.deb
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: deb
|
||||
path: dist/*.deb
|
||||
if-no-files-found: error
|
||||
|
||||
rpm:
|
||||
name: RPM package
|
||||
runs-on: ubuntu-latest
|
||||
container: fedora:latest
|
||||
steps:
|
||||
- name: Install the build tools
|
||||
run: |
|
||||
dnf install -y --setopt=install_weak_deps=False \
|
||||
git make gettext scdoc tar rpm-build rpm-sign systemd-rpm-macros
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check the tag against the Makefile
|
||||
run: packaging/check-version.sh "${{ github.ref_name }}"
|
||||
|
||||
- run: packaging/build-rpm.sh
|
||||
|
||||
# Signed here rather than alongside the APT repository, because this is
|
||||
# the one place with a native rpm-sign.
|
||||
- name: Sign the package
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -z "${GPG_PRIVATE_KEY:-}" ]; then
|
||||
echo "No GPG_PRIVATE_KEY secret; leaving the package unsigned."
|
||||
exit 0
|
||||
fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
||||
rpmsign --define "_gpg_name $keyid" --addsign dist/*.rpm
|
||||
rpm --checksig dist/*.rpm
|
||||
|
||||
- name: Look inside what was built
|
||||
run: |
|
||||
rpm -qip dist/*.rpm
|
||||
rpm -qlp dist/*.rpm
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rpm
|
||||
path: dist/*.rpm
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
name: Release and repositories
|
||||
needs: [deb, rpm]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: incoming
|
||||
merge-multiple: true
|
||||
|
||||
- name: Attach the packages to the release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create "${{ github.ref_name }}" \
|
||||
--title "${{ github.ref_name }}" \
|
||||
--generate-notes \
|
||||
incoming/* \
|
||||
|| gh release upload "${{ github.ref_name }}" incoming/* --clobber
|
||||
|
||||
- name: Install the repository tools
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
dpkg-dev apt-utils createrepo-c
|
||||
|
||||
- name: Import the signing key
|
||||
id: key
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -z "${GPG_PRIVATE_KEY:-}" ]; then
|
||||
echo "present=no" >> "$GITHUB_OUTPUT"
|
||||
echo "::warning::No GPG_PRIVATE_KEY secret - the apt and dnf repositories were not updated. The packages are on the release."
|
||||
exit 0
|
||||
fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
echo "present=yes" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check out the published repositories
|
||||
if: steps.key.outputs.present == 'yes'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: gh-pages
|
||||
path: pages
|
||||
continue-on-error: true
|
||||
|
||||
- name: Update the repositories
|
||||
if: steps.key.outputs.present == 'yes'
|
||||
run: |
|
||||
# First release: the branch does not exist yet.
|
||||
if [ ! -d pages/.git ]; then
|
||||
rm -rf pages && mkdir pages
|
||||
git -C pages init -q -b gh-pages
|
||||
git -C pages remote add origin "https://github.com/${{ github.repository }}.git"
|
||||
fi
|
||||
packaging/publish-repos.sh pages incoming
|
||||
|
||||
- name: Push them
|
||||
if: steps.key.outputs.present == 'yes'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
cd pages
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add -A
|
||||
git diff --quiet --cached && { echo "nothing changed"; exit 0; }
|
||||
git commit -q -m "Publish ${{ github.ref_name }}"
|
||||
git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:gh-pages
|
||||
@@ -1,3 +1,6 @@
|
||||
# build artifacts
|
||||
po/*.mo
|
||||
doc/*.1
|
||||
|
||||
# packages
|
||||
dist/
|
||||
@@ -41,12 +41,18 @@ LIBS := $(wildcard src/lib/*.sh)
|
||||
MSGFMT := $(shell command -v msgfmt 2>/dev/null)
|
||||
SCDOC := $(shell command -v scdoc 2>/dev/null)
|
||||
|
||||
.PHONY: all build install uninstall check clean
|
||||
.PHONY: all build install uninstall check clean version
|
||||
|
||||
all: build
|
||||
|
||||
build: $(MOFILES) $(MANPAGE)
|
||||
|
||||
# The one place the version is written down, for everything that has to agree
|
||||
# with it: the packaging scripts, and the release workflow checking that the
|
||||
# tag it was handed says the same thing.
|
||||
version:
|
||||
@echo $(VERSION)
|
||||
|
||||
po/%.mo: po/%.po
|
||||
ifdef MSGFMT
|
||||
$(MSGFMT) --check --output-file=$@ $<
|
||||
|
||||
@@ -14,9 +14,9 @@ paru -S middleclick-autoscroll # Arch and its derivatives
|
||||
middleclick-autoscroll enable
|
||||
```
|
||||
|
||||
There is no package for anything else yet, so elsewhere it is `make && sudo
|
||||
make install` from a checkout and then the same one command. See
|
||||
[Building from source](#building-from-source).
|
||||
For Debian, Ubuntu, Fedora and openSUSE there is a package repository — see
|
||||
[Installing](#installing) for the three lines that add it. Updates then arrive
|
||||
with the rest of the system's.
|
||||
|
||||
That is the whole setup. Nothing else has to be configured, and no file has to
|
||||
be edited.
|
||||
@@ -205,6 +205,51 @@ Run this before uninstalling the package.
|
||||
|
||||
See `man middleclick-autoscroll` for the details.
|
||||
|
||||
## Installing
|
||||
|
||||
**Arch, CachyOS, EndeavourOS, Manjaro**
|
||||
|
||||
```bash
|
||||
paru -S middleclick-autoscroll
|
||||
```
|
||||
|
||||
**Debian, Ubuntu, Linux Mint, Pop!_OS**
|
||||
|
||||
```bash
|
||||
sudo install -d -m 0755 /etc/apt/keyrings
|
||||
curl -fsSL https://felitendo.github.io/middleclick-autoscroll/KEY.gpg \
|
||||
| sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg
|
||||
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] https://felitendo.github.io/middleclick-autoscroll/deb ./" \
|
||||
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
||||
sudo apt update && sudo apt install middleclick-autoscroll
|
||||
```
|
||||
|
||||
**Fedora, RHEL, CentOS Stream**
|
||||
|
||||
```bash
|
||||
sudo curl -fsSL -o /etc/yum.repos.d/middleclick-autoscroll.repo \
|
||||
https://felitendo.github.io/middleclick-autoscroll/middleclick-autoscroll.repo
|
||||
sudo dnf install middleclick-autoscroll
|
||||
```
|
||||
|
||||
**openSUSE**
|
||||
|
||||
```bash
|
||||
sudo rpm --import https://felitendo.github.io/middleclick-autoscroll/KEY.gpg
|
||||
sudo zypper addrepo --gpgcheck --refresh \
|
||||
https://felitendo.github.io/middleclick-autoscroll/rpm middleclick-autoscroll
|
||||
sudo zypper install middleclick-autoscroll
|
||||
```
|
||||
|
||||
Then `middleclick-autoscroll enable`, once. Every package is signed, and a new
|
||||
version arrives with `apt upgrade`, `dnf upgrade` or `zypper up` like anything
|
||||
else. Anywhere without a package, build it — [from source](#building-from-source)
|
||||
— or take the `.deb` or the `.rpm` off the
|
||||
[releases page](https://github.com/Felitendo/middleclick-autoscroll/releases).
|
||||
|
||||
Run `middleclick-autoscroll disable` before removing the package: it puts back
|
||||
everything that was changed.
|
||||
|
||||
## Distributions
|
||||
|
||||
Any of them. Nothing here is keyed to a distribution name — what differs is
|
||||
@@ -253,6 +298,11 @@ sudo make PREFIX=/usr/local install
|
||||
|
||||
`make check` runs `bash -n` and, if installed, `shellcheck` over every script.
|
||||
|
||||
The `.deb` and the `.rpm` are built from the same `make install`, by
|
||||
`packaging/build-deb.sh` and `packaging/build-rpm.sh`. See
|
||||
[packaging/README.md](packaging/README.md) for how a release is made and how
|
||||
the repositories are signed.
|
||||
|
||||
## License
|
||||
|
||||
GPL-3.0-or-later.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Packaging and releases
|
||||
|
||||
The Makefile installs everything; these only wrap what it produced. That is
|
||||
deliberate — a packaging script that lists the files again is a second
|
||||
description of the layout, and two descriptions drift.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `deb/control`, `deb/copyright` | metadata for the Debian binary package |
|
||||
| `rpm/middleclick-autoscroll.spec` | the RPM spec |
|
||||
| `build-deb.sh`, `build-rpm.sh` | build one package into `dist/` |
|
||||
| `check-version.sh` | refuses a tag that disagrees with the Makefile |
|
||||
| `publish-repos.sh` | regenerates the APT and RPM repositories |
|
||||
| `pages/` | the landing page and the `.repo` file served from GitHub Pages |
|
||||
|
||||
Neither package carries a maintainer script. The units are enabled per user by
|
||||
the program itself, and there is nothing to do as root at install time.
|
||||
|
||||
## Building one by hand
|
||||
|
||||
```bash
|
||||
packaging/build-deb.sh # needs dpkg-dev, gettext, scdoc
|
||||
packaging/build-rpm.sh # needs rpm-build, gettext, scdoc, systemd-rpm-macros
|
||||
```
|
||||
|
||||
Both take the version from `make version` unless one is passed as the first
|
||||
argument.
|
||||
|
||||
## Making a release
|
||||
|
||||
1. Bump `VERSION` in the Makefile.
|
||||
2. Commit, then `git tag vX.Y.Z && git push --tags`.
|
||||
|
||||
The `release` workflow builds both packages in a Debian and a Fedora container,
|
||||
refuses the tag if it disagrees with the Makefile, attaches the packages to a
|
||||
GitHub release, and adds them to the APT and RPM repositories on the `gh-pages`
|
||||
branch. Nothing else has to be done by hand.
|
||||
|
||||
## Setting up the signing, once
|
||||
|
||||
The repositories are signed, so this needs a key. Make one that exists for
|
||||
nothing else — not a personal key — and give it no passphrase: it lives as an
|
||||
encrypted repository secret, and `rpmsign` cannot be handed a passphrase
|
||||
unattended.
|
||||
|
||||
```bash
|
||||
gpg --batch --passphrase '' --quick-generate-key \
|
||||
'middleclick-autoscroll repository <felitendoyt@gmail.com>' rsa4096 sign never
|
||||
|
||||
gpg --armor --export-secret-keys 'middleclick-autoscroll repository' \
|
||||
| gh secret set GPG_PRIVATE_KEY
|
||||
```
|
||||
|
||||
Then, in the repository settings, set **Pages** to deploy from a branch and
|
||||
pick `gh-pages` at the root. The branch is created by the first release that
|
||||
runs with the key in place.
|
||||
|
||||
Without the secret the workflow still builds both packages and attaches them to
|
||||
the release; it says so in the log and leaves the repositories alone.
|
||||
|
||||
## What users end up with
|
||||
|
||||
The public key is published as `KEY.gpg` beside the repositories, and the
|
||||
landing page carries the setup lines for each distribution. After that, a new
|
||||
version arrives with `apt upgrade`, `dnf upgrade` or `zypper up` like anything
|
||||
else.
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Builds the binary package for Debian, Ubuntu and their derivatives into
|
||||
# dist/.
|
||||
#
|
||||
# Everything the package contains comes out of `make install`. This only wraps
|
||||
# what that produced, so there is exactly one description of where a file goes
|
||||
# and it is the Makefile - a packaging script that lists the files again is a
|
||||
# second description, and the two drift.
|
||||
#
|
||||
# Needs: make, dpkg-deb, msgfmt (gettext), scdoc.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
version="${1:-$(make -s -C "$here" version)}"
|
||||
name=middleclick-autoscroll
|
||||
|
||||
# A package without its man page or its translations is not a package this
|
||||
# should be quietly willing to produce: the Makefile skips both when the tools
|
||||
# are missing, and the result would look like a successful build.
|
||||
for tool in msgfmt scdoc dpkg-deb; do
|
||||
command -v "$tool" > /dev/null || { echo "$0: $tool is not installed" >&2; exit 1; }
|
||||
done
|
||||
|
||||
root="$(mktemp -d)"
|
||||
trap 'rm -rf -- "$root"' EXIT
|
||||
|
||||
make -C "$here" install \
|
||||
DESTDIR="$root" \
|
||||
PREFIX=/usr \
|
||||
VERSION="$version" \
|
||||
USERUNITDIR=/usr/lib/systemd/user
|
||||
|
||||
install -d "$root/DEBIAN"
|
||||
sed "s|@VERSION@|$version|g" "$here/packaging/deb/control" > "$root/DEBIAN/control"
|
||||
install -Dm644 "$here/packaging/deb/copyright" \
|
||||
"$root/usr/share/doc/$name/copyright"
|
||||
|
||||
# Relative to the package root, and DEBIAN/ itself is not part of the contents.
|
||||
# Sorted in the C locale so the file comes out the same whatever the locale of
|
||||
# the machine that built it.
|
||||
( cd "$root" && find . -type f ! -path './DEBIAN/*' -printf '%P\0' \
|
||||
| LC_ALL=C sort -z | xargs -0 md5sum > DEBIAN/md5sums )
|
||||
|
||||
mkdir -p "$here/dist"
|
||||
out="$here/dist/${name}_${version}_all.deb"
|
||||
dpkg-deb --root-owner-group --build "$root" "$out" > /dev/null
|
||||
|
||||
echo "$out"
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Builds the binary package for Fedora, RHEL, openSUSE and their derivatives
|
||||
# into dist/.
|
||||
#
|
||||
# The spec takes the version as a macro rather than carrying one of its own,
|
||||
# for the same reason the Debian control file has a placeholder: the Makefile
|
||||
# is where the version is written down.
|
||||
#
|
||||
# Needs: rpmbuild, make, msgfmt (gettext), scdoc, systemd-rpm-macros.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
version="${1:-$(make -s -C "$here" version)}"
|
||||
name=middleclick-autoscroll
|
||||
|
||||
command -v rpmbuild > /dev/null || { echo "$0: rpmbuild is not installed" >&2; exit 1; }
|
||||
|
||||
top="$(mktemp -d)"
|
||||
trap 'rm -rf -- "$top"' EXIT
|
||||
mkdir -p "$top"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS}
|
||||
|
||||
# The working tree as it is, not as it was committed: a package built from a
|
||||
# checkout has to contain what is in that checkout.
|
||||
tar czf "$top/SOURCES/$name-$version.tar.gz" \
|
||||
--transform "s,^\\.,$name-$version," \
|
||||
--exclude=./.git --exclude=./dist --exclude=./po/'*.mo' \
|
||||
-C "$here" .
|
||||
|
||||
rpmbuild \
|
||||
--define "_topdir $top" \
|
||||
--define "_version $version" \
|
||||
-bb "$here/packaging/rpm/$name.spec" > /dev/null
|
||||
|
||||
mkdir -p "$here/dist"
|
||||
cp "$top"/RPMS/noarch/*.rpm "$here/dist/"
|
||||
|
||||
ls "$here/dist/$name-$version"*.rpm
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Refuses a release whose tag and Makefile disagree.
|
||||
#
|
||||
# The version is baked into the program at install time from the Makefile, and
|
||||
# the packages take theirs from the same place - but the tag is what people see
|
||||
# and what the release is named after. A tag that says something else produces
|
||||
# a package called 1.0.4 containing a program that reports 1.0.3, and nothing
|
||||
# would have complained.
|
||||
#
|
||||
# Anything that is not a v-tag - a run started by hand from a branch - is not a
|
||||
# release and has nothing to check.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ref="${1:-}"
|
||||
|
||||
case "$ref" in
|
||||
v[0-9]*) ;;
|
||||
*)
|
||||
echo "not a release tag (${ref:-none}) - nothing to check against"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
tag_version="${ref#v}"
|
||||
make_version="$(make -s -C "$here" version)"
|
||||
|
||||
if [[ $tag_version != "$make_version" ]]; then
|
||||
echo "tag $ref says $tag_version, the Makefile says $make_version" >&2
|
||||
echo "Bump VERSION in the Makefile to match the tag, or retag." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$ref matches the Makefile"
|
||||
@@ -0,0 +1,24 @@
|
||||
Package: middleclick-autoscroll
|
||||
Version: @VERSION@
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Maintainer: Felitendo <felitendoyt@gmail.com>
|
||||
Depends: bash (>= 4.2), coreutils, findutils, grep, sed, mawk | gawk | original-awk
|
||||
Recommends: gettext-base, systemd, desktop-file-utils
|
||||
Homepage: https://github.com/Felitendo/middleclick-autoscroll
|
||||
Description: middle-click autoscroll for Chromium-based applications
|
||||
Blink - the engine inside Chromium, Electron and CEF - has had Windows-style
|
||||
autoscroll for years: hold the middle mouse button, move the pointer, the page
|
||||
scrolls. On Linux it is switched off, because middle click is already taken by
|
||||
primary-selection paste.
|
||||
.
|
||||
This turns it back on for every application on the system that can do it, and
|
||||
for anything installed later. There is no list of supported applications to
|
||||
keep up to date: every launcher is examined, the ones running on Chromium
|
||||
underneath are identified by what they ship rather than by their name, and the
|
||||
argument goes wherever that particular application will actually read it.
|
||||
.
|
||||
Nothing outside the user's home directory is ever written to. Run
|
||||
"middleclick-autoscroll disable" before removing this package, so that
|
||||
everything it changed is put back.
|
||||
@@ -0,0 +1,20 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: middleclick-autoscroll
|
||||
Source: https://github.com/Felitendo/middleclick-autoscroll
|
||||
|
||||
Files: *
|
||||
Copyright: 2026 Felitendo
|
||||
License: GPL-3+
|
||||
|
||||
License: GPL-3+
|
||||
This program is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
.
|
||||
On Debian systems the full text of the GNU General Public License version 3 can
|
||||
be found in /usr/share/common-licenses/GPL-3.
|
||||
@@ -0,0 +1,115 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>middleclick-autoscroll</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--fg: #1b1f23;
|
||||
--muted: #57606a;
|
||||
--rule: #d8dee4;
|
||||
--code-bg: #f6f8fa;
|
||||
--accent: #1793d1;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--bg: #0d1117;
|
||||
--fg: #e6edf3;
|
||||
--muted: #9198a1;
|
||||
--rule: #30363d;
|
||||
--code-bg: #161b22;
|
||||
--accent: #58a6ff;
|
||||
}
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0 auto;
|
||||
padding: 3rem 1.25rem 5rem;
|
||||
max-width: 46rem;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
h1 { font-size: 1.6rem; margin: 0 0 .4rem; }
|
||||
h2 {
|
||||
font-size: 1.05rem; margin: 2.5rem 0 .6rem;
|
||||
padding-bottom: .3rem; border-bottom: 1px solid var(--rule);
|
||||
}
|
||||
p.lead { color: var(--muted); margin: 0 0 2rem; }
|
||||
p { margin: 0 0 1rem; }
|
||||
a { color: var(--accent); }
|
||||
code {
|
||||
background: var(--code-bg); padding: .12em .35em;
|
||||
border-radius: 4px; font-size: .9em;
|
||||
}
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 6px;
|
||||
padding: .9rem 1rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
pre code { background: none; padding: 0; font-size: .85rem; }
|
||||
footer {
|
||||
margin-top: 3.5rem; padding-top: 1rem;
|
||||
border-top: 1px solid var(--rule);
|
||||
color: var(--muted); font-size: .9rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>middleclick-autoscroll</h1>
|
||||
<p class="lead">
|
||||
Middle-click autoscroll — hold the middle mouse button, move the pointer, the
|
||||
page scrolls — in every Chromium-based application on the system, and in
|
||||
anything installed later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This page is the package repository. Set it up once and every new version
|
||||
arrives with the rest of your system updates. The
|
||||
<a href="https://github.com/Felitendo/middleclick-autoscroll">source and the
|
||||
documentation</a> are on GitHub.
|
||||
</p>
|
||||
|
||||
<h2>Debian, Ubuntu, Linux Mint, Pop!_OS</h2>
|
||||
<pre><code>sudo install -d -m 0755 /etc/apt/keyrings
|
||||
curl -fsSL @BASEURL@/KEY.gpg \
|
||||
| sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg
|
||||
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] @BASEURL@/deb ./" \
|
||||
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
||||
sudo apt update
|
||||
sudo apt install middleclick-autoscroll</code></pre>
|
||||
|
||||
<h2>Fedora, RHEL, CentOS Stream</h2>
|
||||
<pre><code>sudo curl -fsSL -o /etc/yum.repos.d/middleclick-autoscroll.repo \
|
||||
@BASEURL@/middleclick-autoscroll.repo
|
||||
sudo dnf install middleclick-autoscroll</code></pre>
|
||||
|
||||
<h2>openSUSE</h2>
|
||||
<pre><code>sudo rpm --import @BASEURL@/KEY.gpg
|
||||
sudo zypper addrepo --gpgcheck --refresh @BASEURL@/rpm middleclick-autoscroll
|
||||
sudo zypper install middleclick-autoscroll</code></pre>
|
||||
|
||||
<h2>Arch, CachyOS, EndeavourOS, Manjaro</h2>
|
||||
<pre><code>paru -S middleclick-autoscroll</code></pre>
|
||||
|
||||
<h2>Then, once</h2>
|
||||
<pre><code>middleclick-autoscroll enable</code></pre>
|
||||
<p>
|
||||
That is the whole setup. Nothing else has to be configured and no file has to
|
||||
be edited. Run <code>middleclick-autoscroll disable</code> before removing the
|
||||
package — it puts back everything that was changed.
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
GPL-3.0-or-later. Packages are signed; the public key is
|
||||
<a href="@BASEURL@/KEY.gpg">KEY.gpg</a>.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
[middleclick-autoscroll]
|
||||
name=middleclick-autoscroll
|
||||
baseurl=@BASEURL@/rpm
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
repo_gpgcheck=1
|
||||
gpgkey=@BASEURL@/KEY.gpg
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Puts the packages that were just built into the APT and RPM repositories on
|
||||
# the gh-pages branch, and regenerates the indexes over everything that is
|
||||
# there.
|
||||
#
|
||||
# Old versions are kept rather than replaced. An index built over all of them
|
||||
# is what lets somebody pin a version or go back to one, and it costs a few
|
||||
# hundred kilobytes.
|
||||
#
|
||||
# Usage: publish-repos.sh <gh-pages checkout> <directory of new packages>
|
||||
#
|
||||
# Needs: dpkg-dev, apt-utils, createrepo-c, gpg, and a secret key already
|
||||
# imported - its id is taken from the keyring.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
pages="$(cd -- "$1" && pwd)"
|
||||
incoming="$(cd -- "$2" && pwd)"
|
||||
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
base_url="${MCA_REPO_URL:-https://felitendo.github.io/middleclick-autoscroll}"
|
||||
|
||||
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
||||
[[ -n $keyid ]] || { echo "$0: no secret key in the keyring" >&2; exit 1; }
|
||||
|
||||
mkdir -p "$pages/deb" "$pages/rpm"
|
||||
cp -- "$incoming"/*.deb "$pages/deb/"
|
||||
cp -- "$incoming"/*.rpm "$pages/rpm/"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# APT
|
||||
# ---------------------------------------------------------------------------
|
||||
# A flat repository: the packages and their index sit in one directory and the
|
||||
# sources line ends in "./". There is one distribution here and it is the same
|
||||
# package for all of them, so the suite and component machinery of a pool
|
||||
# layout would describe nothing.
|
||||
(
|
||||
cd "$pages/deb"
|
||||
|
||||
# The old index must be gone before the new one is written: apt-ftparchive
|
||||
# hashes every file in the directory, and a Release that hashes the
|
||||
# previous Release is a Release that cannot be verified.
|
||||
rm -f Packages Packages.gz Release Release.gpg InRelease
|
||||
|
||||
dpkg-scanpackages --multiversion . > Packages
|
||||
gzip -9kf Packages
|
||||
|
||||
apt-ftparchive \
|
||||
-o APT::FTPArchive::Release::Origin=middleclick-autoscroll \
|
||||
-o APT::FTPArchive::Release::Label=middleclick-autoscroll \
|
||||
-o APT::FTPArchive::Release::Suite=stable \
|
||||
-o APT::FTPArchive::Release::Codename=stable \
|
||||
-o APT::FTPArchive::Release::Architectures=all \
|
||||
-o APT::FTPArchive::Release::Components=main \
|
||||
release . > Release
|
||||
|
||||
# Both signatures: InRelease is what current apt fetches, Release.gpg is
|
||||
# what an older one falls back to.
|
||||
gpg --batch --yes --local-user "$keyid" --clearsign --output InRelease Release
|
||||
gpg --batch --yes --local-user "$keyid" --detach-sign --armor --output Release.gpg Release
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# RPM
|
||||
# ---------------------------------------------------------------------------
|
||||
(
|
||||
cd "$pages/rpm"
|
||||
createrepo_c --quiet --update .
|
||||
rm -f repodata/repomd.xml.asc
|
||||
gpg --batch --yes --local-user "$keyid" --detach-sign --armor repodata/repomd.xml
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The key and the landing page
|
||||
# ---------------------------------------------------------------------------
|
||||
gpg --armor --export "$keyid" > "$pages/KEY.gpg"
|
||||
|
||||
sed "s|@BASEURL@|$base_url|g" "$here/packaging/pages/index.html" > "$pages/index.html"
|
||||
sed "s|@BASEURL@|$base_url|g" "$here/packaging/pages/middleclick-autoscroll.repo" \
|
||||
> "$pages/middleclick-autoscroll.repo"
|
||||
|
||||
# Pages would otherwise hand the whole directory to Jekyll, which drops every
|
||||
# file whose name starts with an underscore and can rewrite the rest.
|
||||
touch "$pages/.nojekyll"
|
||||
|
||||
echo "signed with $keyid"
|
||||
ls -1 "$pages/deb" "$pages/rpm"
|
||||
@@ -0,0 +1,72 @@
|
||||
# Built with `packaging/build-rpm.sh`, which passes the version in rather than
|
||||
# editing this file: the Makefile is where the version is written down, and two
|
||||
# places that have to agree are one place too many.
|
||||
%global upstream_version %{?_version}%{!?_version:1.0.3}
|
||||
|
||||
Name: middleclick-autoscroll
|
||||
Version: %{upstream_version}
|
||||
Release: 1%{?dist}
|
||||
Summary: Middle-click autoscroll for Chromium-based applications
|
||||
|
||||
License: GPL-3.0-or-later
|
||||
URL: https://github.com/Felitendo/middleclick-autoscroll
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildArch: noarch
|
||||
BuildRequires: make
|
||||
BuildRequires: gettext
|
||||
BuildRequires: scdoc
|
||||
# For %{_userunitdir}, which is where the watcher's user units belong.
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
Requires: bash >= 4.2
|
||||
Requires: coreutils
|
||||
Requires: findutils
|
||||
Requires: grep
|
||||
Requires: sed
|
||||
Requires: gawk
|
||||
|
||||
# The interface falls back to English without gettext and picks up new
|
||||
# applications at the next `apply` without systemd, so neither is required.
|
||||
Recommends: /usr/bin/gettext
|
||||
Recommends: systemd
|
||||
Recommends: desktop-file-utils
|
||||
|
||||
%description
|
||||
Blink - the engine inside Chromium, Electron and CEF - has had Windows-style
|
||||
autoscroll for years: hold the middle mouse button, move the pointer, the page
|
||||
scrolls. On Linux it is switched off, because middle click is already taken by
|
||||
primary-selection paste.
|
||||
|
||||
This turns it back on for every application on the system that can do it, and
|
||||
for anything installed later. There is no list of supported applications to keep
|
||||
up to date: every launcher is examined, the ones running on Chromium underneath
|
||||
are identified by what they ship rather than by their name, and the argument goes
|
||||
wherever that particular application will actually read it.
|
||||
|
||||
Nothing outside the user's home directory is ever written to. Run
|
||||
"middleclick-autoscroll disable" before removing this package, so that everything
|
||||
it changed is put back.
|
||||
|
||||
%prep
|
||||
%autosetup -n %{name}-%{version}
|
||||
|
||||
%build
|
||||
%make_build VERSION=%{upstream_version}
|
||||
|
||||
%install
|
||||
%make_install PREFIX=%{_prefix} VERSION=%{upstream_version} \
|
||||
USERUNITDIR=%{_userunitdir}
|
||||
|
||||
%find_lang %{name}
|
||||
|
||||
%files -f %{name}.lang
|
||||
%license LICENSE
|
||||
%doc %{_datadir}/doc/%{name}/README.md
|
||||
%{_bindir}/%{name}
|
||||
%{_datadir}/%{name}/
|
||||
%{_userunitdir}/%{name}.path
|
||||
%{_userunitdir}/%{name}.service
|
||||
%{_mandir}/man1/%{name}.1*
|
||||
|
||||
%changelog
|
||||
Reference in new issue
Block a user