WikiMigrationScript_ChangeLog - itnett/FTD02H-N GitHub Wiki

Det er flott at vi har kommet i mål med migreringen av koden fra wiki til GitHub! La oss nå gå gjennom skriptet og prosessen steg for steg. Jeg vil forklare hver funksjon, utfordringene vi møtte, og hvordan vi løste dem, slik at du får en dypere forståelse av både Python-koden og hvordan Git fungerer.

1. Opprettelse av skriptet og konfigurasjonsfilen

input.yml

Konfigurasjonsfilen input.yml brukes til å spesifisere viktige variabler som skriptet trenger for å fungere. Her definerer vi URL-ene for det gamle wiki-repositoriet, målkatalogene for koden, og hvor koden skal legges inn i GitHub.

wiki_repo_url: "https://github.com/itnett/FTD02H-N.wiki.git"
dump_directory: "C:\\WikiMigration\\git\\code_dump"
code_repo_url: "https://github.com/itnett/FTD02N"
code_repo_directory: "C:\\WikiMigration\\git\\code_repo"
  • wiki_repo_url: URL til det gamle wiki-repositoriet som skal klones.
  • dump_directory: Katalogen hvor wiki-repoet klones midlertidig.
  • code_repo_url: URL til koden sitt GitHub-repo.
  • code_repo_directory: Katalogen hvor skriptene fra wiki-repoet skal lagres.

2. Logging og feilhåndtering

Vi setter opp logging slik at alle handlinger og feil i skriptet blir logget til en fil. Dette er nyttig for å kunne spore hva som skjer under kjøringen, spesielt når vi støter på feil.

logging.basicConfig(filename="C:\\WikiMigration\\migration.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

def log(message):
    logging.info(message)
    print(message)

def log_exception(e):
    log(f"Exception occurred: {str(e)}")
    log(traceback.format_exc())
  • log(message): Logger en generell melding.
  • log_exception(e): Logger en unntaksmelding og stacktrace for debugging.

3. Laste inn konfigurasjonen

Her laster vi inn konfigurasjonsfilen og validerer den for å sikre at alle nødvendige nøkler er til stede og at ingen av dem er tomme.

def load_input_config(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            config = yaml.safe_load(file)
        validate_config(config)
        log(f"Loaded configuration from {file_path}")
        return config
    except Exception as e:
        log_exception(e)
        raise

def validate_config(config):
    required_keys = ['wiki_repo_url', 'dump_directory', 'code_repo_url', 'code_repo_directory']
    for key in required_keys:
        if key not in config:
            raise ValueError(f"Missing required config key: {key}")
        if not config[key]:
            raise ValueError(f"Config key {key} cannot be empty.")
    log("Configuration validated successfully.")
  • load_input_config(file_path): Leser inn konfigurasjonsfilen og validerer innholdet.
  • validate_config(config): Sjekker at alle nødvendige nøkler er til stede og at de ikke er tomme.

4. Håndtering av skrivebeskyttede filer

For å sikre at vi kan slette skrivebeskyttede filer, implementerer vi en funksjon som endrer filtilgang før sletting.

def handle_remove_readonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove, os.unlink) and excvalue.errno == errno.EACCES:
        os.chmod(path, stat.S_IRWXU)
        func(path)
    else:
        raise
  • handle_remove_readonly(func, path, exc): Endrer filtilgang til skrivebeskyttet modus før sletting hvis nødvendig.

5. Kloning av wiki-repositoriet

Skriptet kloner wiki-repositoriet til en midlertidig katalog.

def clone_wiki_repo(wiki_repo_url, target_directory):
    try:
        if os.path.exists(target_directory):
            shutil.rmtree(target_directory, onerror=handle_remove_readonly)
        os.makedirs(target_directory)
        run_git_command(["git", "clone", wiki_repo_url, target_directory], cwd=target_directory)
        log(f"Cloned Wiki repository to {target_directory}")
    except Exception as e:
        log_exception(e)
        raise
  • Utfordring: Skrivebeskyttede filer førte til feil under sletting av kataloger. Dette ble løst ved å bruke handle_remove_readonly.
  • Løsning: Etter at funksjonen handle_remove_readonly ble implementert, ble problemet med å slette skrivebeskyttede filer løst.

6. Behandle wiki-filer og trekke ut kode

Denne funksjonen går gjennom alle markdown-filene i wiki-repositoriet, finner kodeblokker, trekker dem ut, og lagrer dem i riktig katalog. Samtidig oppdateres wiki-filene med lenker til den nye koden i GitHub-repositoriet.

def sanitize_filename(filename):
    filename = re.sub(r'[<>:"/\\|?*]', '_', filename)
    filename = filename[:100]  # Begrens lengden til 100 tegn
    return filename

def process_wiki_files(wiki_dir, code_repo_url, code_repo_dir):
    try:
        for root, dirs, files in os.walk(wiki_dir):
            for file in files:
                if file.endswith(".md"):
                    wiki_filepath = os.path.join(root, file)
                    with open(wiki_filepath, 'r', encoding='utf-8') as f:
                        content = f.read()

                    code_blocks = re.findall(r'```(.*?)\n(.*?)```', content, re.DOTALL)
                    updated_content = content

                    for idx, (lang, code) in enumerate(code_blocks):
                        sanitized_file = sanitize_filename(f"{os.path.splitext(file)[0]}_snippet_{idx+1}.{lang}")
                        code_filepath = os.path.join(code_repo_dir, sanitized_file)

                        with open(code_filepath, 'w', encoding='utf-8') as code_file:
                            code_file.write(code.strip())

                        github_link = f"[{sanitized_file}]({code_repo_url}/blob/main/{sanitized_file})"
                        updated_content = updated_content.replace(f"```{lang}\n{code}```", github_link)

                    with open(wiki_filepath, 'w', encoding='utf-8') as f:
                        f.write(updated_content)

                    log(f"Processed {wiki_filepath} and moved code to {code_repo_dir}")
    except Exception as e:
        log_exception(e)
        raise
  • Utfordring: Lange filnavn og spesialtegn forårsaket problemer.
  • Løsning: Implementerte funksjonen sanitize_filename som fjerner uønskede tegn og begrenser filnavnene til 100 tegn.

7. Oppdatere changelog

For å holde styr på endringer, oppdateres en changelog-fil med alle endringer som gjøres.

def update_changelog(code_repo_dir, log_message):
    try:
        changelog_path = os.path.join(code_repo_dir, "CHANGELOG.md")
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        log_entry = f"{timestamp} - {log_message}\n"

        with open(changelog_path, 'a' if os.path.exists(changelog_path) else 'w', encoding='utf-8') as changelog_file:
            if not os.path.exists(changelog_path):
                changelog_file.write("# CHANGELOG\n\n")
            changelog_file.write(log_entry)

        log(f"Updated CHANGELOG.md with: {log_message}")
    except Exception as e:
        log_exception(e)
        raise
  • update_changelog(code_repo_dir, log_message): Legger til en ny linje i CHANGELOG.md med en beskrivelse av hva som ble endret.

8. Git-operasjoner

Til slutt gjør vi Git-operasjoner som å initiere et nytt repo (om nødvendig), legge til filer i staging, og comitte endringer.

def init_commit_code_repo(code_repo_dir, commit_message):
    try:
        if not os.path.exists(os.path.join(code_repo_dir, ".git")):
            run_git_command(["git", "init"], cwd=code_repo_dir)
            log("Initialized a new git repo.")
        else:
            log("Git repo already initialized.")

        run_git_command(["git", "add", "."], cwd=code_repo_dir)
        run_git_command(["git", "commit", "-m", commit_message], cwd=code_repo_dir)
        log(f"Committed changes with message: {commit_message}")
    except Exception as e:
        log_exception(e)
        raise
  • init_commit_code_repo(code_repo_dir, commit_message): Initialiserer Git-repoet, legger til filer i staging, og comitter med en melding.

9. **Oppsummering av

endringer**

Endringer og forbedringer gjort under utviklingen:

  • Versjon 1.1 til 1.6: Håndterte problemer med skrivebeskyttede filer, feil i Git-kloning, lange filnavn, og spesialtegn i filnavn.
  • Versjon 1.6: Optimalisering av filnavn og sikker håndtering av skrivebeskyttede filer. Lagt til logging for bedre feilsøking.

Dette skriptet gir deg nå en robust løsning for å migrere kode fra wiki til GitHub på en ryddig måte, med fullstendig logging og feilrapportering. Hvis du trenger mer hjelp med Git eller Python, kan jeg gjerne gi deg videre opplæring eller veiledning.