From a5cc0c677696d09c8e0329130395abd77e6f3217 Mon Sep 17 00:00:00 2001 From: deepend-tildeclub Date: Tue, 9 Jun 2026 12:09:14 -0600 Subject: [PATCH] Fix offline docs install paths --- data/misc/fetch_offline_docs.py | 79 +++++++++++++++++++++++++------- flatpak/net.zoite.Zoitechat.json | 3 +- meson_options.txt | 4 +- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/data/misc/fetch_offline_docs.py b/data/misc/fetch_offline_docs.py index e18261e3..442817cb 100644 --- a/data/misc/fetch_offline_docs.py +++ b/data/misc/fetch_offline_docs.py @@ -1,42 +1,89 @@ #!/usr/bin/env python3 + import html import io import pathlib import shutil import sys import tarfile +import tempfile import urllib.error import urllib.request + url = sys.argv[1] out_dir = pathlib.Path(sys.argv[2]) source_dir = pathlib.Path(sys.argv[3]) if len(sys.argv) > 3 else pathlib.Path.cwd() -docs_dir = out_dir / 'offline-docs' +docs_dir = out_dir / "offline-docs" + if docs_dir.exists(): shutil.rmtree(docs_dir) docs_dir.mkdir(parents=True, exist_ok=True) -def write_source_docs(): - parts = ['ZoiteChat Documentation

ZoiteChat Documentation

'] - for name in ('readme.md', 'troubleshooting.md', 'changelog.rst'): + +def write_source_docs() -> None: + parts = [ + '' + "ZoiteChat Documentation" + "

ZoiteChat Documentation

" + ] + + for name in ("readme.md", "troubleshooting.md", "changelog.rst"): path = source_dir / name if path.exists(): - parts.append(f'

{html.escape(name)}

{html.escape(path.read_text(encoding="utf-8", errors="replace"))}
') - parts.append('') - (docs_dir / 'index.html').write_text('\n'.join(parts), encoding='utf-8') + parts.append( + f"

{html.escape(name)}

" + f"
{html.escape(path.read_text(encoding='utf-8', errors='replace'))}
" + ) + + parts.append("") + (docs_dir / "index.html").write_text("\n".join(parts), encoding="utf-8") + + +def safe_extract(tar: tarfile.TarFile, target: pathlib.Path) -> None: + target = target.resolve() + + for member in tar.getmembers(): + member_path = (target / member.name).resolve() + if not str(member_path).startswith(str(target) + "/"): + raise tarfile.TarError(f"unsafe archive path: {member.name}") + + tar.extractall(target) + + +def copy_index_tree(extracted_dir: pathlib.Path) -> bool: + indexes = sorted(extracted_dir.rglob("index.html")) + if not indexes: + return False + + root = indexes[0].parent + for item in root.iterdir(): + dest = docs_dir / item.name + if item.is_dir(): + shutil.copytree(item, dest, dirs_exist_ok=True) + else: + shutil.copy2(item, dest) + + return (docs_dir / "index.html").exists() + if url: try: - with urllib.request.urlopen(url, timeout=30) as r: - data = r.read() - with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tar: - try: - tar.extractall(docs_dir, filter='data') - except TypeError: - tar.extractall(docs_dir) + with urllib.request.urlopen(url, timeout=30) as response: + data = response.read() + + with tempfile.TemporaryDirectory() as tmp: + extract_dir = pathlib.Path(tmp) + with tarfile.open(fileobj=io.BytesIO(data), mode="r:gz") as tar: + safe_extract(tar, extract_dir) + + if not copy_index_tree(extract_dir): + write_source_docs() + except (OSError, tarfile.TarError, urllib.error.URLError) as error: - print(f'offline docs download failed: {error}', file=sys.stderr) + print(f"offline docs download failed: {error}", file=sys.stderr) write_source_docs() else: write_source_docs() -(out_dir / 'offline-docs.stamp').write_text('ok') + +(out_dir / "offline-docs.stamp").write_text("ok", encoding="utf-8") diff --git a/flatpak/net.zoite.Zoitechat.json b/flatpak/net.zoite.Zoitechat.json index 9b37e0ad..477797d9 100644 --- a/flatpak/net.zoite.Zoitechat.json +++ b/flatpak/net.zoite.Zoitechat.json @@ -57,7 +57,8 @@ "-Dwith-perl=perl", "-Dwith-python=python3", "-Dwith-lua=lua", - "-Doffline-docs-package=net.zoite.Zoitechat" + "-Doffline-docs-package=net.zoite.Zoitechat", + "-Doffline-docs-dir=share/zoitechat/offline-docs" ], "build-options": { "cflags": "-Wno-error=missing-include-dirs" diff --git a/meson_options.txt b/meson_options.txt index 63bc81b1..3559db56 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -63,12 +63,12 @@ option('with-perl-legacy-api', type: 'boolean', value: false, description: 'Enables the legacy IRC perl module for compatibility with old scripts' ) -option('offline-docs-url', type: 'string', value: '', +option('offline-docs-url', type: 'string', value: 'https://dl.zoitechat.org/offlinedocs/zoitechat-docs-html-2.18.1.tar.gz', description: 'URL for offline documentation archive (tar.gz)' ) option('offline-docs-package', type: 'string', value: '', description: 'Package or app id to use under the installed documentation directory' ) -option('offline-docs-dir', type: 'string', value: 'https://dl.zoitechat.org/offlinedocs/zoitechat-docs-html-2.18.1.tar.gz', +option('offline-docs-dir', type: 'string', value: '', description: 'Installed offline documentation directory relative to prefix' )