Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# The on-device path: scripts/build.sh inside Debian bookworm (what the
# printers run), on both architectures, then a daemon handshake check.
daemon:
name: daemon (bookworm ${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
container: debian:bookworm
steps:
- name: Install dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
build-essential cmake pkg-config git ca-certificates python3 \
libusb-1.0-0-dev libudev-dev nlohmann-json3-dev

- uses: actions/checkout@v4

- name: Build (scripts/build.sh)
# Runner speed isn't a Pi's, so this only reports the time; the
# updater's real limit is 60 s on the device.
run: time scripts/build.sh

- name: Smoke test (installed binary)
run: scripts/smoke_test.py bin/device_discoveryd

# Every target in Debug, including the CLI and the pybind11 module.
full-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake pkg-config libusb-1.0-0-dev libudev-dev nlohmann-json3-dev

- name: Configure
run: cmake -S . -B build-dev -DCMAKE_BUILD_TYPE=Debug

- name: Build all targets
run: cmake --build build-dev -j"$(nproc)"

- name: Run CLI
run: build-dev/device_discovery

- name: Smoke test (Debug daemon)
run: python3 scripts/smoke_test.py build-dev/device_discoveryd

python:
name: python ${{ matrix.python }}
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
python: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake pkg-config libusb-1.0-0-dev libudev-dev nlohmann-json3-dev

- name: pip install .
run: pip install -v .

- name: Import and scan
run: |
cd /tmp
python - <<'EOF'
import DeviceDiscovery as dd
serial = dd.scan_serial()
usb = dd.scan_all_usb()
print(f"serial={serial}\nusb={usb}")
assert isinstance(serial, list) and isinstance(usb, list)
EOF
109 changes: 109 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Release

# Pushing a v* tag publishes prebuilt bookworm daemons as GitHub Release
# assets. Printers set up with `install.sh --prebuilt` download them through
# scripts/fetch_release.sh; the rest keep compiling with scripts/build.sh.
#
# Asset names carry no version, so releases/latest/download/<name> always
# resolves; the version is in the VERSION file inside each tarball.

on:
push:
tags: ["v*"]

permissions:
contents: read

jobs:
build:
name: build (bookworm ${{ matrix.arch }})
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
container: debian:bookworm
steps:
- name: Install dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
build-essential cmake pkg-config git ca-certificates python3 \
libusb-1.0-0-dev libudev-dev nlohmann-json3-dev

- uses: actions/checkout@v4

- name: Build
run: scripts/build.sh

- name: Smoke test
run: scripts/smoke_test.py bin/device_discoveryd

- name: Package
run: |
name="device_discoveryd-bookworm-${{ matrix.arch }}"
mkdir -p dist/"$name"
cp bin/device_discoveryd dist/"$name"/
strip dist/"$name"/device_discoveryd
echo "$GITHUB_REF_NAME $GITHUB_SHA" > dist/"$name"/VERSION
cp -r systemd udev docs/PROTOCOL.md LICENSE dist/"$name"/
cd dist
tar czf "$name.tar.gz" "$name"
sha256sum "$name.tar.gz" > "$name.tar.gz.sha256"

- uses: actions/upload-artifact@v4
with:
name: daemon-${{ matrix.arch }}
path: dist/device_discoveryd-*.tar.gz*

publish:
needs: build
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
merge-multiple: true

- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" \
--repo "$GITHUB_REPOSITORY" \
--title "$GITHUB_REF_NAME" \
--generate-notes \
device_discoveryd-*.tar.gz*

# Installs the just-published release the way a --prebuilt printer does,
# then runs it.
verify:
name: verify (bookworm ${{ matrix.arch }})
needs: publish
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
container: debian:bookworm
steps:
- name: Install runtime dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
curl ca-certificates git python3 libusb-1.0-0 libudev1

- uses: actions/checkout@v4

- name: Fetch release
run: DD_GH_REPO="$GITHUB_REPOSITORY" scripts/fetch_release.sh "$GITHUB_REF_NAME"

- name: Smoke test
run: scripts/smoke_test.py bin/device_discoveryd
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ compile_commands.json
__pycache__/
*.so
*.pyc
bin/
.install-mode
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,43 @@ systemd/ device-discoveryd.service (linked into /etc/systemd/system
udev/ optional USB permission rule
scripts/install.sh one-time machine setup (sudo)
scripts/build.sh incremental daemon-only build (run on every update)
scripts/fetch_release.sh download the prebuilt daemon from GitHub Releases
docs/PROTOCOL.md socket protocol: the contract with BlocksScreen
docs/WORKFLOW.md CI/CD: what GitHub Actions checks, how releases work
scripts/smoke_test.py daemon handshake check (used by CI)
.github/workflows/ CI and release workflows
ANALYSIS.md code analysis and known problems
```

## Install on a printer (one time)

```bash
git clone https://github.com/BlocksTechnology/DeviceDiscovery.git ~/DeviceDiscovery
~/DeviceDiscovery/scripts/install.sh # add --usb-access to also install the udev rule
~/DeviceDiscovery/scripts/install.sh # build from source on the printer
~/DeviceDiscovery/scripts/install.sh --prebuilt # or: download the release binary (amd64/arm64)
```

This installs the build dependencies (`cmake`, `libusb-1.0-0-dev`, `libudev-dev`, `nlohmann-json3-dev`), builds the daemon, and links and enables `device-discoveryd.service`. The unit expects the repo at `/home/blocks/DeviceDiscovery` and runs as `blocks:blocksscreen`.
Add `--usb-access` to either command to also install the udev rule.

There are two install modes:

| Mode | Installs | How the daemon gets onto the printer |
|---|---|---|
| **Source** (default) | build deps (`cmake`, `libusb-1.0-0-dev`, `libudev-dev`, `nlohmann-json3-dev`) | `scripts/build.sh` compiles it |
| **Prebuilt** (`--prebuilt`) | runtime libs and `curl` only, no compiler | `scripts/fetch_release.sh` downloads it from [GitHub Releases](https://github.com/BlocksTechnology/DeviceDiscovery/releases) and checks its sha256 |

Both modes put the daemon in `bin/device_discoveryd` and record where it came from in `bin/VERSION` (`source <commit>` or `release <tag> <commit>`). The installer then links and enables `device-discoveryd.service`. The unit expects the repo at `/home/blocks/DeviceDiscovery` and runs as `blocks:blocksscreen`.

The chosen mode is saved in `.install-mode`. To switch, run `install.sh` again with or without `--prebuilt`.

## Updates

The BlocksScreen updater manages this repo as the `DeviceDiscovery` component (see BlocksScreen's `updater/components.yaml`). After each git update, BlocksScreen's `updater/hooks/DeviceDiscovery.sh` runs `scripts/build.sh`, and then the updater restarts `device-discoveryd.service`. No sudo is needed after the first install.

`scripts/build.sh` must finish within the updater's 60 s hook timeout. That's why it builds only the daemon, and why it keeps `build/` between updates so only changed files recompile.
`scripts/build.sh` follows the install mode:

- **Source:** compiles the daemon. It must finish within the updater's 60 s hook timeout. That's why it builds only the daemon, and why it keeps `build/` between updates so only changed files recompile.
- **Prebuilt:** runs `scripts/fetch_release.sh`. If HEAD is exactly on a release tag, it installs that release, and skips the download if it's already installed. Otherwise it installs the latest release, which can be older than the checked-out source.

## Development

Expand All @@ -56,3 +75,5 @@ pip install .
```

Logs under systemd: `journalctl -u device-discoveryd -f`.

CI runs on every pull request; see [docs/WORKFLOW.md](docs/WORKFLOW.md) for what it checks and how to run the same checks locally.
Loading
Loading