From 1f31e318dcbdf5f3002211ba252cc5aee3597fe2 Mon Sep 17 00:00:00 2001 From: Moncef STITI Date: Tue, 4 Feb 2025 21:25:16 +0100 Subject: [PATCH] =?UTF-8?q?Am=C3=A9liorations=20des=20d=C3=A9pendances=20c?= =?UTF-8?q?irculaire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bakefile.jar | Bin 10176 -> 10566 bytes src/fr/monlouyan/bakefile/BakeEngine.java | 2 +- .../monlouyan/bakefile/CommandExecutor.java | 64 ++++++++---- .../bakefile/DependencyResolver.java | 98 ++++++++++++------ tests/{ => C}/test-01-from-nothing/Bakefile | 0 tests/{ => C}/test-01-from-nothing/README.md | 0 tests/{ => C}/test-01-from-nothing/main.c | 0 tests/{ => C}/test-02-already-exist/Bakefile | 0 tests/{ => C}/test-02-already-exist/README.md | 0 tests/{ => C}/test-02-already-exist/main | Bin tests/{ => C}/test-02-already-exist/main.c | 0 tests/{ => C}/test-03-circular/Bakefile | 0 tests/{ => C}/test-03-circular/README.md | 0 tests/{ => C}/test-03-circular/a.c | 0 tests/{ => C}/test-03-circular/a.h | 0 tests/{ => C}/test-03-circular/b.c | 0 tests/{ => C}/test-03-circular/b.h | 0 tests/{ => C}/test-03-circular/c.c | 0 tests/{ => C}/test-03-circular/c.h | 0 tests/{ => C}/test-04-edited/Bakefile | 0 tests/{ => C}/test-04-edited/README.md | 0 tests/{ => C}/test-04-edited/main | Bin tests/{ => C}/test-04-edited/main.c | 0 tests/{ => C}/test-05-variables/Bakefile | 0 tests/{ => C}/test-05-variables/README.md | 0 tests/{ => C}/test-05-variables/main.c | 0 .../test-06-variables-on-cascade/Bakefile | 0 .../test-06-variables-on-cascade/README.md | 0 .../test-06-variables-on-cascade/main.c | 0 tests/Java/test-03-circular/Bakefile | 11 ++ tests/Java/test-03-circular/ClasseA.java | 7 ++ tests/Java/test-03-circular/ClasseB.java | 7 ++ tests/Java/test-03-circular/ClasseC.java | 9 ++ tests/Java/test-03-circular/Main.java | 16 +++ tests/bakefile.jar | Bin 10176 -> 10566 bytes 35 files changed, 156 insertions(+), 58 deletions(-) rename tests/{ => C}/test-01-from-nothing/Bakefile (100%) rename tests/{ => C}/test-01-from-nothing/README.md (100%) rename tests/{ => C}/test-01-from-nothing/main.c (100%) rename tests/{ => C}/test-02-already-exist/Bakefile (100%) rename tests/{ => C}/test-02-already-exist/README.md (100%) rename tests/{ => C}/test-02-already-exist/main (100%) rename tests/{ => C}/test-02-already-exist/main.c (100%) rename tests/{ => C}/test-03-circular/Bakefile (100%) rename tests/{ => C}/test-03-circular/README.md (100%) rename tests/{ => C}/test-03-circular/a.c (100%) rename tests/{ => C}/test-03-circular/a.h (100%) rename tests/{ => C}/test-03-circular/b.c (100%) rename tests/{ => C}/test-03-circular/b.h (100%) rename tests/{ => C}/test-03-circular/c.c (100%) rename tests/{ => C}/test-03-circular/c.h (100%) rename tests/{ => C}/test-04-edited/Bakefile (100%) rename tests/{ => C}/test-04-edited/README.md (100%) rename tests/{ => C}/test-04-edited/main (100%) rename tests/{ => C}/test-04-edited/main.c (100%) rename tests/{ => C}/test-05-variables/Bakefile (100%) rename tests/{ => C}/test-05-variables/README.md (100%) rename tests/{ => C}/test-05-variables/main.c (100%) rename tests/{ => C}/test-06-variables-on-cascade/Bakefile (100%) rename tests/{ => C}/test-06-variables-on-cascade/README.md (100%) rename tests/{ => C}/test-06-variables-on-cascade/main.c (100%) create mode 100644 tests/Java/test-03-circular/Bakefile create mode 100644 tests/Java/test-03-circular/ClasseA.java create mode 100644 tests/Java/test-03-circular/ClasseB.java create mode 100644 tests/Java/test-03-circular/ClasseC.java create mode 100644 tests/Java/test-03-circular/Main.java diff --git a/bakefile.jar b/bakefile.jar index 873142097bfa736a5fdf99ff6a228278b6f4b5d1..d445db8aec4dd896f5a6baf60d4a2d1872eef94e 100644 GIT binary patch delta 4448 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 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 873142097bfa736a5fdf99ff6a228278b6f4b5d1..d445db8aec4dd896f5a6baf60d4a2d1872eef94e 100644 GIT binary patch delta 4448 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