diff --git a/.github/workflows/deploy-publicsite.yml b/.github/workflows/deploy-publicsite.yml index a1e89acb..d10b9764 100644 --- a/.github/workflows/deploy-publicsite.yml +++ b/.github/workflows/deploy-publicsite.yml @@ -46,7 +46,7 @@ jobs: - name: Setup Python and uv uses: astral-sh/setup-uv@v6 with: - enable-cache: true + enable-cache: false - name: Install ArchiveBox and screenshot dependencies run: uv sync --no-cache --frozen diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5a6a414d..8cf89917 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,7 +49,7 @@ jobs: uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Resolve Docker through abxpkg diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7e47db1b..af9e2570 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -26,7 +26,7 @@ jobs: - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Install ArchiveBox development dependencies run: uv sync --no-cache --locked --dev @@ -81,7 +81,7 @@ jobs: if: ${{ !contains(fromJSON('["freebsd", "openbsd"]'), matrix.environment) }} with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Install ArchiveBox if: ${{ !contains(fromJSON('["freebsd", "openbsd"]'), matrix.environment) }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fe954753..85f3f081 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,11 +25,11 @@ jobs: uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Verify checked dependency lock - run: uv lock --check + run: uv lock --no-cache --check - name: Install dependencies with uv run: uv sync --no-cache --locked --dev --extra sonic --extra debug diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index 21655ebe..750cc6d2 100755 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -23,13 +23,13 @@ jobs: uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: ${{ env.UV_VERSION }} - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Build every distribution run: | set -Eeuo pipefail - uv build --all-packages --no-sources --out-dir dist --clear + uv build --no-cache --all-packages --no-sources --out-dir dist --clear shopt -s nullglob artifacts=(dist/*) @@ -92,7 +92,7 @@ jobs: uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: ${{ env.UV_VERSION }} - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Download distributions diff --git a/.github/workflows/test-parallel.yml b/.github/workflows/test-parallel.yml index 5c161dfa..eb337203 100644 --- a/.github/workflows/test-parallel.yml +++ b/.github/workflows/test-parallel.yml @@ -30,7 +30,7 @@ jobs: - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Resolve discovery tools through abxpkg @@ -96,7 +96,7 @@ jobs: - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Resolve optional build dependencies through abxpkg diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1f3608b0..d35616ad 100755 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,7 +46,7 @@ jobs: uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: version: "0.11.3" - enable-cache: true + enable-cache: false cache-dependency-glob: uv.lock - name: Prepare abxpkg environment diff --git a/archivebox/cli/archivebox_install.py b/archivebox/cli/archivebox_install.py index b0ad33df..48cd83fa 100755 --- a/archivebox/cli/archivebox_install.py +++ b/archivebox/cli/archivebox_install.py @@ -12,6 +12,63 @@ from rich import print from archivebox.misc.util import docstring, enforce_types +def _resolve_install_plugin_names( + requested_names: tuple[str, ...], +) -> list[str]: + """Resolve `archivebox install ` tokens to installable plugin names.""" + from archivebox.config import CONSTANTS + from archivebox.config.common import get_config, normalize_runtime_config + from archivebox.machine.models import Machine + from abx_dl.config import get_required_binary_requests + from abx_dl.models import discover_plugins, filter_plugins + + plugins = discover_plugins(runtime="archivebox") + config = get_config(include_machine=False) + runtime_config = normalize_runtime_config(config.for_crawl(), json_safe=False) + derived_config = normalize_runtime_config(Machine.current().config, json_safe=False) + selected_plugins = dict(filter_plugins(plugins, list(requested_names), include_providers=True)) + unmatched_names: list[str] = [] + + for requested_name in requested_names: + if requested_name in selected_plugins: + continue + + matched_plugin_names: list[str] = [] + for plugin_name, plugin in plugins.items(): + logical_records = get_required_binary_requests( + plugin, + plugin.config.required_binaries, + overrides=runtime_config, + derived_overrides=derived_config, + run_output_dir=CONSTANTS.DATA_DIR, + ) + actual_records = get_required_binary_requests( + plugin, + plugin.config.required_binaries, + overrides=runtime_config, + derived_overrides=derived_config, + run_output_dir=CONSTANTS.DATA_DIR, + logical_names=False, + ) + for logical_record, actual_record in zip(logical_records, actual_records, strict=False): + logical_name = str(logical_record["name"]) + actual_name = str(actual_record["name"]) + display_name = Path(actual_name).expanduser().name if ("/" in actual_name or actual_name.startswith("~")) else actual_name + if requested_name in {logical_name, actual_name, display_name}: + matched_plugin_names.append(plugin_name) + break + + if matched_plugin_names: + selected_plugins.update(filter_plugins(plugins, matched_plugin_names, include_providers=True)) + else: + unmatched_names.append(requested_name) + + if unmatched_names: + raise click.UsageError(f"No plugins or required binaries found matching: {', '.join(unmatched_names)}") + + return sorted(selected_plugins) + + def ensure_data_dir_lib_symlink(data_dir: Path, abxpkg_lib_dir: Path) -> Path | None: """Expose the shared abxpkg lib dir at DATA_DIR/lib after install.""" link_path = data_dir / "lib" @@ -90,7 +147,7 @@ def install(binaries: tuple[str, ...] = (), binproviders: str = "*", dry_run: bo setup_django() - plugin_names = list(binaries) + plugin_names = _resolve_install_plugin_names(binaries) if binaries else [] if binproviders != "*": plugin_names.extend(provider.strip() for provider in binproviders.split(",") if provider.strip()) diff --git a/bin/collect_ui_screenshots.sh b/bin/collect_ui_screenshots.sh index 4a497d4c..40cb8d43 100755 --- a/bin/collect_ui_screenshots.sh +++ b/bin/collect_ui_screenshots.sh @@ -27,7 +27,7 @@ CAPTURE_PROFILES=$'desktop|1600|1000\ntablet|1024|1366\nmobile|390|844' stop_background_runner() { ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from archivebox.workers.supervisord_util import get_existing_supervisord_process, stop_worker; supervisor=get_existing_supervisord_process(quiet=True); supervisor is not None and stop_worker(supervisor, "worker_runner")' ) >/dev/null } @@ -79,7 +79,7 @@ cleanup() { if [[ "$CREATED_TEMP_USER" == "1" && -f "$DATA_DIR/index.sqlite3" ]]; then ( cd "$DATA_DIR" - UI_SCREENSHOT_USERNAME="$USERNAME" uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + UI_SCREENSHOT_USERNAME="$USERNAME" uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'import os; from django.contrib.auth import get_user_model; get_user_model().objects.filter(username=os.environ["UI_SCREENSHOT_USERNAME"]).delete()' ) >/dev/null 2>&1 || true fi @@ -91,12 +91,12 @@ mkdir -p "$DATA_DIR" "$OUTPUT_DIR" "$PUBLIC_OUTPUT_DIR" echo "[*] Initializing the ArchiveBox collection at $DATA_DIR" ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox init --quick + uv run --no-cache --project "$REPO_DIR" archivebox init --quick ) SEED_STATE="$( ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from django.db.models import Count; from archivebox.core.models import Snapshot, ArchiveResult; from archivebox.crawls.models import CrawlSchedule; from archivebox.personas.models import Persona; from archivebox.api.models import APIToken; from signal_webhooks.utils import get_webhook_model; recent=list(Snapshot.objects.filter(status=Snapshot.StatusChoices.SEALED).order_by("-bookmarked_at").values_list("id", "status")[:100]); counts=dict(ArchiveResult.objects.filter(snapshot_id__in=[row[0] for row in recent], status="succeeded").values_list("snapshot_id").annotate(Count("id"))); screenshots=set(ArchiveResult.objects.filter(snapshot_id__in=[row[0] for row in recent], plugin="screenshot", status="succeeded").values_list("snapshot_id", flat=True)); useful=sum(counts.get(snapshot_id,0)>=8 and snapshot_id in screenshots for snapshot_id,status in recent)>=2; print(int(useful)); print(CrawlSchedule.objects.count()); print(Persona.objects.exclude(name="Default").count()); print(APIToken.objects.count()); print(get_webhook_model().objects.count())' ) | tail -5)" HAS_USEFUL_SNAPSHOT="$(printf '%s\n' "$SEED_STATE" | sed -n '1p')" @@ -109,7 +109,7 @@ if [[ "$HAS_USEFUL_SNAPSHOT" == "0" ]]; then echo "[*] Archiving real reference sites so snapshot views have meaningful outputs" ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox add \ + uv run --no-cache --project "$REPO_DIR" archivebox add \ --depth=0 \ --overwrite \ --tag=documentation,reference \ @@ -122,7 +122,7 @@ if [[ "$HAS_SCHEDULE" == "0" ]]; then echo "[*] Creating a real weekly documentation crawl schedule" ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox schedule --every=weekly --depth=0 --tag=documentation https://archivebox.io/feed.xml + uv run --no-cache --project "$REPO_DIR" archivebox schedule --every=weekly --depth=0 --tag=documentation https://archivebox.io/feed.xml ) fi @@ -130,7 +130,7 @@ if [[ "$HAS_PERSONA" == "0" ]]; then echo "[*] Creating a real browser persona for the populated Persona views" ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox persona create "Research Browser" + uv run --no-cache --project "$REPO_DIR" archivebox persona create "Research Browser" ) fi @@ -139,7 +139,7 @@ fi ROUTE_CONFIG="$( ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from urllib.parse import urlparse; from archivebox.config.common import get_config; from archivebox.core.routes_util import get_admin_base_url, get_web_base_url; config = get_config(); admin = get_admin_base_url(config=config); web = get_web_base_url(config=config); parsed = urlparse(admin); print(admin); print(web); print(parsed.port or (443 if parsed.scheme == "https" else 80))' ) | tail -3)" ADMIN_BASE_URL="$(printf '%s\n' "$ROUTE_CONFIG" | sed -n '1p')" @@ -155,10 +155,10 @@ fi echo "[*] Creating a temporary screenshot admin" ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from django.contrib.auth import get_user_model; get_user_model().objects.filter(username__startswith="archivebox-screenshots-").delete()' UI_SCREENSHOT_USERNAME="$USERNAME" UI_SCREENSHOT_PASSWORD="$PASSWORD" \ - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'import os; from django.contrib.auth import get_user_model; get_user_model().objects.create_superuser(username=os.environ["UI_SCREENSHOT_USERNAME"], password=os.environ["UI_SCREENSHOT_PASSWORD"])' ) CREATED_TEMP_USER=1 @@ -169,7 +169,7 @@ echo "[*] Starting ArchiveBox on port $PORT" # Use the real server command so the runner, worker, and log views describe # the same persistent runtime that an operator sees. UI_SCREENSHOT_HIDE_HIGH_LOAD_WARNING=1 \ - exec uv run --project "$REPO_DIR" archivebox server "127.0.0.1:$PORT" + exec uv run --no-cache --project "$REPO_DIR" archivebox server "127.0.0.1:$PORT" ) >"$DATA_DIR/ui-screenshot-server.log" 2>&1 & SERVER_PID=$! @@ -265,7 +265,7 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do fi elif [[ "$profile" == "desktop" || "$capture_mode" == wait-replay:* || -z "${ABXPKG_LIB_DIR:-}" ]]; then capture_log="$CAPTURE_ROOT/$(printf '%02d' "$capture_index")-$profile-abx-dl.log" - if ! env "${capture_env[@]}" uv run --project "$REPO_DIR" abx-dl dl \ + if ! env "${capture_env[@]}" uv run --no-cache --project "$REPO_DIR" abx-dl dl \ --plugins=screenshot \ --timeout=120 \ --dir "$capture_dir" \ @@ -281,7 +281,7 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do echo "[!] Screenshot navigation metadata is missing for $profile $url" >&2 exit 1 fi - uv run --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" validate \ + uv run --no-cache --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" validate \ "$screenshot_metadata_path" "$expected_path" else screenshot_path="$capture_dir/screenshot.png" @@ -300,7 +300,7 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do SCREENSHOT_VARIANTS_JSON="$responsive_variants" \ SCREENSHOT_COLLAPSE_FILTERS=1 \ node "$REPO_DIR/bin/take_screenshot.js" "$url" "$screenshot_path" >"$capture_dir/report.json" - uv run --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" validate \ + uv run --no-cache --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" validate \ "$capture_dir/report.json" "$expected_path" fi fi @@ -312,14 +312,14 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do cp "$screenshot_path" "$PUBLIC_OUTPUT_DIR/$filename" UI_SCREENSHOT_NAME="$name" UI_SCREENSHOT_URL="$url" UI_SCREENSHOT_SOURCE="$source" \ UI_SCREENSHOT_FILENAME="$filename" UI_SCREENSHOT_PROFILE="$profile" \ - uv run --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" append \ + uv run --no-cache --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" append \ "$MANIFEST_FILE" "$OUTPUT_DIR/$filename" done <<<"$CAPTURE_PROFILES" # Capture the public views before login because the real admin-login hint # intentionally redirects authenticated personas away from /public/. if [[ "$capture_index" == "2" ]]; then - ABXPKG_LIB_DIR="$(uv run --project "$REPO_DIR" abx-dl config --get ABXPKG_LIB_DIR | sed 's/^[^=]*=//; s/^"//; s/"$//')" + ABXPKG_LIB_DIR="$(uv run --no-cache --project "$REPO_DIR" abx-dl config --get ABXPKG_LIB_DIR | sed 's/^[^=]*=//; s/^"//; s/"$//')" SCREENSHOT_CHROME_BINARY="$ABXPKG_LIB_DIR/env/bin/chromium" if [[ ! -x "$SCREENSHOT_CHROME_BINARY" ]]; then echo "[!] abx-dl projected Chromium was not found at $SCREENSHOT_CHROME_BINARY" >&2 @@ -344,7 +344,7 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do CREATE_WEBHOOK="$CREATE_WEBHOOK" \ node "$REPO_DIR/bin/setup_ui_screenshot_data.js" "$ADMIN_BASE_URL" "$USERNAME" - OPENCODE_PORT="$(uv run --project "$REPO_DIR" python - <<'PY' + OPENCODE_PORT="$(uv run --no-cache --project "$REPO_DIR" python - <<'PY' import socket with socket.socket() as sock: @@ -354,20 +354,20 @@ PY )" ( cd "$DATA_DIR" - OPENCODE_PORT="$OPENCODE_PORT" uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + OPENCODE_PORT="$OPENCODE_PORT" uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'import os; from archivebox.machine.models import Machine; Machine.from_json({"config": {"OPENCODE_ENABLED": True, "OPENCODE_PORT": int(os.environ["OPENCODE_PORT"])}})' - uv run --project "$REPO_DIR" archivebox install opencode --binproviders=env,pnpm + uv run --no-cache --project "$REPO_DIR" archivebox install opencode --binproviders=env,pnpm ) SWEETING_CAPTURE_STARTED_AT="$( ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from django.utils import timezone; print(timezone.now().isoformat())' ) | tail -1)" echo "[*] Starting a real Sweeting.me capture for the live progress view" ( cd "$DATA_DIR" - exec uv run --project "$REPO_DIR" archivebox add \ + exec uv run --no-cache --project "$REPO_DIR" archivebox add \ --depth=0 \ --overwrite \ --tag=screenshot-gallery \ @@ -379,7 +379,7 @@ PY for _attempt in $(seq 1 120); do LIVE_SNAPSHOT_RECORD="$( ( cd "$DATA_DIR" - UI_SCREENSHOT_CAPTURE_STARTED_AT="$SWEETING_CAPTURE_STARTED_AT" uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + UI_SCREENSHOT_CAPTURE_STARTED_AT="$SWEETING_CAPTURE_STARTED_AT" uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'import os; from django.utils.dateparse import parse_datetime; from archivebox.core.models import Snapshot; from archivebox.core.routes_util import build_snapshot_url; started_at=parse_datetime(os.environ["UI_SCREENSHOT_CAPTURE_STARTED_AT"]); snapshot=Snapshot.objects.filter(url__startswith="https://sweeting.me",bookmarked_at__gte=started_at).order_by("-bookmarked_at").first(); print(build_snapshot_url(str(snapshot.id), "") if snapshot else "")' ) | tail -1)" if [[ -n "$LIVE_SNAPSHOT_RECORD" ]]; then @@ -403,7 +403,7 @@ PY RECORD_CONFIG="$( ( cd "$DATA_DIR" - uv run --project "$REPO_DIR" archivebox manage shell --no-imports -c \ + uv run --no-cache --project "$REPO_DIR" archivebox manage shell --no-imports -c \ 'from django.db.models import Count; from archivebox.core.models import Snapshot, ArchiveResult, Tag; from archivebox.crawls.models import Crawl, CrawlSchedule; from archivebox.personas.models import Persona; from archivebox.machine.models import Machine, NetworkInterface, Binary, Process; from archivebox.api.models import APIToken; from django.contrib.auth import get_user_model; from signal_webhooks.utils import get_webhook_model; from archivebox.core.routes_util import build_snapshot_url; recent=list(Snapshot.objects.filter(status=Snapshot.StatusChoices.SEALED).order_by("-bookmarked_at").values_list("id", flat=True)[:1000]); counts=dict(ArchiveResult.objects.filter(snapshot_id__in=recent,status="succeeded").values_list("snapshot_id").annotate(Count("id"))); snapshot_id=str(max(recent,key=lambda item: counts.get(item,0))); snapshot=Snapshot.objects.get(id=snapshot_id); result=ArchiveResult.objects.filter(snapshot_id=snapshot_id,status="succeeded").order_by("-output_size").first() or ArchiveResult.objects.filter(snapshot_id=snapshot_id).first(); tag=snapshot.tags.first() or Tag.objects.first(); crawl=snapshot.crawl or Crawl.objects.order_by("-created_at").first(); schedule=CrawlSchedule.objects.order_by("-created_at").first(); persona=Persona.objects.exclude(name="Default").order_by("-created_at").first() or Persona.objects.first(); machine=Machine.objects.order_by("-modified_at").first(); interface=NetworkInterface.objects.order_by("-modified_at").first(); binary=Binary.objects.order_by("-modified_at").first(); process=Process.objects.order_by("-created_at").first(); token=APIToken.objects.order_by("-created_at").first(); webhook=get_webhook_model().objects.order_by("-created_at").first(); user=get_user_model().objects.get(username="'"$USERNAME"'"); values={"SNAPSHOT_ID":snapshot_id,"SNAPSHOT_VIEW_URL":build_snapshot_url(snapshot_id,""),"SNAPSHOT_FILES_URL":build_snapshot_url(snapshot_id,"/?files=1"),"ARCHIVERESULT_ID":str(result.id),"TAG_ID":str(tag.id),"USER_ID":str(user.id),"CRAWL_ID":str(crawl.id),"SCHEDULE_ID":str(schedule.id),"PERSONA_ID":str(persona.id),"MACHINE_ID":str(machine.id),"INTERFACE_ID":str(interface.id),"BINARY_ID":str(binary.id),"PROCESS_ID":str(process.id),"TOKEN_ID":str(token.id),"WEBHOOK_ID":str(webhook.id)}; [print(f"{key}={value}") for key,value in values.items()]' ) | tail -15)" eval "$RECORD_CONFIG" @@ -474,7 +474,7 @@ PY SCREENSHOT_WIDTH=1600 \ SCREENSHOT_HEIGHT=1000 \ node "$REPO_DIR/bin/take_screenshot.js" "$LIVE_SNAPSHOT_VIEW_URL" "$CAPTURE_ROOT/snapshot-output-discovery.png" >"$SNAPSHOT_DISCOVERY_REPORT" - SNAPSHOT_OUTPUT_PLUGINS="$(UI_SCREENSHOT_DISCOVERY_REPORT="$SNAPSHOT_DISCOVERY_REPORT" uv run --project "$REPO_DIR" python -c \ + SNAPSHOT_OUTPUT_PLUGINS="$(UI_SCREENSHOT_DISCOVERY_REPORT="$SNAPSHOT_DISCOVERY_REPORT" uv run --no-cache --project "$REPO_DIR" python -c \ 'import json, os; from urllib.parse import urlsplit; report=json.load(open(os.environ["UI_SCREENSHOT_DISCOVERY_REPORT"])); print("\n".join("{}\t{}".format(output["plugin"], "wait-replay:Nick Sweeting" if urlsplit(output["previewUrl"]).path.endswith(".wacz") else "") for output in report["checks"]["snapshotOutputs"]))')" if [[ -z "$SNAPSHOT_OUTPUT_PLUGINS" ]]; then echo "[!] The Sweeting.me snapshot detail page exposed no selectable outputs" >&2 @@ -492,7 +492,7 @@ PY done [[ "$MAX_VIEWS" != "0" ]] && export UI_SCREENSHOT_ALLOW_PARTIAL=1 -uv run --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" build \ +uv run --no-cache --project "$REPO_DIR" "$REPO_DIR/bin/generate_ui_screenshot_gallery.py" build \ "$MANIFEST_FILE" "$REPO_DIR/docs/Screenshots.md" "$PUBLIC_OUTPUT_DIR/index.html" echo "[+] Captured $capture_index views at desktop, tablet, and mobile sizes" diff --git a/etc/package.json b/etc/package.json index 5b30d65a..eb8b71ef 100644 --- a/etc/package.json +++ b/etc/package.json @@ -1,6 +1,6 @@ { "name": "archivebox", - "version": "0.9.35rc163", + "version": "0.9.35rc164", "repository": "github:ArchiveBox/ArchiveBox", "license": "MIT", "dependencies": { diff --git a/pyproject.toml b/pyproject.toml index 499be683..1c0ba14a 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "archivebox" -version = "0.9.35rc163" +version = "0.9.35rc164" requires-python = ">=3.13" description = "Self-hosted internet archiving solution." authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}] @@ -83,7 +83,7 @@ dependencies = [ "abxbus==2.5.40", # EventBus API "abxpkg", # direct imports only; version constrained by abx-dl -> abx-plugins "abx-plugins", # direct imports only; version constrained by abx-dl - "abx-dl==1.12.29", # shared ArchiveBox downloader package + "abx-dl==1.12.31", # shared ArchiveBox downloader package ### UUID7 backport for Python <3.14 "uuid7>=0.1.0; python_version < '3.14'", # provides the uuid_extensions module on Python 3.13 ] @@ -348,7 +348,7 @@ Donate = "https://github.com/ArchiveBox/ArchiveBox/wiki/Donations" [tool.bumpver] -current_version = "v0.9.35rc163" +current_version = "v0.9.35rc164" version_pattern = "vMAJOR.MINOR.PATCH[PYTAGNUM]" commit_message = "bump version {old_version} -> {new_version}" tag_message = "{new_version}" diff --git a/uv.lock b/uv.lock index 2bfeb335..0dc05849 100644 --- a/uv.lock +++ b/uv.lock @@ -24,7 +24,7 @@ abxpkg = "2100-01-01T00:00:00Z" [[package]] name = "abx-dl" -version = "1.12.29" +version = "1.12.31" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "abx-plugins" }, @@ -39,14 +39,14 @@ dependencies = [ { name = "rich" }, { name = "rich-click" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/27/1c/ef4512b5209a94f3e3945907ae3fbefc47ff2b630aff9f7d957cfb8917da/abx_dl-1.12.29.tar.gz", hash = "sha256:d072755cb069ae8f412316810ab38a7c754e03555d02e0d9a8eb5ae04a8b0d60", size = 86814, upload-time = "2026-07-28T17:52:24.237Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/12/a17dbf6ff8cd8a17ecbbd8b2c1b5ea47d2562299d9efd7bc7ba00b38d623/abx_dl-1.12.31.tar.gz", hash = "sha256:544a8ac11a08b390c021a92bfb7d648f85a3b110ed728864c6c6f798333b39d0", size = 86789, upload-time = "2026-07-29T03:20:31.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/ea/9c15aeacf2492004bca3874008dad34557e06c56ae6c6caf037c068b93a9/abx_dl-1.12.29-py3-none-any.whl", hash = "sha256:429da9b175680ead21cae69ebf3e22204ad16a48c0e656d65d82b9153014caf7", size = 90704, upload-time = "2026-07-28T17:52:23.154Z" }, + { url = "https://files.pythonhosted.org/packages/da/9d/2c02fbea7239f0aac9857c0670328b40ee16e5491ebd3fe802e2cb56a7a8/abx_dl-1.12.31-py3-none-any.whl", hash = "sha256:41c389573c05c6db47bb93ae0d45876cdbc22468dbf075204546d6da8eb23579", size = 90708, upload-time = "2026-07-29T03:20:29.935Z" }, ] [[package]] name = "abx-plugins" -version = "1.12.32" +version = "1.12.39" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "abxbus" }, @@ -56,9 +56,9 @@ dependencies = [ { name = "rich-click" }, { name = "uv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ac/08/0f0150ce87f2ed6d7bf946f0f5bb075d8dd7dc5ff2e42c92691ce62231b6/abx_plugins-1.12.32.tar.gz", hash = "sha256:24d18831da390fe88a81c239ebaf22b500cc36e6ebfd6f375a57824b6cc8c334", size = 260578, upload-time = "2026-07-28T15:20:39.477Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/2c/63433217fd2ae742cc81d00acd3585a714b1439b9916ea0dec3d25831f1a/abx_plugins-1.12.39.tar.gz", hash = "sha256:596bf68fd994364dd37bb4f2830dfe11ef0e676f9880ac44e278ea4f5fb0b964", size = 260565, upload-time = "2026-07-29T02:47:16.992Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0d/3cca76c0f94a883e3b619180b80232319932474448c0b38c633dd90b255d/abx_plugins-1.12.32-py3-none-any.whl", hash = "sha256:721d921554d4cacc6c756b737735b315ff7e74921ee1ce303d37f4ea727f05ba", size = 411230, upload-time = "2026-07-28T15:20:38.194Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5f/a7f3b33db738b52e96d16768cc6bbccaa230497b7f446cf3aa94201c66c9/abx_plugins-1.12.39-py3-none-any.whl", hash = "sha256:15d54449c7a0e534152ddb71bdb7fa83b0fa01f5883c52f5c52ead8a8dea5c74", size = 411239, upload-time = "2026-07-29T02:47:15.565Z" }, ] [[package]] @@ -77,7 +77,7 @@ wheels = [ [[package]] name = "abxpkg" -version = "1.12.25" +version = "1.12.26" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pip" }, @@ -86,9 +86,9 @@ dependencies = [ { name = "rich-click" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/e1ccdb0cee3bc18e33d00a6484273887836db54e96c75e5a2244287de97f/abxpkg-1.12.25.tar.gz", hash = "sha256:2cac56e9d624565c8b175d5f5469147ab7a756c0092b9bd13ee52ba94ae89287", size = 220914, upload-time = "2026-07-28T09:35:55.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/aa/ba5ad1fea91287a05eb6d563bd4bc8904104824e5429865671a4610d200d/abxpkg-1.12.26.tar.gz", hash = "sha256:fde0d3eaf854af21acc296a1aceeb51cae439fbd16d162183c774121f84e0a9a", size = 221167, upload-time = "2026-07-29T01:52:10.984Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/e1/80657dc861e6f73444579915f54994a4df86f940ab9f7fa447eb2756d569/abxpkg-1.12.25-py3-none-any.whl", hash = "sha256:d1580766c63ff7cd67209ce6bb3c61c6efcb5ae65fa332d482fca44f5f1dfbd4", size = 234632, upload-time = "2026-07-28T09:35:54.448Z" }, + { url = "https://files.pythonhosted.org/packages/76/2f/c3befcb4446a24f8ad22c51feae972cadf67cb5be4e169b809580a7c73c7/abxpkg-1.12.26-py3-none-any.whl", hash = "sha256:b3f11b4ceefebf8651311b59b5b34048eb9dfcfa090b735ec81da4264de13d54", size = 234868, upload-time = "2026-07-29T01:52:11.977Z" }, ] [[package]] @@ -123,7 +123,7 @@ wheels = [ [[package]] name = "archivebox" -version = "0.9.35rc163" +version = "0.9.35rc164" source = { editable = "." } dependencies = [ { name = "abx-dl" }, @@ -223,7 +223,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "abx-dl", specifier = "==1.12.29" }, + { name = "abx-dl", specifier = "==1.12.31" }, { name = "abx-plugins" }, { name = "abxbus", specifier = "==2.5.40" }, { name = "abxpkg" },