Integrate G15 submodules with Debian 13 packaging and devcontainer
This commit is contained in:
commit
795db7924b
28 files changed
+714
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
compose.usb.yaml
|
||||||
|
compose.usb.yaml.tmp.*
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
dev:
|
||||||
|
image: g15-packaging:latest
|
||||||
|
build:
|
||||||
|
context: ../packaging
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
command: ["sleep", "infinity"]
|
||||||
|
volumes:
|
||||||
|
- ..:/work
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "G15 Debian 13",
|
||||||
|
"dockerComposeFile": ["compose.yaml", "compose.usb.yaml"],
|
||||||
|
"service": "dev",
|
||||||
|
"workspaceFolder": "/work",
|
||||||
|
"initializeCommand": ["bash", "${localWorkspaceFolder}/.devcontainer/initialize.sh"],
|
||||||
|
"overrideCommand": false,
|
||||||
|
"shutdownAction": "stopCompose"
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Require a local native Linux daemon, not SSH/TCP or Docker Desktop's VM.
|
||||||
|
[[ $(uname -s) == Linux ]] || { echo 'Local Linux Docker required.' >&2; exit 1; }
|
||||||
|
if [[ -n ${DOCKER_CONTEXT:-} ]]; then
|
||||||
|
endpoint=$(docker context inspect "$DOCKER_CONTEXT" --format '{{.Endpoints.docker.Host}}')
|
||||||
|
elif [[ -n ${DOCKER_HOST:-} ]]; then
|
||||||
|
endpoint=$DOCKER_HOST
|
||||||
|
else
|
||||||
|
endpoint=$(docker context inspect --format '{{.Endpoints.docker.Host}}')
|
||||||
|
fi
|
||||||
|
[[ $endpoint == unix://* ]] || { echo 'Remote Docker endpoints are unsupported.' >&2; exit 1; }
|
||||||
|
os=$(docker info --format '{{.OperatingSystem}}')
|
||||||
|
[[ $os != *"Docker Desktop"* ]] || { echo 'Docker Desktop USB mapping is unsupported.' >&2; exit 1; }
|
||||||
|
|
||||||
|
# shellcheck source=.devcontainer/usb.sh
|
||||||
|
source "$(dirname "${BASH_SOURCE[0]}")/usb.sh"
|
||||||
|
output="$(dirname "${BASH_SOURCE[0]}")/compose.usb.yaml"
|
||||||
|
tmp=$(mktemp "$output.tmp.XXXXXX")
|
||||||
|
trap 'rm -f "$tmp"' EXIT
|
||||||
|
generate_usb /sys/bus/usb/devices /dev/bus/usb > "$tmp"
|
||||||
|
mv "$tmp" "$output"
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
for command in devcontainer docker node; do
|
||||||
|
command -v "$command" >/dev/null || { echo "Required command missing: $command" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
workspace=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
devcontainer up --workspace-folder "$workspace" > "$tmp/up.json"
|
||||||
|
container=$(node -e '
|
||||||
|
const result = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||||
|
if (result.outcome !== "success" || !result.containerId) throw Error("CLI startup failed");
|
||||||
|
process.stdout.write(result.containerId);
|
||||||
|
' "$tmp/up.json")
|
||||||
|
docker inspect "$container" > "$tmp/inspect.json"
|
||||||
|
node - "$tmp/inspect.json" "$workspace" <<'NODE'
|
||||||
|
const fs = require('fs');
|
||||||
|
const assert = require('assert/strict');
|
||||||
|
const [container] = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
||||||
|
const host = container.HostConfig;
|
||||||
|
const expected = [];
|
||||||
|
const products = new Set(['c222', 'c225', 'c227', 'c22b', 'c22d', 'c22e']);
|
||||||
|
for (const entry of fs.readdirSync('/sys/bus/usb/devices')) {
|
||||||
|
const base = `/sys/bus/usb/devices/${entry}`;
|
||||||
|
const read = name => fs.readFileSync(`${base}/${name}`, 'utf8').trim();
|
||||||
|
try {
|
||||||
|
if (read('idVendor') !== '046d' || !products.has(read('idProduct'))) continue;
|
||||||
|
const bus = read('busnum'), number = read('devnum');
|
||||||
|
assert.match(bus, /^\d{1,3}$/);
|
||||||
|
assert.match(number, /^\d{1,3}$/);
|
||||||
|
const node = `/dev/bus/usb/${String(Number(bus)).padStart(3, '0')}/${String(Number(number)).padStart(3, '0')}`;
|
||||||
|
if (fs.statSync(node).isCharacterDevice()) expected.push(node);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT') throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.equal(container.State.Running, true, 'container must be running');
|
||||||
|
assert.equal(host.Privileged, false, 'privileged mode forbidden');
|
||||||
|
assert.notEqual(host.NetworkMode, 'host', 'host networking forbidden');
|
||||||
|
assert.deepEqual(host.DeviceCgroupRules || [], [], 'device cgroup overrides forbidden');
|
||||||
|
assert.deepEqual(host.DeviceRequests || [], [], 'additional device requests forbidden');
|
||||||
|
const devices = host.Devices || [];
|
||||||
|
assert.deepEqual(devices.map(device => device.PathOnHost).sort(), expected.sort(),
|
||||||
|
'USB mappings must match current host allowlist; reconnects may require container recreation');
|
||||||
|
for (const device of devices) {
|
||||||
|
assert.equal(device.PathInContainer, device.PathOnHost, 'device remapping forbidden');
|
||||||
|
assert.equal(device.CgroupPermissions, 'rw', 'only rw device access allowed');
|
||||||
|
}
|
||||||
|
// Only the checkout bind and the CLI's optional editor volume are permitted.
|
||||||
|
assert(container.Mounts.some(mount => mount.Type === 'bind' &&
|
||||||
|
mount.Source === process.argv[3] && mount.Destination === '/work'), 'workspace bind missing');
|
||||||
|
for (const mount of container.Mounts) {
|
||||||
|
assert((mount.Type === 'bind' && mount.Source === process.argv[3] && mount.Destination === '/work') ||
|
||||||
|
(mount.Type === 'volume' && mount.Name === 'vscode' && mount.Destination === '/vscode'),
|
||||||
|
`unexpected mount: ${mount.Source} -> ${mount.Destination}`);
|
||||||
|
}
|
||||||
|
console.log(`PASS: real Docker configuration; ${devices.length} exact allowed USB mapping(s)`);
|
||||||
|
NODE
|
||||||
|
# Expand PWD inside the container, not on the host.
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
devcontainer exec --workspace-folder "$workspace" bash -c \
|
||||||
|
'set -euo pipefail; test "$PWD" = /work; test -f .devcontainer/devcontainer.json; test ! -e /dev/uinput; printf "PASS: CLI exec and no /dev/uinput; no keyboard I/O performed\n"'
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Initialization supplies the real host sysfs and USB device paths.
|
||||||
|
generate_usb() {
|
||||||
|
local sys=$1 dev=$2 entry vendor product bus number node
|
||||||
|
local -a nodes=()
|
||||||
|
for entry in "$sys"/*; do
|
||||||
|
[[ -r $entry/idVendor && -r $entry/idProduct ]] || continue
|
||||||
|
read -r vendor < "$entry/idVendor" || continue
|
||||||
|
read -r product < "$entry/idProduct" || continue
|
||||||
|
[[ $vendor == 046d ]] || continue
|
||||||
|
case $product in c222|c225|c227|c22b|c22d|c22e) ;; *) continue ;; esac
|
||||||
|
[[ -r $entry/busnum && -r $entry/devnum ]] || continue
|
||||||
|
read -r bus < "$entry/busnum" || continue
|
||||||
|
read -r number < "$entry/devnum" || continue
|
||||||
|
[[ $bus =~ ^[0-9]{1,3}$ && $number =~ ^[0-9]{1,3}$ ]] || continue
|
||||||
|
printf -v node '%s/%03d/%03d' "$dev" "$((10#$bus))" "$((10#$number))"
|
||||||
|
[[ -c $node ]] || continue
|
||||||
|
nodes+=("$node")
|
||||||
|
done
|
||||||
|
printf 'services:\n dev:\n'
|
||||||
|
if ((${#nodes[@]})); then
|
||||||
|
printf ' devices:\n'
|
||||||
|
for node in "${nodes[@]}"; do
|
||||||
|
printf ' - "%s:%s:rw"\n' "$node" "$node"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
printf ' devices: []\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
name: Debian 13 packages
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'packaging/**'
|
||||||
|
- '.github/**'
|
||||||
|
- '.devcontainer/**'
|
||||||
|
- '.gitmodules'
|
||||||
|
- '.gitignore'
|
||||||
|
- 'README.md'
|
||||||
|
- 'libg15'
|
||||||
|
- 'libg15render'
|
||||||
|
- 'g15daemon'
|
||||||
|
- 'g15macro'
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
submodules: recursive
|
||||||
|
- name: Build and validate in Debian 13
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for script in packaging/*.sh packaging/overlays/v1/*.sh .devcontainer/*.sh; do bash -n "$script"; done
|
||||||
|
# Real devcontainer CLI validation is a separate local check; see README.md.
|
||||||
|
docker run --rm -v "$GITHUB_WORKSPACE/.github:/repo/.github:ro" -w /repo \
|
||||||
|
rhysd/actionlint@sha256:887a259a5a534f3c4f36cb02dca341673c6089431057242cdc931e9f133147e9 \
|
||||||
|
.github/workflows/debian.yml
|
||||||
|
mkdir -p "$RUNNER_TEMP/debs"
|
||||||
|
bash packaging/run.sh "$RUNNER_TEMP/debs"
|
||||||
|
docker run --rm -v "$GITHUB_WORKSPACE/packaging:/checks/packaging:ro" \
|
||||||
|
-v "$GITHUB_WORKSPACE/.devcontainer:/checks/.devcontainer:ro" \
|
||||||
|
-w /checks g15-packaging bash -c 'shellcheck packaging/*.sh packaging/overlays/v1/*.sh .devcontainer/*.sh'
|
||||||
|
test -z "$(git submodule foreach --quiet --recursive 'git status --porcelain')"
|
||||||
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||||
|
with:
|
||||||
|
name: debian13-amd64
|
||||||
|
path: ${{ runner.temp }}/debs/*
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
release:
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 10
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
|
with:
|
||||||
|
name: debian13-amd64
|
||||||
|
path: artifacts
|
||||||
|
- name: Attach verified packages and sources
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
GH_REPO: ${{ github.repository }}
|
||||||
|
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||||
|
run: |
|
||||||
|
cd artifacts
|
||||||
|
sha256sum -c SHA256SUMS
|
||||||
|
gh release upload "$RELEASE_TAG" -- ./*
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/.vscode/
|
||||||
|
/dist/
|
||||||
|
/distro.zip
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
[submodule "libg15"]
|
||||||
|
path = libg15
|
||||||
|
url = https://gt.uo1.net/mikhail/libg15
|
||||||
|
[submodule "g15daemon"]
|
||||||
|
path = g15daemon
|
||||||
|
url = https://gt.uo1.net/mikhail/g15daemon
|
||||||
|
[submodule "g15macro"]
|
||||||
|
path = g15macro
|
||||||
|
url = https://gt.uo1.net/mikhail/g15macro
|
||||||
|
[submodule "libg15render"]
|
||||||
|
path = libg15render
|
||||||
|
url = https://gt.uo1.net/mikhail/libg15render
|
||||||
|
[submodule "g15stats"]
|
||||||
|
path = g15stats
|
||||||
|
url = https://gt.uo1.net/mikhail/g15stats
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# G15 tools: Debian 13 development and packages
|
||||||
|
|
||||||
|
This outer repository builds and packages four pinned Git submodules: `libg15`,
|
||||||
|
`libg15render`, `g15daemon`, and `g15macro`. A fifth submodule, `g15stats`, is
|
||||||
|
present but is not integrated into the build or packaging pipeline.
|
||||||
|
Initialize a fresh clone with
|
||||||
|
`git submodule update --init --recursive`. Builds reject missing, dirty, or
|
||||||
|
misaligned submodules; they export committed, unpatched Debian sources and
|
||||||
|
never modify submodule working trees or refs.
|
||||||
|
|
||||||
|
## Build and verify release packages
|
||||||
|
|
||||||
|
Create an empty directory outside the checkout (for example with `mktemp -d`)
|
||||||
|
and run `bash packaging/run.sh /absolute/path/to/that-directory`.
|
||||||
|
The runner uses disposable Debian 13 Docker containers to build all four
|
||||||
|
projects in dependency order, install their own development packages before
|
||||||
|
downstream builds, test distro replacement, and rebuild all four source packages
|
||||||
|
without the checkout mounted. It mounts only an allowlist of build inputs;
|
||||||
|
`.vscode` is not exposed to release build containers.
|
||||||
|
|
||||||
|
Outputs include eight binary packages, debug symbols, four standalone Debian
|
||||||
|
source packages, build metadata, submodule provenance and checksums. See
|
||||||
|
`packaging/NOTES.md` for versions, overlays, QA and release behavior. The old
|
||||||
|
outer `git archive` ZIP is not a source distribution: it omits submodule content.
|
||||||
|
Use the verified Debian source artifacts instead.
|
||||||
|
|
||||||
|
**Safety limitation:** legacy macro memory/configuration handling has known
|
||||||
|
preexisting defects. Compatibility overlays do not repair the macro engine.
|
||||||
|
Do not run it as root or use untrusted configuration. Build and install tests
|
||||||
|
are not hardware or security certification; see `packaging/overlays/v1/README.md`.
|
||||||
|
|
||||||
|
## Recommended: Debian 13 container and packages
|
||||||
|
|
||||||
|
Use local Linux Docker Engine with Compose and the Dev Containers CLI (or
|
||||||
|
VS Code's Reopen in Container). From the repository root, run
|
||||||
|
`devcontainer up --workspace-folder .`, then
|
||||||
|
`devcontainer exec --workspace-folder . bash`.
|
||||||
|
The container reuses `packaging/Dockerfile` (Debian 13/trixie), with GCC,
|
||||||
|
Make, Autotools, Debian packaging tools, libusb-1.0, FreeType and XTest headers.
|
||||||
|
The image does not preinstall distro G15 development libraries: package builds
|
||||||
|
install the versions built from the submodules. Its normal packaging command
|
||||||
|
is replaced with `sleep infinity`.
|
||||||
|
No host package installation is needed beyond your existing container tooling.
|
||||||
|
|
||||||
|
For distributable packages, follow `packaging/NOTES.md`
|
||||||
|
using its disposable build container, not the development shell: the packaging
|
||||||
|
scripts install their outputs.
|
||||||
|
|
||||||
|
Initialization regenerates ignored `.devcontainer/compose.usb.yaml`, including
|
||||||
|
only existing exact USB character nodes for Logitech `046d` keyboards
|
||||||
|
`c222`, `c225`, `c227`, `c22b`, `c22d`, `c22e`. No keyboard is required for
|
||||||
|
build-only use. Speakers and gamepanels are excluded. Remote SSH/TCP Docker
|
||||||
|
endpoints and Docker Desktop are rejected; use a native local Linux daemon
|
||||||
|
whose USB paths match this host (do not use a forwarded Unix socket).
|
||||||
|
After reconnecting a keyboard, recreate the container with
|
||||||
|
`devcontainer up --workspace-folder . --remove-existing-container` to refresh
|
||||||
|
device mappings. A device disappearing during startup may require retrying.
|
||||||
|
|
||||||
|
There are no whole-USB mounts, wildcard device rules, privileged mode, Docker
|
||||||
|
socket mounts, or host networking. `/dev/uinput` is deliberately omitted:
|
||||||
|
host input injection does not work by default. If needed, manually configure
|
||||||
|
only that device and host permissions after reviewing the security implications.
|
||||||
|
Rootless Docker/device permissions may further limit hardware access. Building
|
||||||
|
and container checks do not establish keyboard functionality; do not run a
|
||||||
|
second daemon against a keyboard already owned by a host service.
|
||||||
|
|
||||||
|
Run `bash .devcontainer/test.sh` with local Linux Docker Engine, Compose,
|
||||||
|
the installed Dev Containers CLI and host Node.js. It runs real CLI `up` and
|
||||||
|
`exec` with the absolute checkout path, then checks `docker inspect` against
|
||||||
|
the current host sysfs allowlist and rejects unexpected devices, mounts,
|
||||||
|
device cgroup overrides, privileged mode and host networking. It also checks
|
||||||
|
that `/dev/uinput` is absent. No keyboard is required; an empty allowlist must
|
||||||
|
produce no device mappings. The container is left running for development.
|
||||||
|
If USB devices changed, recreate the container as described above and rerun.
|
||||||
|
These configuration checks perform no keyboard I/O, USB driver changes or
|
||||||
|
keyboard functional validation. See `packaging/NOTES.md` for release test
|
||||||
|
coverage and safety limitations.
|
||||||
Submodule
+1
Submodule g15daemon added at 21349f7892.
Submodule
+1
Submodule g15macro added at b2f8cd2195.
Submodule
+1
Submodule g15stats added at 95de11a526.
Submodule
+1
Submodule libg15 added at 1cba4225b6.
Submodule
+1
Submodule libg15render added at b29a7d05ea.
@@ -0,0 +1,8 @@
|
|||||||
|
FROM debian:trixie-slim
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN printf 'deb-src http://deb.debian.org/debian trixie main\n' > /etc/apt/sources.list.d/g15-source.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends build-essential autoconf automake libtool pkg-config debhelper dpkg-dev libusb-1.0-0-dev git ca-certificates fakeroot lintian devscripts dh-sequence-movetousr libfreetype-dev libxtst-dev quilt shellcheck \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
WORKDIR /work
|
||||||
|
CMD ["bash", "packaging/container-build.sh"]
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# Debian 13 packaging
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Use a regular, initialized Git clone on Linux with Docker Engine. Create an
|
||||||
|
empty output directory with `mktemp -d`, then run
|
||||||
|
`bash packaging/run.sh /absolute/path/to/output`. No host package installation,
|
||||||
|
API keys or `.env` are needed. Build scripts install packages and require a
|
||||||
|
disposable root container; do not run them in the hardware-enabled devcontainer.
|
||||||
|
`G15_BUILD_IMAGE` optionally changes the shared image tag.
|
||||||
|
|
||||||
|
`run.sh` builds `packaging/Dockerfile`, mounts only Git metadata, the four
|
||||||
|
submodules and `packaging/` read-only, then runs build and lifecycle tests.
|
||||||
|
A second fresh container mounts only artifacts and `rebuild.sh`, proving that
|
||||||
|
the source packages do not need this repository. All working sources are in
|
||||||
|
container temporary directories. Outputs and logs should remain outside the
|
||||||
|
checkout. Linked Git worktrees with external gitdirs are not supported by the
|
||||||
|
allowlisted mount layout. No container receives USB, uinput or a Docker socket.
|
||||||
|
|
||||||
|
## Sources, patches and versions
|
||||||
|
|
||||||
|
Order: `libg15`, `libg15render`, `g15daemon`, `g15macro`. Each stage installs
|
||||||
|
its own runtime and development packages before the next stage resolves build
|
||||||
|
dependencies. The base image does not supply distro G15 development packages.
|
||||||
|
Each of these four build submodules must match its indexed gitlink and be clean.
|
||||||
|
The additional `g15stats` submodule is not built, packaged or recorded in package
|
||||||
|
provenance. Git
|
||||||
|
archives export immutable HEADs, not working-tree contents. No checkout,
|
||||||
|
patching, committing, ref updates or pushing occurs in submodules.
|
||||||
|
|
||||||
|
Orig tarballs contain the complete committed upstream tree without `debian/`;
|
||||||
|
tracked generated Autotools inputs are preserved rather than guessed away.
|
||||||
|
No Git metadata, untracked objects or local build state is exported. Debian
|
||||||
|
quilt patches stay unapplied in orig tarballs and are applied by dpkg-source.
|
||||||
|
The existing libusb-1.0 port and daemon buffer-overflow fix are retained.
|
||||||
|
|
||||||
|
`overlays/v1/` is the explicit local compatibility layer, applied only in
|
||||||
|
temporary copies. It backports daemon -14.1's t64 transition from -14, adds
|
||||||
|
G110 systemd hotplug activation, and replaces macro's historical compat-5 CDBS
|
||||||
|
packaging with debhelper 13. Macro receives only two upstream build fixes:
|
||||||
|
remove bare `-I` and make an implicit `int` parameter explicit. All changes are
|
||||||
|
included in the Debian tarballs; macro C/build changes are quilt patches.
|
||||||
|
The source packages carry `debian/README.local-build` and original attribution.
|
||||||
|
|
||||||
|
The daemon control file and SONAME override are compared against the official
|
||||||
|
`g15daemon=1.9.5.3-14.1` source obtained through authenticated APT indexes, before
|
||||||
|
changing the local Maintainer. This preserves architecture-dependent
|
||||||
|
`${t64:Provides}`, `Replaces: libg15daemon-client1` and versioned `Breaks`.
|
||||||
|
Runtime package filenames/manpages are renamed, without changing SONAME.
|
||||||
|
The inherited `dh_installsystemd --no-start` remains in force.
|
||||||
|
|
||||||
|
Versions use `<upstream>+g15.git<12-character-commit>-1`. Macro's upstream
|
||||||
|
version is 1.0.5 (configure.ac), not the historical Debian changelog's 1.0.3.
|
||||||
|
Tests require versions above every available trixie candidate, including binNMUs.
|
||||||
|
There is no trixie macro candidate: macro is tested as a fresh installation,
|
||||||
|
not falsely reported as a distro upgrade. Increment the local Debian revision
|
||||||
|
when changing overlays for an already-published source commit. Git hashes are
|
||||||
|
identifiers, not monotonically increasing versions between local releases.
|
||||||
|
|
||||||
|
Orig tar ordering, ownership, timestamps and changelog dates are deterministic
|
||||||
|
from the source commit; `SOURCE_DATE_EPOCH` is set. `.buildinfo` records installed
|
||||||
|
dependencies. Debian mirrors and the trixie image intentionally float, so this
|
||||||
|
is repeatable source export and standalone rebuilding, NOT a claim of bit-for-bit
|
||||||
|
binary reproducibility. Keep complete released artifacts. No signing is performed.
|
||||||
|
|
||||||
|
## Outputs and gates
|
||||||
|
|
||||||
|
Eight packages: `libg15-1`, `libg15-dev`, `libg15render1`, `libg15render-dev`,
|
||||||
|
`g15daemon`, `libg15daemon-client1t64`, `libg15daemon-client-dev`, `g15macro`;
|
||||||
|
plus five debug-symbol packages on amd64. Each of the four sources has a `.dsc`,
|
||||||
|
orig tarball, Debian tarball, `.buildinfo` and `.changes`. `SUBMODULES` records
|
||||||
|
pins and `SHA256SUMS` covers all artifacts. The outer Git ZIP is not a substitute.
|
||||||
|
|
||||||
|
Tests check exact package names, candidate ordering, checksums, Lintian errors,
|
||||||
|
clean installs, distro upgrades, all three libraries' exported symbols and
|
||||||
|
SONAMEs, executable linking, development headers/linking, t64 fields, service
|
||||||
|
and udev installation, macro help/version and purge cleanup. Source rebuilds
|
||||||
|
install newly rebuilt dependencies, not binaries from the first build.
|
||||||
|
|
||||||
|
CI uses recursive checkout on relevant PRs, manual dispatch and published
|
||||||
|
releases. Build permissions are read-only; a separate write-permission job
|
||||||
|
downloads the verified artifact and checks checksums before uploading release
|
||||||
|
assets. All actions are commit-pinned. Existing assets are not overwritten.
|
||||||
|
Lint failures, build failures and source rebuild failures block publication.
|
||||||
|
|
||||||
|
## Safety and validation limits
|
||||||
|
|
||||||
|
Development-container configuration is checked separately with
|
||||||
|
`bash .devcontainer/test.sh` using local Docker, the Dev Containers CLI and
|
||||||
|
host Node.js (see `README.md`). It starts the real container, inspects exact
|
||||||
|
USB mappings against host sysfs and checks isolation, then exercises CLI exec
|
||||||
|
without keyboard I/O or driver changes. Package CI syntax-checks this script
|
||||||
|
but does not run it; package gates do not imply devcontainer or keyboard
|
||||||
|
functional validation.
|
||||||
|
|
||||||
|
Risk: high (legacy native code and distro replacement). Macro has preexisting
|
||||||
|
memory initialization, recording bounds, configuration-index and string-copy
|
||||||
|
defects. These are explicitly outside this build-compatibility change; compiler
|
||||||
|
warnings are not suppressed. Do not run macro as root or load untrusted config.
|
||||||
|
Its historical Debian archive import did not verify the descriptor signature;
|
||||||
|
that provenance limitation remains in `debian/README.source`.
|
||||||
|
|
||||||
|
Hardware operation, X11 recording/playback, hotplug under booted systemd,
|
||||||
|
32-bit t64 ABI behavior and actual GitHub publishing are not covered by local
|
||||||
|
package tests. No runtime-safety or security certification is claimed. Passing
|
||||||
|
packaging gates does not resolve those upstream security concerns.
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Installs dependencies and outputs: disposable Debian 13 containers ONLY.
|
||||||
|
set -euo pipefail
|
||||||
|
export LC_ALL=C
|
||||||
|
root=$(cd -- "$(dirname -- "$0")/.." && pwd)
|
||||||
|
[[ -f /.dockerenv && $EUID == 0 ]] || { echo 'Disposable root Docker container required' >&2; exit 1; }
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. /etc/os-release
|
||||||
|
[[ $ID == debian && $VERSION_ID == 13 ]] || exit 1
|
||||||
|
out=$(realpath "${1:?empty artifact directory required}")
|
||||||
|
[[ -d $out && -z $(find "$out" -mindepth 1 -print -quit) ]] || exit 1
|
||||||
|
work=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
export DEB_BUILD_OPTIONS=${DEB_BUILD_OPTIONS:-parallel=2}
|
||||||
|
export DEBFULLNAME='G15 packaging contributors' DEBEMAIL='noreply@example.invalid'
|
||||||
|
git config --global --add safe.directory "$root"
|
||||||
|
for source in libg15 libg15render g15daemon g15macro; do
|
||||||
|
git config --global --add safe.directory "$root/$source"
|
||||||
|
pin=$(git -C "$root" ls-files --stage -- "$source" | awk '$1 == 160000 {print $2}')
|
||||||
|
[[ -n $pin && $(git -C "$root/$source" rev-parse HEAD) == "$pin" ]]
|
||||||
|
[[ -z $(git -C "$root/$source" status --porcelain --untracked-files=all) ]]
|
||||||
|
done
|
||||||
|
git -C "$root" submodule status --recursive -- libg15 libg15render g15daemon g15macro > "$out/SUBMODULES"
|
||||||
|
if grep -q '^[+U-]' "$out/SUBMODULES"; then echo 'Submodule pin mismatch or missing module' >&2; exit 1; fi
|
||||||
|
for source in libg15 libg15render g15daemon g15macro; do
|
||||||
|
mkdir "$work/$source"
|
||||||
|
cd "$work/$source"
|
||||||
|
sha=$(git -C "$root/$source" rev-parse HEAD)
|
||||||
|
export SOURCE_DATE_EPOCH
|
||||||
|
SOURCE_DATE_EPOCH=$(git -C "$root/$source" show -s --format=%ct HEAD)
|
||||||
|
mkdir tree
|
||||||
|
git -C "$root/$source" archive HEAD | tar -x -C tree
|
||||||
|
[[ ! -d tree/.pc ]] || { echo 'Expected unapplied quilt checkout' >&2; exit 1; }
|
||||||
|
base=$(dpkg-parsechangelog -l tree/debian/changelog -S Version)
|
||||||
|
upstream=${base%-*}
|
||||||
|
[[ $source != g15macro ]] || upstream=1.0.5
|
||||||
|
upstream+=+g15.git${sha:0:12}
|
||||||
|
version=$upstream-1
|
||||||
|
mv tree "$source-$upstream"
|
||||||
|
tree=$PWD/$source-$upstream
|
||||||
|
tar --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0 --numeric-owner \
|
||||||
|
--exclude="$source-$upstream/debian" -cJf "${source}_${upstream}.orig.tar.xz" "$source-$upstream"
|
||||||
|
(cd "$tree" && bash "$root/packaging/overlays/v1/apply.sh" "$source" "$root")
|
||||||
|
if [[ $source == g15daemon ]]; then
|
||||||
|
mkdir official
|
||||||
|
(cd official && apt-get source --download-only g15daemon=1.9.5.3-14.1 && dpkg-source --skip-patches -x ./*.dsc source)
|
||||||
|
diff -u official/source/debian/control "$tree/debian/control"
|
||||||
|
diff -u official/source/debian/libg15daemon-client1t64.lintian-overrides "$tree/debian/libg15daemon-client1t64.lintian-overrides"
|
||||||
|
fi
|
||||||
|
cd "$tree"
|
||||||
|
sed -i "s/^Maintainer:.*/Maintainer: $DEBFULLNAME <$DEBEMAIL>/" debian/control
|
||||||
|
dch --newversion "$version" --distribution trixie --force-distribution \
|
||||||
|
"Export $source commit $sha; apply documented outer packaging overlay v1."
|
||||||
|
sed -i "0,/^ -- /s/^ -- .*/ -- $DEBFULLNAME <$DEBEMAIL> $(date -u -R -d "@$SOURCE_DATE_EPOCH")/" debian/changelog
|
||||||
|
cp "$root/packaging/overlays/v1/README.md" debian/README.local-build
|
||||||
|
apt-get build-dep -y .
|
||||||
|
dpkg-buildpackage -us -uc -sa
|
||||||
|
cd ..
|
||||||
|
cp ./*.deb ./*.dsc ./*.tar.* ./*.buildinfo ./*.changes "$out/"
|
||||||
|
apt-get install -y ./*.deb
|
||||||
|
done
|
||||||
|
cd "$out"
|
||||||
|
sha256sum -- *.deb *.dsc *.tar.* *.buildinfo *.changes SUBMODULES > SHA256SUMS
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
# This entry point installs packages: use only in a disposable container.
|
||||||
|
[[ -f /.dockerenv && $EUID == 0 ]] || { echo 'Disposable root Docker container required' >&2; exit 1; }
|
||||||
|
apt-get update
|
||||||
|
bash packaging/build.sh /out
|
||||||
|
bash packaging/test.sh /out
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# Repository G110 backend (extra keys, no LCD).
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c22b", TAG+="systemd", ENV{SYSTEMD_WANTS}+="g15daemon.service"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Local build overlay v1 (2026-09-07)
|
||||||
|
|
||||||
|
Applied only to temporary git archives. Original submodules are never patched.
|
||||||
|
All upstream Debian quilt series, including the daemon client buffer-overflow
|
||||||
|
fix and libg15 libusb-1.0 conversion, remain intact. Orig tarballs contain the
|
||||||
|
unpatched committed source; local upstream changes are additional quilt patches.
|
||||||
|
Debian metadata changes are carried in each emitted Debian tarball.
|
||||||
|
|
||||||
|
The daemon overlay backports the Debian 1.9.5.3-14.1 t64 control fields and
|
||||||
|
file renames; the builder compares control and the SONAME override against the
|
||||||
|
authenticated trixie source archive. G110 hotplug activation is added separately.
|
||||||
|
|
||||||
|
Macro: replace historical compat-5 CDBS with debhelper 13, remove obsolete
|
||||||
|
configure switches, obsolete watch file and redundant install manifest. Keep
|
||||||
|
copyright, historical provenance, manual and changelog. Autoreconf regenerates
|
||||||
|
the stale generated build system. The build patch removes an invalid bare -I
|
||||||
|
and makes map_gkey's historical implicit int parameter explicit (GCC 14).
|
||||||
|
Package upstream version is 1.0.5, matching configure.ac, not historical 1.0.3.
|
||||||
|
|
||||||
|
This is build compatibility, NOT a macro-engine security repair. Preexisting
|
||||||
|
unchecked configuration indices, string copies, recording bounds and incorrect
|
||||||
|
memory initialization remain. Do not run macro as root or consume untrusted
|
||||||
|
configuration. Hardware, X11 playback and booted systemd require separate tests.
|
||||||
|
The imported historical macro archive signature was not verified; its existing
|
||||||
|
debian/README.source preserves that limitation. No security certification is made.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Called with cwd in a disposable git archive, NEVER a submodule.
|
||||||
|
set -euo pipefail
|
||||||
|
source=${1:?source} root=${2:?repository}
|
||||||
|
[[ ! -e .git && -f debian/control ]] || exit 1
|
||||||
|
case $source in
|
||||||
|
libg15|libg15render) ;;
|
||||||
|
g15daemon)
|
||||||
|
# shellcheck disable=SC2016 # Debian substvars must remain literal.
|
||||||
|
sed -i 's/^Build-Depends:$/Build-Depends: dpkg-dev (>= 1.22.5),/; s/libg15daemon-client1/libg15daemon-client1t64/g; /Package: libg15daemon-client1t64/a Provides: ${t64:Provides}\nReplaces: libg15daemon-client1\nBreaks: libg15daemon-client1 (<< ${source:Version})' debian/control
|
||||||
|
mv debian/libg15daemon-client1.install debian/libg15daemon-client1t64.install
|
||||||
|
mv debian/libg15daemon-client1.manpages debian/libg15daemon-client1t64.manpages
|
||||||
|
printf '%s\n' 'libg15daemon-client1t64: package-name-doesnt-match-sonames libg15daemon-client1' > debian/libg15daemon-client1t64.lintian-overrides
|
||||||
|
cat "$root/packaging/g110.udev" >> debian/g15daemon.udev
|
||||||
|
;;
|
||||||
|
g15macro)
|
||||||
|
cp "$root/packaging/overlays/v1/g15macro.control" debian/control
|
||||||
|
cp "$root/packaging/overlays/v1/g15macro.rules" debian/rules
|
||||||
|
chmod +x debian/rules
|
||||||
|
rm debian/compat debian/g15macro.install debian/watch
|
||||||
|
mkdir -p debian/source debian/patches
|
||||||
|
printf '3.0 (quilt)\n' > debian/source/format
|
||||||
|
cp "$root/packaging/overlays/v1/g15macro-build.patch" debian/patches/local-build.patch
|
||||||
|
printf 'local-build.patch\n' > debian/patches/series
|
||||||
|
;;
|
||||||
|
*) exit 1 ;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Description: Fix legacy build include switch and implicit-int declaration
|
||||||
|
Author: G15 packaging contributors
|
||||||
|
Forwarded: not-needed
|
||||||
|
Last-Update: 2026-09-07
|
||||||
|
--- a/Makefile.am
|
||||||
|
+++ b/Makefile.am
|
||||||
|
@@ -11,7 +11,6 @@
|
||||||
|
image_DATA = ${top_builddir}/g15macro.wbmp
|
||||||
|
|
||||||
|
LIBS = -Wl,--no-add-needed -lg15daemon_client -lg15render -lX11 -lXtst -lpthread
|
||||||
|
-IMCLUDES = -I
|
||||||
|
g15macro_SOURCES = g15macro.c
|
||||||
|
|
||||||
|
|
||||||
|
--- a/g15macro.c
|
||||||
|
+++ b/g15macro.c
|
||||||
|
@@ -191,1 +191,1 @@
|
||||||
|
-int map_gkey(keystate){
|
||||||
|
+int map_gkey(int keystate){
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
Source: g15macro
|
||||||
|
Section: utils
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: G15 packaging contributors <noreply@example.invalid>
|
||||||
|
Build-Depends: debhelper-compat (= 13), libxtst-dev, libg15-dev, libg15render-dev, libg15daemon-client-dev
|
||||||
|
Standards-Version: 4.7.0
|
||||||
|
Homepage: https://sourceforge.net/projects/g15tools/
|
||||||
|
Rules-Requires-Root: no
|
||||||
|
|
||||||
|
Package: g15macro
|
||||||
|
Architecture: any
|
||||||
|
Depends: g15daemon, ${shlibs:Depends}, ${misc:Depends}
|
||||||
|
Description: Macro recording/playback application for G15Daemon
|
||||||
|
G15macro records and plays back keyboard macros using the M and G keys
|
||||||
|
on Logitech G15 keyboards in an X11 session.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Standalone source QA: mount artifacts and this script, NOT the repository.
|
||||||
|
set -euo pipefail
|
||||||
|
export LC_ALL=C
|
||||||
|
[[ -f /.dockerenv && $EUID == 0 ]] || exit 1
|
||||||
|
out=$(realpath "${1:?artifact directory}")
|
||||||
|
(cd "$out" && sha256sum -c SHA256SUMS)
|
||||||
|
work=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
export DEB_BUILD_OPTIONS=parallel=2
|
||||||
|
for source in libg15 libg15render g15daemon g15macro; do
|
||||||
|
mkdir "$work/$source"
|
||||||
|
cd "$work/$source"
|
||||||
|
dsc=("$out/${source}_"*.dsc)
|
||||||
|
[[ ${#dsc[@]} == 1 ]]
|
||||||
|
dpkg-source -x "${dsc[0]}" tree
|
||||||
|
cd tree
|
||||||
|
apt-get build-dep -y .
|
||||||
|
dpkg-buildpackage -us -uc -b
|
||||||
|
cd ..
|
||||||
|
apt-get install -y ./*.deb
|
||||||
|
done
|
||||||
|
echo 'PASS: all four source artifacts rebuilt standalone in dependency order.'
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Host orchestration: no package installation or generated source in workspace.
|
||||||
|
set -euo pipefail
|
||||||
|
root=$(cd -- "$(dirname -- "$0")/.." && pwd)
|
||||||
|
out=$(realpath "${1:?create an empty output directory outside the checkout}")
|
||||||
|
[[ -d $out && -z $(find "$out" -mindepth 1 -print -quit) ]] || exit 1
|
||||||
|
case $out in "$root"|"$root"/*) echo 'Output must be outside the checkout' >&2; exit 1 ;; esac
|
||||||
|
[[ -d $root/.git ]] || { echo 'Regular clone required (external gitdirs unsupported)' >&2; exit 1; }
|
||||||
|
image=${G15_BUILD_IMAGE:-g15-packaging}
|
||||||
|
docker build -t "$image" -f "$root/packaging/Dockerfile" "$root/packaging"
|
||||||
|
# Allowlist mounts: .vscode and other unrelated local files are not exposed.
|
||||||
|
mounts=()
|
||||||
|
for path in .git .gitmodules packaging libg15 libg15render g15daemon g15macro; do
|
||||||
|
mounts+=(--mount "type=bind,src=$root/$path,dst=/work/$path,readonly")
|
||||||
|
done
|
||||||
|
docker run --rm "${mounts[@]}" --mount "type=bind,src=$out,dst=/out" "$image"
|
||||||
|
docker run --rm --mount "type=bind,src=$out,dst=/out,readonly" \
|
||||||
|
--mount "type=bind,src=$root/packaging/rebuild.sh,dst=/rebuild.sh,readonly" \
|
||||||
|
"$image" bash -c 'apt-get update && bash /rebuild.sh /out'
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Destructive package lifecycle checks, only in a disposable container.
|
||||||
|
set -euo pipefail
|
||||||
|
export LC_ALL=C
|
||||||
|
[[ -f /.dockerenv && $EUID == 0 ]] || exit 1
|
||||||
|
out=$(realpath "${1:?artifact directory required}")
|
||||||
|
cd "$out"
|
||||||
|
sha256sum -c SHA256SUMS
|
||||||
|
packages=(libg15-1 libg15-dev libg15render1 libg15render-dev g15daemon libg15daemon-client1t64 libg15daemon-client-dev g15macro)
|
||||||
|
distro=()
|
||||||
|
for package in "${packages[@]}"; do
|
||||||
|
files=("${package}"_*.deb)
|
||||||
|
[[ ${#files[@]} == 1 && -f ${files[0]} ]]
|
||||||
|
[[ $(dpkg-deb -f "${files[0]}" Package) == "$package" ]]
|
||||||
|
candidate=$(apt-cache madison "$package" | awk 'NR == 1 {print $3}')
|
||||||
|
if [[ -n $candidate ]]; then
|
||||||
|
dpkg --compare-versions "$(dpkg-deb -f "${files[0]}" Version)" gt "$candidate"
|
||||||
|
distro+=("$package=$candidate")
|
||||||
|
else
|
||||||
|
[[ $package == g15macro ]] || exit 1
|
||||||
|
echo 'g15macro has no trixie candidate; fresh installation only.'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
lintian --fail-on error ./*.changes
|
||||||
|
scratch=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$scratch"' EXIT
|
||||||
|
multiarch=$(dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||||
|
libraries=(libg15 libg15render libg15daemon_client)
|
||||||
|
mapfile -t allpackages < <(for deb in ./*.deb; do dpkg-deb -f "$deb" Package; done)
|
||||||
|
purge() {
|
||||||
|
local package
|
||||||
|
local -a installed=()
|
||||||
|
for package in "${allpackages[@]}"; do
|
||||||
|
if dpkg-query -W -f='${db:Status-Status}' "$package" 2>/dev/null | grep -qx installed; then
|
||||||
|
installed+=("$package")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ((${#installed[@]})); then apt-get purge -y "${installed[@]}"; fi
|
||||||
|
}
|
||||||
|
smoke() {
|
||||||
|
local package files
|
||||||
|
for package in "${packages[@]}"; do
|
||||||
|
files=("${package}"_*.deb)
|
||||||
|
[[ $(dpkg-query -W -f='${Version}' "$package") == "$(dpkg-deb -f "${files[0]}" Version)" ]]
|
||||||
|
done
|
||||||
|
for binary in /usr/sbin/g15daemon /usr/bin/g15macro; do
|
||||||
|
ldd "$binary" > "$scratch/ldd"
|
||||||
|
cat "$scratch/ldd"
|
||||||
|
if grep -q 'not found' "$scratch/ldd"; then exit 1; fi
|
||||||
|
done
|
||||||
|
for library in "${libraries[@]}"; do
|
||||||
|
readelf -d "/usr/lib/$multiarch/$library.so.1" | grep "SONAME.*$library.so.1"
|
||||||
|
done
|
||||||
|
test -f /usr/lib/systemd/system/g15daemon.service
|
||||||
|
grep -q c22b /usr/lib/udev/rules.d/*g15daemon.rules
|
||||||
|
printf '#include <libg15.h>\n#include <libg15render.h>\n#include <g15daemon_client.h>\nint main(void) { g15canvas c; g15r_initCanvas(&c); return g15daemon_version() == 0; }\n' | \
|
||||||
|
cc -x c - -Wl,--no-as-needed -lg15 -lg15render -lg15daemon_client -o "$scratch/client-smoke"
|
||||||
|
"$scratch/client-smoke"
|
||||||
|
/usr/bin/g15macro --version
|
||||||
|
/usr/bin/g15macro --help
|
||||||
|
}
|
||||||
|
purge
|
||||||
|
apt-get install -y ./*.deb
|
||||||
|
smoke
|
||||||
|
purge
|
||||||
|
apt-get install -y "${distro[@]}"
|
||||||
|
for library in "${libraries[@]}"; do
|
||||||
|
nm -D --defined-only "/usr/lib/$multiarch/$library.so.1" | awk '{print $3}' | sort > "$scratch/$library.before"
|
||||||
|
done
|
||||||
|
apt-get install -y ./*.deb
|
||||||
|
for library in "${libraries[@]}"; do
|
||||||
|
nm -D --defined-only "/usr/lib/$multiarch/$library.so.1" | awk '{print $3}' | sort > "$scratch/$library.after"
|
||||||
|
comm -23 "$scratch/$library.before" "$scratch/$library.after" > "$scratch/$library.missing"
|
||||||
|
test ! -s "$scratch/$library.missing" || { cat "$scratch/$library.missing"; exit 1; }
|
||||||
|
done
|
||||||
|
version=$(dpkg-query -W -f='${Version}' libg15daemon-client1t64)
|
||||||
|
[[ $(dpkg-query -W -f='${Replaces}' libg15daemon-client1t64) == libg15daemon-client1 ]]
|
||||||
|
[[ $(dpkg-query -W -f='${Breaks}' libg15daemon-client1t64) == "libg15daemon-client1 (<< $version)" ]]
|
||||||
|
# amd64 retains the old ABI; dpkg generates architecture-dependent t64 Provides.
|
||||||
|
if [[ $(dpkg --print-architecture) == amd64 ]]; then
|
||||||
|
[[ $(dpkg-query -W -f='${Provides}' libg15daemon-client1t64) == "libg15daemon-client1 (= $version)" ]]
|
||||||
|
fi
|
||||||
|
smoke
|
||||||
|
purge
|
||||||
|
test ! -e /usr/lib/systemd/system/g15daemon.service
|
||||||
|
echo 'PASS: fresh install, distro upgrade, symbols, linking, t64 metadata and purge; no hardware I/O.'
|
||||||
Reference in new issue
Block a user