diff --git a/bakefile.jar b/bakefile.jar index 8731420..d445db8 100644 Binary files a/bakefile.jar and b/bakefile.jar differ diff --git a/src/fr/monlouyan/bakefile/BakeEngine.java b/src/fr/monlouyan/bakefile/BakeEngine.java index 8306fa0..e0bc724 100644 --- a/src/fr/monlouyan/bakefile/BakeEngine.java +++ b/src/fr/monlouyan/bakefile/BakeEngine.java @@ -10,12 +10,12 @@ public class BakeEngine { public BakeEngine() { this.parser = new BakefileParser("Bakefile"); this.resolver = new DependencyResolver(BakeCLI.isDebug()); - this.executor = new CommandExecutor(BakeCLI.isDebug()); } public void run() { List rules = parser.parse(); List rulesToBuild = resolver.resolve(rules, BakeCLI.getTargets()); + this.executor = new CommandExecutor(BakeCLI.isDebug(), resolver.isCircular()); for (Rule rule : rulesToBuild) { executor.execute(rule); diff --git a/src/fr/monlouyan/bakefile/CommandExecutor.java b/src/fr/monlouyan/bakefile/CommandExecutor.java index 0779d65..65b6645 100644 --- a/src/fr/monlouyan/bakefile/CommandExecutor.java +++ b/src/fr/monlouyan/bakefile/CommandExecutor.java @@ -4,9 +4,12 @@ import java.io.IOException; public class CommandExecutor { private boolean debug; - - public CommandExecutor(boolean debug) { + private boolean needsUpdate = false; // Pour tracker si quelque chose doit être mis à jour + private boolean isCircular = false; // Pour tracker si un cycle a été détecté + + public CommandExecutor(boolean debug, boolean isCircular) { this.debug = debug; + this.isCircular = isCircular; } public void execute(Rule rule) { @@ -15,28 +18,43 @@ public class CommandExecutor { return; } - if (!rule.needsUpdate()) { - if (rule.getName().equals(BakefileParser.getFirstTarget())) { - System.out.println("bake: '" + rule.getName() + "' is up to date."); - } - return; + // On vérifie d'abord si cette règle a besoin d'être mise à jour + boolean ruleNeedsUpdate = rule.needsUpdate(); + if (ruleNeedsUpdate) { + needsUpdate = true; // Au moins une règle doit être mise à jour } - - - try { - for (String command : rule.getCommands()) { - System.out.println(command); // Affichage de la commande executée - ProcessBuilder pb = new ProcessBuilder("sh", "-c", command); - Process process = pb.start(); - int exitCode = process.waitFor(); - if (debug) System.out.println("Executed: " + command + " with exit code " + exitCode); - if (exitCode != 0) { - System.err.println("Error executing " + rule.getName() + ""); - break; + + for (String command : rule.getCommands()) { + if (isCircular){ + System.out.println(command); + } + + // Mais on n'exécute que si nécessaire + if (ruleNeedsUpdate) { + try { + if(!isCircular){ + System.out.println(command); + } + if (debug) System.out.println("Debug: Executing " + command); + ProcessBuilder pb = new ProcessBuilder("sh", "-c", command); + Process process = pb.start(); + int exitCode = process.waitFor(); + + if (exitCode != 0) { + System.err.println("Error executing " + rule.getName()); + System.exit(1); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + System.exit(1); } } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); } - } -} + + // On affiche "up to date" seulement après avoir traité TOUTES les règles + // et seulement si AUCUNE règle n'avait besoin d'être mise à jour + if (rule.getName().equals(BakefileParser.getFirstTarget()) && !needsUpdate) { + System.out.println("bake: '" + rule.getName() + "' is up to date."); + } + } +} \ No newline at end of file diff --git a/src/fr/monlouyan/bakefile/DependencyResolver.java b/src/fr/monlouyan/bakefile/DependencyResolver.java index e47a015..6ee3349 100644 --- a/src/fr/monlouyan/bakefile/DependencyResolver.java +++ b/src/fr/monlouyan/bakefile/DependencyResolver.java @@ -5,52 +5,98 @@ import java.util.*; public class DependencyResolver { private boolean debug; private Map ruleMap; + private boolean isCircular; public DependencyResolver(boolean debug) { this.debug = debug; + this.isCircular = false; } public List resolve(List allRules, List requestedRules) { List rulesToBuild = new ArrayList<>(); ruleMap = new HashMap<>(); - Set builtRules = new HashSet<>(); // Éviter d'ajouter des règles déjà vérifiées + // Construire la map des règles for (Rule rule : allRules) { ruleMap.put(rule.getName(), rule); } - + + // Premier passage : détection et suppression des cycles Set visited = new HashSet<>(); Set stack = new HashSet<>(); + + List targetRules = requestedRules.isEmpty() ? + Collections.singletonList(BakefileParser.getFirstTarget()) : + requestedRules; - for (String ruleName : requestedRules.isEmpty() ? ruleMap.keySet() : requestedRules) { + for (String ruleName : targetRules) { if (ruleMap.containsKey(ruleName)) { - detectCycle(ruleName, visited, stack); - collectDependencies(ruleName, rulesToBuild, builtRules); + detectCycle(ruleName, visited, stack, ruleName); } else if (debug) { System.out.println("Warning: Rule '" + ruleName + "' not found."); } } - + + // Deuxième passage : collecte des dépendances dans l'ordre + Set processed = new HashSet<>(); + List buildOrder = new ArrayList<>(); + + for (String ruleName : targetRules) { + topologicalSort(ruleName, processed, buildOrder); + } + + // Construire la liste finale des règles dans l'ordre + for (String ruleName : buildOrder) { + Rule rule = ruleMap.get(ruleName); + if (rule != null) { + rulesToBuild.add(rule); + } + } + return rulesToBuild; } - /** - * Détection des cycles avec DFS - */ - private void detectCycle(String ruleName, Set visited, Set stack) { - if (stack.contains(ruleName)) { - throw new RuntimeException("Dependency cycle detected involving rule: " + ruleName); + private void topologicalSort(String ruleName, Set processed, List buildOrder) { + if (!ruleMap.containsKey(ruleName) || processed.contains(ruleName)) { + return; } + + processed.add(ruleName); + Rule rule = ruleMap.get(ruleName); + + // D'abord traiter les dépendances + for (String dep : rule.getDependencies()) { + topologicalSort(dep, processed, buildOrder); + } + + // Puis ajouter la règle courante + buildOrder.add(ruleName); + } + // La méthode detectCycle reste inchangée + private void detectCycle(String ruleName, Set visited, Set stack, String parent) { + if (stack.contains(ruleName)) { + if (parent != null) { + System.out.println("make: Circular " + parent + " <- " + ruleName + " dependency dropped."); + this.isCircular = true; + Rule parentRule = ruleMap.get(parent); + if (parentRule != null) { + parentRule.getDependencies().remove(ruleName); + } + } + return; + } + if (!visited.contains(ruleName)) { visited.add(ruleName); stack.add(ruleName); - + Rule rule = ruleMap.get(ruleName); if (rule != null) { - for (String dependency : rule.getDependencies()) { + List dependenciesCopy = new ArrayList<>(rule.getDependencies()); + for (String dependency : dependenciesCopy) { if (ruleMap.containsKey(dependency)) { - detectCycle(dependency, visited, stack); + detectCycle(dependency, visited, stack, ruleName); } } } @@ -58,23 +104,7 @@ public class DependencyResolver { } } - /** - * Collecte récursive des règles à construire en évitant les doublons - */ - private void collectDependencies(String ruleName, List rulesToBuild, Set builtRules) { - if (builtRules.contains(ruleName)) { - return; // Évite d'ajouter une règle plusieurs fois - } - - Rule rule = ruleMap.get(ruleName); - if (rule != null) { - for (String dependency : rule.getDependencies()) { - if (ruleMap.containsKey(dependency)) { - collectDependencies(dependency, rulesToBuild, builtRules); - } - } - rulesToBuild.add(rule); - builtRules.add(ruleName); - } + public boolean isCircular() { + return isCircular; } -} +} \ No newline at end of file diff --git a/tests/test-01-from-nothing/Bakefile b/tests/C/test-01-from-nothing/Bakefile similarity index 100% rename from tests/test-01-from-nothing/Bakefile rename to tests/C/test-01-from-nothing/Bakefile diff --git a/tests/test-01-from-nothing/README.md b/tests/C/test-01-from-nothing/README.md similarity index 100% rename from tests/test-01-from-nothing/README.md rename to tests/C/test-01-from-nothing/README.md diff --git a/tests/test-01-from-nothing/main.c b/tests/C/test-01-from-nothing/main.c similarity index 100% rename from tests/test-01-from-nothing/main.c rename to tests/C/test-01-from-nothing/main.c diff --git a/tests/test-02-already-exist/Bakefile b/tests/C/test-02-already-exist/Bakefile similarity index 100% rename from tests/test-02-already-exist/Bakefile rename to tests/C/test-02-already-exist/Bakefile diff --git a/tests/test-02-already-exist/README.md b/tests/C/test-02-already-exist/README.md similarity index 100% rename from tests/test-02-already-exist/README.md rename to tests/C/test-02-already-exist/README.md diff --git a/tests/test-02-already-exist/main b/tests/C/test-02-already-exist/main similarity index 100% rename from tests/test-02-already-exist/main rename to tests/C/test-02-already-exist/main diff --git a/tests/test-02-already-exist/main.c b/tests/C/test-02-already-exist/main.c similarity index 100% rename from tests/test-02-already-exist/main.c rename to tests/C/test-02-already-exist/main.c diff --git a/tests/test-03-circular/Bakefile b/tests/C/test-03-circular/Bakefile similarity index 100% rename from tests/test-03-circular/Bakefile rename to tests/C/test-03-circular/Bakefile diff --git a/tests/test-03-circular/README.md b/tests/C/test-03-circular/README.md similarity index 100% rename from tests/test-03-circular/README.md rename to tests/C/test-03-circular/README.md diff --git a/tests/test-03-circular/a.c b/tests/C/test-03-circular/a.c similarity index 100% rename from tests/test-03-circular/a.c rename to tests/C/test-03-circular/a.c diff --git a/tests/test-03-circular/a.h b/tests/C/test-03-circular/a.h similarity index 100% rename from tests/test-03-circular/a.h rename to tests/C/test-03-circular/a.h diff --git a/tests/test-03-circular/b.c b/tests/C/test-03-circular/b.c similarity index 100% rename from tests/test-03-circular/b.c rename to tests/C/test-03-circular/b.c diff --git a/tests/test-03-circular/b.h b/tests/C/test-03-circular/b.h similarity index 100% rename from tests/test-03-circular/b.h rename to tests/C/test-03-circular/b.h diff --git a/tests/test-03-circular/c.c b/tests/C/test-03-circular/c.c similarity index 100% rename from tests/test-03-circular/c.c rename to tests/C/test-03-circular/c.c diff --git a/tests/test-03-circular/c.h b/tests/C/test-03-circular/c.h similarity index 100% rename from tests/test-03-circular/c.h rename to tests/C/test-03-circular/c.h diff --git a/tests/test-04-edited/Bakefile b/tests/C/test-04-edited/Bakefile similarity index 100% rename from tests/test-04-edited/Bakefile rename to tests/C/test-04-edited/Bakefile diff --git a/tests/test-04-edited/README.md b/tests/C/test-04-edited/README.md similarity index 100% rename from tests/test-04-edited/README.md rename to tests/C/test-04-edited/README.md diff --git a/tests/test-04-edited/main b/tests/C/test-04-edited/main similarity index 100% rename from tests/test-04-edited/main rename to tests/C/test-04-edited/main diff --git a/tests/test-04-edited/main.c b/tests/C/test-04-edited/main.c similarity index 100% rename from tests/test-04-edited/main.c rename to tests/C/test-04-edited/main.c diff --git a/tests/test-05-variables/Bakefile b/tests/C/test-05-variables/Bakefile similarity index 100% rename from tests/test-05-variables/Bakefile rename to tests/C/test-05-variables/Bakefile diff --git a/tests/test-05-variables/README.md b/tests/C/test-05-variables/README.md similarity index 100% rename from tests/test-05-variables/README.md rename to tests/C/test-05-variables/README.md diff --git a/tests/test-05-variables/main.c b/tests/C/test-05-variables/main.c similarity index 100% rename from tests/test-05-variables/main.c rename to tests/C/test-05-variables/main.c diff --git a/tests/test-06-variables-on-cascade/Bakefile b/tests/C/test-06-variables-on-cascade/Bakefile similarity index 100% rename from tests/test-06-variables-on-cascade/Bakefile rename to tests/C/test-06-variables-on-cascade/Bakefile diff --git a/tests/test-06-variables-on-cascade/README.md b/tests/C/test-06-variables-on-cascade/README.md similarity index 100% rename from tests/test-06-variables-on-cascade/README.md rename to tests/C/test-06-variables-on-cascade/README.md diff --git a/tests/test-06-variables-on-cascade/main.c b/tests/C/test-06-variables-on-cascade/main.c similarity index 100% rename from tests/test-06-variables-on-cascade/main.c rename to tests/C/test-06-variables-on-cascade/main.c diff --git a/tests/Java/test-03-circular/Bakefile b/tests/Java/test-03-circular/Bakefile new file mode 100644 index 0000000..4544088 --- /dev/null +++ b/tests/Java/test-03-circular/Bakefile @@ -0,0 +1,11 @@ +main: ClasseA ClasseB ClasseC Main.java + javac Main.java + +ClasseA: ClasseB + javac ClasseA.java + +ClasseB: ClasseA + javac ClasseB.java + +ClasseC: ClasseB ClasseA + javac ClasseC.java \ No newline at end of file diff --git a/tests/Java/test-03-circular/ClasseA.java b/tests/Java/test-03-circular/ClasseA.java new file mode 100644 index 0000000..7d10704 --- /dev/null +++ b/tests/Java/test-03-circular/ClasseA.java @@ -0,0 +1,7 @@ +public class ClasseA { + private ClasseB b; + + public ClasseA(ClasseB b) { + this.b = b; + } +} diff --git a/tests/Java/test-03-circular/ClasseB.java b/tests/Java/test-03-circular/ClasseB.java new file mode 100644 index 0000000..67fd6ac --- /dev/null +++ b/tests/Java/test-03-circular/ClasseB.java @@ -0,0 +1,7 @@ +public class ClasseB { + private ClasseA a; + + public ClasseB(ClasseA a) { + this.a = a; + } +} diff --git a/tests/Java/test-03-circular/ClasseC.java b/tests/Java/test-03-circular/ClasseC.java new file mode 100644 index 0000000..4f9f759 --- /dev/null +++ b/tests/Java/test-03-circular/ClasseC.java @@ -0,0 +1,9 @@ +public class ClasseC { + private ClasseA a; + private ClasseB b; + + public ClasseC(ClasseA a, ClasseB b) { + this.a = a; + this.b = b; + } +} diff --git a/tests/Java/test-03-circular/Main.java b/tests/Java/test-03-circular/Main.java new file mode 100644 index 0000000..c8c8ab7 --- /dev/null +++ b/tests/Java/test-03-circular/Main.java @@ -0,0 +1,16 @@ +public class Main { + private ClasseA a; + private ClasseB b; + private ClasseC c; + + public Main() { + this.a = new ClasseA(b); + this.b = new ClasseB(a); + this.c = new ClasseC(a,b); + } + + public static void main(String[] args) { + Main m = new Main(); + System.out.println("Ceci est un test de dépendences circulaires"); + } +} diff --git a/tests/bakefile.jar b/tests/bakefile.jar index 8731420..d445db8 100644 Binary files a/tests/bakefile.jar and b/tests/bakefile.jar differ