From 79f285d0202d3907d0d88f6104a4246677e24510 Mon Sep 17 00:00:00 2001 From: Moncef STITI <moncef.stiti@etu.u-pec.fr> Date: Sat, 8 Feb 2025 23:15:07 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20la=20m=C3=A9thode=20getRule=20dans?= =?UTF-8?q?=20BakeEngine=20et=20am=C3=A9lioration=20de=20la=20gestion=20de?= =?UTF-8?q?s=20d=C3=A9pendances=20dans=20la=20classe=20Rule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fr/monlouyan/bakefile/BakeEngine.java | 7 +- src/fr/monlouyan/bakefile/BakefileParser.java | 71 +++++++----- src/fr/monlouyan/bakefile/Rule.java | 101 +++++++----------- 3 files changed, 84 insertions(+), 95 deletions(-) diff --git a/src/fr/monlouyan/bakefile/BakeEngine.java b/src/fr/monlouyan/bakefile/BakeEngine.java index be1f436..a536064 100644 --- a/src/fr/monlouyan/bakefile/BakeEngine.java +++ b/src/fr/monlouyan/bakefile/BakeEngine.java @@ -17,9 +17,12 @@ public class BakeEngine { } public static boolean hasRule(String target) { - // Vérifie si une règle existe pour créer cette cible return ruleMap.containsKey(target); } + + public static Rule getRule(String target) { + return ruleMap.get(target); + } public void run() { List<Rule> rules = parser.parse(); @@ -35,4 +38,4 @@ public class BakeEngine { executor.execute(rule); } } -} +} \ No newline at end of file diff --git a/src/fr/monlouyan/bakefile/BakefileParser.java b/src/fr/monlouyan/bakefile/BakefileParser.java index 7d1a0ac..3177d7a 100644 --- a/src/fr/monlouyan/bakefile/BakefileParser.java +++ b/src/fr/monlouyan/bakefile/BakefileParser.java @@ -32,6 +32,12 @@ public class BakefileParser { */ private static final Pattern VARIABLE_PATTERN = Pattern.compile("^(\\w+)\\s*=\\s*([^#]*?)\\s*(?:#.*)?$"); + /** + * Regex pour détecter les déclarations .PHONY + * Format : ".PHONY: clean all" + */ + private static final Pattern PHONY_PATTERN = Pattern.compile("^\\.PHONY:\\s*([^#]*?)\\s*(?:#.*)?$"); + /** * Première cible trouvée dans le fichier Bakefile. */ @@ -42,13 +48,12 @@ public class BakefileParser { */ private Map<String, String> variables = new HashMap<>(); - public BakefileParser(String filename) { this.filename = filename; firstTarget = null; } - private List<String> splitDependencies(String depStr) { + private List<String> splitDependencies(String depStr) { if (depStr == null || depStr.trim().isEmpty()) { return new ArrayList<>(); } @@ -63,7 +68,6 @@ public class BakefileParser { .collect(Collectors.toList()); } - public List<Rule> parse() { List<Rule> rules = new ArrayList<>(); Set<String> phonyTargets = new HashSet<>(); @@ -86,6 +90,7 @@ public class BakefileParser { Matcher varMatcher = VARIABLE_PATTERN.matcher(line); Matcher targetMatcher = TARGET_PATTERN.matcher(line); Matcher commandMatcher = COMMAND_PATTERN.matcher(line); + Matcher phonyMatcher = PHONY_PATTERN.matcher(line); if (line.trim().isEmpty()) { continue; @@ -96,32 +101,35 @@ public class BakefileParser { System.exit(1); } + if (phonyMatcher.matches()) { + // Ajouter les cibles .PHONY à l'ensemble des cibles phony + String[] phonies = phonyMatcher.group(1).trim().split("\\s+"); + Collections.addAll(phonyTargets, phonies); + continue; + } + if (varMatcher.matches()) { - // Stocke la variable en enlevant les espaces en début et fin variables.put(varMatcher.group(1), varMatcher.group(2).trim()); } else if (targetMatcher.matches()) { if (currentTarget != null) { + String resolvedTarget = replaceVariables(currentTarget.trim()); rules.add(new Rule( - replaceVariables(currentTarget.trim()), - splitDependencies(dependencies.stream() - .collect(Collectors.joining(" "))), - replaceVariablesInList(commands), - phonyTargets.contains(currentTarget.trim()) - )); + resolvedTarget, + splitDependencies(dependencies.stream() + .collect(Collectors.joining(" "))), + replaceVariablesInList(commands), + phonyTargets.contains(resolvedTarget) + )); + + // Ne définir firstTarget que si ce n'est pas une cible .PHONY + if (firstTarget == null && !phonyTargets.contains(resolvedTarget)) { + firstTarget = resolvedTarget; + } } currentTarget = targetMatcher.group(1); - String depStr = targetMatcher.group(2); - dependencies = splitDependencies(depStr); - - if (firstTarget == null) { - firstTarget = replaceVariables(currentTarget.trim()); - } - - if (currentTarget.equals("clean")) { - phonyTargets.add(currentTarget); - } - + String depStr = targetMatcher.group(2); + dependencies = splitDependencies(depStr); commands = new ArrayList<>(); } else if (commandMatcher.matches()) { commands.add(commandMatcher.group(1)); @@ -129,12 +137,18 @@ public class BakefileParser { } if (currentTarget != null) { + String resolvedTarget = replaceVariables(currentTarget.trim()); rules.add(new Rule( - replaceVariables(currentTarget.trim()), + resolvedTarget, replaceVariablesInList(dependencies), replaceVariablesInList(commands), - phonyTargets.contains(currentTarget.trim()) + phonyTargets.contains(resolvedTarget) )); + + // Vérifier une dernière fois pour firstTarget + if (firstTarget == null && !phonyTargets.contains(resolvedTarget)) { + firstTarget = resolvedTarget; + } } } catch (IOException e) { @@ -143,7 +157,7 @@ public class BakefileParser { return rules; } - private String replaceVariables(String input) { + private String replaceVariables(String input) { if (input == null) return null; String result = input; boolean replaced; @@ -161,7 +175,7 @@ public class BakefileParser { return result.trim(); } - private List<String> replaceVariablesInList(List<String> items) { + private List<String> replaceVariablesInList(List<String> items) { List<String> resolved = new ArrayList<>(); for (String item : items) { resolved.add(replaceVariables(item)); @@ -169,10 +183,11 @@ public class BakefileParser { return resolved; } - /** * Permet de récupérer la première cible trouvée dans le fichier Bakefile. * @return La première cible trouvée */ - public static String getFirstTarget() { return firstTarget; } -} + public static String getFirstTarget() { + return firstTarget; + } +} \ No newline at end of file diff --git a/src/fr/monlouyan/bakefile/Rule.java b/src/fr/monlouyan/bakefile/Rule.java index 84ebae2..7a7d2ab 100644 --- a/src/fr/monlouyan/bakefile/Rule.java +++ b/src/fr/monlouyan/bakefile/Rule.java @@ -3,42 +3,12 @@ package fr.monlouyan.bakefile; import java.io.File; import java.util.List; -/** - * Représente une règle dans un fichier Bakefile - * Dernière modification : 04/02/2025 - * - * @author Moncef STITI, Yanis HAMOUDI - * @version 1.0 - * @date 04/02/2025 - */ public class Rule { - /** - * Nom de la règle - */ private String name; - - /** - * Liste des dépendances de la règle - */ private List<String> dependencies; - - /** - * Liste des commandes de la règle (actions à exécuter) - */ private List<String> commands; - - /** - * Indique si la règle est une règle phony - */ private boolean isPhony; - /** - * Constructeur de la classe Rule - * @param name Nom de la règle - * @param dependencies Liste des dépendances de la règle - * @param commands Liste des commandes de la règle à exécuter - * @param isPhony Si la règle est une règle phony ou non - */ public Rule(String name, List<String> dependencies, List<String> commands, boolean isPhony) { this.name = name; this.dependencies = dependencies; @@ -46,60 +16,50 @@ public class Rule { this.isPhony = isPhony; } - /** - * Permet de récupérer le nom de la règle - * @return Le nom de la règle - */ public String getName() { return name; } - - /** - * Permet de récupérer les dépendances de la règle - * @return La liste des dépendances de la règle - */ public List<String> getDependencies() { return dependencies; } - - /** - * Permet de récupérer les commandes de la règle - * @return La liste des commandes de la règle - */ public List<String> getCommands() { return commands; } - - /** - * Permet de savoir si la règle est une règle phony - * @return true si la règle est une règle phony, false sinon - */ public boolean isPhony() { return isPhony; } - - /** - * Permet de savoir si la règle est vide (sans dépendances ni commandes) - * @return true si la règle est vide, false sinon - */ public boolean isEmpty() { return dependencies.isEmpty() && commands.isEmpty(); } - /** - * Détermine si la règle doit être mise à jour. - * Une règle doit être mise à jour si l'un de ses fichiers de sortie est plus ancien qu'un de ses fichiers de dépendance. - * De plus, les règles phony sont toujours mises à jour. - * - * @return true si la règle doit être mise à jour, false sinon. - */ public boolean needsUpdate() { if (BakeCLI.isDebug()){ System.out.println("Debug : Checking if rule " + name + " needs update"); } + // Les règles phony sont toujours mises à jour if (isPhony) { if (BakeCLI.isDebug()) { System.out.println("Debug : Rule " + name + " is phony, always needs update"); } - return true; // Les règles phony sont toujours mises à jour + return true; } - - File targetFile = new File(name); + // Si la règle n'a pas de commandes, on vérifie seulement si une dépendance doit être mise à jour + if (commands.isEmpty()) { + for (String dependency : dependencies) { + File depFile = new File(dependency); + if (!depFile.exists() && !dependency.isEmpty() && !BakeEngine.hasRule(dependency)) { + System.out.println("bake: *** No rule to make target '" + dependency + "', needed by '" + name + "'. Stop."); + System.exit(1); + } + Rule depRule = BakeEngine.getRule(dependency); + if (depRule != null && depRule.needsUpdate()) { + if (BakeCLI.isDebug()) { + System.out.println("Debug : Dependency rule " + dependency + " needs update"); + } + return true; + } + } + return false; + } + + // Pour les règles avec des commandes, on vérifie aussi les timestamps + File targetFile = new File(name); if (BakeCLI.isDebug()){ System.out.println("Debug : Checking if target file " + name + " exist and is up to date"); } + long targetTimestamp = targetFile.exists() ? TimestampManager.getTimestamp(targetFile) : 0; if (BakeCLI.isDebug()) { @@ -114,6 +74,7 @@ public class Rule { System.out.println("Debug : Dependency '" + dependency + "' last modified at " + TimestampManager.formatTimestamp(depTimestamp)); } + // Vérifier si une règle existe pour cette dépendance boolean hasRule = BakeEngine.hasRule(dependency); if (!depFile.exists() && !dependency.isEmpty() && !hasRule) { @@ -121,6 +82,16 @@ public class Rule { System.exit(1); } + // Si la dépendance est une règle et qu'elle a besoin d'être mise à jour + Rule depRule = BakeEngine.getRule(dependency); + if (depRule != null && depRule.needsUpdate()) { + if (BakeCLI.isDebug()) { + System.out.println("Debug : Dependency rule " + dependency + " needs update"); + } + return true; + } + + // Vérifier les timestamps seulement si le fichier existe if (depFile.exists() && TimestampManager.getTimestamp(depFile) > targetTimestamp) { if (BakeCLI.isDebug()) { System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update"); @@ -130,4 +101,4 @@ public class Rule { } return false; } -} +} \ No newline at end of file