Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rpi-package-download service #5

Merged
merged 1 commit into from
Aug 2, 2024
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
9 changes: 9 additions & 0 deletions nfpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ depends:
- curl
- bash
- gzip
- dctrl-tools
- diffutils
- findutils

# Recommended packages. (overridable)
# This will expand any env var you set in the field, e.g. ${RECOMMENDS_BLA}
Expand Down Expand Up @@ -219,6 +222,12 @@ contents:
- src: fetch-repo-package-list/fetch-repo-package-list
dst: /usr/local/bin/fetch-repo-package-list

- src: rpi-package-download/rpi-package-download.service
dst: /usr/local/lib/systemd/system/rpi-package-download@.service

- src: rpi-package-download/rpi-package-download
dst: /usr/local/bin/rpi-package-download

# This will add all files in some/directory or in subdirectories at the
# same level under the directory /etc. This means the tree structure in
# some/directory will not be replicated.
Expand Down
17 changes: 17 additions & 0 deletions rpi-package-download/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# rpi-package-download
A oneshot service to download the latest version of a Raspberry Pi OS package
(using a previously fetched package list). The latest package information is
also available in dctrl format.

## Usage
To download the latest version of the alsa-utils package:
```
systemctl start rpi-package-download@$(systemd-escape alsa-utils).service
```

The service makes use of systemd's CacheDirectory during execution. The latest
package can be found by following symlinks in the CacheDirectory which would
typically be as follows for the above example:
```
/var/cache/rpi-package-download@alsa\x2dutils.service/latest/package.deb
```
86 changes: 86 additions & 0 deletions rpi-package-download/rpi-package-download
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env bash

set -e

# Usage: rpi-package-download <systemd escaped package>
# e.g. rpi-package-download 'alsa-utils'
# would download alsa-utils

# deps:
# - dctrl-tools (grep-dctrl)
# - coreutils (mktemp,cut,sha1sum,sha256sum)
# - diffutils (cmp)
# - findutils (xargs)
# - curl

REQUESTED_PACKAGE="${1}"

REPOSITORY="${REPOSITORY:-https://archive.raspberrypi.org/debian}"
RELEASE="${RELEASE:-bookworm}"
ARCH="${ARCH:-arm64}"

# Should be set by systemd
SERVICE_NAME="rpi-package-download@$(systemd-escape ${REQUESTED_PACKAGE}).service"
CACHE_DIRECTORY="${CACHE_DIRECTORY:=/var/cache/${SERVICE_NAME}}"
RUNTIME_DIRECTORY="${RUNTIME_DIRECTORY:=/run/${SERVICE_NAME}}"

# Assume that fetch-repo-package-list@.service RUNTIME_DIRECTORY is available relative to our RUNTIME_DIRECTORY
PACKAGES_FILE="${RUNTIME_DIRECTORY}/../fetch-repo-package-list@$(systemd-escape ${REPOSITORY}).service/Packages"

>&2 echo "Getting latest package information for ${REQUESTED_PACKAGE}"
TMP_PKG_FILE="$(mktemp --tmpdir rpi-package-downloader.XXX)"

grep-dctrl \
--field=Package \
--exact-match "${REQUESTED_PACKAGE}" \
"${PACKAGES_FILE}" \
> ${TMP_PKG_FILE}

LATEST_DIR="${RUNTIME_DIRECTORY}/latest"
LATEST_PKG_FILE="${LATEST_DIR}/Package"

if cmp ${TMP_PKG_FILE} ${LATEST_PKG_FILE} 2>/dev/null; then
>&2 echo "Package up-to-date; nothing to do"
exit
fi

CHKSUM=$(sha1sum ${TMP_PKG_FILE} | cut -d " " -f 1)
WORK_DIR="${CACHE_DIRECTORY}/${CHKSUM}"
mkdir -p $WORK_DIR
PACKAGE_FILE="${WORK_DIR}/Packages"
mv "$TMP_PKG_FILE" "$PACKAGE_FILE"

function get_dctrl_field() {
grep-dctrl \
--field=Package \
--exact-match "${1}" \
--no-field-names \
--show-field="${2}" \
"${PACKAGE_FILE}"
}

PACKAGE_PARTIAL_URL="$(get_dctrl_field ${REQUESTED_PACKAGE} Filename)"
PACKAGE_FULL_URL="${REPOSITORY}/${PACKAGE_PARTIAL_URL}"
PACKAGE_BASENAME="$(basename ${PACKAGE_PARTIAL_URL})"

>&2 echo "Downloading package"
curl \
"${PACKAGE_FULL_URL}" \
-o "${WORK_DIR}/${PACKAGE_BASENAME}" \
2> /dev/null

>&2 echo -n "Verifying package checksum: "
pushd "${WORK_DIR}" > /dev/null
grep-dctrl \
--field=Package \
--exact-match "${REQUESTED_PACKAGE}" \
--show-field=SHA256,Filename \
--no-field-names \
"${PACKAGE_FILE}" | sed 's/.*\///' | xargs > "${PACKAGE_BASENAME}.sha256"

sha256sum --check "${PACKAGE_BASENAME}".sha256
popd > /dev/null

>&2 echo "Updating symlinks"
ln -sf "${WORK_DIR}/${PACKAGE_BASENAME}" "${WORK_DIR}/package.deb"
ln -sf "${WORK_DIR}" "${CACHE_DIRECTORY}/latest"
15 changes: 15 additions & 0 deletions rpi-package-download/rpi-package-download.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Downloads specified Raspberry Pi OS package
After=fetch-repo-package-list@https:--archive.raspberrypi.org-debian.service

[Service]
Type=oneshot
Environment=REPOSITORY="https://archive.raspberrypi.org/debian"
EnvironmentFile=/etc/rpi-sb-provisioner/config
ExecStart=/usr/local/bin/rpi-package-download "%I"
CacheDirectory=%n
RuntimeDirectory=%n
RuntimeDirectoryPreserve=true

[Install]
WantedBy=multi-user.target