Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codespell.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[codespell]
# Skip binary files and images (some image filenames contain historical typos
# that cannot be renamed without breaking existing markdown links)
skip = node_modules,*.png,*.jpg,*.jpeg,*.gif,*.svg,*.pdf,*.ico,*.zip,*.json,*.sh,*.html
skip = node_modules,*Guide-de.md,*Guide-tr.md,*Install-ru-*.md,*resource/manuals*,*.png,*.jpg,*.jpeg,*.gif,*.svg,*.pdf,*.ico,*.zip,*.json,*.sh,*.html
# Known false positives or intentional abbreviations
ignore-words-list = parms,nd,ba,te
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Preserve the pinned upstream schema and extracted DDL formatting.
resources/manuals/source/cacti.sql -whitespace
resource/manuals/cacti-schema.sql -whitespace
87 changes: 87 additions & 0 deletions .github/workflows/manual-editions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: PDF and text manual editions
on:
pull_request:
merge_group:
types: [checks_requested]
push:
branches: [develop]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: manual-editions-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
editions:
name: Build and verify current manual editions
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
- uses: jdx/mise-action@9b200bcecbfd6303e69a4a261b2e09e3757440a7
with:
tool_versions: |
python 3.12.12
uv 0.12.23
- name: Install native PDF libraries, fonts, and review tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libpango-1.0-0 libpangoft2-1.0-0 \
libharfbuzz-subset0 fonts-dejavu-core fonts-dejavu-extra poppler-utils
- name: Export the committed PDF tool lock
run: |
mkdir -p manual-artifacts
mise exec python@3.12.12 uv@0.12.23 -- uv export --locked \
--script bin/build_pdf_docs.py --format requirements-txt \
--output-file "$RUNNER_TEMP/pdf-requirements.txt"
- name: Test edition selection, text conversion, and schema provenance
run: |
renderer=(mise exec python@3.12.12 uv@0.12.23 -- uv run \
--with-requirements "$RUNNER_TEMP/pdf-requirements.txt" --with coverage==7.13.2)
"${renderer[@]}" python -m coverage run --branch --include=bin/build_other_manuals.py \
-m unittest discover -s bin/tests -p test_other_manuals.py
"${renderer[@]}" python -m unittest discover -s bin/tests -p test_navigation_anchors.py
"${renderer[@]}" python -m coverage report --fail-under=100
"${renderer[@]}" python -m coverage json -o manual-artifacts/coverage.json
- name: Build every current PDF and text edition
run: |
mise exec python@3.12.12 uv@0.12.23 -- uv run --locked --python python \
--script bin/build_pdf_docs.py --only manual --companions
- name: Verify actual PDFs, complete text appendices, hashes, and populated preview
run: |
mise exec python@3.12.12 uv@0.12.23 -- uv run \
--with-requirements "$RUNNER_TEMP/pdf-requirements.txt" --with pypdf==6.12.2 \
python bin/tests/verify_other_manuals.py
- name: Summarize publication evidence
if: always()
run: |
mise exec python@3.12.12 -- python - <<'PY'
import json, os
from pathlib import Path
path = Path('manual-artifacts/publication-evidence.json')
summary = '## Manual editions\n\nPublication verification did not complete.\n'
if path.exists():
report = json.loads(path.read_text())
summary = (f"## Manual editions\n\nComplete: {report['complete']}\n\n"
f"Source: {report['source_revision']}\n\n"
f"Editions: {len(report['editions'])}; schema tables: {report['schema_tables']}\n\n")
summary += '| Edition | Chapters | PDF pages |\n| --- | --- | --- |\n'
for name, result in report['editions'].items():
summary += f"| {name} | {result['chapters']} | {result['pdf_pages']} |\n"
with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as output:
output.write(summary)
PY
- name: Preserve manuals, manifests, coverage, and populated PDF preview
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
with:
name: cacti-manual-editions-attempt-${{ github.run_attempt }}
path: |
resource/manuals/
resource/pdf/cacti-manual.pdf
resource/pdf/build_manifest.json
manual-artifacts/
if-no-files-found: warn
retention-days: 14
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ __pycache__/
html-artifacts/
.coverage
/html-check/

/manual-artifacts/
navigation-report.json
!.gitattributes
3 changes: 3 additions & 0 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# The SQL snapshot and its generated reference intentionally repeat upstream DDL.
# Keep authored code in duplication analysis and preserve the project thresholds.
sonar.cpd.exclusions=resource/manuals/cacti-schema.sql,resources/manuals/source/cacti.sql
3 changes: 3 additions & 0 deletions Manual-Index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Cacti 1.2 installations, use the [1.2.x manual][manual-1.2]. Menu visibility
also depends on permissions, enabled features, and plugins. Screenshots can
show an earlier release or a different theme.

[Current editions and contributed archives](Other-Manuals.md) include PDF,
text, localized installation guides, and the development schema reference.

## Install or Upgrade Cacti

Choose the guide for your operating system and installation method.
Expand Down
116 changes: 116 additions & 0 deletions Other-Manuals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Current Manuals and Contributed Archives

These replacements follow **develop**, the unreleased Cacti 1.3 series. Use
the [1.2.x manual][stable] for released Cacti 1.2. The version guidance follows
the website's distinction between released and development documentation.
The manuals reuse the maintained chapter content and existing documentation
styles. They do not import the website's visual design.

## Complete maintained manuals

- [PDF manual](resource/pdf/cacti-manual.pdf), with all current main chapters,
bookmarks, screenshots, and links between chapters.
- [UTF-8 text manual](resource/manuals/manual.txt), with the same main chapters,
command examples, image descriptions, and full link destinations.
- [HTML manual publication](resources/build/HTML-Manual.md), including all
chapters and legacy chapter URLs.
- [Historical ReportIt manual](resource/pdf/manual_reportit.pdf). The newer
plugin manual is maintained separately from these Cacti editions.

## Current replacements for contributed guides

The new guides are separate Cacti documentation, not revisions attributed to
the original contributors. German, Turkish, and Russian editions contain a
new localized introduction and complete relevant English chapters in their
PDF and text appendices. They are not full translations. Language review is
welcome; platform checks and runtime limitations still apply.

| Guide | Read online | PDF | Text |
| --- | --- | --- | --- |
| German installation and operation | [Deutsch](resources/manuals/Guide-de.md) | [PDF](resource/manuals/cacti-guide-de.pdf) | [Text](resource/manuals/cacti-guide-de.txt) |
| Turkish installation and operation | [Türkçe](resources/manuals/Guide-tr.md) | [PDF](resource/manuals/cacti-guide-tr.pdf) | [Text](resource/manuals/cacti-guide-tr.txt) |
| Linux installation | [English](resources/manuals/Install-linux.md) | [PDF](resource/manuals/install-linux.pdf) | [Text](resource/manuals/install-linux.txt) |
| Russian UNIX installation | [Русский](resources/manuals/Install-ru-unix.md) | [PDF](resource/manuals/install-ru-unix.pdf) | [Text](resource/manuals/install-ru-unix.txt) |
| Russian Windows installation | [Русский](resources/manuals/Install-ru-windows.md) | [PDF](resource/manuals/install-ru-windows.pdf) | [Text](resource/manuals/install-ru-windows.txt) |
| Windows installation | [English](Installing-Under-Windows.md) | [PDF](resource/manuals/install-windows.pdf) | [Text](resource/manuals/install-windows.txt) |
| Migration from Solaris | [English](resources/manuals/Migrate-solaris.md) | [PDF](resource/manuals/migrate-solaris.pdf) | [Text](resource/manuals/migrate-solaris.txt) |
| Development database schema | [Reference](resources/manuals/Schema-Reference.md) | [PDF](resource/manuals/schema-reference.pdf) | [Text](resource/manuals/schema-reference.txt) |

The German and Turkish appendices include every current main manual chapter.
Installation editions include the complete platform, first-graph,
troubleshooting, security, and upgrade chapters selected in
[editions.json](resources/manuals/editions.json). Solaris has a migration
guide rather than an unverified new-install procedure. The Windows guides
explain the current development dependency restriction before any install
instructions.

The [schema SQL](resource/manuals/cacti-schema.sql) contains only the pinned
upstream `CREATE TABLE` statements. It is a reference, not an installer or
upgrade script. It has no seed data and does not describe plugin tables.
Use the schema supplied with your exact Cacti release for installation.

![Example graph with populated historical data](images/graphs-edit.png)

This screenshot shows historical sample measurements and an earlier interface.
It is included in the operating guides, not evidence of a deployment on every
listed platform.

## Historical contributions

These originals remain archives at their existing URLs, with their original
credits and rights notices. Their obsolete dependencies and commands do not
apply to current installations. Do not overwrite them with the new guides or
present the new guides as work by the original contributors.

| Original | Credit from the original | Status |
| --- | --- | --- |
| [German documentation][old-de] | Sebastian Larisch, August 2006 | Archive |
| [Turkish handbook][old-tr] | Özgür Karataş, February 2006 | Archive |
| [Linux how-to][old-linux] | Lee Carter, 2004 | Archive |
| [Russian UNIX installation][old-ru-unix] | Translation by Александр Цапкин, December 2006 | Archive |
| [Russian Windows installation][old-ru-windows] | Translation by Александр Цапкин, December 2006 | Archive |
| [Solaris installation][old-solaris] | Original credit and notice remain in the archive | Archive |
| [Windows installation][old-windows] | Original credit and notice remain in the archive | Archive |
| [Previous PDF manual][old-pdf] | Original Cacti manual credits | Archive |
| [Previous text manual][old-text] | Original Cacti manual credits | Archive |
| [Database schema PDF][old-schema] | Original notice remains in the archive | Archive |
| [phpMyAdmin SQL][old-sql] | Original notice remains in the archive | Archive |

The [archive inventory][inventory] records each
original URL, byte count, and SHA-256 captured on 26 October 2026. Original
documents are not copied or translated into the new guides.

## Build and publish

Follow [manual publication][publication] to rebuild and
validate every edition. The [edition manifest][editions-manifest]
records exact sources and checksums. The PDF builder also records its locked
toolchain in [the PDF manifest](resource/pdf/build_manifest.json).

CI publishes review artifacts; it does not deploy the public file host.
Maintainers should publish the new editions under distinct versioned names,
link this index from the download page, and retain the original archive URLs.
Publish the main manual separately from the historic `manual.pdf` and
`manual.txt` names so an existing archive citation keeps its meaning.

[publication]: resources/build/Other-Manuals.md
[inventory]: resources/manuals/archive-inventory.json
[editions-manifest]: resource/manuals/build-manifest.json
[stable]: https://github.com/Cacti/documentation/blob/1.2.x/README.md
[old-de]: https://files.cacti.net/docs/contrib/Cacti-Doku_german.pdf
[old-tr]: https://files.cacti.net/docs/contrib/Cacti-El-Kitab.pdf
[old-linux]: https://files.cacti.net/docs/contrib/Cacti-Linux-How-To.pdf
[old-ru-unix]: https://files.cacti.net/docs/contrib/install_russian_unix.pdf
[old-ru-windows]:
<https://files.cacti.net/docs/contrib/install_russian_windows.pdf>

[old-solaris]: https://files.cacti.net/docs/contrib/install_solaris.html
[old-windows]: https://files.cacti.net/docs/contrib/install_windows.html
[old-pdf]: https://files.cacti.net/docs/pdf/manual.pdf
[old-text]: https://files.cacti.net/docs/text/manual.txt
[old-schema]: https://files.cacti.net/docs/sql/database_schema.pdf
[old-sql]: https://files.cacti.net/docs/sql/phpMyAdmin.sql

---

Copyright (c) 2004-2026 The Cacti Group
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ the requirements supplied with your installed version.
This example from [Graph Overview](Graph-Overview.md) contains historical sample
data and shows an earlier interface. Menu labels can differ in your version.

[Current editions and contributed archives](Other-Manuals.md) include PDF,
text, localized installation guides, and the development schema reference.

<a id="hot-tos"></a>

## What Do You Want to Do

<a id="cacti-installation"></a>
Expand Down
10 changes: 6 additions & 4 deletions bin/build_html_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ def section(body, fragment):
return selected.replace('<h' + start[1] + ' ', '<h1 ', 1).replace('</h' + start[1] + '>', '</h1>', 1)


def document(title, body, prefix, revision, legacy=False):
def document(title, body, prefix, revision, legacy=False, language="en"):
notice = '<p>This legacy chapter URL now presents the corresponding current chapter.</p>' if legacy else ''
return (f'<!doctype html>\n<html lang="en"><head><meta charset="utf-8">'
return (f'<!doctype html>\n<html lang="{escape(language, quote=True)}"><head><meta charset="utf-8">'
'<meta name="viewport" content="width=device-width, initial-scale=1">'
'<meta http-equiv="Content-Security-Policy" content="default-src &#39;none&#39;; '
'img-src &#39;self&#39; https:; style-src &#39;self&#39;; base-uri &#39;none&#39;; form-action &#39;none&#39;">'
Expand Down Expand Up @@ -210,7 +210,9 @@ def render_chapters(root, staging, pages, revision):
target = staging / output_name(name)
target.parent.mkdir(parents=True, exist_ok=True)
prefix = '../' * (len(name.parts) - 1)
target.write_text(document(title, body, prefix, revision))
language = {'Guide-de': 'de', 'Guide-tr': 'tr', 'Install-ru-unix': 'ru',
'Install-ru-windows': 'ru'}.get(name.stem, 'en')
target.write_text(document(title, body, prefix, revision, language=language))
return rendered


Expand Down Expand Up @@ -253,7 +255,7 @@ def build(root, output):
tracked = subprocess.check_output(['git', 'ls-files', '-z', '--', '*.md', 'images', 'resource',
'resources', ':(exclude)resource/html/**'], cwd=root).decode().split('\0')
pages = sorted(root / name for name in filter(None, tracked)
if Path(name).suffix == '.md' and Path(name).parent.as_posix() in {'.', 'Architecture', 'resources/build'})
if Path(name).suffix == '.md' and Path(name).parent.as_posix() in {'.', 'Architecture', 'resources/build', 'resources/manuals'})
assets = [name for name in tracked if name.startswith(('images/', 'resource/', 'resources/'))]
output.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(prefix='cacti-html-', dir=output.parent) as temporary:
Expand Down
Loading