# fileutils.nim # Module responsable des opérations sur les fichiers et répertoires import std/[os, strutils, strformat, options, tables] import zippy/ziparchives import metadata, report, config proc printOutput*(output: string, debug: bool = false, appConfig: Option[AppConfig] = none(AppConfig)) = ## Affiche un message en sortie standard ## Si debug est true, n'affiche le message que si debugModeActive est activé dans la configuration ## Si debug est false, affiche toujours le message ## ## Paramètres: ## - output: Le message à afficher ## - debug: Si true, il s'agit d'un message de débogage ## - appConfig: Configuration de l'application (optionnel) if not debug: # Message normal, toujours affiché echo output else: # Message de débogage, affiché uniquement si debugModeActive est true if appConfig.isSome and appConfig.get().debugModeActive: echo fmt"[DEBUG] {output}" proc debugLog*(message: string, appConfig: AppConfig) = ## Affiche un message de débogage si le mode debug est activé if appConfig.debugModeActive: echo fmt"[DEBUG] {message}" proc walkDirRecFiles*(dir: string, ext: string): seq[string] = ## Parcourt récursivement un répertoire et retourne tous les fichiers avec l'extension spécifiée result = @[] for kind, path in walkDir(dir): if kind == pcDir: result.add(walkDirRecFiles(path, ext)) elif kind == pcFile and path.endsWith(ext): result.add(path) proc readMarkdownFile*(filePath: string): string = ## Lit le contenu d'un fichier Markdown try: return readFile(filePath) except: echo fmt"Erreur lors de la lecture du fichier: {filePath}" return "" proc writeMarkdownFile*(filePath: string, content: string): bool = ## Écrit le contenu dans un fichier Markdown try: echo fmt"DEBUG: Tentative d'écriture dans le fichier: {filePath}" echo fmt"DEBUG: Contenu à écrire (premiers 100 caractères): {content[0..min(99, content.len-1)]}" let parentDir = parentDir(filePath) if not dirExists(parentDir): echo fmt"DEBUG: Création du répertoire parent: {parentDir}" createDir(parentDir) # Normalisation des retours à la ligne pour éviter les problèmes de \n littéraux let normalizedContent = content.replace("\n", "\r\n") echo fmt"DEBUG: Écriture de {normalizedContent.len} caractères" writeFile(filePath, normalizedContent) echo fmt"DEBUG: Fichier écrit avec succès" return true except Exception as e: echo fmt"Erreur lors de l'écriture dans le fichier: {filePath}" echo fmt"DEBUG: Exception: {e.msg}" return false proc copyFileWithDirectories*(sourcePath, targetPath: string, verbose: bool = false): bool = ## Copie un fichier de sourcePath vers targetPath en créant les répertoires ## intermédiaires si nécessaire ## ## Paramètres: ## sourcePath: Chemin source du fichier ## targetPath: Chemin destination du fichier ## verbose: Affiche des informations supplémentaires ## ## Retourne: ## true si la copie a réussi, false sinon try: if verbose: echo fmt"Copie du fichier: {sourcePath} -> {targetPath}" let parentDir = parentDir(targetPath) if not dirExists(parentDir): createDir(parentDir) copyFile(sourcePath, targetPath) return true except Exception as e: echo fmt"Erreur lors de la copie du fichier: {e.msg}" return false proc zipDir*(sourceDir: string, zipFilePath: string = "", verbose: bool = false): bool = ## Crée une archive zip du répertoire source dans un répertoire "backup" ## Si zipFilePath est vide, utilise le nom du répertoire source pour le zip try: let sourceDirName = sourceDir.splitPath().tail parentDir = sourceDir.splitPath().head backupDir = parentDir / "backup" # Créer le répertoire backup s'il n'existe pas if not dirExists(backupDir): if verbose: echo fmt"Création du répertoire backup: {backupDir}" createDir(backupDir) # Déterminer le nom du fichier zip var actualZipPath: string if zipFilePath == "": # Si aucun nom n'est fourni, utiliser le nom du répertoire source actualZipPath = backupDir / fmt"{sourceDirName}.zip" else: # Si un nom est fourni, l'utiliser mais le placer dans le répertoire backup actualZipPath = backupDir / zipFilePath.extractFilename() if verbose: echo fmt"Création d'une archive zip: {actualZipPath} à partir de {sourceDir}" # Utilisons une approche plus simple basée sur la documentation de zippy # Extrayons d'abord tous les fichiers avec leurs chemins relatifs var fileEntries = initTable[string, string]() # Fonction récursive pour ajouter les fichiers proc addFilesRecursively(dir: string, relativePath = "") = for kind, path in walkDir(dir): let relPath = if relativePath.len > 0: relativePath / path.extractFilename else: path.extractFilename if kind == pcFile: # Ajouter le fichier à l'archive if verbose: echo fmt"Ajout du fichier: {path}" fileEntries[relPath] = readFile(path) elif kind == pcDir: # Récursivement parcourir les sous-répertoires addFilesRecursively(path, relPath) # Commencer la compression depuis le répertoire source addFilesRecursively(sourceDir) # Créer l'archive avec toutes les entrées let zipData = ziparchives.createZipArchive(fileEntries) # Sauvegarder l'archive zip writeFile(actualZipPath, zipData) if verbose: echo fmt"Archive zip créée avec succès: {actualZipPath}" return true except Exception as e: echo fmt"Exception lors de la création du zip: {e.msg}" return false proc processMarkdownFileBasic*(sourcePath, targetPath: string, verbose: bool = false): Report = ## Traite un fichier Markdown : lit, analyse les métadonnées, complète si nécessaire, et écrit var report = newReport() if verbose: echo fmt"Traitement du fichier: {sourcePath}" let content = readMarkdownFile(sourcePath) if content == "": report.errors.add(fmt"Impossible de lire le fichier: {sourcePath}") return report # Extraire les métadonnées existantes ou créer de nouvelles métadonnées var metadata: Metadata let metadataOpt = extractMetadataFromYaml(content) # Utiliser correctement l'API Option if metadataOpt.isSome(): metadata = metadataOpt.get() else: metadata = newMetadata() # Compléter les métadonnées manquantes echo ">>> Avant updateMetadata: catégorie = " & metadata.category # Utiliser le targetPath pour déterminer la catégorie au lieu du sourcePath let modified = updateMetadata(metadata, content, targetPath, true, true) echo ">>> Après updateMetadata: catégorie = " & metadata.category if verbose: if metadata.isNew: echo fmt"Métadonnées ajoutées pour: {sourcePath}" elif modified: echo fmt"Métadonnées mises à jour pour: {sourcePath}" else: echo fmt"Métadonnées déjà complètes pour: {sourcePath}" # Ajouter les métadonnées au contenu let newContent = addMetadataToContent(metadata, content) # Écrire le nouveau contenu dans le fichier cible if writeMarkdownFile(targetPath, newContent): if metadata.isNew: report.newMetadata.add(targetPath) elif modified: report.updatedMetadata.add(targetPath) else: report.unchanged.add(targetPath) else: report.errors.add(fmt"Impossible d'écrire dans le fichier: {targetPath}") return report