msos/update_html.py

206 lines
8.4 KiB
Python

import os
import re
import argparse
import shutil
# --- Konfiguracija skripte ---
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) # Predvideva, da je skripta v root direktoriju projekta
TEMPLATES_DIR_NAME = "templates"
LANGUAGES = ['en', 'si', 'mk']
HEADER_TEMPLATE_NAME = "header.html"
FOOTER_TEMPLATE_NAME = "footer.html"
# Označevalci, ki jih skripta išče v HTML datotekah
HEADER_START_MARKER = "<!-- START_HEADER -->"
HEADER_END_MARKER = "<!-- END_HEADER -->"
FOOTER_START_MARKER = "<!-- START_FOOTER -->"
FOOTER_END_MARKER = "<!-- END_FOOTER -->"
# Placeholder za relativne poti v predlogah
ROOT_PREFIX_PLACEHOLDER = "{{ROOT_PREFIX}}"
# --- Pomožne funkcije ---
def load_template(lang, template_type):
"""
Naloži vsebino predloge (header ali footer) za določen jezik.
"""
template_path = os.path.join(PROJECT_ROOT, TEMPLATES_DIR_NAME, lang, f"{template_type}.html")
try:
with open(template_path, 'r', encoding='utf-8') as f:
content = f.read()
# Preveri, ali predloga vsebuje označevalce, ki jih bo skripta uporabljala
if template_type == 'header' and not (HEADER_START_MARKER in content and HEADER_END_MARKER in content):
raise ValueError(f"Predloga za glavo '{template_path}' mora vsebovati '{HEADER_START_MARKER}' in '{HEADER_END_MARKER}'.")
if template_type == 'footer' and not (FOOTER_START_MARKER in content and FOOTER_END_MARKER in content):
raise ValueError(f"Predloga za nogo '{template_path}' mora vsebovati '{FOOTER_START_MARKER}' in '{FOOTER_END_MARKER}'.")
return content
except FileNotFoundError:
print(f"Napaka: Predloga '{template_path}' ni najdena.")
return None
except ValueError as e:
print(f"Napaka pri predlogi: {e}")
return None
except Exception as e:
print(f"Nepredvidena napaka pri nalaganju predloge '{template_path}': {e}")
return None
def find_html_files(root_dir):
"""
Rekurzivno poišče vse HTML datoteke v določenem korenskem imeniku.
Vrne seznam absolutnih poti do datotek.
"""
html_files = []
for dirpath, _, filenames in os.walk(root_dir):
for filename in filenames:
if filename.endswith(".html"):
html_files.append(os.path.join(dirpath, filename))
return html_files
def calculate_root_prefix(file_path):
"""
Izračuna relativno pot od dane HTML datoteke do korenskega imenika projekta.
Npr. za /project_root/si/projects/article/index.html vrne '../../..'
"""
relative_path = os.path.relpath(file_path, PROJECT_ROOT)
# Izloči ime datoteke in jezikovno mapo, da dobimo globino
path_parts = relative_path.split(os.sep)
# Odštej 1 za jezikovno mapo (npr. 'si') in 1 za samo datoteko 'index.html'
# path_parts = ['si', 'projects', 'article', 'index.html'] -> depth = 3
# root_prefix = '../../..'
depth = len(path_parts) - 1 # -1, ker ne štejemo 'index.html'
if depth <= 0:
return "./" # Datoteka je v korenski jezikovni mapi (npr. si/index.html)
else:
return "../" * depth
def process_file(file_path, lang_templates, dry_run=False):
"""
Prebere HTML datoteko, nadomesti header in footer z vsebino predlog
in zapiše spremenjeno datoteko.
"""
print(f"Obdelujem datoteko: {file_path}")
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
print(f" Napaka pri branju datoteke '{file_path}': {e}")
return
original_content = content # Shrani originalno vsebino za primer, če se nič ne spremeni
# Izlušči jezikovno kodo iz poti datoteke
lang_code = file_path.split(os.sep)[-len(os.path.relpath(file_path, PROJECT_ROOT).split(os.sep))]
# Pridobi predloge za trenutni jezik
header_template = lang_templates.get(lang_code, {}).get('header')
footer_template = lang_templates.get(lang_code, {}).get('footer')
if not header_template or not footer_template:
print(f" Opozorilo: Predloge za jezik '{lang_code}' niso naložene ali so nepopolne. Preskakujem.")
return
# Izračunaj root prefix za to datoteko
root_prefix = calculate_root_prefix(file_path)
# Pripravi predloge z ustreznim root prefixom
formatted_header = header_template.replace(ROOT_PREFIX_PLACEHOLDER, root_prefix)
formatted_footer = footer_template.replace(ROOT_PREFIX_PLACEHOLDER, root_prefix)
# --- Zamenjava Headerja ---
header_pattern = re.compile(rf"{re.escape(HEADER_START_MARKER)}.*?{re.escape(HEADER_END_MARKER)}", re.DOTALL)
if header_pattern.search(content):
# formatted_header že vsebuje START in END markerje
content = header_pattern.sub(formatted_header, content)
else:
print(f" Opozorilo: Označevalcev za glavo (header) ni mogoče najti v '{file_path}'.")
# --- Zamenjava Footerja ---
footer_pattern = re.compile(rf"{re.escape(FOOTER_START_MARKER)}.*?{re.escape(FOOTER_END_MARKER)}", re.DOTALL)
if footer_pattern.search(content):
# formatted_footer že vsebuje START in END markerje
content = footer_pattern.sub(formatted_footer, content)
else:
print(f" Opozorilo: Označevalcev za nogo (footer) ni mogoče najti v '{file_path}'.")
if content != original_content:
if dry_run:
print(f" DRY RUN: Datoteka '{file_path}' bi bila spremenjena.")
# Za dry run lahko izpišeš del spremenjene vsebine ali diff
# print("--- Diff (prvih 20 vrstic) ---")
# import difflib
# diff = difflib.unified_diff(original_content.splitlines(keepends=True), content.splitlines(keepends=True), fromfile='original', tofile='modified')
# for i, line in enumerate(diff):
# if i >= 20: break
# print(line.strip())
# print("-----------------------------")
else:
# Ustvari varnostno kopijo pred spremembami
backup_path = file_path + ".bak"
try:
shutil.copy2(file_path, backup_path)
print(f" Varnostna kopija ustvarjena: {backup_path}")
except Exception as e:
print(f" Napaka pri ustvarjanju varnostne kopije za '{file_path}': {e}")
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f" Datoteka uspešno posodobljena: {file_path}")
except Exception as e:
print(f" Napaka pri zapisovanju v datoteko '{file_path}': {e}")
else:
print(f" Datoteka '{file_path}' je že posodobljena ali ni potrebovala sprememb.")
# --- Glavna funkcija ---
def main():
parser = argparse.ArgumentParser(description="Avtomatizirano posodabljanje headerja in footerja v HTML datotekah.")
parser.add_argument("--dry-run", action="store_true", help="Izvede posodobitev, vendar ne zapisuje sprememb v datoteke.")
args = parser.parse_args()
# Naloži vse predloge za vse jezike
all_lang_templates = {}
for lang in LANGUAGES:
header_template = load_template(lang, 'header')
footer_template = load_template(lang, 'footer')
if header_template and footer_template:
all_lang_templates[lang] = {'header': header_template, 'footer': footer_template}
else:
print(f"Opozorilo: Predloge za jezik '{lang}' so nepopolne. Datoteke v tem jeziku ne bodo obdelane.")
if not all_lang_templates:
print("Ni naloženih veljavnih predlog za noben jezik. Skripta se ustavi.")
return
# Obdelaj HTML datoteke po jezikih
for lang in LANGUAGES:
if lang not in all_lang_templates:
continue # Preskoči, če predloge za ta jezik niso bile uspešno naložene
lang_dir = os.path.join(PROJECT_ROOT, lang)
if not os.path.isdir(lang_dir):
print(f"Opozorilo: Jezikovna mapa '{lang_dir}' ne obstaja. Preskakujem.")
continue
print(f"\n--- Začenjam obdelavo HTML datotek za jezik: {lang.upper()} ---")
html_files = find_html_files(lang_dir)
if not html_files:
print(f" V mapi '{lang_dir}' ni najdenih HTML datotek.")
continue
for file_path in html_files:
process_file(file_path, all_lang_templates, args.dry_run)
print("\n--- Obdelava zaključena ---")
if __name__ == "__main__":
main()