diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml
index fa21115e9..67daf3ba2 100644
--- a/.github/workflows/pr-labels.yml
+++ b/.github/workflows/pr-labels.yml
@@ -5,7 +5,7 @@ on:
jobs:
check-labels:
name: Check that PRs against the stable branch are labelled correctly
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Check labels
run: |
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 3528f2756..c2612f004 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -4,7 +4,7 @@ on:
jobs:
lint:
name: Check that it conforms to the style guide
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout the Git repository
uses: actions/checkout@v2
@@ -20,7 +20,7 @@ jobs:
run: make lint
pr:
name: Check that it builds without error
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
needs: lint
steps:
- name: Checkout the Git repository
diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml
index c111f7b4d..b4885bd77 100644
--- a/.github/workflows/stable.yml
+++ b/.github/workflows/stable.yml
@@ -6,7 +6,7 @@ on:
jobs:
stable:
name: Build and publish the stable channel
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout the Git repository
uses: actions/checkout@v2
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index 0e2aaaabb..13f5060e4 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -6,7 +6,7 @@ on:
jobs:
testing:
name: Build and publish the testing channel
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout the Git repository
uses: actions/checkout@v2
diff --git a/Makefile b/Makefile
index 454de0ef2..90ce44d60 100644
--- a/Makefile
+++ b/Makefile
@@ -59,7 +59,7 @@ repo-local:
./scripts/repo_build.py --local $(FLAGS)
repo-new:
- ./scripts/repo_build.py --no-fetch $(FLAGS)
+ ./scripts/repo_build.py --diff $(FLAGS)
repo-check:
./scripts/repo-check build/repo
diff --git a/README.md b/README.md
index 267ac6a8f..8b732dabe 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ To automatically install Opkg, Entware and Toltec, run the bootstrap script in a
```sh
$ wget http://toltec-dev.org/bootstrap
-$ echo "46f556b06f5624b48e974ae040b6213828eff6aa2cc78618a4d8961a27cdc8b3 bootstrap" | sha256sum -c && bash bootstrap
+$ echo "5b494f5b98c4cb5f1d9836f966075026abf48a0cd320a99c026c4b18d76c8a0b bootstrap" | sha256sum -c && bash bootstrap
```
> **Warning:**
diff --git a/docs/package.md b/docs/package.md
index 7e2533080..fc81dbd4f 100644
--- a/docs/package.md
+++ b/docs/package.md
@@ -186,13 +186,44 @@ Note that this may be different from the license of the recipe itself, which is
Type |
- Array of strings |
+ Array of dependency specifications (strings) |
+
+
+
+The list of Toltec or Entware packages that are needed to build, configure and use this package.
+Dependency specifications have the following format: `package-name[(<<|<=|=|=>|>>)version]`.
+For example, `xochitl`, `oxide=1.2`, and `draft<<2.0` are valid dependency specifications.
+
+*At build time,* all the dependencies of a recipe are offline-installed (i.e., no [install script](#install-section) is run) in the build container’s `$SYSROOT` before its build script is executed (see [below](#build-section)).
+For [split packages](#split-packages), only recipe-level dependencies are honoured at this stage.
+Circular dependencies are disallowed.
+
+*At install time,* it is guaranteed that all needed packages are unpacked and configured before this package is configured (i.e., before its `configure()` script is run).
+
+A version constraint can be added after each dependency declaration.
+Repeat the dependency twice to specify the two ends of a version range.
+Version constraints are only checked at install time.
+
+#### `makedepends`
+
+
+
+ Required? |
+ No, defaults to ()
+ |
+
+ Type |
+ Array of dependency specifications (strings) |
-A list of package names that must be installed on the device before this package can be configured and used.
+The list of Debian, Toltec or Entware packages that are needed only to build this package.
+Dependency specifications have the following format: `[host:|build:]package-name`.
+For example, `build:autotools` and `libvncserver>=0.9.13` are valid dependency specifications.
-See .
+*Host-type dependencies* (prefixed with `host:`) are packages from Toltec or Entware that will be installed in the container’s `$SYSROOT` before the recipe’s build script is executed.
+
+*Build-type dependencies* (prefixed with `build:`) are packages from Debian that will be installed in the container’s root system before the recipe’s build script is executed.
#### `conflicts`
@@ -207,9 +238,8 @@ See
-A list of package names that must **NOT** be unpacked at the same time as this package.
-
-See .
+A list of package names that cannot be installed at the same time as this package.
+Note that providing the same functionality as another package is not a sufficient reason for declaring a conflict, unless that package cannot be used in the presence of the other package.
#### `image`
diff --git a/package/appmarkable/package b/package/appmarkable/package
index a6297509a..e100f07eb 100644
--- a/package/appmarkable/package
+++ b/package/appmarkable/package
@@ -5,15 +5,15 @@
pkgnames=(appmarkable)
pkgdesc="Front-end for apps that do not have a graphical user interface"
url="https://github.com/LinusCDE/appmarkable"
-pkgver=0.0.0-8
-timestamp=2020-09-07T00:16Z
+pkgver=0.0.0-9
+timestamp=2021-03-10T18:36Z
section="devel"
maintainer="Linus K. "
license=MIT
-image=rust:v1.1
-source=(https://github.com/LinusCDE/appmarkable/archive/b4226e896f441af9895ed5a4ff183af7f93b11ae.zip)
-sha256sums=(0422cee28668d4e7ff554c26884e45ec63feff840eec92e6b8b2e8a7905a9d3b)
+image=rust:v1.4
+source=(https://github.com/LinusCDE/appmarkable/archive/c44ee87ea2b1f1e41c9592476c076150c9a1acf4.zip)
+sha256sums=(76e151aeae0f18b206dd3c6258bf74bcb5256ee2f803e1ed2073278831158f60)
build() {
rm -r .cargo/
diff --git a/package/calculator/package b/package/calculator/package
index 4d097b7c1..d1c8fc923 100644
--- a/package/calculator/package
+++ b/package/calculator/package
@@ -10,6 +10,7 @@ timestamp=2020-08-20T12:28Z
section="math"
maintainer="Mattéo Delabre "
license=GPL-3.0-or-later
+makedepends=(build:imagemagick build:librsvg2-bin)
image=qt:v1.1
source=(
@@ -24,14 +25,6 @@ sha256sums=(
)
build() {
- # Get needed build packages
- export DEBIAN_FRONTEND=noninteractive
- apt-get update -y
- apt-get install -y \
- --no-install-recommends \
- -o Dpkg::Options::="--force-confdef" \
- imagemagick librsvg2-bin
-
qmake Calculator.pro
make
diff --git a/package/ddvk-hacks/package b/package/ddvk-hacks/package
new file mode 100644
index 000000000..4b18716c5
--- /dev/null
+++ b/package/ddvk-hacks/package
@@ -0,0 +1,180 @@
+#!/usr/bin/env bash
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+pkgnames=(ddvk-hacks)
+pkgdesc="Enhance Xochitl with additional features"
+url=https://github.com/ddvk/remarkable-hacks
+pkgver=17.04-1
+timestamp=2020-12-25T14:32Z
+section="readers"
+maintainer="Mattéo Delabre "
+license=MIT
+flags=(nostrip)
+
+source=(https://github.com/ddvk/remarkable-hacks/archive/4b75aeaffa2794ff7d4c106c75e47278d5855401.zip)
+sha256sums=(41b2e2c3c740c109bc33bb3a2d6db9d52bfe8a282a10029d9da07fa70e0808d3)
+
+_patches_dir="/opt/share/ddvk-hacks"
+_xochitl_path="/usr/bin/xochitl"
+_work_dir="/home/root/.local/share/ddvk-hacks"
+_backup_path="$_work_dir/xochitl.backup"
+_old_backup_path="$_backup_path.old"
+_patched_path="$_work_dir/xochitl.patched"
+
+package() {
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/2113/patch_09
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/22048/patch_10.10
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/22182/patch_11.01
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/23016/patch_12.11
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/23023/patch_13.07
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/23127/patch_14.01
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/24027_rm1/patch_15.1.02
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/24027_rm2/patch_15.2.01
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/24130_rm1/patch_16.1.06
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/24130_rm2/patch_16.2.03
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/25027_rm1/patch_17.1.04
+ install -D -m 644 -t "$pkgdir$_patches_dir" "$srcdir"/patches/25027_rm2/patch_17.2.04
+}
+
+configure() {
+ local build_date
+ build_date="$(cat /etc/version)"
+ local patch_version
+ local device
+ local original_hash
+ local xochitl_version
+
+ case "$build_date" in
+ "20201127104549")
+ patch_version="17.2.04"
+ device="reMarkable 2"
+ original_hash="0ed1af968a31e816513d15321bd02b9625ccb073"
+ xochitl_version="2.5.0.27"
+ ;;
+ "20201127104105")
+ patch_version="17.1.04"
+ device="reMarkable 1"
+ original_hash="4296b9c6d7a66aadd12e1cf61a13b7b19504673d"
+ xochitl_version="2.5.0.27"
+ ;;
+ "20201028164335")
+ patch_version="16.1.06"
+ device="reMarkable 1"
+ original_hash="336529ce6e7ef9d6fadd30872708556ca8711f0b"
+ xochitl_version="2.4.1.30"
+ ;;
+ "20201028163830")
+ patch_version="16.2.03"
+ device="reMarkable 2"
+ original_hash="c88d155b7ca8c770240b2c00048968f8445f8115"
+ xochitl_version="2.4.1.30"
+ ;;
+ "20201016123042")
+ patch_version="15.2.01"
+ device="reMarkable 2"
+ original_hash="797f58ed93d2e22e7d77fcd9de6c6eb5d49a3a7f"
+ xochitl_version="2.4.0.27"
+ ;;
+ "20201016123325")
+ patch_version="15.1.02"
+ device="reMarkable 1"
+ original_hash="891e06535c0ae742eeaa3b9a20e9ff03d0f659d3"
+ xochitl_version="2.4.0.27"
+ ;;
+ "20200914085553" | "20200914090635")
+ patch_version="14.01"
+ device="reMarkable 2"
+ original_hash="596b02f401fb0ceb6a73df470fbab418b305cdbc"
+ xochitl_version="2.3.1.27"
+ ;;
+ "20200904144143")
+ patch_version="13.07"
+ device="reMarkable 2"
+ original_hash="7eb1ed8b75b1b282fd4ecf30ef19118d3a41fcc7"
+ xochitl_version="2.3.0.23"
+ ;;
+ "20200709160645")
+ patch_version="12.11"
+ device="reMarkable 1"
+ original_hash="005b05ef64f079aaf377d373cb7e2889a2aa774a"
+ xochitl_version="2.3.0.16"
+ ;;
+ "20200805214933")
+ patch_version="11.01"
+ device="reMarkable 2"
+ original_hash="c7d965972a5a6d2bf8503b1b09b52a89c422505b"
+ xochitl_version="2.2.1.82"
+ ;;
+ "20200528081414")
+ patch_version="10.10"
+ device="reMarkable 1"
+ original_hash="7e92c177df685972a699db6c4a7a918296447f74"
+ xochitl_version="2.2.0.48"
+ ;;
+ "20200320131825")
+ patch_version="09"
+ device="reMarkable 1"
+ original_hash="c8661fbd74a049134509dc22da415bb651d7feac"
+ xochitl_version="2.1.1.3"
+ ;;
+ *)
+ echo
+ echo "Error: The version the device is running is not supported, yet."
+ echo "Build date: $build_date"
+ echo
+ exit 1
+ ;;
+ esac
+
+ echo
+ echo "Device: $device"
+ echo "Xochitl version: $xochitl_version"
+ echo "Patch version: $patch_version"
+ echo
+
+ if ! sha1sum -c <(echo "$original_hash $_xochitl_path") > /dev/null 2>&1; then
+ echo "Error: Invalid Xochitl checksum"
+ echo "Maybe ddvk-hacks are already installed?"
+ echo
+ exit 1
+ fi
+
+ if [[ -f "$_backup_path" ]]; then
+ mv "$_backup_path" "$_old_backup_path"
+ fi
+
+ mkdir -p "$(dirname "$_backup_path")"
+ cp "$_xochitl_path" "$_backup_path"
+
+ echo "Patching Xochitl"
+ bspatch "$_backup_path" "$_patched_path" "$_patches_dir"/patch_"$patch_version"
+ cp "$_patched_path" "$_xochitl_path"
+ rm -rf /home/root/.cache/remarkable/xochitl/qmlcache/*
+
+ echo "Please restart Xochitl to use the patches"
+ echo
+}
+
+_restore() {
+ echo
+ echo "Restoring the original Xochitl binary"
+
+ if ! diff "$_xochitl_path" "$_patched_path" > /dev/null 2>&1; then
+ echo "Warning: Xochitl binary has changed!"
+ echo "Not restoring the backup"
+ else
+ cp "$_backup_path" "$_xochitl_path"
+ rm -rf /home/root/.cache/remarkable/xochitl/qmlcache/*
+ fi
+
+ echo
+}
+
+preremove() {
+ _restore
+}
+
+preupgrade() {
+ _restore
+}
diff --git a/package/draft/package b/package/draft/package
index bcc4ed468..edd4c7bf5 100644
--- a/package/draft/package
+++ b/package/draft/package
@@ -12,7 +12,7 @@ maintainer="Mattéo Delabre "
license=Apache-2.0
depends=(xochitl)
-image=qt:v1.1
+image=qt:v1.3.2
source=(
https://github.com/dixonary/draft-reMarkable/archive/5bd660a2fd07eba166c6110d2b48cfc58ee67e58.zip
draft.service
diff --git a/package/evtest/package b/package/evtest/package
index 896abbf7f..4b79fdead 100644
--- a/package/evtest/package
+++ b/package/evtest/package
@@ -10,17 +10,14 @@ timestamp=2020-12-30T02:52Z
section="utils"
maintainer="Linus K. "
license=GPL-2.0-only
+makedepends=(build:automake)
image=base:v1.2.1
-source=(https://gitlab.freedesktop.org/libevdev/evtest/-/archive/evtest-1.34/evtest-evtest-1.34.zip)
+source=("https://gitlab.freedesktop.org/libevdev/evtest/-/archive/evtest-${pkgver%-*}/evtest-evtest-${pkgver%-*}.zip")
sha256sums=(62f7e34c5bab91b5015de5b056d79051c677c5bd5702facb2885f8e4ba0df84c)
build() {
- apt-get update
- apt-get install -y autoconf
-
export CC=arm-linux-gnueabihf-gcc
-
./autogen.sh --host armv7
./configure --host armv7
make
diff --git a/package/libdlib/package b/package/libdlib/package
new file mode 100644
index 000000000..18a215be7
--- /dev/null
+++ b/package/libdlib/package
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+pkgnames=(libdlib libdlib-dev)
+pkgdesc="Toolkit for making machine learning and data analysis applications in C++"
+url=http://dlib.net
+pkgver=19.21-1
+timestamp=2020-08-08T19:41:07Z
+section="devel"
+maintainer="Mattéo Delabre "
+license=BSL-1.0
+
+image=base:v1.3.1
+source=("https://github.com/davisking/dlib/archive/v${pkgver%-*}.tar.gz")
+sha256sums=(116f52e58be04b47dab52057eaad4b5c4d5c3032d927fe23d55b0741fc4107a0)
+
+build() {
+ cmake -B build \
+ -DCMAKE_TOOLCHAIN_FILE="/usr/share/cmake/$CHOST.cmake" \
+ -DCMAKE_INSTALL_PREFIX="/opt" \
+ -DBUILD_SHARED_LIBS=ON
+ cmake --build build
+ cmake --build build --target install -- DESTDIR=../install
+}
+
+libdlib() {
+ package() {
+ install -d "$pkgdir"/opt/lib "$pkgdir"/usr/lib
+ cp --no-dereference "$srcdir"/install/opt/lib/lib*.so* "$pkgdir"/opt/lib
+
+ for file in "$pkgdir"/opt/lib/lib*.so*; do
+ base="${file#"$pkgdir"}"
+ ln -s "$base" "${file/\/opt/\/usr}"
+ done
+ }
+}
+
+libdlib-dev() {
+ pkgdesc="$pkgdesc - development files"
+
+ package() {
+ install -d "$pkgdir"/opt/lib
+ cp -r "$srcdir"/install/opt/lib/pkgconfig "$pkgdir"/opt/lib
+ cp -r "$srcdir"/install/opt/lib/cmake "$pkgdir"/opt/lib
+ cp -r "$srcdir"/install/opt/include "$pkgdir"/opt
+ }
+}
diff --git a/package/libvncserver/package b/package/libvncserver/package
new file mode 100644
index 000000000..5e831bd29
--- /dev/null
+++ b/package/libvncserver/package
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+pkgnames=(libvncserver libvncclient libvncserver-dev)
+pkgdesc="C libraries for implementing VNC servers or clients"
+url=https://libvnc.github.io
+pkgver=0.9.13-1
+timestamp=2020-06-13T19:19:11Z
+section="devel"
+maintainer="Mattéo Delabre "
+license=GPL-2.0-or-later
+
+image=base:v1.3.1
+source=("https://github.com/LibVNC/libvncserver/archive/LibVNCServer-${pkgver%-*}.zip")
+sha256sums=(d209d70998a9b98f9120eeb82df7a17767796c477eaa8297e0a55856a977c54f)
+
+build() {
+ cmake -B build \
+ -DCMAKE_TOOLCHAIN_FILE="/usr/share/cmake/$CHOST.cmake" \
+ -DCMAKE_INSTALL_PREFIX="/opt"
+ cmake --build build
+ cmake --build build --target install -- DESTDIR=../install
+}
+
+libvncserver() {
+ pkgdesc="$pkgdesc - server library"
+
+ package() {
+ install -d "$pkgdir"/opt/lib "$pkgdir"/usr/lib
+ cp --no-dereference "$srcdir"/install/opt/lib/libvncserver*.so* "$pkgdir"/opt/lib
+
+ for file in "$pkgdir"/opt/lib/lib*.so*; do
+ base="${file#"$pkgdir"}"
+ ln -s "$base" "${file/\/opt/\/usr}"
+ done
+ }
+}
+
+libvncclient() {
+ pkgdesc="$pkgdesc - client library"
+
+ package() {
+ install -d "$pkgdir"/opt/lib "$pkgdir"/usr/lib
+ cp --no-dereference "$srcdir"/install/opt/lib/libvncclient*.so* "$pkgdir"/opt/lib
+
+ for file in "$pkgdir"/opt/lib/lib*.so*; do
+ base="${file#"$pkgdir"}"
+ ln -s "$base" "${file/\/opt/\/usr}"
+ done
+ }
+}
+
+libvncserver-dev() {
+ pkgdesc="$pkgdesc - development files"
+
+ package() {
+ install -d "$pkgdir"/opt/lib
+ cp -r "$srcdir"/install/opt/lib/pkgconfig "$pkgdir"/opt/lib
+ cp -r "$srcdir"/install/opt/include "$pkgdir"/opt
+ }
+}
diff --git a/package/oxide/package b/package/oxide/package
index de93fe2fc..b224e68ce 100644
--- a/package/oxide/package
+++ b/package/oxide/package
@@ -3,19 +3,19 @@
# SPDX-License-Identifier: MIT
pkgnames=(erode fret oxide rot tarnish decay)
-pkgver=2.1~beta-5
+pkgver=2.1.2~1
timestamp=2021-01-07T03:28Z
maintainer="Eeems "
license=MIT
-source=(https://github.com/Eeems/oxide/releases/download/v2.1/oxide.zip)
-sha256sums=(f3f50688db7a11fab74caeb607f23f26f8315ff1d3ec28566f408d4301af26be)
+source=(https://github.com/Eeems/oxide/releases/download/v2.1.2/oxide.zip)
+sha256sums=(c9e8214dd60346b0865bc41e8180064cbb7e108ed676b6726abecff0b4adb710)
erode() {
pkgdesc="Task manager"
url=https://github.com/Eeems/oxide/tree/master/applications/process-manager
section="admin"
- depends=("tarnish (= $pkgver)")
+ depends=("tarnish=$pkgver")
package() {
install -D -m 755 -t "$pkgdir"/opt/bin "$srcdir"/opt/bin/erode
@@ -27,7 +27,7 @@ fret() {
pkgdesc="Take screenshots"
url=https://github.com/Eeems/oxide/tree/master/applications/screenshot-tool
section="utils"
- depends=("tarnish (= $pkgver)")
+ depends=("tarnish=$pkgver")
package() {
install -D -m 755 -t "$pkgdir"/opt/bin "$srcdir"/opt/bin/fret
@@ -39,7 +39,7 @@ oxide() {
pkgdesc="Launcher application"
url=https://github.com/Eeems/oxide/tree/master/applications/launcher
section="launchers"
- depends=("erode (= $pkgver)" "fret (= $pkgver)" "tarnish (= $pkgver)" "rot (= $pkgver)" "decay (= $pkgver)")
+ depends=("erode=$pkgver" "fret=$pkgver" "tarnish=$pkgver" "rot=$pkgver" "decay=$pkgver")
package() {
install -D -m 755 -t "$pkgdir"/opt/bin "$srcdir"/opt/bin/oxide
@@ -60,7 +60,7 @@ rot() {
pkgdesc="Manage Oxide settings through the command line"
url=https://github.com/Eeems/oxide/tree/master/applications/settings-manager
section="admin"
- depends=("tarnish (= $pkgver)")
+ depends=("tarnish=$pkgver")
package() {
install -D -m 755 -t "$pkgdir"/opt/bin "$srcdir"/opt/bin/rot
@@ -100,7 +100,7 @@ decay() {
pkgdesc="Lockscreen application"
url=https://github.com/Eeems/oxide/tree/master/applications/lockscreen
section="utils"
- depends=("tarnish (= $pkgver)")
+ depends=("tarnish=$pkgver")
package() {
install -D -m 755 -t "$pkgdir"/opt/bin "$srcdir"/opt/bin/decay
diff --git a/package/plato/package b/package/plato/package
index 2e555ce8a..6e4149029 100644
--- a/package/plato/package
+++ b/package/plato/package
@@ -10,21 +10,13 @@ timestamp=2021-01-13T23:43Z
section="readers"
maintainer="Linus K. "
license=AGPL-3.0-or-later
+makedepends=(build:jq build:patchelf build:unzip build:wget)
image=rust:v1.2.1
-source=(https://github.com/LinusCDE/plato/archive/0.9.13-rm-release-7.zip)
+source=("https://github.com/LinusCDE/plato/archive/${pkgver%-*}-rm-release-7.zip")
sha256sums=(17718d74066e5cbec043c98b52958a311eb793674751d6b7789b5baff2227f96)
build() {
- # Get needed build packages
- export DEBIAN_FRONTEND=noninteractive
- apt-get update -y
- apt-get install -y \
- jq \
- patchelf \
- unzip \
- wget
-
# Fall back to system-wide config
rm .cargo/config
diff --git a/package/recrossable/package b/package/recrossable/package
index 4787351b6..fb1ffbfda 100644
--- a/package/recrossable/package
+++ b/package/recrossable/package
@@ -5,34 +5,37 @@
pkgnames=(recrossable)
pkgdesc="Solve crossword puzzles"
url=https://github.com/sandsmark/recrossable
-pkgver=0.0.0-3
-timestamp=2020-10-05T08:43Z
+pkgver=0.0.0-5
+timestamp=2021-01-15T12:58:22Z
section="games"
maintainer="Mattéo Delabre "
license=GPL-2.0-or-later
+depends=(libdlib)
+makedepends=(build:imagemagick build:librsvg2-bin host:libdlib-dev)
-image=qt:v1.2
+image=qt:v1.4
source=(
- https://github.com/sandsmark/recrossable/archive/5faa37c6e8a13e3ddeb0fe6d9d5f15717f83b662.zip
+ https://github.com/sandsmark/recrossable/archive/234d5744c0b20087a588d0ecead0a9f58c1f323d.zip
recrossable.draft
recrossable.svg
)
sha256sums=(
- 51e9f630204262fd2b839dafadb4e288797609467e9f07c29f7581711cb2eaec
+ 24b7512d295df504583ccdde7307e8f59fc561da638b992902b4ebccc412fa92
SKIP
SKIP
)
build() {
- # Get needed build packages
- export DEBIAN_FRONTEND=noninteractive
- apt-get update -y
- apt-get install -y \
- --no-install-recommends \
- -o Dpkg::Options::="--force-confdef" \
- imagemagick librsvg2-bin
-
- sed -i 's/linux-oe-g++/linux-arm-gnueabihf-g++/' recrossable.pro
+ cat << QMAKE >> recrossable.pro
+linux-arm-remarkable-g++ {
+ LIBS += -lqsgepaper
+ DEFINES += REMARKABLE_DEVICE
+
+ CONFIG += link_pkgconfig
+ PKGCONFIG += dlib-1
+}
+QMAKE
+
qmake
make
diff --git a/package/rm2fb/package b/package/rm2fb/package
index 702f7e9b7..51f6573a1 100644
--- a/package/rm2fb/package
+++ b/package/rm2fb/package
@@ -1,26 +1,26 @@
#!/usr/bin/env bash
-# Copyright (c) 2020 The Toltec Contributors
+# Copyright (c) 2021 The Toltec Contributors
# SPDX-License-Identifier: MIT
pkgnames=(rm2fb)
-timestamp=2020-10-10T01:41+00:00
+timestamp=2021-02-21T01:41+00:00
maintainer="raisjn "
license=MIT
pkgdesc="Interface to the reMarkable 2 framebuffer"
url="https://github.com/ddvk/remarkable2-framebuffer"
-pkgver=1.0.0-7
+pkgver=1.0.1-1
section="devel"
image=qt:v1.1
source=(
- https://github.com/ddvk/remarkable2-framebuffer/archive/cd2766864c7985fa50cdf85f4ae0a411d7ca4e56.zip
+ https://github.com/ddvk/remarkable2-framebuffer/archive/aa70ce37c71f84b91434f5c469fa71f4b1bb328c.zip
rm2fb.conf
rm2fb.service
rm2fb-server
rm2fb-client
)
sha256sums=(
- c274c458270eec28950834bd28ff069a0af65e40fcc288a8ff28235001e8914f
+ 76f1c0b72260a9743f3e008100ffddf1f89cd44c6f0376d906e98ae66eaea716
SKIP
SKIP
SKIP
@@ -34,8 +34,10 @@ build() {
package() {
mkdir -p "$pkgdir"/opt/lib "$pkgdir"/opt/etc "$pkgdir"/opt/bin
- install -D -m 755 "$srcdir"/src/client/librm2fb_client.so.${pkgver%-*} "$pkgdir"/opt/lib/
- install -D -m 755 "$srcdir"/src/server/librm2fb_server.so.${pkgver%-*} "$pkgdir"/opt/lib/
+ install -D -m 755 "$srcdir/src/client/librm2fb_client.so.${pkgver%-*}" "$pkgdir"/opt/lib/
+ ln -s "librm2fb_client.so.${pkgver%-*}" "$pkgdir/opt/lib/librm2fb_client.so.${pkgver%.*.*-*}"
+ install -D -m 755 "$srcdir/src/server/librm2fb_server.so.${pkgver%-*}" "$pkgdir"/opt/lib/
+ ln -s "librm2fb_server.so.${pkgver%-*}" "$pkgdir/opt/lib/librm2fb_server.so.${pkgver%.*.*-*}"
install -D -m 755 "$srcdir"/rm2fb-server "$pkgdir"/opt/bin/
install -D -m 755 "$srcdir"/rm2fb-client "$pkgdir"/opt/bin/
install -D -m 644 "$srcdir"/rm2fb.conf "$pkgdir"/etc/systemd/system.conf.d/01-rm2fb.conf
diff --git a/package/rm2fb/rm2fb-client b/package/rm2fb/rm2fb-client
index 4cbd93b4e..8dbb3063a 100644
--- a/package/rm2fb/rm2fb-client
+++ b/package/rm2fb/rm2fb-client
@@ -1,3 +1,2 @@
#!/usr/bin/env bash
-# shellcheck disable=SC2048
-LD_PRELOAD=/opt/lib/librm2fb_client.so.1.0.0 $*
+LD_PRELOAD=/opt/lib/librm2fb_client.so.1 exec "$@"
diff --git a/package/rm2fb/rm2fb-server b/package/rm2fb/rm2fb-server
index bc8c13500..bdc224958 100644
--- a/package/rm2fb/rm2fb-server
+++ b/package/rm2fb/rm2fb-server
@@ -1,4 +1,2 @@
#!/usr/bin/env bash
-# we actually do want to execute this command
-# shellcheck disable=SC2091
-LD_PRELOAD=/opt/lib/librm2fb_server.so.1.0.0 $(command -v remarkable-shutdown)
+LD_PRELOAD=/opt/lib/librm2fb_server.so.1 exec "$(command -v remarkable-shutdown)"
diff --git a/package/rm2fb/rm2fb.conf b/package/rm2fb/rm2fb.conf
index ece51aa2f..9c920e20d 100644
--- a/package/rm2fb/rm2fb.conf
+++ b/package/rm2fb/rm2fb.conf
@@ -1,2 +1,2 @@
[Manager]
-DefaultEnvironment=LD_PRELOAD=/opt/lib/librm2fb_client.so.1.0.0
+DefaultEnvironment=LD_PRELOAD=/opt/lib/librm2fb_client.so.1
diff --git a/package/rm2fb/rm2fb.service b/package/rm2fb/rm2fb.service
index 1e7f1ec0e..f5525b962 100644
--- a/package/rm2fb/rm2fb.service
+++ b/package/rm2fb/rm2fb.service
@@ -1,4 +1,4 @@
-# Copyright (c) 2020 The Toltec Contributors
+# Copyright (c) 2021 The Toltec Contributors
# SPDX-License-Identifier: MIT
[Unit]
@@ -14,7 +14,7 @@ ExecStart=/usr/bin/remarkable-shutdown
Restart=on-failure
RestartSec=5
Environment="HOME=/home/root"
-Environment="LD_PRELOAD=/opt/lib/librm2fb_server.so.1.0.0"
+Environment="LD_PRELOAD=/opt/lib/librm2fb_server.so.1"
[Install]
WantedBy=multi-user.target xochitl.service
diff --git a/package/rmkit/2021_03_05_genie.diff b/package/rmkit/2021_03_05_genie.diff
new file mode 100644
index 000000000..9b329fb43
--- /dev/null
+++ b/package/rmkit/2021_03_05_genie.diff
@@ -0,0 +1,29 @@
+diff --git a/src/genie/gesture_parser.cpy b/src/genie/gesture_parser.cpy
+index fa82b67..c94fd59 100644
+--- a/src/genie/gesture_parser.cpy
++++ b/src/genie/gesture_parser.cpy
+@@ -16,17 +16,18 @@ namespace genie:
+ ;
+
+ void run_command(string command):
++ debug "RUNNING COMMAND", command
++ string cmd = command + "&"
++ c_str := cmd.c_str()
++ _ := system(c_str)
++
+ ui::TaskQueue::add_task([=]() {
+ usleep(1e3 * 50)
+-
+- debug "RUNNING COMMAND", command
+- string cmd = command
+- c_str := cmd.c_str()
+- _ := system(c_str)
+-
+ ui::MainLoop::reset_gestures()
+ })
+
++
++
+ input::SwipeGesture* build_swipe_gesture(GestureConfigData gcd):
+ fb := framebuffer::get()
+ fw, fh := fb->get_display_size()
diff --git a/package/rmkit/changelog b/package/rmkit/changelog
new file mode 100644
index 000000000..172f5ec0a
--- /dev/null
+++ b/package/rmkit/changelog
@@ -0,0 +1,221 @@
+2021-02-25 raisjn
+
+ lamp:
+
+ * add new binary lamp for injecting pen strokes
+
+ iago:
+
+ * add new binary iago for drawing shapes
+
+
+2021-02-17 raisjn
+
+ remux:
+
+ * better multi-touch gesture support
+ * launch more consistently after closing or stylus touches
+ * better power management and ability to toggle (manage_power=no)
+ * update to use less power
+
+ genie:
+
+ * better gesture support
+
+ mines:
+
+ * speed up game over screen
+
+ harmony:
+
+ * add 4 shades of gray
+ * better support for rM1 buffer
+ * faster drawing on first draw
+
+2021-02-04 raisjn
+
+ bufshot -> 0.1.0-1
+
+ * add new binary bufshot for taking screenshots
+
+2021-01-20 raisjn
+
+ rmkit (requires bumping all apps):
+
+ * fix font artifacts when using large font
+ * warn when running on rM2 without rm2fb
+
+ remux:
+
+ * use ?MB for apps we don't know mem usage of
+ * idle fixes for rM2
+ * properly draw 8bit grayscale suspend screens
+ * fix touch flood to use ABS_DISTANCE=2 instead of 0
+
+2021-01-16 raisjn
+
+ rmkit:
+
+ * fix touch event handling while dragging
+
+ harmony:
+
+ * faster drawing on pen down on rM2
+
+ remux:
+
+ * add "quick back" feature
+ * add config file to configure gestures
+ * make killing xochitl harder
+ * remove three finger launch
+
+ nao:
+
+ * use built in wget when available
+
+2021-01-14 raisjn
+
+
+ simple -> 0.1.1:
+
+ * add underline to button text
+ * add widget ID implementation
+
+ remux -> 0.1.6:
+
+ * add "back" feature
+ * add /run/remux.api fifo which accepts "show", "hide" and "back" as input
+
+2021-01-10 raisjn
+
+
+ genie -> 1.1-1:
+
+ * add gesture invalidator when pen is writing
+ * fix environment in service file
+
+2021-01-07 raisjn
+
+
+ genie -> 1.0
+
+ * genie is a gesture based launcher that recognizes gestures and runs commands
+
+2021-01-5 raisjn
+
+
+ remux -> 0.1.5-1
+
+ * launch remux on 3 finger tap (much more useful on rM2)
+
+2020-12-31 raisjn
+
+
+ remux -> 0.1.4
+
+ * use remux with fix for suspend/shutdown threshold == 0
+ * use suspended.png if sleeping.png isn't available
+
+ rmkit
+
+ * update build to make src/build before building stb.o
+
+2020-12-26 raisjn
+
+ rmkit:
+
+ * update remux with fix for broken wifi on suspend
+
+ package:
+
+ * add icons for harmony, mines and nao
+
+2020-12-25 raisjn
+
+ remux:
+
+ * correctly suspend on remux for rM2
+ * add fix to remux so that koreader doesn't restart when focused
+
+2020-12-21 raisjn
+
+ harmony:
+
+ * create saved_images dir in package configure script
+
+
+2020-12-19 raisjn
+
+ remux:
+
+ * update remux with shutdown fix for rM1
+ * update to remux for better cmdline parsing
+ * update remux so LAST_ACTION defaults to now
+
+2020-12-14 raisjn
+
+ rmkit:
+
+ * update rmkit to latest version which supports rm2, release as 0.1.0
+
+ remux:
+
+ * continued rm2 support in remux
+ * fix suspend screen in remux on rm2
+
+2020-11-08 raisjn
+
+ rmkit:
+
+ * update to latest version (11.07.2020)
+
+2020-10-15 raisjn
+
+ remux:
+
+ * add memory usage analyzer to remux
+
+2020-10-08 raisjn
+
+ remux:
+
+ * make remux properly dismissable on first launch
+
+
+2020-09-30 raisjn
+
+ remux:
+
+ * read xochitl command from systemd service file
+ * use rgb565 to draw better quality suspend screen
+ * better KOReader integration
+
+2020-09-27 raisjn
+
+ remux:
+
+ * use process groups for managing programs
+
+ nao:
+
+ * add exit button to main screen
+
+2020-09-21 raisjn
+
+ remux:
+
+ * better plato interaction
+ * fixes for power management
+ * rename remux from remux.exe
+
+ nao:
+
+ * add sync, check and upgrade to main menu
+
+2020-09-14 raisjn
+
+ * split rmkit into harmony, mines, nao and simple packages
+
+2020-09-02 raisjn
+
+ * add rmkit apps: harmony, remux, mines, ...
diff --git a/package/rmkit/package b/package/rmkit/package
index 5e3637752..837cfb789 100644
--- a/package/rmkit/package
+++ b/package/rmkit/package
@@ -2,32 +2,46 @@
# Copyright (c) 2020 The Toltec Contributors
# SPDX-License-Identifier: MIT
-pkgnames=(genie harmony mines nao remux simple)
-timestamp=2021-01-12T14:03-08:00
+pkgnames=(bufshot genie harmony iago lamp mines nao remux simple)
+timestamp=2021-02-24T13:20-08:00
maintainer="raisjn "
license=MIT
image=python:v1.1
source=(
- https://github.com/rmkit-dev/rmkit/archive/3d8ba83684f76b3e4146af9f295de4615a416cb8.zip
+ https://github.com/rmkit-dev/rmkit/archive/681354803a158eca9c267b1f1976affda391bdff.zip
remux.service
genie.service
+ 2021_03_05_genie.diff
)
sha256sums=(
- 3f37bf01547395404d27df788c959895f194711e80ef26839f521d1dedc4faed
+ 6e2b1fb7fa52f6412268b1d063e9dd117d1913411fe26627c34cf3d02a836de5
+ SKIP
SKIP
SKIP
)
build() {
pip3 install okp
+ patch -p1 < 2021_03_05_genie.diff
make
}
+bufshot() {
+ pkgdesc="program for saving the framebuffer as a png"
+ url="https://github.com/rmkit-dev/rmkit/tree/master/src/bufshot"
+ pkgver=0.1.0-2
+ section="utils"
+
+ package() {
+ install -D -m 755 "$srcdir"/src/build/bufshot "$pkgdir"/opt/bin/bufshot
+ }
+}
+
genie() {
pkgdesc="Gesture engine that connects commands to gestures"
url="https://rmkit.dev/apps/genie"
- pkgver=0.1.2-3
+ pkgver=0.1.4-2
section="utils"
package() {
@@ -54,7 +68,7 @@ genie() {
harmony() {
pkgdesc="Procedural sketching app"
url="https://rmkit.dev/apps/harmony"
- pkgver=0.1.1-2
+ pkgver=0.1.2-1
section="drawing"
package() {
@@ -68,10 +82,33 @@ harmony() {
}
}
+iago() {
+ pkgdesc="overlay for drawing shapes via stroke injection"
+ url="https://rmkit.dev/apps/iago"
+ pkgver=0.1.0-1
+ section="utils"
+ depends=("lamp")
+
+ package() {
+ install -D -m 755 "$srcdir"/src/build/iago "$pkgdir"/opt/bin/iago
+ }
+}
+
+lamp() {
+ pkgdesc="config based stroke injection utility"
+ url="https://rmkit.dev/apps/lamp"
+ pkgver=0.1.0-1
+ section="utils"
+
+ package() {
+ install -D -m 755 "$srcdir"/src/build/lamp "$pkgdir"/opt/bin/lamp
+ }
+}
+
mines() {
pkgdesc="Mine detection game"
url="https://rmkit.dev/apps/minesweeper"
- pkgver=0.1.1-2
+ pkgver=0.1.2-1
section="games"
package() {
@@ -84,7 +121,7 @@ mines() {
nao() {
pkgdesc="Nao Package Manager: opkg UI built with SAS"
url="https://rmkit.dev/apps/nao"
- pkgver=0.1.1-1
+ pkgver=0.1.2-1
section="admin"
depends=(simple)
@@ -96,9 +133,9 @@ nao() {
}
remux() {
- pkgdesc="App launcher that supports multi-tasking applications"
+ pkgdesc="Launcher that supports multi-tasking applications"
url="https://rmkit.dev/apps/remux"
- pkgver=0.1.7-3
+ pkgver=0.1.8-1
section="launchers"
package() {
@@ -130,7 +167,7 @@ remux() {
simple() {
pkgdesc="Simple app script for writing scripted applications"
url="https://rmkit.dev/apps/sas"
- pkgver=0.1.2-2
+ pkgver=0.1.3-1
section="devel"
package() {
diff --git a/package/rmservewacominput/package b/package/rmservewacominput/package
index 06406a55b..6a392feb5 100644
--- a/package/rmservewacominput/package
+++ b/package/rmservewacominput/package
@@ -5,16 +5,24 @@
pkgnames=(rmservewacominput)
pkgdesc="Serve pen input on port 33333"
url=https://github.com/LinusCDE/rmWacomToMouse
-pkgver=0.2.5-9
-timestamp=2020-09-06T23:23Z
+pkgver=0.3.0-1
+timestamp=2021-03-10T18:36Z
section="utils"
maintainer="Linus K. "
license=MIT
depends=(appmarkable)
-image=base:v1.1
-source=(https://github.com/LinusCDE/rmWacomToMouse/archive/1a45d3446c8bc11de04800a702576056016875ed.zip)
-sha256sums=(4d51ff9d6b8f57fe4970b4a0adebafe3513ddeb521a2707b81a42d32f73dadb1)
+image=base:v1.4
+source=(
+ https://github.com/LinusCDE/rmWacomToMouse/archive/fd1c5454b65f456f6e890b99109e50a8f576dad1.zip
+ rmservewacominput.draft
+ rmservewacominput-gui
+)
+sha256sums=(
+ c2c15b519a8352a5b52e1b15154e4024acc423552c6cf7559c23fcb8beffcd56
+ SKIP
+ SKIP
+)
build() {
cd c_implementation
@@ -23,6 +31,7 @@ build() {
package() {
install -D -m 755 "$srcdir"/c_implementation/rmServeWacomInput "$pkgdir"/opt/bin/rmservewacominput
- install -D -m 644 "$srcdir"/oxide "$pkgdir"/opt/etc/draft/rmservewacominput
+ install -D -m 755 "$srcdir"/rmservewacominput-gui "$pkgdir"/opt/bin/rmservewacominput-gui
+ install -D -m 644 "$srcdir"/rmservewacominput.draft "$pkgdir"/opt/etc/draft/rmservewacominput.draft
install -D -m 644 "$srcdir"/icon.png "$pkgdir"/opt/etc/draft/icons/rmservewacominput.png
}
diff --git a/package/rmservewacominput/rmservewacominput-gui b/package/rmservewacominput/rmservewacominput-gui
new file mode 100755
index 000000000..f63e49daa
--- /dev/null
+++ b/package/rmservewacominput/rmservewacominput-gui
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+exec /opt/bin/appmarkable /opt/bin/rmservewacominput -n rmServeWacomInput -i /opt/etc/draft/icons/rmservewacominput.png
diff --git a/package/rmservewacominput/rmservewacominput.draft b/package/rmservewacominput/rmservewacominput.draft
new file mode 100644
index 000000000..f56df3c93
--- /dev/null
+++ b/package/rmservewacominput/rmservewacominput.draft
@@ -0,0 +1,8 @@
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+name=rmServeWacomInput
+desc=Open a server on port 33333 and serve pen input
+call=/opt/bin/rmservewacominput-gui
+term=:
+imgFile=rmservewacominput
diff --git a/package/toltec-bootstrap/entware-reenable b/package/toltec-bootstrap/entware-reenable
index 53eaf91d8..1108a67b6 100644
--- a/package/toltec-bootstrap/entware-reenable
+++ b/package/toltec-bootstrap/entware-reenable
@@ -1,6 +1,9 @@
#!/usr/bin/env bash
# Path for the systemd unit that mounts Entware to /opt
-systemd_mount_path=/lib/systemd/system/opt.mount
+systemd_opt_mount_path=/lib/systemd/system/opt.mount
+
+# Path for the systemd unit that mounts /opt/share/zoneinfo to /usr/share/zoneinfo
+systemd_timezone_mount_path=/lib/systemd/system/usr-share-zoneinfo.mount
# Path where the actual Entware distribution resides (will be mounted to /opt)
entware_path=/home/root/.entware
@@ -10,7 +13,7 @@ entware-mount() {
mkdir -p "$entware_path"
# Create systemd mount unit to mount over /opt on reboot
- cat > "$systemd_mount_path" << UNIT
+ cat > "$systemd_opt_mount_path" << UNIT
[Unit]
Description=Bind mount Entware over /opt
DefaultDependencies=no
@@ -28,7 +31,33 @@ WantedBy=local-fs.target
UNIT
systemctl daemon-reload
- systemctl enable --now opt.mount 2> /dev/null
+ systemctl enable --now "$(basename "$systemd_opt_mount_path")" 2> /dev/null
+}
+
+# Mount /opt/share/zoneinfo to /usr/share/zoneinfo
+timezone-mount() {
+ mkdir -p "$entware_path"/share/zoneinfo
+
+ # Create systemd mount unit to mount over /opt on reboot
+ cat > "$systemd_timezone_mount_path" << UNIT
+[Unit]
+Description=Bind mount /opt/share/zoneinfo over /usr/share/zoneinfo
+DefaultDependencies=no
+Conflicts=umount.target
+Before=local-fs.target umount.target
+
+[Mount]
+What=/home/root/.entware/share/zoneinfo
+Where=/usr/share/zoneinfo
+Type=none
+Options=bind
+
+[Install]
+WantedBy=local-fs.target
+UNIT
+
+ systemctl daemon-reload
+ systemctl enable --now "$(basename "$systemd_timezone_mount_path")" 2> /dev/null
}
reinstall-root() {
@@ -48,6 +77,7 @@ reinstall-root() {
main() {
entware-mount
+ timezone-mount
reinstall-root
}
diff --git a/package/toltec-bootstrap/package b/package/toltec-bootstrap/package
index 4d7814d06..8cfe2ff6b 100644
--- a/package/toltec-bootstrap/package
+++ b/package/toltec-bootstrap/package
@@ -5,9 +5,9 @@
pkgnames=(toltec-bootstrap)
pkgdesc="Toltec installation script"
url=https://toltec-dev.org/
-pkgver=0.0.1-3
+pkgver=0.0.2-1
timestamp=2021-01-15T20:15Z
-section=utils
+section="utils"
maintainer="Eeems "
license=MIT
diff --git a/package/vnsee/package b/package/vnsee/package
index c8aeb13a4..9ba6bbfbe 100644
--- a/package/vnsee/package
+++ b/package/vnsee/package
@@ -1,42 +1,27 @@
#!/usr/bin/env bash
-# Copyright (c) 2020 The Toltec Contributors
+# Copyright (c) 2021 The Toltec Contributors
# SPDX-License-Identifier: MIT
pkgnames=(vnsee)
pkgdesc="VNC client allowing you to use the device as a second screen"
url=https://github.com/matteodelabre/vnsee
-pkgver=0.3.1-1
+pkgver=0.3.1-2
timestamp=2021-01-25T12:54:25Z
section="screensharing"
maintainer="Mattéo Delabre "
license=GPL-3.0-only
+depends=(libvncclient)
+makedepends=(host:libvncserver-dev)
-image=base:v1.3
-_vnclib=LibVNCServer-0.9.13
-source=(
- "https://github.com/matteodelabre/vnsee/archive/v${pkgver%-*}.zip"
- "https://github.com/LibVNC/libvncserver/archive/$_vnclib.zip"
-)
-noextract=("$_vnclib.zip")
-sha256sums=(
- f7aa113bd72d6128800501bf53840d127fe6711119f3c8ae60419a35ed2f8583
- d209d70998a9b98f9120eeb82df7a17767796c477eaa8297e0a55856a977c54f
-)
-
-prepare() {
- bsdtar -x \
- --strip-components 1 \
- --directory "$srcdir/libvncserver" \
- --file "$srcdir/$_vnclib.zip"
-}
+image=base:v1.3.2
+source=("https://github.com/matteodelabre/vnsee/archive/3f07c04e1991c1c5ff3b5a4758aa42301bf86fae.zip")
+sha256sums=(57cef02f066ba26f0258e476339586f5c7a0f67ad31bf35cb479a362f1eba525)
build() {
- mkdir build
- cd build
- cmake .. \
- -DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_TOOLCHAIN_FILE="/usr/share/cmake/$CHOST.cmake"
- make
+ cmake -B build \
+ -DCMAKE_TOOLCHAIN_FILE="/usr/share/cmake/$CHOST.cmake" \
+ -DCMAKE_INSTALL_PREFIX="/opt"
+ cmake --build build
}
package() {
diff --git a/package/wikipedia/package b/package/wikipedia/package
new file mode 100644
index 000000000..d2cf5eb75
--- /dev/null
+++ b/package/wikipedia/package
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+pkgnames=(wikipedia)
+pkgdesc="The free encyclopedia"
+url=https://github.com/dps/remarkable-wikipedia
+pkgver=0.1.0-2
+timestamp=2021-03-11T04:50Z
+section="readers"
+maintainer="David Singleton "
+license=MIT
+
+image=qt:v1.2.2
+source=(
+ https://github.com/dps/remarkable-wikipedia/archive/eb00876ef49e7deedc127bc6c1486e3ed13aedcc.zip
+ wikipedia.draft
+ wikipedia.png
+)
+sha256sums=(
+ 9139cf41c8950126780273977b3d70f8126da8a87066db6c21845d8409ad34b2
+ SKIP
+ SKIP
+)
+
+build() {
+ sed -i 's/linux-oe-g++/linux-arm-gnueabihf-g++/' qtwikipedia.pro
+ qmake qtwikipedia.pro
+ make
+}
+
+package() {
+ install -D -m 755 "$srcdir"/qtwikipedia "$pkgdir"/opt/bin/qtwikipedia
+ install -D -m 644 -t "$pkgdir"/opt/etc/draft "$srcdir"/wikipedia.draft
+ install -D -m 644 -t "$pkgdir"/opt/etc/draft/icons "$srcdir"/wikipedia.png
+}
diff --git a/package/wikipedia/wikipedia.draft b/package/wikipedia/wikipedia.draft
new file mode 100644
index 000000000..c49ffcfb9
--- /dev/null
+++ b/package/wikipedia/wikipedia.draft
@@ -0,0 +1,8 @@
+# Copyright (c) 2021 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+name=wikipedia
+desc=The free encyclopedia
+call=/opt/bin/qtwikipedia
+term=:
+imgFile=wikipedia
\ No newline at end of file
diff --git a/package/wikipedia/wikipedia.png b/package/wikipedia/wikipedia.png
new file mode 100644
index 000000000..07746fb2e
Binary files /dev/null and b/package/wikipedia/wikipedia.png differ
diff --git a/package/wireguard/package b/package/wireguard/package
index 3a5dc9eb5..c676c8b31 100755
--- a/package/wireguard/package
+++ b/package/wireguard/package
@@ -5,13 +5,13 @@
pkgnames=(wireguard)
pkgdesc="Fast, modern, secure VPN tunnel"
url=https://www.wireguard.com
-_wireguardver=1.0.20201221
-pkgver=$_wireguardver-1
-timestamp=2020-12-21T11:54Z
+pkgver=1.0.20210219-1
+_wireguardtoolsver=1.0.20210223
+timestamp=2021-02-19T14:08Z
section=utils
maintainer="Jonah Weissman "
-license=GPL-2.0
-depends=(wireguard-tools)
+license=GPL-2.0-only
+makedepends=(build:bc build:lzop build:git)
flags=(nostrip)
_kernelrepo=https://github.com/remarkable/linux
@@ -23,49 +23,64 @@ _defconfigs=(
arch/arm/configs/zero-gravitas_defconfig
arch/arm/configs/zero-sugar_defconfig
)
-_moddirs=(
- 4.9.84-zero-gravitas
- 4.14.78
+
+image=base:v1.3.2
+source=(
+ "https://git.zx2c4.com/wireguard-linux-compat/snapshot/wireguard-linux-compat-${pkgver%-*}.tar.xz"
+ "https://git.zx2c4.com/wireguard-tools/snapshot/wireguard-tools-${_wireguardtoolsver}.tar.xz"
+)
+noextract=("wireguard-tools-${_wireguardtoolsver}.tar.xz")
+sha256sums=(
+ 99d35296b8d847a0d4db97a4dda96b464311a6354e75fe0bef6e7c4578690f00
+ 1f72da217044622d79e0bab57779e136a3df795e3761a3fc1dc0941a9055877c
)
-image=base:v1.2.1
-source=(https://git.zx2c4.com/wireguard-linux-compat/snapshot/wireguard-linux-compat-"$_wireguardver".zip)
-sha256sums=(c74cedb10c9b830d937b5575e4b7d2625a8534d2c06a80368e5530db23e69d3b)
+prepare() {
+ bsdtar -x \
+ --directory "$srcdir" \
+ --file "$srcdir/wireguard-tools-${_wireguardtoolsver}.tar.xz"
+ mv "$srcdir/wireguard-tools-${_wireguardtoolsver}" "$srcdir/wireguard-tools"
+ # the symlink at src/wg-quick/wg needs something to point to
+ touch "$srcdir/wireguard-tools/src/wg"
+}
build() {
- apt-get update
- apt-get install -y bc lzop git
+ make -C wireguard-tools/src PLATFORM=linux "CC=${CROSS_COMPILE}cc"
- # we will save the generated files in .pc,
- # so that they will not be deleted by `make mrproper`
- mkdir .pc
- git init
+ mkdir pkg
+ git init linux
for i in $(seq 0 1); do
- git fetch --depth=1 "$_kernelrepo" "${_kernelrevs[$i]}"
- git checkout -f "${_kernelrevs[$i]}"
- touch .scmversion
- cp "${_defconfigs[$i]}" .config
- echo "CONFIG_NET_FOU=m" >> .config
- make olddefconfig
- make modules
- make modules_prepare
+ (
+ cd linux
+ git fetch --depth=1 "$_kernelrepo" "${_kernelrevs[$i]}"
+ git checkout -f "${_kernelrevs[$i]}"
+ make mrproper
+ touch .scmversion
+ cp "${_defconfigs[$i]}" .config
+ echo "CONFIG_NET_FOU=m" >> .config
+ make olddefconfig
+ make net/ipv4/udp_tunnel.ko
+ make net/ipv6/ip6_udp_tunnel.ko
+ make modules_prepare
+ )
- # make wireguard.ko
- KERNELDIR=$(pwd) make -C src/
- export MOD_INSTALL_PATH=".pc/${_moddirs[$i]}"
- install -D -m 644 net/ipv4/udp_tunnel.ko \
+ make -C src/ "KERNELDIR=$(realpath linux)"
+ KERNELRELEASE=$(cat linux/include/config/kernel.release)
+ export MOD_INSTALL_PATH="pkg/$KERNELRELEASE"
+ install -D -m 644 linux/net/ipv4/udp_tunnel.ko \
"$MOD_INSTALL_PATH/kernel/net/ipv4/udp_tunnel.ko"
- install -D -m 644 net/ipv6/ip6_udp_tunnel.ko \
+ install -D -m 644 linux/net/ipv6/ip6_udp_tunnel.ko \
"$MOD_INSTALL_PATH/kernel/net/ipv6/ip6_udp_tunnel.ko"
install -D -m 644 src/wireguard.ko \
"$MOD_INSTALL_PATH/extra/wireguard.ko"
- make mrproper
done
}
package() {
+ make -C "$srcdir/wireguard-tools/src" DESTDIR="$pkgdir" WITH_WGQUICK=yes \
+ WITH_SYSTEMDUNITS=yes WITH_BASHCOMPLETION=no install
mkdir -p "$pkgdir/lib/modules"
- cp -r "$srcdir/.pc"/* "$pkgdir/lib/modules"
+ cp -r "$srcdir/pkg"/* "$pkgdir/lib/modules"
}
configure() {
diff --git a/package/zoneinfo-utils/package b/package/zoneinfo-utils/package
new file mode 100644
index 000000000..0135e119d
--- /dev/null
+++ b/package/zoneinfo-utils/package
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# Copyright (c) 2020 The Toltec Contributors
+# SPDX-License-Identifier: MIT
+
+# Inspired by https://github.com/archlinux/svntogit-packages/blob/packages/tzdata/trunk/PKGBUILD
+
+pkgnames=(zoneinfo-utils)
+pkgdesc="Utilities for interacting with zoneinfo files"
+url=https://www.iana.org/time-zones
+_tzver=2020f
+pkgver="$_tzver"-1
+timestamp=2020-05-04T06:16Z
+section=utils
+maintainer="Eeems "
+license="custom: public domain"
+depends=(zoneinfo-core)
+makedepends=(build:gawk)
+image=base:v1.3.2
+
+source=(
+ "https://www.iana.org/time-zones/repository/releases/tzcode${_tzver}.tar.gz"
+ "https://www.iana.org/time-zones/repository/releases/tzdata${_tzver}.tar.gz"
+)
+sha256sums=(
+ cfeeea2a7745164f64bd9f6d76e47916f4ac820c4434493674adbbd4324329c5
+ 121131918c3ae6dc5d40f0eb87563a2be920b71a76e2392c09519a5e4a666881
+)
+
+prepare() {
+ sed -i "s:sbin:bin:" Makefile
+}
+
+build() {
+ mkdir .x86
+ pushd .x86 > /dev/null
+
+ shopt -s extglob
+ cp -r ../* .
+ make VERSION="$_tzver"
+
+ popd > /dev/null
+
+ make VERSION="$_tzver" CC=arm-linux-gnueabihf-cc
+}
+
+package() {
+ pushd "${srcdir}" > /dev/null
+ local zic=.x86/zic
+ # install tzcode stuff
+ make DESTDIR="${pkgdir}" zic="$zic" install
+ # install license
+ install -Dm644 LICENSE "${pkgdir}"/opt/usr/share/licenses/tzdata/LICENSE
+
+ popd > /dev/null
+
+ mv "${pkgdir}"/usr/{lib,share/man} "${pkgdir}"/opt/usr
+ mv "${pkgdir}"/usr/{s,}bin "${pkgdir}"/opt
+
+ install -D -m 644 -t "$pkgdir"/opt/share/zoneinfo "$srcdir"/iso3166.tab
+ install -D -m 644 -t "$pkgdir"/opt/share/zoneinfo "$srcdir"/zone1970.tab
+
+ # cleanup
+ rm -rf "${pkgdir:?}"/{etc,usr}
+}
diff --git a/package/zshelf/package b/package/zshelf/package
index a2359e095..4c4d57ed7 100644
--- a/package/zshelf/package
+++ b/package/zshelf/package
@@ -23,7 +23,7 @@ sha256sums=(
SKIP
)
-image=qt:v1.1
+image=qt:v1.3.2
build() {
qmake zshelf.pro
make
diff --git a/scripts/bootstrap/bootstrap b/scripts/bootstrap/bootstrap
index 81562a0da..30267186d 100755
--- a/scripts/bootstrap/bootstrap
+++ b/scripts/bootstrap/bootstrap
@@ -21,8 +21,11 @@ set -eE
[[ -z $wget_path ]] && wget_path=/home/root/.local/bin/wget
# Path for the systemd unit that mounts Entware to /opt
-[[ -z $old_systemd_mount_path ]] && old_systemd_mount_path=/etc/systemd/system/opt.mount
-[[ -z $systemd_mount_path ]] && systemd_mount_path=/lib/systemd/system/opt.mount
+[[ -z $old_systemd_opt_mount_path ]] && old_systemd_opt_mount_path=/etc/systemd/system/opt.mount
+[[ -z $systemd_opt_mount_path ]] && systemd_opt_mount_path=/lib/systemd/system/opt.mount
+
+# Path for the systemd unit that mounts /opt/share/zoneinfo to /usr/share/zoneinfo
+[[ -z $systemd_timezone_mount_path ]] && systemd_timezone_mount_path=/lib/systemd/system/usr-share-zoneinfo.mount
# Path where the actual Entware distribution resides (will be mounted to /opt)
[[ -z $entware_path ]] && entware_path=/home/root/.entware
@@ -65,9 +68,15 @@ error-cleanup() {
rm -rf "$entware_path"
fi
- if [[ -f $systemd_mount_path ]]; then
- systemctl disable --now opt.mount 2> /dev/null
- rm "$systemd_mount_path"
+ if [[ -f $systemd_opt_mount_path ]]; then
+ systemctl disable --now "$(basename "$systemd_opt_mount_path")" 2> /dev/null
+ rm "$systemd_opt_mount_path"
+ systemctl daemon-reload
+ fi
+
+ if [[ -f $systemd_timezone_mount_path ]]; then
+ systemctl disable --now "$(basename "$systemd_timezone_mount_path")" 2> /dev/null
+ rm "$systemd_timezone_mount_path"
systemctl daemon-reload
fi
@@ -119,20 +128,20 @@ entware-mount() {
mkdir -p /opt
mkdir -p "$entware_path"
- if [[ -f $old_systemd_mount_path ]] && [[ ! -f $systemd_mount_path ]]; then
+ if [[ -f $old_systemd_opt_mount_path ]] && [[ ! -f $systemd_opt_mount_path ]]; then
# The user was probably using https://github.com/Evidlo/remarkable_entware
# before switching to toltec. Removing old .mount file to prevent duplicate files
log "Updating opt.mount location"
- if systemctl -q is-enabled opt.mount; then
+ if systemctl -q is-enabled "$(basename "$old_systemd_opt_mount_path")"; then
# Remove path to old file if still symlinked
- systemctl disable opt.mount
+ systemctl disable "$(basename "$old_systemd_opt_mount_path")"
fi
- rm $old_systemd_mount_path
+ rm "$old_systemd_opt_mount_path"
fi
# Create systemd mount unit to mount over /opt on reboot
- cat > "$systemd_mount_path" << UNIT
+ cat > "$systemd_opt_mount_path" << UNIT
[Unit]
Description=Bind mount Entware over /opt
DefaultDependencies=no
@@ -150,7 +159,7 @@ WantedBy=local-fs.target
UNIT
systemctl daemon-reload
- systemctl enable --now opt.mount 2> /dev/null
+ systemctl enable --now "$(basename "$systemd_opt_mount_path")" 2> /dev/null
}
# Install Entware to /opt
@@ -223,6 +232,32 @@ entware-install() {
fi
}
+# Mount /opt/share/zoneinfo to /usr/share/zoneinfo
+timezone-mount() {
+ mkdir -p "$entware_path"/share/zoneinfo
+
+ # Create systemd mount unit to mount over /opt on reboot
+ cat > "$systemd_timezone_mount_path" << UNIT
+[Unit]
+Description=Bind mount /opt/share/zoneinfo over /usr/share/zoneinfo
+DefaultDependencies=no
+Conflicts=umount.target
+Before=local-fs.target umount.target
+
+[Mount]
+What=/home/root/.entware/share/zoneinfo
+Where=/usr/share/zoneinfo
+Type=none
+Options=bind
+
+[Install]
+WantedBy=local-fs.target
+UNIT
+
+ systemctl daemon-reload
+ systemctl enable --now "$(basename "$systemd_timezone_mount_path")" 2> /dev/null
+}
+
# Add Toltec configuration to an existing Entware install
#
# Arguments: List of additional packages to install, one package per argument
@@ -335,11 +370,14 @@ main() {
else
log "Re-enabling existing Entware install"
entware-mount
+ timezone-mount
fi
else
log "Creating $entware_path and mounting to /opt"
entware-mount
entware-install
+ log "Mounting timezone info over /usr/share/zoneinfo"
+ timezone-mount
fi
toltec-install "$@"
diff --git a/scripts/package_build.py b/scripts/package_build.py
index 2479262c9..10955f3ff 100755
--- a/scripts/package_build.py
+++ b/scripts/package_build.py
@@ -6,7 +6,9 @@
import argparse
import logging
import sys
+from toltec import paths
from toltec.builder import Builder
+from toltec.repo import Repo
from toltec.util import argparse_add_verbose, LOGGING_FORMAT
parser = argparse.ArgumentParser(description=__doc__)
@@ -28,9 +30,18 @@
args = parser.parse_args()
logging.basicConfig(format=LOGGING_FORMAT, level=args.verbose)
-builder = Builder()
-if not builder.make(
- args.recipe_name, args.packages_names if args.packages_names else None
-):
+repo = Repo(paths.RECIPE_DIR, paths.REPO_DIR)
+builder = Builder(paths.WORK_DIR, paths.REPO_DIR)
+
+recipe = repo.recipes[args.recipe_name]
+packages = (
+ [recipe.packages[name] for name in args.packages_names]
+ if args.packages_names
+ else None
+)
+
+if not builder.make(recipe, packages):
sys.exit(1)
+
+repo.make_index()
diff --git a/scripts/repo_build.py b/scripts/repo_build.py
index 24a34ec9b..2696d6d67 100755
--- a/scripts/repo_build.py
+++ b/scripts/repo_build.py
@@ -5,6 +5,8 @@
import argparse
import logging
+import os
+from toltec import paths
from toltec.builder import Builder
from toltec.repo import Repo
from toltec.util import argparse_add_verbose, LOGGING_FORMAT
@@ -12,10 +14,10 @@
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
- "-n",
- "--no-fetch",
+ "-d",
+ "--diff",
action="store_true",
- help="do not fetch missing packages from the remote repository",
+ help="only keep new packages that do not exist on the remote repository",
)
argparse_add_verbose(parser)
@@ -44,13 +46,26 @@
remote = args.remote_repo if not args.local else None
logging.basicConfig(format=LOGGING_FORMAT, level=args.verbose)
-repo = Repo()
-builder = Builder()
-missing = repo.fetch_packages(remote, fetch_missing=not args.no_fetch)
+repo = Repo(paths.RECIPE_DIR, paths.REPO_DIR)
+builder = Builder(paths.WORK_DIR, paths.REPO_DIR)
+results = repo.fetch_packages(remote)
+repo.make_index()
+
+fetched = results.fetched
+missing = results.missing
+ordered_missing = repo.order_dependencies(list(missing.keys()))
+
+for recipe in ordered_missing:
+ if missing[recipe]:
+ builder.make(recipe, missing[recipe])
+ repo.make_index()
-for recipe_name, packages in missing.items():
- if packages:
- builder.make(recipe_name, packages)
+if args.diff:
+ for packages in fetched.values():
+ for package in packages:
+ filename = package.filename()
+ local_path = os.path.join(repo.repo_dir, filename)
+ os.remove(local_path)
repo.make_index()
repo.make_listing()
diff --git a/scripts/toltec/builder.py b/scripts/toltec/builder.py
index df2087029..7e6a9100e 100644
--- a/scripts/toltec/builder.py
+++ b/scripts/toltec/builder.py
@@ -3,7 +3,16 @@
"""Build recipes and create packages."""
import shutil
-from typing import Any, Deque, Iterable, MutableMapping, Optional, Tuple
+from typing import (
+ Any,
+ Deque,
+ Dict,
+ Iterable,
+ List,
+ MutableMapping,
+ Optional,
+ Tuple,
+)
from collections import deque
import re
import os
@@ -13,6 +22,7 @@
import requests
from . import bash, util, ipk, paths
from .recipe import Recipe, Package
+from .version import DependencyKind
logger = logging.getLogger(__name__)
@@ -27,15 +37,16 @@ class BuildContextAdapter(logging.LoggerAdapter):
def process(
self, msg: str, kwargs: MutableMapping[str, Any]
) -> Tuple[str, MutableMapping[str, Any]]:
+ prefix = ""
+
if "recipe" in self.extra:
- if "package" in self.extra:
- return (
- "%s (%s): %s"
- % (self.extra["package"], self.extra["recipe"], msg),
- kwargs,
- )
+ prefix += self.extra["recipe"]
+
+ if "package" in self.extra:
+ prefix += f" ({self.extra['package']})"
- return "%s: %s" % (self.extra["recipe"], msg), kwargs
+ if prefix:
+ return f"{prefix}: {msg}", kwargs
return msg, kwargs
@@ -50,12 +61,20 @@ class Builder: # pylint: disable=too-few-public-methods
IMAGE_PREFIX = "ghcr.io/toltec-dev/"
# Toltec Docker image used for generic tasks
- DEFAULT_IMAGE = "base:v1.2.2"
+ DEFAULT_IMAGE = "toolchain:v1.3.1"
- def __init__(self) -> None:
- """Create a builder helper."""
- os.makedirs(paths.WORK_DIR, exist_ok=True)
- os.makedirs(paths.REPO_DIR, exist_ok=True)
+ def __init__(self, work_dir: str, repo_dir: str) -> None:
+ """
+ Create a builder helper.
+
+ :param work_dir: directory where packages are built
+ :param repo_dir: directory where built packages are stored
+ """
+ self.work_dir = work_dir
+ os.makedirs(work_dir, exist_ok=True)
+
+ self.repo_dir = repo_dir
+ os.makedirs(repo_dir, exist_ok=True)
self.install_lib = ""
install_lib_path = os.path.join(paths.SCRIPTS_DIR, "install-lib")
@@ -65,6 +84,9 @@ def __init__(self) -> None:
if not line.strip().startswith("#"):
self.install_lib += line
+ self.context: Dict[str, str] = {}
+ self.adapter = BuildContextAdapter(logger, self.context)
+
try:
self.docker = docker.from_env()
except docker.errors.DockerException as err:
@@ -75,46 +97,26 @@ def __init__(self) -> None:
) from err
def make(
- self, recipe_name: str, packages_names: Optional[Iterable[str]] = None
+ self, recipe: Recipe, packages: Optional[Iterable[Package]] = None
) -> bool:
"""
Build a recipe and create its associated packages.
- :param recipe_name: name of the recipe to make
- :param packages_names: list of packages names of the recipe to make
+ :param recipe: recipe to make
+ :param packages: list of packages of the recipe to make
(default: all of them)
:returns: true if all packages were built correctly
"""
- recipe_dir = os.path.join(paths.RECIPE_DIR, recipe_name)
- build_dir = os.path.join(paths.WORK_DIR, recipe_name)
- recipe = Recipe.from_file(recipe_dir)
-
- context = {"recipe": recipe.name}
- adapter = BuildContextAdapter(logger, context)
-
- try:
- os.mkdir(build_dir)
- except FileExistsError:
- build_dir_rel = os.path.relpath(build_dir)
- ans = util.query_user(
- f"The build directory '{build_dir_rel}' for recipe \
-'{recipe.name}' already exists.\nWould you like to [c]ancel, [r]emove that \
-directory, or [k]eep it (not recommended)?",
- default="c",
- options=["c", "r", "k"],
- aliases={
- "cancel": "c",
- "remove": "r",
- "keep": "k",
- },
- )
-
- if ans == "c":
- return False
-
- if ans == "r":
- shutil.rmtree(build_dir)
- os.mkdir(build_dir)
+ self.context["recipe"] = recipe.name
+ build_dir = os.path.join(self.work_dir, recipe.name)
+
+ if not util.check_directory(
+ build_dir,
+ f"The build directory '{os.path.relpath(build_dir)}' for recipe \
+'{recipe.name}' already exists.\nWould you like to [c]ancel, [r]emove \
+that directory, or [k]eep it (not recommended)?",
+ ):
+ return False
src_dir = os.path.join(build_dir, "src")
os.makedirs(src_dir, exist_ok=True)
@@ -122,43 +124,32 @@ def make(
base_pkg_dir = os.path.join(build_dir, "pkg")
os.makedirs(base_pkg_dir, exist_ok=True)
- self._fetch_source(adapter, recipe, recipe_dir, src_dir)
- self._prepare(adapter, recipe, src_dir)
- self._build(adapter, recipe, src_dir)
- self._strip(adapter, recipe, src_dir)
+ self._fetch_source(recipe, src_dir)
+ self._prepare(recipe, src_dir)
+ self._build(recipe, src_dir)
+ self._strip(recipe, src_dir)
- for package_name in (
- packages_names
- if packages_names is not None
- else recipe.packages.keys()
+ for package in (
+ packages if packages is not None else recipe.packages.values()
):
- if package_name not in recipe.packages:
- raise BuildError(
- f"Package '{package_name}' does not exist in \
-recipe '{recipe.name}'"
- )
-
- assert package_name is not None
- package = recipe.packages[package_name]
- context["package"] = package_name
+ self.context["package"] = package.name
- pkg_dir = os.path.join(base_pkg_dir, package_name)
+ pkg_dir = os.path.join(base_pkg_dir, package.name)
os.makedirs(pkg_dir, exist_ok=True)
- self._package(adapter, package, src_dir, pkg_dir)
- self._archive(adapter, package, pkg_dir)
+ self._package(package, src_dir, pkg_dir)
+ self._archive(package, pkg_dir)
+ del self.context["package"]
return True
def _fetch_source(
self,
- adapter: BuildContextAdapter,
recipe: Recipe,
- recipe_dir: str,
src_dir: str,
) -> None:
"""Fetch and extract all source files required to build a recipe."""
- adapter.info("Fetching source files")
+ self.adapter.info("Fetching source files")
for source in recipe.sources:
filename = os.path.basename(source.url)
@@ -166,7 +157,7 @@ def _fetch_source(
if self.URL_REGEX.match(source.url) is None:
# Get source file from the recipe’s directory
- shutil.copy2(os.path.join(recipe_dir, source.url), local_path)
+ shutil.copy2(os.path.join(recipe.path, source.url), local_path)
else:
# Fetch source file from the network
req = requests.get(source.url)
@@ -193,22 +184,20 @@ def _fetch_source(
# Automatically extract source archives
if not source.noextract:
if not util.auto_extract(local_path, src_dir):
- adapter.debug(
+ self.adapter.debug(
"Not extracting %s (unsupported archive type)",
local_path,
)
- def _prepare(
- self, adapter: BuildContextAdapter, recipe: Recipe, src_dir: str
- ) -> None:
+ def _prepare(self, recipe: Recipe, src_dir: str) -> None:
"""Prepare source files before building."""
script = recipe.functions["prepare"]
if not script:
- adapter.info("Skipping prepare (nothing to do)")
+ self.adapter.debug("Skipping prepare (nothing to do)")
return
- adapter.info("Preparing source files")
+ self.adapter.info("Preparing source files")
logs = bash.run_script(
script=script,
variables={
@@ -218,19 +207,17 @@ def _prepare(
},
)
- self._print_logs(logs, adapter, "prepare()")
+ self._print_logs(logs, "prepare()")
- def _build(
- self, adapter: BuildContextAdapter, recipe: Recipe, src_dir: str
- ) -> None:
+ def _build(self, recipe: Recipe, src_dir: str) -> None:
"""Build artifacts for a recipe."""
script = recipe.functions["build"]
if not script:
- adapter.info("Skipping build (nothing to do)")
+ self.adapter.debug("Skipping build (nothing to do)")
return
- adapter.info("Building artifacts")
+ self.adapter.info("Building artifacts")
# Set fixed atime and mtime for all the source files
epoch = int(recipe.timestamp.timestamp())
@@ -239,7 +226,41 @@ def _build(
os.utime(filename, (epoch, epoch))
mount_src = "/src"
+ repo_src = "/repo"
uid = os.getuid()
+ pre_script: List[str] = []
+
+ # Install required dependencies
+ build_deps = []
+ host_deps = []
+
+ for dep in recipe.makedepends:
+ if dep.kind == DependencyKind.Build:
+ build_deps.append(dep.package)
+ elif dep.kind == DependencyKind.Host:
+ host_deps.append(dep.package)
+
+ if build_deps:
+ pre_script.extend(
+ (
+ "export DEBIAN_FRONTEND=noninteractive",
+ "apt-get update -qq",
+ "apt-get install -qq --no-install-recommends"
+ ' -o Dpkg::Options::="--force-confdef"'
+ ' -o Dpkg::Options::="--force-confold"'
+ " -- " + " ".join(build_deps),
+ )
+ )
+
+ if host_deps:
+ pre_script.extend(
+ (
+ "opkg update --verbosity=0 --offline-root $SYSROOT",
+ "opkg install --verbosity=0 --no-install-recommends"
+ " --offline-root $SYSROOT"
+ " -- " + " ".join(host_deps),
+ )
+ )
logs = bash.run_script_in_container(
self.docker,
@@ -249,7 +270,12 @@ def _build(
type="bind",
source=os.path.abspath(src_dir),
target=mount_src,
- )
+ ),
+ docker.types.Mount(
+ type="bind",
+ source=os.path.abspath(self.repo_dir),
+ target=repo_src,
+ ),
],
variables={
**recipe.variables,
@@ -258,6 +284,7 @@ def _build(
},
script="\n".join(
(
+ *pre_script,
f'cd "{mount_src}"',
script,
f'chown -R {uid}:{uid} "{mount_src}"',
@@ -265,17 +292,15 @@ def _build(
),
)
- self._print_logs(logs, adapter, "build()")
+ self._print_logs(logs, "build()")
- def _strip(
- self, adapter: BuildContextAdapter, recipe: Recipe, src_dir: str
- ) -> None:
+ def _strip(self, recipe: Recipe, src_dir: str) -> None:
"""Strip all debugging symbols from binaries."""
if "nostrip" in recipe.flags:
- adapter.info("Not stripping binaries (nostrip flag set)")
+ self.adapter.debug("Not stripping binaries (nostrip flag set)")
return
- adapter.info("Stripping binaries")
+ self.adapter.info("Stripping binaries")
mount_src = "/src"
logs = bash.run_script_in_container(
@@ -301,17 +326,11 @@ def _strip(
),
)
- self._print_logs(logs, adapter)
+ self._print_logs(logs)
- def _package(
- self,
- adapter: BuildContextAdapter,
- package: Package,
- src_dir: str,
- pkg_dir: str,
- ) -> None:
+ def _package(self, package: Package, src_dir: str, pkg_dir: str) -> None:
"""Make a package from a recipe’s build artifacts."""
- adapter.info("Packaging build artifacts")
+ self.adapter.info("Packaging build artifacts")
logs = bash.run_script(
script=package.functions["package"],
variables={
@@ -322,23 +341,20 @@ def _package(
},
)
- self._print_logs(logs, adapter, "package()")
-
- adapter.debug("Resulting tree:")
+ self._print_logs(logs, "package()")
+ self.adapter.debug("Resulting tree:")
for filename in util.list_tree(pkg_dir):
- adapter.debug(
+ self.adapter.debug(
" - %s",
os.path.normpath(
os.path.join("/", os.path.relpath(filename, pkg_dir))
),
)
- def _archive(
- self, adapter: BuildContextAdapter, package: Package, pkg_dir: str
- ) -> None:
+ def _archive(self, package: Package, pkg_dir: str) -> None:
"""Create an archive for a package."""
- adapter.info("Creating archive")
+ self.adapter.info("Creating archive")
ar_path = os.path.join(paths.REPO_DIR, package.filename())
# Inject Oxide-specific hook for reloading apps
@@ -425,13 +441,13 @@ def _archive(
scripts[step + "rm"] = script
- adapter.debug("Install scripts:")
+ self.adapter.debug("Install scripts:")
if scripts:
for script in sorted(scripts):
- adapter.debug(" - %s", script)
+ self.adapter.debug(" - %s", script)
else:
- adapter.debug("(none)")
+ self.adapter.debug("(none)")
epoch = int(package.parent.timestamp.timestamp())
@@ -447,10 +463,9 @@ def _archive(
# Set fixed atime and mtime for the resulting archive
os.utime(ar_path, (epoch, epoch))
- @staticmethod
def _print_logs(
+ self,
logs: bash.LogGenerator,
- adapter: BuildContextAdapter,
function_name: str = None,
max_lines_on_fail: int = 50,
) -> None:
@@ -459,7 +474,6 @@ def _print_logs(
if a ScriptError is caught.
:param logs: generator of log lines
- :param adapter: logging output
:param function_name: calling function name
:param max_lines_on_fail: number of context lines to print
in non-debug mode
@@ -467,22 +481,22 @@ def _print_logs(
log_buffer: Deque[str] = deque()
try:
for line in logs:
- if adapter.getEffectiveLevel() <= logging.DEBUG:
- adapter.debug(line)
+ if self.adapter.getEffectiveLevel() <= logging.DEBUG:
+ self.adapter.debug(line)
else:
if len(log_buffer) == max_lines_on_fail:
log_buffer.popleft()
log_buffer.append(line)
except bash.ScriptError as err:
if len(log_buffer) > 0:
- adapter.info(
+ self.adapter.info(
f"Only showing up to {max_lines_on_fail} lines of context. "
+ "Use --verbose for the full output."
)
for line in log_buffer:
- adapter.error(line)
+ self.adapter.error(line)
if function_name:
- adapter.error(f"{function_name} failed")
+ self.adapter.error(f"{function_name} failed")
raise err
diff --git a/scripts/toltec/graphlib.py b/scripts/toltec/graphlib.py
new file mode 100644
index 000000000..2a303928c
--- /dev/null
+++ b/scripts/toltec/graphlib.py
@@ -0,0 +1,271 @@
+# Copied from Python 3.9’s graphlib.py module to enable using the
+# topological sorting algorithm on earlier Python versions
+# SPDX-License-Identifier: PSF-2.0
+"""Functionality to operate with graph-like structures"""
+
+from typing import (
+ Generic,
+ List,
+ Iterable,
+ MutableMapping,
+ Mapping,
+ Optional,
+ Tuple,
+ TypeVar,
+)
+
+__all__ = ["TopologicalSorter", "CycleError"]
+
+_T = TypeVar("_T")
+_NODE_OUT = -1
+_NODE_DONE = -2
+
+
+class _NodeInfo(Generic[_T]): # pylint: disable=too-few-public-methods
+ __slots__ = "node", "npredecessors", "successors"
+
+ def __init__(self, node: _T):
+ # The node this class is augmenting.
+ self.node = node
+
+ # Number of predecessors, generally >= 0. When this value falls to
+ # 0, and is returned by get_ready(), this is set to _NODE_OUT and
+ # when the node is marked done by a call to done(), set to
+ # _NODE_DONE.
+ self.npredecessors = 0
+
+ # List of successor nodes. The list can contain duplicated elements
+ # as long as they're all reflected in the successor's npredecessors
+ # attribute).
+ self.successors: List[_T] = []
+
+
+class CycleError(ValueError):
+ """Subclass of ValueError raised by TopologicalSorter.prepare if cycles
+ exist in the working graph.
+
+ If multiple cycles exist, only one undefined choice among them will be
+ reported and included in the exception. The detected cycle can be
+ accessed via the second element in the *args* attribute of the
+ exception instance and consists in a list of nodes, such that each node
+ is, in the graph, an immediate predecessor of the next node in the
+ list. In the reported list, the first and the last node will be the
+ same, to make it clear that it is cyclic.
+ """
+
+
+class TopologicalSorter(Generic[_T]):
+ """Provides functionality to topologically sort a graph of hashable
+ nodes"""
+
+ def __init__(self, graph: Optional[Mapping[_T, Iterable[_T]]] = None):
+ self._node2info: MutableMapping[_T, _NodeInfo[_T]] = {}
+ self._ready_nodes: Optional[List[_T]] = None
+ self._npassedout = 0
+ self._nfinished = 0
+
+ if graph is not None:
+ for node, predecessors in graph.items():
+ self.add(node, *predecessors)
+
+ def _get_nodeinfo(self, node: _T) -> _NodeInfo[_T]:
+ if (result := self._node2info.get(node)) is None:
+ self._node2info[node] = result = _NodeInfo(node)
+ return result
+
+ def add(self, node: _T, *predecessors: _T) -> None:
+ """Add a new node and its predecessors to the graph.
+
+ Both the *node* and all elements in *predecessors* must be
+ hashable.
+
+ If called multiple times with the same node argument, the set of
+ dependencies will be the union of all dependencies passed in.
+
+ It is possible to add a node with no dependencies (*predecessors*
+ is not provided) as well as provide a dependency twice. If a node
+ that has not been provided before is included among *predecessors*
+ it will be automatically added to the graph with no predecessors of
+ its own.
+
+ Raises ValueError if called after "prepare".
+ """
+ if self._ready_nodes is not None:
+ raise ValueError("Nodes cannot be added after a call to prepare()")
+
+ # Create the node -> predecessor edges
+ nodeinfo = self._get_nodeinfo(node)
+ nodeinfo.npredecessors += len(predecessors)
+
+ # Create the predecessor -> node edges
+ for pred in predecessors:
+ pred_info = self._get_nodeinfo(pred)
+ pred_info.successors.append(node)
+
+ def prepare(self) -> None:
+ """Mark the graph as finished and check for cycles in the graph.
+
+ If any cycle is detected, "CycleError" will be raised, but
+ "get_ready" can still be used to obtain as many nodes as possible
+ until cycles block more progress. After a call to this function,
+ the graph cannot be modified and therefore no more nodes can be
+ added using "add".
+ """
+ if self._ready_nodes is not None:
+ raise ValueError("cannot prepare() more than once")
+
+ self._ready_nodes = [
+ i.node for i in self._node2info.values() if i.npredecessors == 0
+ ]
+ # ready_nodes is set before we look for cycles on purpose:
+ # if the user wants to catch the CycleError, that's fine,
+ # they can continue using the instance to grab as many
+ # nodes as possible before cycles block more progress
+ cycle = self._find_cycle()
+ if cycle:
+ raise CycleError("nodes are in a cycle", cycle)
+
+ def get_ready(self) -> Tuple[_T, ...]:
+ """Return a tuple of all the nodes that are ready.
+
+ Initially it returns all nodes with no predecessors; once those are
+ marked as processed by calling "done", further calls will return
+ all new nodes that have all their predecessors already processed.
+ Once no more progress can be made, empty tuples are returned.
+
+ Raises ValueError if called without calling "prepare" previously.
+ """
+ if self._ready_nodes is None:
+ raise ValueError("prepare() must be called first")
+
+ # Get the nodes that are ready and mark them
+ result = tuple(self._ready_nodes)
+ n2i = self._node2info
+ for node in result:
+ n2i[node].npredecessors = _NODE_OUT
+
+ # Clean the list of nodes that are ready and update
+ # the counter of nodes that we have returned.
+ self._ready_nodes.clear()
+ self._npassedout += len(result)
+
+ return result
+
+ def is_active(self) -> bool:
+ """Return ``True`` if more progress can be made and ``False``
+ otherwise.
+
+ Progress can be made if cycles do not block the resolution and
+ either there are still nodes ready that haven't yet been returned
+ by "get_ready" or the number of nodes marked "done" is less than
+ the number that have been returned by "get_ready".
+
+ Raises ValueError if called without calling "prepare" previously.
+ """
+ if self._ready_nodes is None:
+ raise ValueError("prepare() must be called first")
+ return self._nfinished < self._npassedout or bool(self._ready_nodes)
+
+ def __bool__(self) -> bool:
+ return self.is_active()
+
+ def done(self, *nodes: _T) -> None:
+ """Marks a set of nodes returned by "get_ready" as processed.
+
+ This method unblocks any successor of each node in *nodes* for
+ being returned in the future by a call to "get_ready".
+
+ Raises :exec:`ValueError` if any node in *nodes* has already been
+ marked as processed by a previous call to this method, if a node
+ was not added to the graph by using "add" or if called without
+ calling "prepare" previously or if node has not yet been returned
+ by "get_ready".
+ """
+
+ if self._ready_nodes is None:
+ raise ValueError("prepare() must be called first")
+
+ n2i = self._node2info
+
+ for node in nodes:
+ # Check if we know about this node (it was added previously
+ # using add()
+ if (nodeinfo := n2i.get(node)) is None:
+ raise ValueError(f"node {node!r} was not added using add()")
+
+ # If the node has not being returned (marked as ready)
+ # previously, inform the user.
+ stat = nodeinfo.npredecessors
+ if stat != _NODE_OUT:
+ if stat >= 0:
+ raise ValueError(
+ f"node {node!r} was not passed out (still not ready)"
+ )
+ if stat == _NODE_DONE:
+ raise ValueError(f"node {node!r} was already marked done")
+ assert False, f"node {node!r}: unknown status {stat}"
+
+ # Mark the node as processed
+ nodeinfo.npredecessors = _NODE_DONE
+
+ # Go to all the successors and reduce the number of
+ # predecessors, collecting all the ones that are ready to be
+ # returned in the next get_ready() call.
+ for successor in nodeinfo.successors:
+ successor_info = n2i[successor]
+ successor_info.npredecessors -= 1
+ if successor_info.npredecessors == 0:
+ self._ready_nodes.append(successor)
+ self._nfinished += 1
+
+ def _find_cycle(self) -> Optional[List[_T]]:
+ n2i = self._node2info
+ stack: List[_T] = []
+ itstack = []
+ seen = set()
+ node2stacki: MutableMapping[_T, int] = {}
+
+ for node in n2i:
+ if node in seen:
+ continue
+
+ while True:
+ if node in seen:
+ # If we have seen already the node and is in the
+ # current stack we have found a cycle.
+ if node in node2stacki:
+ return stack[node2stacki[node] :] + [node]
+ # else go on to get next successor
+ else:
+ seen.add(node)
+ itstack.append(iter(n2i[node].successors).__next__)
+ node2stacki[node] = len(stack)
+ stack.append(node)
+
+ # Backtrack to the topmost stack entry with
+ # at least another successor.
+ while stack:
+ try:
+ node = itstack[-1]()
+ break
+ except StopIteration:
+ del node2stacki[stack.pop()]
+ itstack.pop()
+ else:
+ break
+ return None
+
+ def static_order(self) -> Iterable[_T]:
+ """Returns an iterable of nodes in a topological order.
+
+ The particular order that is returned may depend on the specific
+ order in which the items were inserted in the graph.
+
+ Using this method does not require to call "prepare" or "done". If
+ any cycle is detected, :exc:`CycleError` will be raised.
+ """
+ self.prepare()
+ while self.is_active():
+ node_group = self.get_ready()
+ yield from node_group
+ self.done(*node_group)
diff --git a/scripts/toltec/recipe.py b/scripts/toltec/recipe.py
index 888ecdca9..b8ab5a195 100644
--- a/scripts/toltec/recipe.py
+++ b/scripts/toltec/recipe.py
@@ -14,7 +14,8 @@
import os
import textwrap
import dateutil.parser
-from . import bash, version
+from .version import Version, Dependency, DependencyKind
+from . import bash
class RecipeError(Exception):
@@ -33,15 +34,29 @@ class Source:
class Recipe: # pylint:disable=too-many-instance-attributes,disable=too-few-public-methods
"""Load recipes."""
- def __init__(self, name: str, definition: str):
+ @staticmethod
+ def from_file(path: str) -> "Recipe":
+ """
+ Load a recipe from its directory.
+
+ :param path: path to the directory containing the recipe definition
+ :returns: loaded recipe
+ """
+ name = os.path.basename(path)
+ with open(os.path.join(path, "package"), "r") as recipe:
+ return Recipe(name, path, recipe.read())
+
+ def __init__(self, name: str, path: str, definition: str):
"""
Load a recipe from a Bash source.
:param name: name of the recipe
+ :param path: path to the directory containing the recipe definition
:param definition: source string of the recipe
:raises RecipeError: if the recipe contains an error
"""
self.name = name
+ self.path = path
variables, functions = bash.get_declarations(definition)
# Original declarations of standard fields and functions
@@ -64,8 +79,7 @@ def _load_fields(self, variables: bash.Variables) -> None:
self.timestamp = dateutil.parser.isoparse(timestamp_str)
except ValueError as err:
raise RecipeError(
- "Field 'timestamp' does not contain a \
-valid ISO-8601 date"
+ "Field 'timestamp' does not contain a valid ISO-8601 date"
) from err
self.maintainer = _pop_field_string(variables, "maintainer")
@@ -88,11 +102,20 @@ def _load_fields(self, variables: bash.Variables) -> None:
if len(sources) != len(sha256sums):
raise RecipeError(
- f"Expected the same number of sources \
-and checksums, got {len(sources)} source(s) and \
-{len(sha256sums)} checksum(s)"
+ f"Expected the same number of sources and checksums, got \
+{len(sources)} source(s) and {len(sha256sums)} checksum(s)"
)
+ depends_raw = _pop_field_indexed(variables, "depends", [])
+ variables["depends"] = depends_raw
+
+ makedepends_raw = _pop_field_indexed(variables, "makedepends", [])
+ self.variables["makedepends"] = makedepends_raw
+
+ self.makedepends = [
+ Dependency.parse(dep or "") for dep in depends_raw + makedepends_raw
+ ]
+
self.sources = []
for source, checksum in zip(sources, sha256sums):
@@ -108,14 +131,14 @@ def _load_functions(self, functions: bash.Functions) -> None:
"""Parse and check standard functions."""
if self.image and "build" not in functions:
raise RecipeError(
- "Missing build() function for a recipe \
-which declares a build image"
+ "Missing build() function for a recipe which declares a \
+build image"
)
if not self.image and "build" in functions:
raise RecipeError(
- "Missing image declaration for a recipe \
-which has a build() step"
+ "Missing image declaration for a recipe which has a \
+build() step"
)
self.functions["prepare"] = functions.pop("prepare", "")
@@ -141,8 +164,8 @@ def _load_packages(
for pkg_name in pkgnames:
if pkg_name not in functions:
raise RecipeError(
- "Missing required function \
-{pkg_name}() for corresponding package"
+ "Missing required function {pkg_name}() for \
+corresponding package"
)
pkg_def = functions.pop(pkg_name)
@@ -161,13 +184,6 @@ def _load_packages(
for pkg_name, (pkg_vars, pkg_funcs) in pkg_decls.items():
self.packages[pkg_name] = Package(self, pkg_vars, pkg_funcs)
- @staticmethod
- def from_file(path: str) -> "Recipe":
- """Load a recipe from a file."""
- name = os.path.basename(path)
- with open(os.path.join(path, "package"), "r") as recipe:
- return Recipe(name, recipe.read())
-
class Package: # pylint:disable=too-many-instance-attributes
"""Load packages."""
@@ -203,7 +219,7 @@ def _load_fields(self, variables: bash.Variables) -> None:
pkgver_str = _pop_field_string(variables, "pkgver")
self.variables["pkgver"] = pkgver_str
- self.version = version.Version.parse(pkgver_str)
+ self.version = Version.parse(pkgver_str)
self.arch = _pop_field_string(variables, "arch", "armv7-3.2")
self.variables["arch"] = self.arch
@@ -220,18 +236,39 @@ def _load_fields(self, variables: bash.Variables) -> None:
self.license = _pop_field_string(variables, "license")
self.variables["license"] = self.license
- self.depends = _pop_field_indexed(variables, "depends", [])
- self.variables["depends"] = self.depends
+ depends_raw = _pop_field_indexed(variables, "depends", [])
+ self.variables["depends"] = depends_raw
+ self.depends = []
+
+ for dep_raw in depends_raw:
+ dep = Dependency.parse(dep_raw or "")
+
+ if dep.kind != DependencyKind.Host:
+ raise RecipeError(
+ "Only host packages are supported in the 'depends' field"
+ )
+
+ self.depends.append(dep)
+
+ conflicts_raw = _pop_field_indexed(variables, "conflicts", [])
+ self.variables["conflicts"] = conflicts_raw
+ self.conflicts = []
+
+ for conflict_raw in conflicts_raw:
+ conflict = Dependency.parse(conflict_raw or "")
+
+ if dep.kind != DependencyKind.Host:
+ raise RecipeError(
+ "Only host packages are supported in the 'conflicts' field"
+ )
- self.conflicts = _pop_field_indexed(variables, "conflicts", [])
- self.variables["conflicts"] = self.conflicts
+ self.conflicts.append(conflict)
def _load_functions(self, functions: bash.Functions) -> None:
"""Parse and check standard functions."""
if "package" not in functions:
raise RecipeError(
- f"Missing required function package() \
-for package {self.name}"
+ f"Missing required function package() for package {self.name}"
)
self.functions["package"] = functions.pop("package")
@@ -291,14 +328,14 @@ def control_fields(self) -> str:
if self.depends:
control += (
"Depends: "
- + ", ".join(item for item in self.depends if item)
+ + ", ".join(dep.to_debian() for dep in self.depends if dep)
+ "\n"
)
if self.conflicts:
control += (
"Conflicts: "
- + ", ".join(item for item in self.conflicts if item)
+ + ", ".join(dep.to_debian() for dep in self.conflicts if dep)
+ "\n"
)
diff --git a/scripts/toltec/repo.py b/scripts/toltec/repo.py
index ecc0a9418..2e585be4b 100644
--- a/scripts/toltec/repo.py
+++ b/scripts/toltec/repo.py
@@ -4,100 +4,145 @@
Build the package repository.
"""
+from collections import namedtuple
from datetime import datetime
import gzip
import itertools
import logging
import os
-from typing import Dict, List, Optional
+from typing import Dict, Iterable, List, Optional
import requests
-from .recipe import Recipe
+from .graphlib import TopologicalSorter
+from .recipe import Package, Recipe
from .util import file_sha256, HTTP_DATE_FORMAT
-from . import paths, templating
+from .version import DependencyKind
+from . import templating
logger = logging.getLogger(__name__)
+GroupedPackages = Dict[Recipe, List[Package]]
+FetchedMissing = namedtuple("FetchedMissing", ["fetched", "missing"])
class Repo:
"""Repository of Toltec packages."""
- def __init__(self) -> None:
- """Initialize the package repository."""
+ def __init__(self, recipe_dir: str, repo_dir: str) -> None:
+ """
+ Initialize the package repository.
+
+ :param recipe_dir: directory where recipe definitions are stored
+ :param repo_dir: directory where built packages are stored
+ """
+ self.recipe_dir = recipe_dir
+ self.repo_dir = repo_dir
self.recipes = {}
- for name in os.listdir(paths.RECIPE_DIR):
+ for name in os.listdir(self.recipe_dir):
if name[0] != ".":
self.recipes[name] = Recipe.from_file(
- os.path.join(paths.RECIPE_DIR, name)
+ os.path.join(self.recipe_dir, name)
)
- def fetch_packages(
- self, remote: Optional[str], fetch_missing: bool
- ) -> Dict[str, List[str]]:
+ def fetch_packages(self, remote: Optional[str]) -> FetchedMissing:
"""
- Fetch missing packages.
+ Fetch locally missing packages from a remote server and report which
+ packages are missing from the remote and need to be built locally.
+
+ If `remote` is None, no packages are fetched from the network and all
+ the packages that are not in the local repo will be considered missing.
:param remote: remote server from which to check for existing packages
- :param fetch_missing: pass true to fetch missing packages from remote
- :returns: missing packages grouped by parent recipe
+ :returns: tuple containing fetched and missing packages grouped by
+ their parent recipe
"""
logger.info("Scanning for missing packages")
- missing: Dict[str, List[str]] = {}
+ fetched: GroupedPackages = {}
+ missing: GroupedPackages = {}
for recipe in self.recipes.values():
- missing[recipe.name] = []
+ fetched[recipe] = []
+ missing[recipe] = []
for package in recipe.packages.values():
filename = package.filename()
- local_path = os.path.join(paths.REPO_DIR, filename)
+ local_path = os.path.join(self.repo_dir, filename)
if os.path.isfile(local_path):
continue
if remote is not None:
remote_path = os.path.join(remote, filename)
+ req = requests.get(remote_path)
- if fetch_missing:
- req = requests.get(remote_path)
+ if req.status_code == 200:
+ with open(local_path, "wb") as local:
+ for chunk in req.iter_content(chunk_size=1024):
+ local.write(chunk)
- if req.status_code == 200:
- with open(local_path, "wb") as local:
- for chunk in req.iter_content(chunk_size=1024):
- local.write(chunk)
+ last_modified = int(
+ datetime.strptime(
+ req.headers["Last-Modified"],
+ HTTP_DATE_FORMAT,
+ ).timestamp()
+ )
- last_modified = int(
- datetime.strptime(
- req.headers["Last-Modified"],
- HTTP_DATE_FORMAT,
- ).timestamp()
- )
-
- os.utime(local_path, (last_modified, last_modified))
- continue
- else:
- req = requests.head(remote_path)
- if req.status_code == 200:
- continue
+ os.utime(local_path, (last_modified, last_modified))
+ fetched[recipe].append(package)
+ continue
logger.info(
"Package %s (%s) is missing", package.pkgid(), recipe.name
)
- missing[recipe.name].append(package.name)
+ missing[recipe].append(package)
+
+ return FetchedMissing(fetched=fetched, missing=missing)
+
+ @staticmethod
+ def order_dependencies(recipes: List[Recipe]) -> Iterable[Recipe]:
+ """
+ Order a list of recipes so that all recipes that a recipe needs
+ come before that recipe in the list.
+
+ :param recipes: list of recipes to order
+ :returns: ordered list of recipes
+ :raises graphlib.CycleError: if a circular dependency exists
+ """
+ # See
+ toposort: TopologicalSorter[ # pylint:disable=unsubscriptable-object
+ Recipe
+ ] = TopologicalSorter()
+ parent_recipes = {}
+
+ for recipe in recipes:
+ for package in recipe.packages.values():
+ parent_recipes[package.name] = recipe
+
+ for recipe in recipes:
+ deps = []
+
+ for dep in recipe.makedepends:
+ if (
+ dep.kind == DependencyKind.Host
+ and dep.package in parent_recipes
+ ):
+ deps.append(parent_recipes[dep.package])
+
+ toposort.add(recipe, *deps)
- return missing
+ return toposort.static_order()
def make_index(self) -> None:
"""Generate index files for all the packages in the repo."""
logger.info("Generating package index")
- index_path = os.path.join(paths.REPO_DIR, "Packages")
- index_gzip_path = os.path.join(paths.REPO_DIR, "Packages.gz")
+ index_path = os.path.join(self.repo_dir, "Packages")
+ index_gzip_path = os.path.join(self.repo_dir, "Packages.gz")
with open(index_path, "w") as index_file:
with gzip.open(index_gzip_path, "wt") as index_gzip_file:
for recipe in self.recipes.values():
for package in recipe.packages.values():
filename = package.filename()
- local_path = os.path.join(paths.REPO_DIR, filename)
+ local_path = os.path.join(self.repo_dir, filename)
if not os.path.isfile(local_path):
continue
@@ -129,7 +174,7 @@ def make_listing(self) -> None:
)
)
- listing_path = os.path.join(paths.REPO_DIR, "index.html")
+ listing_path = os.path.join(self.repo_dir, "index.html")
template = templating.env.get_template("listing.html")
with open(listing_path, "w") as listing_file:
diff --git a/scripts/toltec/templates/listing.html b/scripts/toltec/templates/listing.html
index 4f9673318..eca4eb499 100644
--- a/scripts/toltec/templates/listing.html
+++ b/scripts/toltec/templates/listing.html
@@ -7,7 +7,7 @@