-
-
Notifications
You must be signed in to change notification settings - Fork 209
seo: per-app software pages + per-page og/meta tags #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| #!/usr/bin/env bash | ||
| # Offline preview of the docs, reproducing the "Pull from Armbian config" CI job | ||
| # locally: generate the software pages in configng, copy them into this repo, | ||
| # then serve with live reload. | ||
| # | ||
| # ./serve-docs-local.sh generate + stage + serve at http://127.0.0.1:8000 | ||
| # ./serve-docs-local.sh build generate + stage + one-shot build into ./site | ||
| # ./serve-docs-local.sh clean revert the staged generated pages, leave tree clean | ||
| # | ||
| # Override repo locations with CONFIGNG=/path DOCS=/path if they aren't the | ||
| # defaults below. | ||
| set -euo pipefail | ||
|
|
||
| DOCS="${DOCS:-$(cd "$(dirname "$0")" && pwd)}" | ||
| CONFIGNG="${CONFIGNG:-$(cd "$DOCS/../configng" && pwd)}" | ||
| VENV="${VENV:-$DOCS/.venv-docs}" | ||
| cmd="${1:-serve}" | ||
|
|
||
| # Revert exactly what the staging block below writes: the generated hub/config | ||
| # pages and images (restore tracked ones, drop untracked ones), and the wholly | ||
| # generated docs/software tree. Only touches those paths. | ||
| stage_clean() { | ||
| for d in docs/User-Guide_Armbian-Software docs/User-Guide_Armbian-Config docs/images; do | ||
| git -C "$DOCS" checkout -- "$d" 2>/dev/null || true # restore tracked files | ||
| git -C "$DOCS" clean -fdq "$d" 2>/dev/null || true # drop untracked generated files | ||
| done | ||
| rm -rf "$DOCS/docs/software" # wholly generated | ||
| echo "reverted generated pages/images/software; check 'git status'" | ||
| } | ||
|
|
||
| if [[ "$cmd" == "clean" ]]; then stage_clean; exit 0; fi | ||
|
|
||
| # 1) pick a mkdocs that actually has this site's plugins. A bare PATH mkdocs may | ||
| # lack mkdocs-material / mkdocs-redirects / mdx_truly_sane_lists and fail | ||
| # confusingly, so use it only if those import; otherwise a local venv built | ||
| # from requirements.txt (first run needs pip/network). | ||
| has_deps() { "$1" -c 'import material, mkdocs_redirects, mdx_truly_sane_lists' >/dev/null 2>&1; } | ||
| if command -v mkdocs >/dev/null 2>&1 && has_deps "$(command -v python3)"; then | ||
| MK=mkdocs | ||
| else | ||
| [[ -x "$VENV/bin/mkdocs" ]] && has_deps "$VENV/bin/python" || { | ||
| echo ">> creating venv at $VENV and installing docs requirements (one-time, needs network)" | ||
| python3 -m venv "$VENV" | ||
| "$VENV/bin/pip" install -q --disable-pip-version-check -r "$DOCS/requirements.txt" \ | ||
| || "$VENV/bin/pip" install -q mkdocs mkdocs-material mkdocs-redirects mdx_truly_sane_lists | ||
| } | ||
| MK="$VENV/bin/mkdocs" | ||
| fi | ||
|
|
||
| # 2) generate the markdown from configng (uses the committed config.jobs.json). | ||
| echo ">> generating software pages in $CONFIGNG" | ||
| ( cd "$CONFIGNG" && python3 tools/config-markdown.py -u ) | ||
|
|
||
| # 3) stage into the docs tree exactly like pull-from-armbian-config.yml. | ||
| echo ">> staging generated pages into $DOCS/docs" | ||
| mkdir -p "$DOCS/docs/images" "$DOCS/docs/User-Guide_Armbian-Config" \ | ||
| "$DOCS/docs/User-Guide_Armbian-Software" "$DOCS/docs/software" | ||
| rsync -a "$CONFIGNG/tools/include/images/." "$DOCS/docs/images/" | ||
| for p in Localisation Network System; do | ||
| rsync -a "$CONFIGNG/docs/$p/$p.md" "$DOCS/docs/User-Guide_Armbian-Config/" | ||
| done | ||
| rsync -a --exclude="Software.user.md" "$CONFIGNG/docs/Software/"* "$DOCS/docs/User-Guide_Armbian-Software/" | ||
| rsync -a --delete "$CONFIGNG/docs/software/." "$DOCS/docs/software/" | ||
|
|
||
| # 3b) rebuild the ARMBIAN SOFTWARE nav from the staged app pages, exactly as the | ||
| # pull-from-armbian-config workflow does, so the local preview matches CI. | ||
| echo ">> rebuilding software navigation" | ||
| python3 "$DOCS/tools/build-software-nav.py" | ||
|
|
||
| # 4) serve or build. | ||
| cd "$DOCS" | ||
| if [[ "$cmd" == "build" ]]; then | ||
| "$MK" build --clean | ||
| echo ">> built into $DOCS/site — open site/software/netdata/index.html" | ||
| else | ||
| echo ">> serving at http://127.0.0.1:8000 (Ctrl-C to stop, then: ./serve-docs-local.sh clean)" | ||
| "$MK" serve | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| #!/usr/bin/env python3 | ||
| # Rebuild the "ARMBIAN SOFTWARE" nav in mkdocs.yml so each category is a section | ||
| # (its hub page as the section index, via navigation.indexes) with the per-app | ||
| # pages nested beneath it. App pages and their `category:` come from the configng | ||
| # generator (docs/software/<slug>.md); this only groups them for the left nav — | ||
| # the /software/<slug>/ URLs are unaffected. | ||
| # | ||
| # Idempotent: rewrites only the region between the BEGIN/END markers. Category | ||
| # labels + order are curated here (rarely change); a new category needs one line. | ||
| import re | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| ROOT = Path(__file__).resolve().parent.parent | ||
| MKDOCS = ROOT / "mkdocs.yml" | ||
| APPS_DIR = ROOT / "docs" / "software" | ||
| HUB_DIR = "User-Guide_Armbian-Software" | ||
|
|
||
| BEGIN = "# BEGIN software-nav" | ||
| END = "# END software-nav" | ||
| IND = " " * 8 # category entries sit 8 spaces in, under 'ARMBIAN SOFTWARE' | ||
|
|
||
| # Curated label + order, mapped to the category id used by the hub file name and | ||
| # the app pages' `category:` field. | ||
| CATEGORIES = [ | ||
| ("Armbian", "Armbian"), | ||
| ("Backup", "Backup"), | ||
| ("Containers", "Containers"), | ||
| ("Database", "Database"), | ||
| ("Development tools", "DevTools"), | ||
| ("DNS blockers", "DNS"), | ||
| ("Downloaders", "Downloaders"), | ||
| ("Finance", "Finance"), | ||
| ("Home automation", "HomeAutomation"), | ||
| ("Management", "Management"), | ||
| ("Media", "Media"), | ||
| ("Monitoring", "Monitoring"), | ||
| ("Netconfig", "Netconfig"), | ||
| ("Printing", "Printing"), | ||
| ("VPN", "VPN"), | ||
| ("Web hosting", "WebHosting"), | ||
| ] | ||
|
|
||
|
|
||
| def read_front_matter(md_path): | ||
| """Return (title, category) from a page's YAML front-matter, or (None, None).""" | ||
| text = md_path.read_text(encoding="utf-8") | ||
| m = re.match(r"^---\n(.*?)\n---\n", text, re.DOTALL) | ||
| if not m: | ||
| return None, None | ||
| fm = m.group(1) | ||
| title = re.search(r'^title:\s*"?(.*?)"?\s*$', fm, re.MULTILINE) | ||
| cat = re.search(r'^category:\s*"?(.*?)"?\s*$', fm, re.MULTILINE) | ||
| return (title.group(1) if title else None, | ||
| cat.group(1) if cat else None) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
|
|
||
| def collect_apps(): | ||
| """category_id -> sorted list of (title, slug).""" | ||
| by_cat = {} | ||
| for md in sorted(APPS_DIR.glob("*.md")): | ||
| title, cat = read_front_matter(md) | ||
| if not title or not cat: | ||
| continue | ||
| by_cat.setdefault(cat, []).append((title, md.stem)) | ||
| for cat in by_cat: | ||
| by_cat[cat].sort(key=lambda t: t[0].lower()) | ||
| return by_cat | ||
|
|
||
|
|
||
| def yq(s): | ||
| return "'" + s.replace("'", "''") + "'" | ||
|
|
||
|
|
||
| def build_block(by_cat): | ||
| lines = [] | ||
| seen = set() | ||
| for label, cat_id in CATEGORIES: | ||
| seen.add(cat_id) | ||
| apps = by_cat.get(cat_id, []) | ||
| if not apps: | ||
| # Defunct/phantom category (no app pages generated) — skip it, so a | ||
| # category that was removed or merged upstream can't linger in the nav. | ||
| continue | ||
| # Category is a collapsible toggle with its apps under it. The hub page | ||
| # (kept for SEO / the old URL) is intentionally NOT listed here — it is | ||
| # redundant with the app list and is marked not_in_nav in mkdocs.yml. | ||
| lines.append(f"{IND}- {yq(label)}:") | ||
| for title, slug in apps: | ||
| lines.append(f"{IND} - {yq(title)}: {yq(f'software/{slug}.md')}") | ||
| # Any category with app pages but no curated label still gets rendered (with | ||
| # a prettified id as the label) so new upstream categories never silently | ||
| # vanish; warn so a nicer label can be added. | ||
| for cat in sorted(set(by_cat) - seen): | ||
| label = re.sub(r'(?<=[a-z])(?=[A-Z])', ' ', cat) | ||
| print(f"::warning:: software-nav: category {cat!r} has app pages but no " | ||
| f"curated label — using {label!r}; add one in tools/build-software-nav.py", | ||
| file=sys.stderr) | ||
| lines.append(f"{IND}- {yq(label)}:") | ||
| for title, slug in by_cat[cat]: | ||
| lines.append(f"{IND} - {yq(title)}: {yq(f'software/{slug}.md')}") | ||
| return "\n".join(lines) | ||
|
|
||
|
|
||
| def main(): | ||
| text = MKDOCS.read_text(encoding="utf-8") | ||
| if BEGIN not in text or END not in text: | ||
| sys.exit(f"markers {BEGIN!r}/{END!r} not found in {MKDOCS}") | ||
| by_cat = collect_apps() | ||
| if not by_cat: | ||
| # No per-app pages present (e.g. the configng generator that emits | ||
| # docs/software/<slug>.md with title/category hasn't run/synced yet). | ||
| # Leave the existing nav block untouched rather than blanking it. | ||
| print(f"software-nav: no app pages found under {APPS_DIR} — nav left unchanged.") | ||
| return | ||
| block = build_block(by_cat) | ||
| new = re.sub( | ||
| rf"({re.escape(IND)}{re.escape(BEGIN)}[^\n]*\n).*?(\n{re.escape(IND)}{re.escape(END)})", | ||
| lambda m: m.group(1) + block + m.group(2), | ||
| text, count=1, flags=re.DOTALL) | ||
| MKDOCS.write_text(new, encoding="utf-8") | ||
| total = sum(len(v) for v in by_cat.values()) | ||
| print(f"software-nav: {total} app pages grouped under {len(CATEGORIES)} categories.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.