Compare commits
18
Commits
v0.9.72rc97
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fcda80297 | ||
|
|
e94a489daa | ||
|
|
df605452ba | ||
|
|
b472401d2f | ||
|
|
e4a1e400e8 | ||
|
|
2ce7074118 | ||
|
|
03bd48e399 | ||
|
|
edd1265b42 | ||
|
|
6bafaa99d7 | ||
|
|
53e3e9787b | ||
|
|
8e82de7f4a | ||
|
|
41dfc384aa | ||
|
|
66d88542f6 | ||
|
|
268b520394 | ||
|
|
3a3557ac72 | ||
|
|
b8ba9a64cd | ||
|
|
58a7955835 | ||
|
|
564af2fa3e |
No files matched your search
@@ -451,7 +451,9 @@ jobs:
|
||||
"$DOCKER_BINARY" run --name www-nginx -p 80:80 -d nginx:1.29.5@sha256:0236ee02dcbce00b9bd83e0f5fbc51069e7e1161bd59d99885b3ae1734f3392e
|
||||
|
||||
"$DOCKER_BINARY" run -v "$PWD"/data:/data --network host "$ARCHIVEBOX_IMAGE" add http://www.test-nginx-1.local
|
||||
echo "http://www.test-nginx-2.local" | "$DOCKER_BINARY" run -i --network host -v "$PWD"/data:/data "$ARCHIVEBOX_IMAGE" add
|
||||
# The argument form above exercises the complete default pipeline.
|
||||
# Keep a real capture for stdin parsing without repeating every plugin.
|
||||
echo "http://www.test-nginx-2.local" | "$DOCKER_BINARY" run -i --network host -v "$PWD"/data:/data "$ARCHIVEBOX_IMAGE" add --plugins=wget,hashes
|
||||
|
||||
archive_list="$("$DOCKER_BINARY" run -v "$PWD"/data:/data "$ARCHIVEBOX_IMAGE" list)"
|
||||
[[ "$archive_list" == *"www.test-nginx-1.local"* ]] || { echo "The site 1 isn't in the list"; exit 1; }
|
||||
|
||||
@@ -120,6 +120,9 @@ jobs:
|
||||
if [[ "$CI_RUNNER_ENVIRONMENT" == github-hosted ]]; then
|
||||
workers="$(nproc)"
|
||||
cache_suffix="-workers-$workers"
|
||||
# Avoid the hosted image's cold Chromium executable page faults.
|
||||
# abxpkg owns installation and reuse in the existing runtime cache.
|
||||
echo "CHROME_BINPROVIDERS=playwright,puppeteer" >> "$GITHUB_ENV"
|
||||
fi
|
||||
{
|
||||
echo "CI_TEST_WORKERS=$workers"
|
||||
|
||||
@@ -170,6 +170,18 @@ class ResourceAdmission:
|
||||
used_bytes = 0
|
||||
for child in processes:
|
||||
try:
|
||||
if sys.platform.startswith("linux"):
|
||||
try:
|
||||
memory = child.memory_full_info()
|
||||
# Chrome's processes share substantial resident
|
||||
# memory. RSS charges those pages once per process
|
||||
# and can falsely serialize captures on an idle host.
|
||||
used_bytes += memory.pss + memory.swap
|
||||
continue
|
||||
except psutil.AccessDenied:
|
||||
# Restricted /proc access still gets conservative
|
||||
# accounting through the available RSS measurement.
|
||||
pass
|
||||
used_bytes += child.memory_info().rss
|
||||
except (psutil.Error, OSError):
|
||||
continue
|
||||
|
||||
@@ -52,6 +52,7 @@ def test_persona_import_real_browser_session(initialized_archive, tmp_path, http
|
||||
import json
|
||||
import shlex
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from werkzeug.wrappers import Response
|
||||
from archivebox.tests.conftest import resolve_abxpkg_chrome_env
|
||||
@@ -167,7 +168,9 @@ const puppeteer = require(process.argv[1]);
|
||||
assert archived.returncode == 0, archived.stderr
|
||||
launch_commands = list((initialized_archive / "archive" / "users").glob("*/crawls/**/chrome/cmd.sh"))
|
||||
assert len(launch_commands) == 1
|
||||
assert shlex.split(launch_commands[0].read_text().splitlines()[1])[0] == browser_env["CHROME_BINARY"]
|
||||
launched_browser = Path(shlex.split(launch_commands[0].read_text().splitlines()[1])[0])
|
||||
# abxpkg's environment and provider projections can name the same binary.
|
||||
assert launched_browser.samefile(browser_env["CHROME_BINARY"])
|
||||
outputs = list((initialized_archive / "archive" / "users").glob("*/snapshots/**/dom/output.html"))
|
||||
assert len(outputs) == 1
|
||||
html = outputs[0].read_text()
|
||||
|
||||
@@ -159,7 +159,7 @@ print(json.dumps({{
|
||||
assert not Path(retained["archiveresult_dir"]).exists()
|
||||
|
||||
|
||||
def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
def test_delete_after_real_add_page_and_rest_create_paths(client, recursive_test_site):
|
||||
from archivebox.personas.models import Persona
|
||||
|
||||
# Match init/server startup; visiting /add/ must not create persona records.
|
||||
@@ -172,6 +172,7 @@ def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
)
|
||||
|
||||
client.force_login(admin_user)
|
||||
ui_url, rest_url = recursive_test_site["child_urls"][:2]
|
||||
response = client.get(reverse("add"), HTTP_HOST=ADMIN_HOST)
|
||||
assert response.status_code == 200
|
||||
assert 'name="delete_after"' in response.content.decode()
|
||||
@@ -179,7 +180,7 @@ def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
response = client.post(
|
||||
reverse("add"),
|
||||
data={
|
||||
"url": "https://example.com/delete-after-ui",
|
||||
"url": ui_url,
|
||||
"tag": "retention-ui",
|
||||
"depth": "0",
|
||||
"max_urls": "1",
|
||||
@@ -203,13 +204,13 @@ def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
|
||||
from archivebox.crawls.models import Crawl
|
||||
|
||||
ui_crawl = Crawl.objects.get(urls__contains="https://example.com/delete-after-ui")
|
||||
ui_crawl = Crawl.objects.get(urls=ui_url)
|
||||
assert ui_crawl.config["DELETE_AFTER"] == "2h"
|
||||
assert ui_crawl.delete_at is not None
|
||||
from archivebox.services.runner import run_due_crawl
|
||||
|
||||
assert run_due_crawl(ui_crawl, lock_seconds=10)
|
||||
ui_snapshot = ui_crawl.snapshot_set.get(url="https://example.com/delete-after-ui")
|
||||
ui_snapshot = ui_crawl.snapshot_set.get(url=ui_url)
|
||||
assert ui_snapshot.delete_at is not None
|
||||
assert not ui_snapshot.output_dir.joinpath("staticfile", "stdin.txt").exists()
|
||||
|
||||
@@ -221,10 +222,12 @@ def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
"/api/v1/crawls/crawls",
|
||||
data=json.dumps(
|
||||
{
|
||||
"urls": ["https://example.com/delete-after-rest"],
|
||||
"urls": [rest_url],
|
||||
"max_depth": 0,
|
||||
"max_urls": 1,
|
||||
"config": {"DELETE_AFTER": "3h"},
|
||||
# Exercise retention through a real capture. The full plugin
|
||||
# pipeline has its own recursive-crawl integration coverage.
|
||||
"config": {"DELETE_AFTER": "3h", "PLUGINS": "wget,hashes"},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
@@ -232,9 +235,16 @@ def test_delete_after_real_add_page_and_rest_create_paths(client):
|
||||
HTTP_X_ARCHIVEBOX_API_KEY=api_token.token,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
rest_crawl = Crawl.objects.get(urls__contains="https://example.com/delete-after-rest")
|
||||
rest_crawl = Crawl.objects.get(urls=rest_url)
|
||||
assert rest_crawl.config["DELETE_AFTER"] == "3h"
|
||||
assert rest_crawl.delete_at is not None
|
||||
assert run_due_crawl(rest_crawl, lock_seconds=10)
|
||||
rest_snapshot = rest_crawl.snapshot_set.get(url="https://example.com/delete-after-rest")
|
||||
rest_snapshot = rest_crawl.snapshot_set.get(url=rest_url)
|
||||
assert rest_snapshot.delete_at is not None
|
||||
from archivebox.core.models import ArchiveResult
|
||||
|
||||
for plugin in ("wget", "hashes"):
|
||||
result = rest_snapshot.archiveresult_set.get(plugin=plugin)
|
||||
assert result.status == ArchiveResult.StatusChoices.SUCCEEDED
|
||||
assert result.delete_at is not None
|
||||
assert result.output_size > 0
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from archivebox.services.resource_admission import ResourceAdmission, disk_backed_swap_free_bytes
|
||||
|
||||
@@ -55,6 +56,59 @@ def test_memory_observation_tracks_a_real_child_process():
|
||||
assert child.wait(timeout=10) == 0
|
||||
|
||||
|
||||
def test_memory_observation_counts_shared_pages_once_on_linux():
|
||||
admission = ResourceAdmission()
|
||||
before = admission.memory_headroom()
|
||||
assert before is not None
|
||||
size = 128 * 1024 * 1024
|
||||
child = subprocess.Popen(
|
||||
[
|
||||
"uv",
|
||||
"run",
|
||||
"python",
|
||||
"-c",
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
allocation = bytearray(128 * 1024 * 1024)
|
||||
children = []
|
||||
for _ in range(2):
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
sys.stdin.read()
|
||||
os._exit(0)
|
||||
children.append(pid)
|
||||
print(len(allocation), flush=True)
|
||||
sys.stdin.read()
|
||||
for pid in children:
|
||||
os.waitpid(pid, 0)
|
||||
""",
|
||||
],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
try:
|
||||
assert child.stdout is not None
|
||||
assert child.stdout.readline().strip() == str(size)
|
||||
during = admission.memory_headroom()
|
||||
assert during is not None
|
||||
growth = during[0] - before[0]
|
||||
assert growth > size // 2
|
||||
finite_cgroup = any(
|
||||
(path / "memory.max").is_file() and (path / "memory.max").read_text().strip() != "max" for path in admission.cgroup_paths()
|
||||
)
|
||||
if sys.platform.startswith("linux") and not finite_cgroup:
|
||||
# These three real processes share one allocation. Linux PSS and
|
||||
# summing RSS differ by two copies. A finite cgroup instead measures
|
||||
# the entire container, including unrelated concurrent test workers.
|
||||
assert growth < size * 2, f"Shared allocation counted repeatedly: {growth}"
|
||||
finally:
|
||||
assert child.stdin is not None
|
||||
child.stdin.close()
|
||||
assert child.wait(timeout=10) == 0
|
||||
|
||||
|
||||
def test_disk_backed_swap_headroom_excludes_zram_but_keeps_backing_swap():
|
||||
swaps = """Filename Type Size Used Priority
|
||||
/dev/zram0 partition 1000 100 100
|
||||
|
||||
@@ -659,6 +659,14 @@ def test_plugin_grid_includes_all_visible_plugins_and_timestamps_last(admin_clie
|
||||
assert len(names) == len(expected)
|
||||
for name in expected:
|
||||
assert f'data-plugin-name="{name}"'.encode() in response.content
|
||||
# The same schema drives both editors, including newly installed plugins.
|
||||
# Check every plugin's category and rendered controls, not a fixed allowlist.
|
||||
catalog = get_plugin_catalog()
|
||||
for group in form.plugin_groups:
|
||||
for card in group["plugins"]:
|
||||
assert group["field_name"] == f"{catalog[card['name']].config.category}_plugins"
|
||||
for field in card["config_fields"]:
|
||||
assert f'name="{field["input_name"]}"'.encode() in response.content
|
||||
postprocessing = next(group for group in form.plugin_groups if group["field_name"] == "postprocessing_plugins")
|
||||
assert postprocessing["plugins"][-1]["name"] == "opentimestamps"
|
||||
assert b'name="plugin_config__opentimestamps__OPENTIMESTAMPS_TIMEOUT"' in response.content
|
||||
|
||||
@@ -156,7 +156,6 @@ if [[ "$HAS_USEFUL_SNAPSHOT" == "0" ]]; then
|
||||
--depth=0 \
|
||||
--overwrite \
|
||||
--tag=documentation,reference \
|
||||
--plugins=title,headers,wget,screenshot,pdf,dom,readability,htmltotext,hashes,dns \
|
||||
https://docs.sweeting.me/s/cookie-dilemma https://archivebox.io
|
||||
)
|
||||
fi
|
||||
@@ -267,11 +266,11 @@ VIEWS=(
|
||||
add_supplementary_template_capture() {
|
||||
local plugin_names="$1"
|
||||
local source_url="$2"
|
||||
local prepare_plugins="$3"
|
||||
local capture_plugins="${prepare_plugins:-$plugin_names}"
|
||||
local capture_log="$CAPTURE_ROOT/${plugin_names}-supplementary-capture.log"
|
||||
local supplementary_plugins=()
|
||||
IFS=',' read -r -a supplementary_plugins <<<"$plugin_names"
|
||||
# These are real all-plugin captures. The recipe only selects which output
|
||||
# to photograph, never which extractors run or which dependencies get saved.
|
||||
echo "[*] Capturing real $plugin_names source for template coverage"
|
||||
if ! (
|
||||
cd "$DATA_DIR"
|
||||
@@ -279,7 +278,6 @@ add_supplementary_template_capture() {
|
||||
--depth=0 \
|
||||
--overwrite \
|
||||
--tag=screenshot-gallery \
|
||||
--plugins="$capture_plugins" \
|
||||
"$source_url"
|
||||
) >"$capture_log" 2>&1; then
|
||||
echo "[!] Supplementary $plugin_names capture failed" >&2
|
||||
@@ -302,20 +300,6 @@ add_supplementary_template_capture() {
|
||||
|
||||
local snapshot_id snapshot_view_url snapshot_view_path
|
||||
IFS=$'\t' read -r snapshot_id snapshot_view_url snapshot_view_path <<<"$snapshot_record"
|
||||
if [[ -n "$prepare_plugins" ]]; then
|
||||
if ! (
|
||||
cd "$DATA_DIR"
|
||||
uv run --no-cache --project "$REPO_DIR" archivebox extract \
|
||||
--plugins="$plugin_names" \
|
||||
"$snapshot_id"
|
||||
) >>"$capture_log" 2>&1; then
|
||||
echo "[!] $plugin_names extraction failed for the prepared snapshot" >&2
|
||||
tail -100 "$capture_log" >&2
|
||||
exit 1
|
||||
fi
|
||||
stop_background_runner
|
||||
fi
|
||||
|
||||
local discovery_report="$CAPTURE_ROOT/${plugin_names}-output-discovery.json"
|
||||
NODE_PATH="$ABXPKG_LIB_DIR/pnpm/packages/chrome/node_modules" \
|
||||
CHROME_BINARY="$SCREENSHOT_CHROME_BINARY" \
|
||||
@@ -360,6 +344,12 @@ while [[ "$capture_index" -lt "${#VIEWS[@]}" ]]; do
|
||||
[[ "$capture_mode" != wait-text:* ]] || wait_for_text="${capture_mode#wait-text:}"
|
||||
preview_wait_for_text=""
|
||||
[[ "$capture_mode" != wait-preview-text:* ]] || preview_wait_for_text="${capture_mode#wait-preview-text:}"
|
||||
config_selector=""
|
||||
config_click_selector=""
|
||||
if [[ "$capture_mode" == plugin-config:* ]]; then
|
||||
config_selector="[data-plugin-name='${capture_mode#plugin-config:}']"
|
||||
config_click_selector="$config_selector .plugin-config-marker"
|
||||
fi
|
||||
view_timing_report=""
|
||||
while IFS='|' read -r profile _viewport_width _viewport_height; do
|
||||
filename="$slug-$profile.png"
|
||||
@@ -483,6 +473,8 @@ PY
|
||||
SCREENSHOT_HEIGHT=1000 \
|
||||
SCREENSHOT_VARIANTS_JSON="$output_variants" \
|
||||
SCREENSHOT_COLLAPSE_FILTERS=1 \
|
||||
SCREENSHOT_CLICK_SELECTOR="$config_click_selector" \
|
||||
SCREENSHOT_SCROLL_SELECTOR="$config_selector" \
|
||||
SCREENSHOT_SNAPSHOT_HEADER="$snapshot_header" \
|
||||
SCREENSHOT_WAIT_FOR_TEXT="$wait_for_text" \
|
||||
SCREENSHOT_PREVIEW_WAIT_FOR_TEXT="$preview_wait_for_text" \
|
||||
@@ -655,11 +647,18 @@ PY
|
||||
[[ -z "$plugin_name" ]] && continue
|
||||
VIEWS+=("Snapshot View ($plugin_name)|$LIVE_SNAPSHOT_VIEW_URL#$output_path|$LIVE_SNAPSHOT_VIEW_PATH|archivebox/templates/core/snapshot.html|$output_capture_mode")
|
||||
done <<<"$SNAPSHOT_OUTPUT_PLUGINS"
|
||||
while IFS='|' read -r example_plugins example_url example_prepare; do
|
||||
while IFS='|' read -r example_plugins example_url; do
|
||||
[[ -z "$example_plugins" ]] && continue
|
||||
add_supplementary_template_capture "$example_plugins" "$example_url" "$example_prepare"
|
||||
add_supplementary_template_capture "$example_plugins" "$example_url"
|
||||
done < <(uv run --no-cache --project "$REPO_DIR" python -c \
|
||||
'import json,sys; plan=json.load(open(sys.argv[1])); print("\n".join("|".join((",".join(example["plugins"]), example["url"], ",".join(example["prepare_plugins"]))) for example in plan["examples"]))' \
|
||||
'import json,sys; plan=json.load(open(sys.argv[1])); print("\n".join("|".join((",".join(example["plugins"]), example["url"])) for example in plan["examples"]))' \
|
||||
"$PLUGIN_SCREENSHOT_PLAN")
|
||||
|
||||
while IFS='|' read -r config_name config_plugin; do
|
||||
[[ -z "$config_plugin" ]] && continue
|
||||
VIEWS+=("$config_name|$ADMIN_BASE_URL/add/|/add/|archivebox/templates/plugins/plugin_config_grid.html|plugin-config:$config_plugin")
|
||||
done < <(uv run --no-cache --project "$REPO_DIR" python -c \
|
||||
'import json,sys; print("\n".join(view["name"] + "|" + view["plugin"] for view in json.load(open(sys.argv[1]))["config_views"]))' \
|
||||
"$PLUGIN_SCREENSHOT_PLAN")
|
||||
|
||||
VIEWS+=("Snapshot View (header collapsed)|$LIVE_SNAPSHOT_VIEW_URL|$LIVE_SNAPSHOT_VIEW_PATH|archivebox/templates/core/snapshot.html|snapshot-collapsed")
|
||||
|
||||
@@ -67,6 +67,7 @@ def plugin_screenshot_plan() -> dict:
|
||||
required = []
|
||||
examples = {}
|
||||
overrides = {}
|
||||
config_views = []
|
||||
enabled_plugins = []
|
||||
for plugin_dir in sorted(get_plugins_dir().iterdir()):
|
||||
config_path = plugin_dir / "config.json"
|
||||
@@ -81,6 +82,8 @@ def plugin_screenshot_plan() -> dict:
|
||||
enabled = True
|
||||
if recipe.get("view"):
|
||||
required.append(recipe["view"])
|
||||
if recipe.get("config"):
|
||||
config_views.append({"name": recipe["view"], "plugin": plugin})
|
||||
elif enabled and (
|
||||
recipe.get("url")
|
||||
or (plugin_dir / "templates/full.html").is_file()
|
||||
@@ -89,10 +92,16 @@ def plugin_screenshot_plan() -> dict:
|
||||
required.append(f"Snapshot View ({plugin})")
|
||||
if recipe.get("url"):
|
||||
overrides[plugin] = recipe
|
||||
key = (recipe["url"], tuple(recipe.get("prepare_plugins", [])))
|
||||
example = examples.setdefault(key, {"url": key[0], "prepare_plugins": list(key[1]), "plugins": []})
|
||||
key = recipe["url"]
|
||||
example = examples.setdefault(key, {"url": key, "plugins": []})
|
||||
example["plugins"].append(plugin)
|
||||
return {"required": required, "examples": list(examples.values()), "overrides": overrides, "enabled": enabled_plugins}
|
||||
return {
|
||||
"required": required,
|
||||
"examples": list(examples.values()),
|
||||
"overrides": overrides,
|
||||
"enabled": enabled_plugins,
|
||||
"config_views": config_views,
|
||||
}
|
||||
|
||||
|
||||
def build_provenance() -> dict[str, str]:
|
||||
|
||||
@@ -374,12 +374,7 @@ async function main() {
|
||||
if (process.env.SCREENSHOT_AFTER_CLICK_WAIT_SELECTOR) {
|
||||
await page.waitForSelector(process.env.SCREENSHOT_AFTER_CLICK_WAIT_SELECTOR, { timeout: 45000 });
|
||||
}
|
||||
if (process.env.SCREENSHOT_SCROLL_SELECTOR) {
|
||||
await page.waitForSelector(process.env.SCREENSHOT_SCROLL_SELECTOR, { timeout: 45000 }).catch(() => {});
|
||||
await page.evaluate((selector) => {
|
||||
document.querySelector(selector)?.scrollIntoView({ block: 'start', inline: 'nearest' });
|
||||
}, process.env.SCREENSHOT_SCROLL_SELECTOR);
|
||||
}
|
||||
|
||||
|
||||
if (requireLiveProgress) {
|
||||
await waitForLiveProgress(page, liveProgressDeadline, screencastResponses);
|
||||
@@ -446,6 +441,14 @@ async function main() {
|
||||
const screenshotPaths = [];
|
||||
if (requireLiveProgress) checks.liveProgressCaptures = [];
|
||||
const capture = async (screenshotPath) => {
|
||||
// Resizing can move the target to a different row/column. Re-anchor each
|
||||
// gallery variant so it photographs the requested controls at every width.
|
||||
if (process.env.SCREENSHOT_SCROLL_SELECTOR) {
|
||||
await page.waitForSelector(process.env.SCREENSHOT_SCROLL_SELECTOR, { timeout: 45000 }).catch(() => {});
|
||||
await page.evaluate((selector) => {
|
||||
document.querySelector(selector)?.scrollIntoView({ block: 'start', inline: 'nearest' });
|
||||
}, process.env.SCREENSHOT_SCROLL_SELECTOR);
|
||||
}
|
||||
await waitForVisibleCardPreviews(page, requireLiveProgress ? Math.max(1, liveProgressDeadline - Date.now()) : 45000);
|
||||
if (requireLiveProgress) {
|
||||
const liveProgress = await waitForLiveProgress(page, liveProgressDeadline, screencastResponses);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "archivebox",
|
||||
"version": "0.9.72rc97",
|
||||
"version": "0.9.72rc105",
|
||||
"repository": "github:ArchiveBox/ArchiveBox",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "archivebox"
|
||||
version = "0.9.72rc97"
|
||||
version = "0.9.72rc105"
|
||||
requires-python = ">=3.13"
|
||||
description = "Self-hosted internet archiving solution."
|
||||
authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}]
|
||||
@@ -79,8 +79,8 @@ dependencies = [
|
||||
### Binary/Package Management
|
||||
"abxbus==2.5.74", # direct imports only; version constrained by abx-dl -> abx-plugins
|
||||
"abxpkg==1.13.33", # direct imports only; version constrained by abx-dl -> abx-plugins
|
||||
"abx-plugins[opencode]==1.13.147", # optional AI runtime clients are owned by the plugin
|
||||
"abx-dl==1.13.122", # shared ArchiveBox downloader package
|
||||
"abx-plugins[opencode]==1.13.161", # optional AI runtime clients are owned by the plugin
|
||||
"abx-dl==1.13.126", # 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
|
||||
"browser-cookie3>=0.20.1",
|
||||
@@ -344,7 +344,7 @@ Donate = "https://github.com/ArchiveBox/ArchiveBox/wiki/Donations"
|
||||
|
||||
|
||||
[tool.bumpver]
|
||||
current_version = "v0.9.72rc97"
|
||||
current_version = "v0.9.72rc105"
|
||||
version_pattern = "vMAJOR.MINOR.PATCH[PYTAGNUM]"
|
||||
commit_message = "bump version {old_version} -> {new_version}"
|
||||
tag_message = "{new_version}"
|
||||
|
||||
@@ -13,18 +13,18 @@ supported-markers = [
|
||||
]
|
||||
|
||||
[options]
|
||||
exclude-newer = "2026-09-30T02:56:00.744881213Z"
|
||||
exclude-newer = "2026-10-01T07:11:37.418401316Z"
|
||||
exclude-newer-span = "P5D"
|
||||
|
||||
[options.exclude-newer-package]
|
||||
abxbus = { timestamp = "2026-10-05T02:55:59.744891265Z", span = "PT1S" }
|
||||
abxbus = { timestamp = "2026-10-06T07:11:36.418414Z", span = "PT1S" }
|
||||
abx-plugins = "2100-01-01T00:00:00Z"
|
||||
abx-dl = "2100-01-01T00:00:00Z"
|
||||
abxpkg = "2100-01-01T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "abx-dl"
|
||||
version = "1.13.122"
|
||||
version = "1.13.126"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "abx-plugins", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -38,14 +38,14 @@ dependencies = [
|
||||
{ name = "rich", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
{ name = "rich-click", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a4/f3/a0c4f9a6433d0f05f4b3c4b2d92768f344a02e8b2eda27a509c876bdc7db/abx_dl-1.13.122.tar.gz", hash = "sha256:04580f090bee8b80c4002b54cb604aee33174b51db7ad7b612d9747b9df48f0c", size = 98174, upload-time = "2026-10-05T02:54:52.145Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/80/f30434e2e081d33c1b46233e9b284c98cff9eb8895b5fd546204953849b7/abx_dl-1.13.126.tar.gz", hash = "sha256:bdd29b626fba7a35f39865e5769b3b6ea1145a9953f2cf3aa14379eae192c248", size = 98185, upload-time = "2026-10-06T07:10:19.966Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/b9/84694686adc69316f7a50e22eb0d65bb42e09a533153b2d61cc9b11f5da8/abx_dl-1.13.122-py3-none-any.whl", hash = "sha256:71615ee13ec81105955835d78cd8ed407f2a2f538be21dacc48b326bfd9242a9", size = 103547, upload-time = "2026-10-05T02:54:53.173Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/3e/f666f8294a31a8acd9189d790585f453e0ccecbb0a9ed9c9163c28ba6a10/abx_dl-1.13.126-py3-none-any.whl", hash = "sha256:7eb1e7295b4d11c5225d6fcd100e51069dc1022818e0c8f50abdf7d24ba4434d", size = 103547, upload-time = "2026-10-06T07:10:21.456Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abx-plugins"
|
||||
version = "1.13.147"
|
||||
version = "1.13.161"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "abxbus", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -54,9 +54,9 @@ dependencies = [
|
||||
{ name = "rich-click", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
{ name = "uv", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7e/74/af72b84bc3cacb335c0b981fd60c6e46d97dfda339b2662269ddbff29e4e/abx_plugins-1.13.147.tar.gz", hash = "sha256:f8727dbf674d1ef8070d4edff7119e8e8f8d74c26f4f3bd4d92147c969c65de7", size = 504853, upload-time = "2026-10-05T02:48:06.025Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/9d/9e442f90b30eb34fe4be44444d399685f453d3e452961018f7f91eaca173/abx_plugins-1.13.161.tar.gz", hash = "sha256:eb80af30d259716d4c713c708197328ca7fe0ad0b7fe05c27ef3bcb8112913e3", size = 509069, upload-time = "2026-10-06T07:02:15.305Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/82/ad/e828a1f0deba8d74f6b1fb830bd73a46f53ed5bab7c6ab2ee26910c98164/abx_plugins-1.13.147-py3-none-any.whl", hash = "sha256:4f41b387cd40644110fc281e3aed70a88e7f5692e734a8ee28d9f8aa1ba3f4b1", size = 733937, upload-time = "2026-10-05T02:48:07.7Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/2b/da4c917bd49e92ba059b5a93b21f49499b5d385c15db23e2bc4ced834eb9/abx_plugins-1.13.161-py3-none-any.whl", hash = "sha256:1a88ec1580fa522718cf77049fd841441bd041cea63d8e38d4d1947e8b5b7b6a", size = 739583, upload-time = "2026-10-06T07:02:12.819Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -127,7 +127,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "archivebox"
|
||||
version = "0.9.72rc97"
|
||||
version = "0.9.72rc105"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "abx-dl", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -228,8 +228,8 @@ dev = [
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "abx-dl", specifier = "==1.13.122" },
|
||||
{ name = "abx-plugins", extras = ["opencode"], specifier = "==1.13.147" },
|
||||
{ name = "abx-dl", specifier = "==1.13.126" },
|
||||
{ name = "abx-plugins", extras = ["opencode"], specifier = "==1.13.161" },
|
||||
{ name = "abxbus", specifier = "==2.5.74" },
|
||||
{ name = "abxpkg", specifier = "==1.13.33" },
|
||||
{ name = "archivebox", extras = ["sonic", "ldap", "debug"], marker = "extra == 'all'" },
|
||||
|
||||
Reference in new issue
Block a user