201 lines
8.3 KiB
Python
201 lines
8.3 KiB
Python
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import yaml
|
|
import re
|
|
|
|
# Configuration
|
|
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
BUILD_DIR = os.path.join(ROOT_DIR, "_site_src")
|
|
DOCS_DIR = os.path.join(BUILD_DIR, "docs")
|
|
MKDOCS_CONFIG = os.path.join(ROOT_DIR, "mkdocs.yml")
|
|
GEMINI_CLI = os.path.join(ROOT_DIR, ".gemini", "gemini_cli.py")
|
|
|
|
def clean_build_dir():
|
|
if os.path.exists(BUILD_DIR):
|
|
try:
|
|
shutil.rmtree(BUILD_DIR)
|
|
except Exception as e:
|
|
print(f"Warning cleaning build dir: {e}")
|
|
|
|
os.makedirs(DOCS_DIR, exist_ok=True)
|
|
|
|
def clean_folder_name(name):
|
|
# Converts 'documentacao zammad' to 'Zammad'
|
|
# Converts 'documentacao backup-restore' to 'Backup Restore'
|
|
if name.startswith("documentacao "):
|
|
name = name.replace("documentacao ", "")
|
|
|
|
# Capitalize words
|
|
return name.title()
|
|
|
|
def process_markdown_content(content):
|
|
# Remove the Manual Revision History Block
|
|
# Look for ## 1. HISTÓRICO DE REVISÃO until the next ## header
|
|
# Pattern: ## 1. HISTÓRICO... (anything until next ## or end)
|
|
pattern = r"## 1\. HISTÓRICO DE REVISÃO.*?(?=## |\Z)"
|
|
content = re.sub(pattern, "", content, flags=re.DOTALL)
|
|
|
|
# Also strip any numbering from H2 headers if needed, but user might want them.
|
|
return content
|
|
|
|
def copy_manuals():
|
|
print("Copying manuals to build directory...")
|
|
# Find all 'documentacao *' folders
|
|
for item in os.listdir(ROOT_DIR):
|
|
if os.path.isdir(os.path.join(ROOT_DIR, item)) and item.startswith("documentacao"):
|
|
src_path = os.path.join(ROOT_DIR, item)
|
|
|
|
# Nice name for the folder
|
|
clean_name = clean_folder_name(item)
|
|
dst_path = os.path.join(DOCS_DIR, clean_name)
|
|
|
|
print(f"Processing {item} -> {clean_name}")
|
|
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
|
|
|
|
# Post-process files in the new destination
|
|
for root, dirs, files in os.walk(dst_path):
|
|
for file in files:
|
|
if file.lower().endswith('.md'):
|
|
# Inject PDF Link + Strip Revision History
|
|
full_path = os.path.join(root, file)
|
|
|
|
# Generate/Check PDF name
|
|
pdf_name = file.rsplit('.', 1)[0] + ".pdf"
|
|
|
|
try:
|
|
with open(full_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
modified_content = process_markdown_content(content)
|
|
|
|
# Add PDF Button
|
|
display_name = "Baixar PDF"
|
|
link = f'<a class="md-button md-button--primary download-pdf-btn" href="./{pdf_name}">:material-file-pdf-box: {display_name}</a>\n\n'
|
|
|
|
# Insert link after header or at top
|
|
if modified_content.startswith("---"):
|
|
# Split frontmatter
|
|
parts = modified_content.split("---", 2)
|
|
if len(parts) >= 3:
|
|
parts[2] = link + parts[2]
|
|
modified_content = "---".join(parts)
|
|
else:
|
|
modified_content = link + modified_content
|
|
else:
|
|
# Try to find H1
|
|
if "# " in modified_content:
|
|
modified_content = modified_content.replace("\n# ", f"\n{link}\n# ", 1) # Put before? No, after is better.
|
|
# Actually, let's put it AT THE TOP of content, below title if possible.
|
|
# Simple regex replace for first H1
|
|
modified_content = re.sub(r'(^# .+)', r'\1\n\n' + link, modified_content, count=1, flags=re.MULTILINE)
|
|
else:
|
|
modified_content = link + modified_content
|
|
|
|
with open(full_path, 'w', encoding='utf-8') as f:
|
|
f.write(modified_content)
|
|
except Exception as e:
|
|
print(f"Error processing {file}: {e}")
|
|
|
|
|
|
# Copy contents of 'assets' folder in root to 'docs/assets'
|
|
root_assets = os.path.join(ROOT_DIR, "assets")
|
|
docs_assets = os.path.join(DOCS_DIR, "assets")
|
|
if os.path.exists(root_assets):
|
|
print(f"Copying root assets from {root_assets} to {docs_assets}")
|
|
shutil.copytree(root_assets, docs_assets, dirs_exist_ok=True)
|
|
|
|
def create_index():
|
|
print("Creating index.md from README.md...")
|
|
readme_path = os.path.join(ROOT_DIR, "README.md")
|
|
if not os.path.exists(readme_path):
|
|
print("README.md not found, creating basic index.")
|
|
return
|
|
|
|
with open(readme_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
# We need to fix links like [Title](documentacao%20folder/file.md)
|
|
# to work in the site structure: [Title](./Folder/file.md)
|
|
# The folders in site are cleaned via clean_folder_name(item)
|
|
|
|
def fix_link(match):
|
|
label = match.group(1)
|
|
path = match.group(2)
|
|
|
|
# Unquote path
|
|
import urllib.parse
|
|
raw_path = urllib.parse.unquote(path)
|
|
|
|
if "documentacao " in raw_path:
|
|
# documentacao zammad/[Nível 1]...md -> Zammad/[Nível 1]...md
|
|
parts = raw_path.split("/", 1)
|
|
if len(parts) == 2:
|
|
clean_folder = clean_folder_name(parts[0])
|
|
# Remove .md if it's there to let awesome-pages handle it?
|
|
# Actually, link should point to the .md or .html.
|
|
# MkDocs converts .md to .html but relative links inside MD work.
|
|
new_path = f"./{clean_folder}/{parts[1]}"
|
|
return f"[[{label}]]({urllib.parse.quote(new_path)})"
|
|
|
|
return match.group(0)
|
|
|
|
# Use a regex that specifically looks for nested double brackets if present
|
|
# Or just stay greedy. [[Title]](path) -> group1=[Title], group2=path
|
|
content = re.sub(r"\[\[(.*?)\]\]\((.*?)\)", fix_link, content)
|
|
|
|
# Also fix relative image paths if any (assets/logo.png -> ./assets/logo.png)
|
|
content = content.replace("](assets/", "](./assets/")
|
|
|
|
with open(os.path.join(DOCS_DIR, "index.md"), 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
def generate_pdfs():
|
|
print("Generating PDFs...")
|
|
# Call gemini_cli batch_convert on the DOCS_DIR
|
|
# We need to make sure we use the same python env
|
|
subprocess.check_call([sys.executable, GEMINI_CLI, "batch-convert", DOCS_DIR])
|
|
|
|
def build_mkdocs():
|
|
print("Building MkDocs site...")
|
|
|
|
# Load base config
|
|
# Use unsafe_load to handle !!python tags
|
|
with open(os.path.join(ROOT_DIR, "mkdocs.yml"), "r") as f:
|
|
base_config = yaml.unsafe_load(f)
|
|
|
|
# Update config to point to our source folder
|
|
# IMPORTANT: We use relative path so MkDocs can find it from ROOT
|
|
base_config["docs_dir"] = "_site_src/docs"
|
|
base_config["site_dir"] = "_site_src/site"
|
|
|
|
# Ensure extra_css is copied
|
|
extra_css_src = os.path.join(ROOT_DIR, ".gemini", "stylesheets")
|
|
extra_css_dst = os.path.join(DOCS_DIR, "stylesheets")
|
|
if os.path.exists(extra_css_src):
|
|
shutil.copytree(extra_css_src, extra_css_dst, dirs_exist_ok=True)
|
|
|
|
# Write temporary config in ROOT (so it sees .git)
|
|
temp_config_path = os.path.join(ROOT_DIR, "mkdocs_generated.yml")
|
|
with open(temp_config_path, "w") as f:
|
|
yaml.dump(base_config, f)
|
|
|
|
# Run build using the generated config in ROOT
|
|
subprocess.check_call(["mkdocs", "build", "-f", "mkdocs_generated.yml"])
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
clean_build_dir()
|
|
copy_manuals()
|
|
create_index()
|
|
generate_pdfs()
|
|
build_mkdocs()
|
|
print("Build Complete! Site is in _site_src/site")
|
|
except Exception as e:
|
|
print(f"Build Failed: {e}")
|
|
# print stack trace
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|