From 7d392117e952e9cffae4c4ef785a119e0a0ffa45 Mon Sep 17 00:00:00 2001
From: Moncef STITI <moncef.stiti@etu.u-pec.fr>
Date: Sat, 15 Mar 2025 16:37:25 +0100
Subject: [PATCH] =?UTF-8?q?Correction=20de=20bug=20-=20=C3=80=20v=C3=A9rif?=
 =?UTF-8?q?ier?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/fr/monlouyan/bakefile/BakeEngine.java |   9 +
 src/fr/monlouyan/bakefile/Rule.java       | 297 ++++++++++++----------
 2 files changed, 176 insertions(+), 130 deletions(-)

diff --git a/src/fr/monlouyan/bakefile/BakeEngine.java b/src/fr/monlouyan/bakefile/BakeEngine.java
index 22b5a7d..4b2dd29 100644
--- a/src/fr/monlouyan/bakefile/BakeEngine.java
+++ b/src/fr/monlouyan/bakefile/BakeEngine.java
@@ -3,6 +3,7 @@ package fr.monlouyan.bakefile;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Moteur principal de l'application Bake.
@@ -85,4 +86,12 @@ public class BakeEngine {
             executor.execute(rule);
         }
     }
+
+	/**
+	 * Récupère les noms de toutes les règles.
+	 * @return Un ensemble contenant les noms de toutes les règles
+	 */
+	public static Set<String> getAllRuleNames() {
+		return ruleMap.keySet();
+	}
 }
\ No newline at end of file
diff --git a/src/fr/monlouyan/bakefile/Rule.java b/src/fr/monlouyan/bakefile/Rule.java
index 59b24b0..2ad047b 100644
--- a/src/fr/monlouyan/bakefile/Rule.java
+++ b/src/fr/monlouyan/bakefile/Rule.java
@@ -1,6 +1,7 @@
 package fr.monlouyan.bakefile;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -73,135 +74,171 @@ public class Rule {
 	 * Vérifie si la règle doit être mise à 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;
-        }
-    
-        // Skip targets with tilde in path (home directory) to match make behavior
-        if (name.startsWith("~")) {
-            if (BakeCLI.isDebug()) {
-                System.out.println("Debug : Skipping home directory path: " + name);
-            }
-            return false;
-        }
-    
-        // Vérifier d'abord toutes les dépendances avant d'exécuter quoi que ce soit
-        for (String dependency : dependencies) {
-            // Skip dependencies with tilde in path
-            if (dependency.startsWith("~")) {
-                continue;
-            }
-            
-            File depFile = new File(dependency);
-            boolean hasRule = BakeEngine.hasRule(dependency);
-            
-            // Ignorer les options de compilation qui pourraient avoir un ':' dedans
-            if (dependency.startsWith("-") || dependency.contains(":")) {
-                continue;
-            }
-            
-            if (!depFile.exists() && !dependency.isEmpty() && !hasRule) {
-                System.out.println("bake: *** No rule to make target `" + dependency + "', needed by `" + name + "'.  Stop.");
-                System.exit(2);
-            }
-        }
+	public boolean needsUpdate() {
+		if (BakeCLI.isDebug()){
+			System.out.println("Debug : Checking if rule " + name + " needs update");
+		}
 
-        // Si le fichier cible n'existe pas et qu'il y a des commandes, il doit être mis à jour
-        File targetFile = new File(name);
-        if (!targetFile.exists() && !commands.isEmpty()) {
-            if (BakeCLI.isDebug()) {
-                System.out.println("Debug : Target file " + name + " does not exist and has commands, needs update");
-            }
-            return true;
-        }
-    
-        // 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) {
-                // Skip dependencies with tilde in path or compiler options
-                if (dependency.startsWith("~") || dependency.startsWith("-") || dependency.contains(":")) {
-                    continue;
-                }
-                
-                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
-        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()) {
-            System.out.println("Debug : Target file '" + name + "' last modified at " + TimestampManager.formatTimestamp(targetTimestamp));
-        }
-    
-        long currentTime = System.currentTimeMillis();
-        
-        for (String dependency : dependencies) {
-            // Skip dependencies with tilde in path or compiler options
-            if (dependency.startsWith("~") || dependency.startsWith("-") || dependency.contains(":")) {
-                continue;
-            }
-            
-            File depFile = new File(dependency);
-            if (!depFile.exists()) {
-                continue;
-            }
-            
-            long depTimestamp = TimestampManager.getTimestamp(depFile);
-    
-            // Vérifier si le timestamp de la dépendance est dans le futur
-            if (depTimestamp > currentTime) {
-                // Avertissement similaire à make
-                System.out.println("bake: Warning: File '" + dependency + "' has modification time " 
-                                  + ((depTimestamp - currentTime) / 1000) + " s in the future");
-                if (BakeCLI.isDebug()) {
-                    System.out.println("Debug : Dependency " + dependency + " has a timestamp in the future, needs update");
-                }
-                return true;
-            }
-    
-            if (BakeCLI.isDebug()) {
-                System.out.println("Debug : Dependency '" + dependency + "' last modified at " + TimestampManager.formatTimestamp(depTimestamp));
-            }
-    
-            // 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 (depTimestamp > targetTimestamp) {
-                if (BakeCLI.isDebug()) {
-                    System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update");
-                }
-                return true;
-            }
-        }
-        
-        return false;
-    }
+		// 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;
+		}
+
+		// Skip targets with tilde in path (home directory) to match make behavior
+		if (name.startsWith("~")) {
+			if (BakeCLI.isDebug()) {
+				System.out.println("Debug : Skipping home directory path: " + name);
+			}
+			return false;
+		}
+
+		// Si le fichier cible n'existe pas et qu'il y a des commandes, il doit être mis à jour
+		File targetFile = new File(name);
+		if (!targetFile.exists() && !commands.isEmpty()) {
+			if (BakeCLI.isDebug()) {
+				System.out.println("Debug : Target file " + name + " does not exist and has commands, needs update");
+			}
+			return true;
+		}
+
+		// Vérifier d'abord toutes les dépendances avant d'exécuter quoi que ce soit
+		for (String dependency : dependencies) {
+			// Skip dependencies with tilde in path
+			if (dependency.startsWith("~")) {
+				continue;
+			}
+			
+			// Ignorer les options de compilation qui pourraient avoir un ':' dedans
+			if (dependency.startsWith("-") || dependency.contains(":")) {
+				continue;
+			}
+			
+			File depFile = new File(dependency);
+			boolean hasRule = BakeEngine.hasRule(dependency);
+			
+			if (!depFile.exists() && !dependency.isEmpty() && !hasRule) {
+				// Vérifier si on est en situation de dépendance circulaire déjà traitée
+				boolean isPartOfCircularDependency = false;
+				
+				// Vérifier si cette dépendance est impliquée dans une relation circulaire
+				for (Rule rule : getAllRules()) {
+					if (rule.getName().equals(dependency) && rule.getDependencies().contains(name)) {
+						if (BakeCLI.isDebug()) {
+							System.out.println("Debug: Found circular dependency between " + name + " and " + dependency);
+						}
+						isPartOfCircularDependency = true;
+						break;
+					}
+				}
+				
+				if (isPartOfCircularDependency) {
+					if (BakeCLI.isDebug()) {
+						System.out.println("Debug: Ignoring circular dependency: " + dependency);
+					}
+					continue;
+				}
+				
+				System.out.println("bake: *** No rule to make target `" + dependency + "', needed by `" + name + "'.  Stop.");
+				System.exit(2);
+			}
+		}
+
+		// 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) {
+				// Skip dependencies with tilde in path or compiler options
+				if (dependency.startsWith("~") || dependency.startsWith("-") || dependency.contains(":")) {
+					continue;
+				}
+				
+				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
+		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()) {
+			System.out.println("Debug : Target file '" + name + "' last modified at " + TimestampManager.formatTimestamp(targetTimestamp));
+		}
+
+		long currentTime = System.currentTimeMillis();
+		
+		for (String dependency : dependencies) {
+			// Skip dependencies with tilde in path or compiler options
+			if (dependency.startsWith("~") || dependency.startsWith("-") || dependency.contains(":")) {
+				continue;
+			}
+			
+			File depFile = new File(dependency);
+			if (!depFile.exists()) {
+				continue;
+			}
+			
+			long depTimestamp = TimestampManager.getTimestamp(depFile);
+
+			// Vérifier si le timestamp de la dépendance est dans le futur
+			if (depTimestamp > currentTime) {
+				// Avertissement similaire à make
+				System.out.println("bake: Warning: File '" + dependency + "' has modification time " 
+								+ ((depTimestamp - currentTime) / 1000) + " s in the future");
+				if (BakeCLI.isDebug()) {
+					System.out.println("Debug : Dependency " + dependency + " has a timestamp in the future, needs update");
+				}
+				return true;
+			}
+
+			if (BakeCLI.isDebug()) {
+				System.out.println("Debug : Dependency '" + dependency + "' last modified at " + TimestampManager.formatTimestamp(depTimestamp));
+			}
+
+			// 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 (depTimestamp > targetTimestamp) {
+				if (BakeCLI.isDebug()) {
+					System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update");
+				}
+				return true;
+			}
+		}
+		
+		return false;
+	}
+
+	/**
+	 * Permet de récupérer la liste de toutes les règles
+	 * @return La liste de toutes les règles
+	 */
+	private List<Rule> getAllRules() {
+		List<Rule> allRules = new ArrayList<>();
+		for (String ruleName : BakeEngine.getAllRuleNames()) {
+			Rule rule = BakeEngine.getRule(ruleName);
+			if (rule != null) {
+				allRules.add(rule);
+			}
+		}
+		return allRules;
+	}
 }
\ No newline at end of file