From 3187bb550269f280a0ecef1e7498c75ba46a0453 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lopes" Date: Mon, 13 Apr 2026 16:15:46 +0100 Subject: [PATCH] init! --- .gitea/scripts/commit-update-main.sh | 36 +++++++++++++ .gitea/scripts/update-appimage-nix.sh | 72 +++++++++++++++++++++++++ .gitea/workflows/handy-update.yml | 44 +++++++++++++++ .gitea/workflows/helium-update.yml | 44 +++++++++++++++ .gitea/workflows/t3code-update.yml | 44 +++++++++++++++ .gitea/workflows/zen-browser-update.yml | 44 +++++++++++++++ README.md | 21 ++++++++ flake.lock | 64 ++++++++++++++++++++++ flake.nix | 17 ++++++ modules/pkgs/handy.nix | 29 ++++++++++ modules/pkgs/helium.nix | 22 ++++++++ modules/pkgs/t3code.nix | 37 +++++++++++++ modules/pkgs/zen-browser.nix | 41 ++++++++++++++ modules/systems.nix | 6 +++ 14 files changed, 521 insertions(+) create mode 100755 .gitea/scripts/commit-update-main.sh create mode 100755 .gitea/scripts/update-appimage-nix.sh create mode 100644 .gitea/workflows/handy-update.yml create mode 100644 .gitea/workflows/helium-update.yml create mode 100644 .gitea/workflows/t3code-update.yml create mode 100644 .gitea/workflows/zen-browser-update.yml create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 modules/pkgs/handy.nix create mode 100644 modules/pkgs/helium.nix create mode 100644 modules/pkgs/t3code.nix create mode 100644 modules/pkgs/zen-browser.nix create mode 100644 modules/systems.nix diff --git a/.gitea/scripts/commit-update-main.sh b/.gitea/scripts/commit-update-main.sh new file mode 100755 index 0000000..065d410 --- /dev/null +++ b/.gitea/scripts/commit-update-main.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${FILE:?FILE is required}" +: "${COMMIT_MESSAGE:?COMMIT_MESSAGE is required}" + +git config user.name "gitea actions" +git config user.email "actions@localhost" + +# schedule runs can checkout a detached HEAD, so create a throwaway branch +branch="automation/update-$(date +%s)" +git switch -C "$branch" + +git add "$FILE" + +if git diff --cached --quiet; then + echo "No staged changes for ${FILE}; skipping commit" + exit 0 +fi + +git commit -m "$COMMIT_MESSAGE" + +for attempt in 1 2 3 4 5; do + if git push origin HEAD:main; then + echo "Pushed to main" + exit 0 + fi + + echo "Push failed (attempt ${attempt}); rebasing on origin/main and retrying" + git fetch origin main + git rebase origin/main + sleep 2 +done + +echo "Failed to push update after retries" +exit 1 diff --git a/.gitea/scripts/update-appimage-nix.sh b/.gitea/scripts/update-appimage-nix.sh new file mode 100755 index 0000000..72e3752 --- /dev/null +++ b/.gitea/scripts/update-appimage-nix.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${FILE:?FILE is required}" +: "${LATEST_RELEASE_URL:?LATEST_RELEASE_URL is required}" +: "${DOWNLOAD_URL_TEMPLATE:?DOWNLOAD_URL_TEMPLATE is required}" + +if command -v python >/dev/null 2>&1; then + PYTHON_BIN=python +elif command -v python3 >/dev/null 2>&1; then + PYTHON_BIN=python3 +else + echo "python is required but was not found" + exit 1 +fi + +version_strip_prefix="${LATEST_VERSION_STRIP_PREFIX:-v}" +release_tag_template="${RELEASE_TAG_TEMPLATE:-{version}}" +release_tag_template="${release_tag_template//$'\r'/}" + +current_version=$($PYTHON_BIN - <<'PY' +import re +import os +p=os.environ["FILE"] +s=open(p).read() +m=re.search(r'version\s*=\s*"([^"]+)";', s) +print(m.group(1) if m else "") +PY +) + +latest_version=$(curl -fsSLI -o /dev/null -w '%{url_effective}' "$LATEST_RELEASE_URL" \ + | sed -E 's#.*/##') + +if [ -n "$version_strip_prefix" ]; then + latest_version="${latest_version#${version_strip_prefix}}" +fi + +echo "current=$current_version" +echo "latest=$latest_version" + +if [ -z "$latest_version" ] || [ "$latest_version" = "$current_version" ]; then + echo "updated=false" >> "$GITHUB_OUTPUT" + exit 0 +fi + +download_url="${DOWNLOAD_URL_TEMPLATE//\{version\}/$latest_version}" +new_hash=$(nix store prefetch-file --json "$download_url" | "$PYTHON_BIN" -c 'import json,sys; print(json.load(sys.stdin)["hash"])') + +export LATEST_VERSION="$latest_version" +export NEW_HASH="$new_hash" + +"$PYTHON_BIN" - <<'PY' +import os +import re +p=os.environ["FILE"] +s=open(p).read() +s=re.sub(r'version\s*=\s*"[^"]+"', f'version = "{os.environ["LATEST_VERSION"]}"', s, count=1) +s=re.sub(r'hash\s*=\s*"[^"]+"', f'hash = "{os.environ["NEW_HASH"]}"', s, count=1) +open(p,"w").write(s) +PY + +release_tag="${release_tag_template//\{version\}/$latest_version}" +release_tag="${release_tag#\{}" +release_tag="${release_tag%\}}" +release_tag="${release_tag#\'}" +release_tag="${release_tag%\'}" +release_url="${LATEST_RELEASE_URL%/latest}/tag/${release_tag}" + +echo "updated=true" >> "$GITHUB_OUTPUT" +echo "version=$latest_version" >> "$GITHUB_OUTPUT" +echo "previous_version=$current_version" >> "$GITHUB_OUTPUT" +echo "release_url=$release_url" >> "$GITHUB_OUTPUT" diff --git a/.gitea/workflows/handy-update.yml b/.gitea/workflows/handy-update.yml new file mode 100644 index 0000000..341122c --- /dev/null +++ b/.gitea/workflows/handy-update.yml @@ -0,0 +1,44 @@ +name: handy update + +on: + schedule: + - cron: "10 3 * * *" # UTC + workflow_dispatch: + +jobs: + update-handy: + runs-on: ubuntu-latest + concurrency: + group: handy-update + cancel-in-progress: false + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: install nix + uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: check latest handy release and update file + id: update + env: + FILE: modules/pkgs/handy.nix + LATEST_RELEASE_URL: https://github.com/cjpais/Handy/releases/latest + DOWNLOAD_URL_TEMPLATE: https://github.com/cjpais/Handy/releases/download/v{version}/Handy_{version}_amd64.AppImage + RELEASE_TAG_TEMPLATE: v{version} + shell: bash + run: bash .gitea/scripts/update-appimage-nix.sh + + - name: commit and push to main + if: steps.update.outputs.updated == 'true' + shell: bash + run: | + set -euo pipefail + version="${{ steps.update.outputs.version }}" + + FILE="modules/pkgs/handy.nix" \ + COMMIT_MESSAGE="update handy to ${version}" \ + bash .gitea/scripts/commit-update-main.sh diff --git a/.gitea/workflows/helium-update.yml b/.gitea/workflows/helium-update.yml new file mode 100644 index 0000000..aae93d5 --- /dev/null +++ b/.gitea/workflows/helium-update.yml @@ -0,0 +1,44 @@ +name: helium update + +on: + schedule: + - cron: "0 3 * * *" # UTC + workflow_dispatch: + +jobs: + update-helium: + runs-on: ubuntu-latest + concurrency: + group: helium-update + cancel-in-progress: false + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: install nix + uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: check latest helium release and update file + id: update + env: + FILE: modules/pkgs/helium.nix + LATEST_RELEASE_URL: https://github.com/imputnet/helium-linux/releases/latest + DOWNLOAD_URL_TEMPLATE: https://github.com/imputnet/helium-linux/releases/download/{version}/helium-{version}-x86_64.AppImage + RELEASE_TAG_TEMPLATE: '{version}' + shell: bash + run: bash .gitea/scripts/update-appimage-nix.sh + + - name: commit and push to main + if: steps.update.outputs.updated == 'true' + shell: bash + run: | + set -euo pipefail + version="${{ steps.update.outputs.version }}" + + FILE="modules/pkgs/helium.nix" \ + COMMIT_MESSAGE="update helium to ${version}" \ + bash .gitea/scripts/commit-update-main.sh diff --git a/.gitea/workflows/t3code-update.yml b/.gitea/workflows/t3code-update.yml new file mode 100644 index 0000000..d6afe2a --- /dev/null +++ b/.gitea/workflows/t3code-update.yml @@ -0,0 +1,44 @@ +name: t3code update + +on: + schedule: + - cron: "30 3 * * *" # UTC + workflow_dispatch: + +jobs: + update-t3code: + runs-on: ubuntu-latest + concurrency: + group: t3code-update + cancel-in-progress: false + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: install nix + uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: check latest t3code release and update file + id: update + env: + FILE: modules/pkgs/t3code.nix + LATEST_RELEASE_URL: https://github.com/pingdotgg/t3code/releases/latest + DOWNLOAD_URL_TEMPLATE: https://github.com/pingdotgg/t3code/releases/download/v{version}/T3-Code-{version}-x86_64.AppImage + RELEASE_TAG_TEMPLATE: v{version} + shell: bash + run: bash .gitea/scripts/update-appimage-nix.sh + + - name: commit and push to main + if: steps.update.outputs.updated == 'true' + shell: bash + run: | + set -euo pipefail + version="${{ steps.update.outputs.version }}" + + FILE="modules/pkgs/t3code.nix" \ + COMMIT_MESSAGE="update t3code to ${version}" \ + bash .gitea/scripts/commit-update-main.sh diff --git a/.gitea/workflows/zen-browser-update.yml b/.gitea/workflows/zen-browser-update.yml new file mode 100644 index 0000000..7c81c41 --- /dev/null +++ b/.gitea/workflows/zen-browser-update.yml @@ -0,0 +1,44 @@ +name: zen browser update + +on: + schedule: + - cron: "20 3 * * *" # UTC + workflow_dispatch: + +jobs: + update-zen-browser: + runs-on: ubuntu-latest + concurrency: + group: zen-browser-update + cancel-in-progress: false + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: install nix + uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: check latest zen browser release and update file + id: update + env: + FILE: modules/pkgs/zen-browser.nix + LATEST_RELEASE_URL: https://github.com/zen-browser/desktop/releases/latest + DOWNLOAD_URL_TEMPLATE: https://github.com/zen-browser/desktop/releases/download/{version}/zen-x86_64.AppImage + RELEASE_TAG_TEMPLATE: '{version}' + shell: bash + run: bash .gitea/scripts/update-appimage-nix.sh + + - name: commit and push to main + if: steps.update.outputs.updated == 'true' + shell: bash + run: | + set -euo pipefail + version="${{ steps.update.outputs.version }}" + + FILE="modules/pkgs/zen-browser.nix" \ + COMMIT_MESSAGE="update zen browser to ${version}" \ + bash .gitea/scripts/commit-update-main.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4586d9 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# nix-pkgs + +Small Nix flake with personal desktop packages (mostly AppImages) that are auto-updated by Gitea Actions. + +## packages + +- `handy` +- `helium` +- `t3code` +- `zen-browser` + +## automation + +Each package has its own daily workflow and pushes directly to `main` when a new upstream release is found. + +Schedules (UTC): + +- 03:00 — helium +- 03:10 — handy +- 03:20 — zen-browser +- 03:30 — t3code diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..458e4ca --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775087534, + "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "import-tree": { + "locked": { + "lastModified": 1773693634, + "narHash": "sha256-BtZ2dtkBdSUnFPPFc+n0kcMbgaTxzFNPv2iaO326Ffg=", + "owner": "vic", + "repo": "import-tree", + "rev": "c41e7d58045f9057880b0d85e1152d6a4430dbf1", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "import-tree", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1775710090, + "narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4c1018dae018162ec878d42fec712642d214fdfa", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "import-tree": "import-tree", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a331414 --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + + import-tree.url = "github:vic/import-tree"; + }; + + outputs = + inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } + (inputs.import-tree ./modules); +} diff --git a/modules/pkgs/handy.nix b/modules/pkgs/handy.nix new file mode 100644 index 0000000..4d646a1 --- /dev/null +++ b/modules/pkgs/handy.nix @@ -0,0 +1,29 @@ +{...}: { + perSystem = {pkgs, ...}: { + packages.handy = pkgs.appimageTools.wrapType2 rec { + pname = "handy"; + version = "0.8.0"; + + src = pkgs.fetchurl { + url = "https://github.com/cjpais/Handy/releases/download/v${version}/Handy_${version}_amd64.AppImage"; + hash = "sha256-PLcssfd6iMx51mglAJ7D4+67HFazwfhJMImgU9WiNDk="; + }; + + extraInstallCommands = let + contents = pkgs.appimageTools.extract {inherit pname version src;}; + in '' + desktop_file=$(find ${contents} -name "*.desktop" | head -n1) + if [ -n "$desktop_file" ]; then + install -m 444 -D "$desktop_file" "$out/share/applications/${pname}.desktop" + substituteInPlace "$out/share/applications/${pname}.desktop" \ + --replace 'Exec=AppRun' 'Exec=${pname}' || true + sed -i -E 's|^Exec=.*$|Exec=${pname}|g' "$out/share/applications/${pname}.desktop" || true + fi + + if [ -d ${contents}/usr/share/icons ]; then + cp -r ${contents}/usr/share/icons $out/share + fi + ''; + }; + }; +} diff --git a/modules/pkgs/helium.nix b/modules/pkgs/helium.nix new file mode 100644 index 0000000..9f95d07 --- /dev/null +++ b/modules/pkgs/helium.nix @@ -0,0 +1,22 @@ +{ ... }: { + perSystem = { pkgs, ... }: { + packages.helium = pkgs.appimageTools.wrapType2 rec { + pname = "helium"; + version = "0.10.6.1"; + + src = pkgs.fetchurl { + url = "https://github.com/imputnet/helium-linux/releases/download/${version}/${pname}-${version}-x86_64.AppImage"; + hash = "sha256-6xqNRaP3aqitEseexRVEEjKkJClC0j1HHZoRGQanhSk="; + }; + + extraInstallCommands = let + contents = pkgs.appimageTools.extract { inherit pname version src; }; + in '' + install -m 444 -D ${contents}/${pname}.desktop -t $out/share/applications + substituteInPlace $out/share/applications/${pname}.desktop \ + --replace 'Exec=AppRun' 'Exec=${pname}' + cp -r ${contents}/usr/share/icons $out/share + ''; + }; + }; +} diff --git a/modules/pkgs/t3code.nix b/modules/pkgs/t3code.nix new file mode 100644 index 0000000..623cf66 --- /dev/null +++ b/modules/pkgs/t3code.nix @@ -0,0 +1,37 @@ +{lib, ...}: { + perSystem = {pkgs, ...}: { + packages.t3code = pkgs.appimageTools.wrapType2 rec { + pname = "t3code"; + version = "0.0.13"; + + src = pkgs.fetchurl { + url = "https://github.com/pingdotgg/t3code/releases/download/v${version}/T3-Code-${version}-x86_64.AppImage"; + hash = "sha256-oHKIh+aHsbGVHEoLLjItl6AbVRwvWVlZaIWyHKiekVc="; + }; + + extraInstallCommands = let + contents = pkgs.appimageTools.extract {inherit pname version src;}; + in '' + desktop_file=$(find ${contents} -name "*.desktop" | head -n1) + if [ -n "$desktop_file" ]; then + install -m 444 -D "$desktop_file" "$out/share/applications/${pname}.desktop" + substituteInPlace "$out/share/applications/${pname}.desktop" \ + --replace 'Exec=AppRun' 'Exec=${pname}' \ + --replace 'Exec=T3-Code' 'Exec=${pname}' \ + --replace 'Exec=t3-code' 'Exec=${pname}' || true + fi + + if [ -d ${contents}/usr/share/icons ]; then + cp -r ${contents}/usr/share/icons $out/share + fi + ''; + + meta = { + description = "T3 Chat Desktop"; + homepage = "https://t3.codes"; + license = lib.licenses.mit; + platforms = ["x86_64-linux"]; + }; + }; + }; +} diff --git a/modules/pkgs/zen-browser.nix b/modules/pkgs/zen-browser.nix new file mode 100644 index 0000000..0a26ee7 --- /dev/null +++ b/modules/pkgs/zen-browser.nix @@ -0,0 +1,41 @@ +{lib, ...}: { + perSystem = {pkgs, ...}: let + pname = "zen-browser"; + version = "1.19.3b"; + + src = pkgs.fetchurl { + url = "https://github.com/zen-browser/desktop/releases/download/${version}/zen-x86_64.AppImage"; + hash = "sha256-p00Irv2z6brDXMx3cr0234lOZZ2a7FmJMDzN494nzMw="; + }; + + appimageContents = pkgs.appimageTools.extract {inherit pname version src;}; + in { + packages.zen-browser = pkgs.appimageTools.wrapType2 { + inherit pname version src; + + extraPkgs = pkgs: [pkgs.ffmpeg-full]; + + extraInstallCommands = '' + desktop_file=$(find ${appimageContents} -name "*.desktop" | head -n1) + if [ -n "$desktop_file" ]; then + install -m 444 -D "$desktop_file" "$out/share/applications/${pname}.desktop" + substituteInPlace "$out/share/applications/${pname}.desktop" \ + --replace 'Exec=zen' 'Exec=${pname}' + fi + + if [ -d ${appimageContents}/usr/share/icons ]; then + cp -r ${appimageContents}/usr/share/icons $out/share + fi + + ln -s $out/bin/${pname} $out/bin/zen + ''; + + meta = { + description = "Experience tranquillity while browsing the web without people tracking you!"; + homepage = "https://zen-browser.app"; + license = lib.licenses.mpl20; + platforms = ["x86_64-linux"]; + }; + }; + }; +} diff --git a/modules/systems.nix b/modules/systems.nix new file mode 100644 index 0000000..991fba3 --- /dev/null +++ b/modules/systems.nix @@ -0,0 +1,6 @@ +{ + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; +}