release: archivebox 0.9.34rc54

This commit is contained in:
Nick Sweeting 2026-06-04 00:48:47 -07:00
parent 70b325f959
commit caf0acdec8
No known key found for this signature in database
22 changed files with 62 additions and 978 deletions

View File

@ -1,214 +0,0 @@
name: Build Debian package
on:
workflow_dispatch:
workflow_call:
push:
branches: ['**']
paths:
- 'pkg/debian/**'
- 'bin/build_deb.sh'
- 'bin/release_deb.sh'
- '.github/workflows/debian.yml'
- 'pyproject.toml'
# release trigger is handled by release.yml to avoid double-runs
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
arch: [amd64, arm64]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Get version
id: version
run: echo "version=$(grep '^version = ' pyproject.toml | awk -F'\"' '{print $2}')" >> "$GITHUB_OUTPUT"
- name: Install nfpm
env:
NFPM_VERSION: "2.45.1"
run: |
curl -fsSL "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_Linux_x86_64.tar.gz" \
| sudo tar -xz -C /usr/local/bin nfpm
nfpm --version
- name: Build .deb package
run: |
export VERSION="${{ steps.version.outputs.version }}"
export ARCH="${{ matrix.arch }}"
./bin/build_deb.sh
- name: Verify .deb package contents
run: |
DEB_FILE="$(ls dist/archivebox*.deb | head -1)"
echo "=== Package info ==="
dpkg-deb --info "$DEB_FILE"
echo ""
echo "=== Package contents ==="
dpkg-deb --contents "$DEB_FILE"
echo ""
echo "=== Control fields ==="
dpkg-deb --field "$DEB_FILE"
- name: Upload .deb artifact
uses: actions/upload-artifact@v4
with:
name: archivebox-${{ steps.version.outputs.version }}-${{ matrix.arch }}.deb
path: dist/*.deb
test:
needs: build
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: false
- name: Install build dependencies
uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0
with:
packages: build-essential python3-dev python3-setuptools libssl-dev libldap2-dev libsasl2-dev zlib1g-dev libatomic1
version: 1.0
- name: Build local wheel
run: |
uv sync --all-extras --no-install-project --no-install-workspace --no-sources --no-cache
uv build --wheel --out-dir /tmp/wheels/
- name: Download .deb artifact
uses: actions/download-artifact@v4
with:
pattern: archivebox-*-${{ matrix.arch }}.deb
merge-multiple: true
- name: Install system dependencies
run: |
sudo apt-get install -y python3.13 python3.13-venv python3-pip git curl wget
- name: Pre-seed virtualenv with local wheel before dpkg install
run: |
# CI-only: pre-seed the venv with a local wheel so we test the
# unreleased code, not whatever is on PyPI. We explicitly use python3.13
# here (matching the system dep installed above) to ensure the venv is
# created with the correct Python version. On real installs, install.sh
# handles this by preferring python3.13 and failing if < 3.13.
# When postinstall.sh runs during dpkg -i, it finds the venv already
# populated and just upgrades deps.
sudo mkdir -p /opt/archivebox
sudo python3.13 -m venv /opt/archivebox/venv
sudo /opt/archivebox/venv/bin/python3 -m pip install --quiet --upgrade pip setuptools
sudo /opt/archivebox/venv/bin/pip install --quiet /tmp/wheels/archivebox-*.whl
echo "[√] Pre-seeded /opt/archivebox/venv with local wheel"
- name: Install .deb package
run: |
# dpkg install will run postinstall which creates the user,
# sets up systemd, and tries pip install (which finds it already installed)
sudo dpkg -i archivebox*.deb || sudo apt-get install -f -y
- name: Verify archivebox is installed
run: |
which archivebox
archivebox version
- name: Verify wrapper script works
run: |
/usr/bin/archivebox version
/usr/bin/archivebox --help | head -5
- name: Test archivebox init as archivebox user
run: |
# The postinstall should have created the user
id archivebox
sudo mkdir -p /tmp/archivebox-test
sudo chown archivebox:archivebox /tmp/archivebox-test
sudo -u archivebox bash -c 'cd /tmp/archivebox-test && /opt/archivebox/venv/bin/archivebox init'
- name: Test archivebox status
run: |
sudo -u archivebox bash -c 'cd /tmp/archivebox-test && /opt/archivebox/venv/bin/archivebox status'
- name: Test archivebox add
run: |
sudo -u archivebox bash -c 'cd /tmp/archivebox-test && /opt/archivebox/venv/bin/archivebox add "https://example.com"'
- name: Verify systemd service file exists
run: |
test -f /usr/lib/systemd/system/archivebox.service
cat /usr/lib/systemd/system/archivebox.service
# Upload .deb to GitHub Release only after tests pass
release:
if: github.event_name == 'release' || github.event_name == 'workflow_call'
needs: [build, test]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Determine release tag
id: tag
run: |
TAG="${{ github.event.release.tag_name }}"
if [ -z "$TAG" ]; then
TAG="v$(grep '^version = ' pyproject.toml | awk -F'\"' '{print $2}')"
echo "[i] No release tag in event context, using version from pyproject.toml: $TAG"
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
- name: Download all .deb artifacts
uses: actions/download-artifact@v4
with:
pattern: archivebox-*.deb
merge-multiple: true
- name: Upload .deb to GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.tag.outputs.tag }}"
# Verify the release exists before uploading
if ! gh release view "$TAG" >/dev/null 2>&1; then
echo "[!] No GitHub Release found for tag $TAG."
if [ -n "${{ github.event.release.tag_name }}" ]; then
echo "[X] This was triggered by a release event — the release should exist. Failing."
exit 1
fi
echo "[i] Skipping upload (workflow_dispatch without a release)."
echo " Create a release first or trigger via the release event."
exit 0
fi
gh release upload "$TAG" *.deb --clobber

View File

@ -1,233 +0,0 @@
name: Build Homebrew formula
on:
workflow_dispatch:
workflow_call:
push:
branches: ['**']
paths:
- 'brew_dist/**'
- 'bin/build_brew.sh'
- 'bin/release_brew.sh'
- '.github/workflows/homebrew.yml'
- 'pyproject.toml'
# release trigger is handled by release.yml to avoid double-runs
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-test:
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-24.04]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Get version
id: version
run: echo "version=$(grep '^version = ' pyproject.toml | awk -F'\"' '{print $2}')" >> "$GITHUB_OUTPUT"
- name: Validate formula template syntax
run: ruby -c brew_dist/archivebox.rb
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: false
- name: Install build dependencies (Linux)
if: runner.os == 'Linux'
uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0
with:
packages: build-essential python3-dev python3-setuptools libssl-dev libldap2-dev libsasl2-dev zlib1g-dev libatomic1
version: 1.0
- name: Build local sdist
run: |
uv sync --all-extras --no-install-project --no-install-workspace --no-sources --no-cache
uv build --sdist --out-dir /tmp/sdist/
- name: Generate formula from local sdist
run: |
VERSION="${{ steps.version.outputs.version }}"
SDIST_PATH="$(ls /tmp/sdist/archivebox-*.tar.gz | head -1)"
SDIST_SHA256="$(shasum -a 256 "$SDIST_PATH" | awk '{print $1}')"
# Install archivebox + poet into a temp venv to generate resource stanzas
python3 -m venv /tmp/poet-venv
source /tmp/poet-venv/bin/activate
pip install --quiet "$SDIST_PATH" homebrew-pypi-poet
echo "[+] Generating resource stanzas with homebrew-pypi-poet..."
RESOURCES="$(poet archivebox)"
deactivate
# For CI: use file:// URL pointing to local sdist
# For release: this gets overridden with the PyPI URL
SDIST_URL="file://${SDIST_PATH}"
cat > /tmp/archivebox.rb << RUBY
class Archivebox < Formula
include Language::Python::Virtualenv
desc "Self-hosted internet archiving solution"
homepage "https://github.com/ArchiveBox/ArchiveBox"
url "${SDIST_URL}"
sha256 "${SDIST_SHA256}"
license "MIT"
depends_on "python@3.13"
${RESOURCES}
def install
virtualenv_install_with_resources
end
def post_install
data_dir = var/"archivebox"
data_dir.mkpath
ENV["DATA_DIR"] = data_dir.to_s
system bin/"archivebox", "init"
end
def caveats
<<~EOS
ArchiveBox data is stored in:
#{var}/archivebox
To start archiving, run:
cd #{var}/archivebox && archivebox add 'https://example.com'
To start the web UI:
cd #{var}/archivebox && archivebox server 0.0.0.0:8000
EOS
end
test do
assert_match version.to_s, shell_output("#{bin}/archivebox version")
end
end
RUBY
echo "[√] Generated formula:"
ruby -c /tmp/archivebox.rb
cat /tmp/archivebox.rb
- name: Install Homebrew (Linux only)
if: runner.os == 'Linux'
run: |
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
echo "HOMEBREW_PREFIX=$HOMEBREW_PREFIX" >> "$GITHUB_ENV"
echo "HOMEBREW_CELLAR=$HOMEBREW_CELLAR" >> "$GITHUB_ENV"
echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY" >> "$GITHUB_ENV"
echo "$HOMEBREW_PREFIX/bin" >> "$GITHUB_PATH"
echo "$HOMEBREW_PREFIX/sbin" >> "$GITHUB_PATH"
- name: Install brew dependencies
run: brew install python@3.13
- name: Install archivebox via brew from local formula
run: |
brew install --build-from-source --verbose /tmp/archivebox.rb
- name: Verify archivebox version
run: archivebox version
- name: Test archivebox init
run: |
mkdir -p /tmp/archivebox-test && cd /tmp/archivebox-test
archivebox init
- name: Test archivebox status
run: |
cd /tmp/archivebox-test
archivebox status
# On release only: generate the real formula with PyPI URL and push to tap
release:
if: github.event_name == 'release' || github.event_name == 'workflow_call'
needs: build-and-test
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Get version
id: version
run: echo "version=$(grep '^version = ' pyproject.toml | awk -F'\"' '{print $2}')" >> "$GITHUB_OUTPUT"
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Wait for PyPI package availability
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "[+] Waiting for archivebox==${VERSION} to be available on PyPI..."
for i in $(seq 1 30); do
if pip index versions archivebox 2>/dev/null | grep -q "$VERSION"; then
echo "[√] archivebox==${VERSION} is available on PyPI"
break
fi
if [ "$i" -eq 30 ]; then
echo "[!] Timed out waiting for PyPI. Trying to install anyway..."
break
fi
echo " Attempt $i/30 - not yet available, waiting 30s..."
sleep 30
done
- name: Generate release formula via build_brew.sh
run: ./bin/build_brew.sh
- name: Test formula install
run: |
brew install --build-from-source brew_dist/archivebox.rb
archivebox version
- name: Upload formula artifact
uses: actions/upload-artifact@v4
with:
name: archivebox.rb
path: brew_dist/archivebox.rb
- name: Push to homebrew-archivebox tap
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
git clone "https://x-access-token:${GH_TOKEN}@github.com/ArchiveBox/homebrew-archivebox.git" /tmp/tap
cp brew_dist/archivebox.rb /tmp/tap/Formula/archivebox.rb 2>/dev/null || \
cp brew_dist/archivebox.rb /tmp/tap/archivebox.rb
cd /tmp/tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
if git diff --cached --quiet; then
echo "[i] No changes to formula, skipping push."
else
git commit -m "Update archivebox to v${VERSION}"
git push origin HEAD
echo "[√] Formula pushed to homebrew-archivebox tap"
fi

View File

@ -2,8 +2,8 @@ name: Release
# Orchestrates the full release pipeline:
# 1. Build and publish pip package to PyPI
# 2. Build .deb packages and Homebrew formula (in parallel, after pip)
# 3. Build Docker images (in parallel with deb/brew)
# 2. Build Homebrew formula after pip
# 3. Build Docker images in parallel
#
# Individual workflows also run on push for CI (see their own triggers).
# Manual fallback for the hosted release pipeline. The normal prerelease loop
@ -28,12 +28,6 @@ jobs:
uses: ./.github/workflows/pip.yml
secrets: inherit
debian:
name: Build .deb packages
needs: pip
uses: ./.github/workflows/debian.yml
secrets: inherit
homebrew:
name: Update Homebrew formula
needs: pip

View File

@ -0,0 +1,35 @@
name: Update Homebrew tap
on:
push:
branches: [dev]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: update-homebrew-tap-${{ github.ref }}
cancel-in-progress: true
jobs:
dispatch:
runs-on: ubuntu-latest
steps:
- name: Dispatch tap update
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -z "$HOMEBREW_TAP_TOKEN" ]; then
echo "HOMEBREW_TAP_TOKEN is not configured; tap hourly fallback will update the formula."
exit 0
fi
curl --fail-with-body \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${HOMEBREW_TAP_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/ArchiveBox/homebrew-archivebox/dispatches \
-d '{"event_type":"archivebox-dev-updated"}'

View File

@ -295,12 +295,10 @@ See <a href="#%EF%B8%8F-cli-usage">below</a> for more usage examples using the C
<summary><b><img src="https://user-images.githubusercontent.com/511499/117448075-49597580-af0c-11eb-91ba-f34fff10096b.png" alt="aptitude" height="28px" align="top"/> <code>apt</code></b> (Ubuntu/Debian/etc.)</summary>
<br/>
<ol>
<li>Download and install the <code>.deb</code> package from the <a href="https://github.com/ArchiveBox/ArchiveBox/releases">latest release</a>.
<pre lang="bash"><code style="white-space: pre-line"># download the .deb for your architecture (amd64 or arm64)
ARCH="$(dpkg --print-architecture)"
VERSION="$(curl -fsSL https://api.github.com/repos/ArchiveBox/ArchiveBox/releases/latest | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'].lstrip('v'))")"
curl -fsSL "https://github.com/ArchiveBox/ArchiveBox/releases/latest/download/archivebox_${VERSION}_${ARCH}.deb" -o /tmp/archivebox.deb
sudo apt install /tmp/archivebox.deb
<li>Add the third-party ArchiveBox apt repo and install <code>archivebox</code>.
<pre lang="bash"><code style="white-space: pre-line">echo 'deb [trusted=yes] https://archivebox.github.io/debian-archivebox dev main' | sudo tee /etc/apt/sources.list.d/archivebox.list
sudo apt update
sudo apt install archivebox
archivebox version # make sure all dependencies are installed
</code></pre>
</li>

View File

@ -1,5 +1,6 @@
import os
import socket
import subprocess
from pathlib import Path
from types import SimpleNamespace
from urllib.parse import quote
@ -97,6 +98,15 @@ def live_opencode(opencode_archive_config):
settings["archivebox_base_url"] = "http://admin.archivebox.localhost:8000"
settings["archivebox_admin_url"] = "http://admin.archivebox.localhost:8000/admin"
settings["archivebox_api_url"] = "http://admin.archivebox.localhost:8000/api/"
binary, binary_env = views._resolve_binary(settings["binary"], settings["config"])
version = subprocess.run(
[binary, "--version"],
env={**os.environ, **binary_env},
text=True,
capture_output=True,
timeout=120,
)
assert version.returncode == 0, version.stderr or version.stdout
ok, error = views._ensure_opencode(settings)
assert ok, error

View File

@ -19,13 +19,9 @@ cd "$REPO_DIR"
# the order matters
./bin/build_docs.sh
./bin/build_pip.sh
./bin/build_deb.sh
./bin/build_brew.sh
./bin/build_docker.sh
echo "[√] Done. Install the built package by running:"
echo " pip install archivebox"
echo " # or"
echo " sudo apt install ./dist/archivebox*.deb"
echo " # or"
echo " brew tap archivebox/archivebox && brew install archivebox"

View File

@ -1,112 +0,0 @@
#!/usr/bin/env bash
### Bash Environment Setup
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
IFS=$'\n'
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd .. && pwd )"
cd "$REPO_DIR"
VERSION="$(grep '^version = ' "${REPO_DIR}/pyproject.toml" | awk -F'"' '{print $2}')"
FORMULA_FILE="$REPO_DIR/brew_dist/archivebox.rb"
echo "[+] Building Homebrew formula for archivebox==${VERSION}..."
# Create a temporary virtualenv for generating the formula
TMPDIR="$(mktemp -d)"
trap "rm -rf $TMPDIR" EXIT
python3 -m venv "$TMPDIR/venv"
source "$TMPDIR/venv/bin/activate"
pip install --quiet "archivebox==${VERSION}" homebrew-pypi-poet 2>/dev/null
echo "[+] Generating resource stanzas with homebrew-pypi-poet..."
RESOURCES="$(poet archivebox)"
# Get the sdist URL and SHA256 from PyPI JSON API (works on macOS and Linux)
SDIST_URL=""
SDIST_SHA256=""
PYPI_JSON="$(curl -fsSL "https://pypi.org/pypi/archivebox/${VERSION}/json" 2>/dev/null || echo '')"
if [ -n "$PYPI_JSON" ]; then
SDIST_URL="$(echo "$PYPI_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(next((u['url'] for u in d['urls'] if u['packagetype']=='sdist'), ''))" 2>/dev/null || echo '')"
SDIST_SHA256="$(echo "$PYPI_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(next((u['digests']['sha256'] for u in d['urls'] if u['packagetype']=='sdist'), ''))" 2>/dev/null || echo '')"
fi
if [ -z "$SDIST_URL" ]; then
SDIST_URL="https://files.pythonhosted.org/packages/source/a/archivebox/archivebox-${VERSION}.tar.gz"
fi
if [ -z "$SDIST_SHA256" ]; then
# Fallback: download and compute locally
mkdir -p "$TMPDIR/sdist"
pip download --no-binary :all: --no-deps -d "$TMPDIR/sdist" "archivebox==${VERSION}" 2>/dev/null || true
SDIST_SHA256="$(shasum -a 256 "$TMPDIR/sdist/"*.tar.gz 2>/dev/null | awk '{print $1}' || echo '')"
fi
deactivate
echo "[+] Updating formula file: $FORMULA_FILE"
# Build the formula from the template
cat > "$FORMULA_FILE" << RUBY
# Auto-generated by bin/build_brew.sh using homebrew-pypi-poet.
# Users install with: brew tap archivebox/archivebox && brew install archivebox
class Archivebox < Formula
include Language::Python::Virtualenv
desc "Self-hosted internet archiving solution"
homepage "https://github.com/ArchiveBox/ArchiveBox"
url "${SDIST_URL}"
sha256 "${SDIST_SHA256}"
license "MIT"
head "https://github.com/ArchiveBox/ArchiveBox.git", branch: "dev"
depends_on "python@3.13"
# All other runtime deps (node, chrome, yt-dlp, etc.) are installed
# on-demand by \`archivebox install\` and should NOT be declared here.
# Python dependency resource blocks auto-generated by homebrew-pypi-poet
# AUTOGENERATED_RESOURCES_START
${RESOURCES}
# AUTOGENERATED_RESOURCES_END
def install
virtualenv_install_with_resources
end
def post_install
# Initialize ArchiveBox data in the Homebrew-managed var directory
data_dir = var/"archivebox"
data_dir.mkpath
ENV["DATA_DIR"] = data_dir.to_s
system bin/"archivebox", "init"
end
def caveats
<<~EOS
ArchiveBox data is stored in:
#{var}/archivebox
To start archiving, run:
cd #{var}/archivebox && archivebox add 'https://example.com'
To start the web UI:
cd #{var}/archivebox && archivebox server 0.0.0.0:8000
EOS
end
test do
assert_match version.to_s, shell_output("#{bin}/archivebox version")
end
end
RUBY
echo "[√] Formula updated: $FORMULA_FILE"
echo " Version: ${VERSION}"
echo " URL: ${SDIST_URL}"

View File

@ -1,43 +0,0 @@
#!/usr/bin/env bash
### Bash Environment Setup
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
IFS=$'\n'
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd .. && pwd )"
cd "$REPO_DIR"
VERSION="$(grep '^version = ' "${REPO_DIR}/pyproject.toml" | awk -F'"' '{print $2}')"
export VERSION
# Default to amd64, can be overridden with ARCH=arm64
export ARCH="${ARCH:-amd64}"
echo "[+] Building .deb package for archivebox_${VERSION}_${ARCH}..."
# Check for nfpm
if ! command -v nfpm &>/dev/null; then
echo "[!] nfpm not found. Install it with one of:"
echo " go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest"
echo " uv tool install nfpm"
echo " brew install goreleaser/tap/nfpm"
echo " curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh"
exit 1
fi
mkdir -p "$REPO_DIR/dist"
nfpm package \
--config "$REPO_DIR/pkg/debian/nfpm.yaml" \
--packager deb \
--target "$REPO_DIR/dist/"
echo
echo "[√] Built .deb package:"
ls -la "$REPO_DIR/dist/"archivebox*.deb

View File

@ -1,48 +0,0 @@
#!/usr/bin/env bash
### Bash Environment Setup
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
IFS=$'\n'
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd .. && pwd )"
cd "$REPO_DIR"
VERSION="$(grep '^version = ' "${REPO_DIR}/pyproject.toml" | awk -F'"' '{print $2}')"
FORMULA_FILE="$REPO_DIR/brew_dist/archivebox.rb"
TAP_REPO="ArchiveBox/homebrew-archivebox"
if [ ! -f "$FORMULA_FILE" ]; then
echo "[!] Formula not found at $FORMULA_FILE"
echo " Run ./bin/build_brew.sh first to generate it."
exit 1
fi
echo "[+] Releasing Homebrew formula for archivebox==${VERSION} to ${TAP_REPO}..."
# Clone the tap repo, update formula, commit, and push
TMPDIR="$(mktemp -d)"
trap "rm -rf $TMPDIR" EXIT
git clone "https://github.com/${TAP_REPO}.git" "$TMPDIR/tap"
cp "$FORMULA_FILE" "$TMPDIR/tap/archivebox.rb"
cd "$TMPDIR/tap"
git add archivebox.rb
if git diff --cached --quiet; then
echo "[i] No changes to formula, skipping release."
exit 0
fi
git commit -m "Update archivebox to v${VERSION}"
git push origin HEAD
echo "[√] Homebrew formula pushed to ${TAP_REPO}"
echo " Users can install with:"
echo " brew tap archivebox/archivebox"
echo " brew install archivebox"

View File

@ -1,33 +0,0 @@
#!/usr/bin/env bash
### Bash Environment Setup
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
IFS=$'\n'
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && cd .. && pwd )"
cd "$REPO_DIR"
VERSION="$(grep '^version = ' "${REPO_DIR}/pyproject.toml" | awk -F'"' '{print $2}')"
echo "[+] Releasing .deb package for archivebox==${VERSION}..."
DEB_FILE="$(ls -1 "$REPO_DIR/dist/"archivebox*.deb 2>/dev/null | head -1)"
if [ -z "$DEB_FILE" ]; then
echo "[!] No .deb file found in dist/. Run ./bin/build_deb.sh first."
exit 1
fi
echo "[+] Uploading $DEB_FILE to GitHub Release v${VERSION}..."
gh release upload "v${VERSION}" "$DEB_FILE" --clobber 2>/dev/null || \
gh release create "v${VERSION}" "$DEB_FILE" --title "v${VERSION}" --generate-notes
echo "[√] .deb package uploaded to GitHub Release v${VERSION}"
echo " Users can install with:"
echo " curl -fsSL https://github.com/ArchiveBox/ArchiveBox/releases/download/v${VERSION}/archivebox_${VERSION}_amd64.deb -o /tmp/archivebox.deb"
echo " sudo apt install /tmp/archivebox.deb"

View File

@ -1,50 +0,0 @@
# Auto-generated by bin/build_brew.sh using homebrew-pypi-poet.
# Users install with: brew tap archivebox/archivebox && brew install archivebox
class Archivebox < Formula
include Language::Python::Virtualenv
desc "Self-hosted internet archiving solution"
homepage "https://github.com/ArchiveBox/ArchiveBox"
url "https://files.pythonhosted.org/packages/source/a/archivebox/archivebox-0.9.3.tar.gz"
sha256 "" # auto-filled by bin/build_brew.sh
license "MIT"
head "https://github.com/ArchiveBox/ArchiveBox.git", branch: "dev"
depends_on "python@3.13"
# All other runtime deps (node, chrome, yt-dlp, etc.) are installed
# on-demand by `archivebox install` and should NOT be declared here.
# Python dependency resource blocks auto-generated by homebrew-pypi-poet
# AUTOGENERATED_RESOURCES_START
# AUTOGENERATED_RESOURCES_END
def install
virtualenv_install_with_resources
end
def post_install
# Initialize ArchiveBox data in the Homebrew-managed var directory
data_dir = var/"archivebox"
data_dir.mkpath
ENV["DATA_DIR"] = data_dir.to_s
system bin/"archivebox", "init"
end
def caveats
<<~EOS
ArchiveBox data is stored in:
#{var}/archivebox
To start archiving, run:
cd #{var}/archivebox && archivebox add 'https://example.com'
To start the web UI:
cd #{var}/archivebox && archivebox server 0.0.0.0:8000
EOS
end
test do
assert_match version.to_s, shell_output("#{bin}/archivebox version")
end
end

View File

@ -86,8 +86,6 @@ curl -fsSL 'https://get.archivebox.io' | bash
```
The script explains what it installs beforehand, and will prompt for user confirmation before making any changes to your system. The script uses Docker if already installed, but you can decline and it will attempt to auto-install everything using `apt`/`brew`/`pkg` + `pip` instead.
<sub>Note: The script will currently still attempt to install via `brew` on macOS. This will fail as ArchiveBox is no longer distributed as a Homebrew formula.</sub>
<img src="https://imgur.zervice.io/VMTzm0G.png" width="99%"/>
After running the setup script, continue with the [Quickstart](https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-next-steps) guide... ➡️

View File

@ -34,15 +34,16 @@ archivebox version # shows lots of useful info about installed dependencie
(ensure the version shown is the most recent available from [Releases](https://github.com/ArchiveBox/ArchiveBox/releases))
### macOS
**✨ ArchiveBox no longer needs to be `brew`-installed:**
✅ ArchiveBox still fully supports macOS, don't worry!
📦 Just install it using `pip` (or `pipx`) instead now:
ArchiveBox can be installed with Homebrew or `pip`/`pipx` on macOS:
```bash
brew tap archivebox/archivebox
brew install archivebox
mkdir -p ~/archivebox/data
cd ~/archivebox/data # (for example, can be anywhere)
pip install archivebox # just use pip to get archivebox
archivebox install # then finish installing dependencies
archivebox init
archivebox install # finish installing runtime dependencies
```
More info: https://github.com/ArchiveBox/homebrew-archivebox

View File

@ -1,6 +1,6 @@
{
"name": "archivebox",
"version": "0.9.34rc53",
"version": "0.9.34rc54",
"repository": "github:ArchiveBox/ArchiveBox",
"license": "MIT",
"dependencies": {

View File

@ -1,15 +0,0 @@
#!/bin/bash
# /usr/bin/archivebox - wrapper script installed by the archivebox .deb package
# Activates the pip-installed virtualenv and runs archivebox CLI
ARCHIVEBOX_VENV="/opt/archivebox/venv"
if [ ! -f "$ARCHIVEBOX_VENV/bin/archivebox" ]; then
echo "Error: ArchiveBox is not installed in $ARCHIVEBOX_VENV"
echo "Try running: sudo /opt/archivebox/install.sh"
exit 1
fi
# Export venv bin to PATH so bundled console scripts (yt-dlp, etc.) are discoverable
export PATH="$ARCHIVEBOX_VENV/bin:$PATH"
exec "$ARCHIVEBOX_VENV/bin/archivebox" "$@"

View File

@ -1,20 +0,0 @@
# The archivebox user/group and /var/lib/archivebox directory are created by
# postinstall.sh (which runs after dpkg unpacks the package contents).
[Unit]
Description=ArchiveBox Web Archiving Server
After=network.target
[Service]
Type=simple
User=archivebox
Group=archivebox
WorkingDirectory=/var/lib/archivebox
Environment="PATH=/opt/archivebox/venv/bin:/usr/local/bin:/usr/bin:/bin"
ExecStartPre=/usr/bin/archivebox init
ExecStart=/usr/bin/archivebox server 0.0.0.0:8000
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@ -1,51 +0,0 @@
#!/bin/bash
# /opt/archivebox/install.sh - installs/upgrades archivebox into its virtualenv
# Called by the postinstall script and can be run manually to upgrade
set -e
ARCHIVEBOX_VENV="/opt/archivebox/venv"
ARCHIVEBOX_VERSION="${ARCHIVEBOX_VERSION:-}"
# ArchiveBox requires Python >= 3.13 (per pyproject.toml).
# Prefer python3.13 explicitly; fall back to python3 with a version check.
if command -v python3.13 >/dev/null 2>&1; then
PYTHON="python3.13"
elif command -v python3 >/dev/null 2>&1; then
PYTHON="python3"
PY_MAJOR="$("$PYTHON" -c 'import sys; print(sys.version_info.major)')"
PY_MINOR="$("$PYTHON" -c 'import sys; print(sys.version_info.minor)')"
if [ "$PY_MAJOR" -lt 3 ] || { [ "$PY_MAJOR" -eq 3 ] && [ "$PY_MINOR" -lt 13 ]; }; then
PY_VER="${PY_MAJOR}.${PY_MINOR}"
echo "[!] Error: ArchiveBox requires Python >= 3.13, but found Python $PY_VER"
echo " Install python3.13: sudo apt install python3.13 python3.13-venv"
exit 1
fi
else
echo "[!] Error: python3 not found. Install python3.13: sudo apt install python3.13 python3.13-venv"
exit 1
fi
echo "[+] Setting up ArchiveBox virtualenv in $ARCHIVEBOX_VENV (using $PYTHON)..."
# Create the virtualenv if it doesn't exist
if [ ! -d "$ARCHIVEBOX_VENV" ]; then
"$PYTHON" -m venv "$ARCHIVEBOX_VENV"
fi
# Upgrade pip inside the virtualenv
"$ARCHIVEBOX_VENV/bin/python3" -m pip install --quiet --upgrade pip setuptools
# Install or upgrade archivebox.
# ARCHIVEBOX_VERSION is set by postinstall.sh from the .deb package version.
# When run manually without it, install the latest release from PyPI.
if [ -n "$ARCHIVEBOX_VERSION" ]; then
echo "[+] Installing archivebox==$ARCHIVEBOX_VERSION..."
"$ARCHIVEBOX_VENV/bin/pip" install --quiet --upgrade "archivebox==$ARCHIVEBOX_VERSION"
else
echo "[+] Installing latest archivebox (no version pinned)..."
"$ARCHIVEBOX_VENV/bin/pip" install --quiet --upgrade archivebox
fi
echo "[√] ArchiveBox installed successfully."
echo " Run 'archivebox version' to verify."

View File

@ -1,69 +0,0 @@
# nFPM configuration for building ArchiveBox .deb packages
# Docs: https://nfpm.goreleaser.com/configuration/
# Usage: nfpm package --config pkg/debian/nfpm.yaml --packager deb --target dist/
name: archivebox
arch: "${ARCH:-amd64}"
platform: linux
version: "${VERSION}"
version_schema: semver
maintainer: "Nick Sweeting <nfpm@archivebox.io>"
description: |
Self-hosted internet archiving solution.
Save pages from the web including HTML, PDF, screenshots, media, and more.
Install with: sudo apt install archivebox && archivebox init --setup
vendor: "ArchiveBox"
homepage: "https://archivebox.io"
license: "MIT"
section: "web"
priority: "optional"
depends:
# python3 >= 3.11 allows dpkg to install on more systems (e.g. Ubuntu 24.04).
# install.sh enforces the real >= 3.13 requirement at venv creation time,
# failing early with a clear error if only an older python3 is available.
- python3 (>= 3.11)
- python3-pip
- python3-venv
# All other runtime deps (node, chrome, yt-dlp, etc.) are installed on-demand
# by `archivebox install` and should NOT be declared as package dependencies.
recommends:
# Common utilities used by archivebox extractors. Declared as recommends
# (not depends) so dpkg doesn't hard-fail if they're missing, but apt
# installs them by default so users have a working baseline out of the box.
- git
- curl
- wget
contents:
# Wrapper script for /usr/bin/archivebox
- src: pkg/debian/archivebox
dst: /usr/bin/archivebox
file_info:
mode: 0755
# Install helper script
- src: pkg/debian/install.sh
dst: /opt/archivebox/install.sh
file_info:
mode: 0755
# Systemd service file
- src: pkg/debian/archivebox.service
dst: /usr/lib/systemd/system/archivebox.service
file_info:
mode: 0644
# Create data directory (unpacked as root; postinstall.sh chowns to archivebox user)
- dst: /var/lib/archivebox
type: dir
file_info:
mode: 0755
scripts:
postinstall: pkg/debian/scripts/postinstall.sh
preremove: pkg/debian/scripts/preremove.sh
deb:
compression: zstd

View File

@ -1,32 +0,0 @@
#!/bin/bash
# postinstall script for archivebox .deb package
set -e
# Create archivebox system user if it doesn't exist
if ! id -u archivebox >/dev/null 2>&1; then
useradd --system --shell /bin/bash --home-dir /var/lib/archivebox --create-home archivebox
echo "[+] Created archivebox system user"
fi
# Ensure data directory exists and is owned by archivebox
mkdir -p /var/lib/archivebox
chown archivebox:archivebox /var/lib/archivebox
# Run the virtualenv install script, pinning to the .deb package version
ARCHIVEBOX_VERSION="$(dpkg-query -W -f='${Version}' archivebox 2>/dev/null || echo '')"
export ARCHIVEBOX_VERSION
/opt/archivebox/install.sh
# Reload systemd to pick up the service file (skip if systemd is not running)
if command -v systemctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
systemctl daemon-reload
# On upgrade: restart the service if it was enabled (prerm stopped it)
if [ "$1" = "configure" ] && systemctl is-enabled archivebox >/dev/null 2>&1; then
systemctl start archivebox 2>/dev/null || true
echo "[+] Restarted archivebox service after upgrade"
else
echo "[i] To start ArchiveBox: sudo systemctl start archivebox"
echo "[i] To enable on boot: sudo systemctl enable archivebox"
fi
fi

View File

@ -1,27 +0,0 @@
#!/bin/bash
# preremove script for archivebox .deb package
set -e
# dpkg passes "$1" as "remove", "purge", or "upgrade".
# Always stop the service before removing or upgrading, because postinstall
# replaces the venv in-place — the running process would use stale binaries.
if command -v systemctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
systemctl stop archivebox 2>/dev/null || true
fi
# Only disable + clean up on full removal, not during upgrade.
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
if command -v systemctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
systemctl disable archivebox 2>/dev/null || true
fi
echo "[+] Removing ArchiveBox virtualenv..."
rm -rf /opt/archivebox/venv
echo "[i] Your ArchiveBox data in /var/lib/archivebox has NOT been removed."
echo " The 'archivebox' system user has NOT been removed."
echo " Remove them manually if you no longer need them:"
echo " sudo rm -rf /var/lib/archivebox"
echo " sudo userdel archivebox"
fi

View File

@ -1,6 +1,6 @@
[project]
name = "archivebox"
version = "0.9.34rc53"
version = "0.9.34rc54"
requires-python = ">=3.13"
description = "Self-hosted internet archiving solution."
authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}]
@ -79,9 +79,9 @@ dependencies = [
### Extractor dependencies (optional binaries detected at runtime via shutil.which)
### Binary/Package Management
"abxbus==2.5.10", # EventBus API
"abxpkg>=1.11.167", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm
"abx-plugins>=1.11.171", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring
"abx-dl>=1.11.171", # shared ArchiveBox downloader package with blocking install preflight
"abxpkg>=1.11.169", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm
"abx-plugins>=1.11.173", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring
"abx-dl>=1.11.173", # shared ArchiveBox downloader package with blocking install preflight
### UUID7 backport for Python <3.14
"uuid7>=0.1.0; python_version < '3.14'", # provides the uuid_extensions module on Python 3.13
]
@ -119,7 +119,6 @@ dev = [
### BUILD
"uv>=0.11.3",
"bumpver>=2023.1129",
#"homebrew-pypi-poet>=0.10.0", # for: generating archivebox.rb brewfile list of python packages
### DOCS
"recommonmark>=0.7.1",
"sphinx>=8.1.3",