Ajout de la méthode getRule dans BakeEngine et amélioration de la gestion des dépendances dans la classe Rule
This commit is contained in:
parent
2e51ca7491
commit
79f285d020
src/fr/monlouyan/bakefile
@ -17,9 +17,12 @@ public class BakeEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasRule(String target) {
|
public static boolean hasRule(String target) {
|
||||||
// Vérifie si une règle existe pour créer cette cible
|
|
||||||
return ruleMap.containsKey(target);
|
return ruleMap.containsKey(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Rule getRule(String target) {
|
||||||
|
return ruleMap.get(target);
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
List<Rule> rules = parser.parse();
|
List<Rule> rules = parser.parse();
|
||||||
@ -35,4 +38,4 @@ public class BakeEngine {
|
|||||||
executor.execute(rule);
|
executor.execute(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,6 +32,12 @@ public class BakefileParser {
|
|||||||
*/
|
*/
|
||||||
private static final Pattern VARIABLE_PATTERN = Pattern.compile("^(\\w+)\\s*=\\s*([^#]*?)\\s*(?:#.*)?$");
|
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.
|
* Première cible trouvée dans le fichier Bakefile.
|
||||||
*/
|
*/
|
||||||
@ -42,13 +48,12 @@ public class BakefileParser {
|
|||||||
*/
|
*/
|
||||||
private Map<String, String> variables = new HashMap<>();
|
private Map<String, String> variables = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public BakefileParser(String filename) {
|
public BakefileParser(String filename) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
firstTarget = null;
|
firstTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> splitDependencies(String depStr) {
|
private List<String> splitDependencies(String depStr) {
|
||||||
if (depStr == null || depStr.trim().isEmpty()) {
|
if (depStr == null || depStr.trim().isEmpty()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -63,7 +68,6 @@ public class BakefileParser {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<Rule> parse() {
|
public List<Rule> parse() {
|
||||||
List<Rule> rules = new ArrayList<>();
|
List<Rule> rules = new ArrayList<>();
|
||||||
Set<String> phonyTargets = new HashSet<>();
|
Set<String> phonyTargets = new HashSet<>();
|
||||||
@ -86,6 +90,7 @@ public class BakefileParser {
|
|||||||
Matcher varMatcher = VARIABLE_PATTERN.matcher(line);
|
Matcher varMatcher = VARIABLE_PATTERN.matcher(line);
|
||||||
Matcher targetMatcher = TARGET_PATTERN.matcher(line);
|
Matcher targetMatcher = TARGET_PATTERN.matcher(line);
|
||||||
Matcher commandMatcher = COMMAND_PATTERN.matcher(line);
|
Matcher commandMatcher = COMMAND_PATTERN.matcher(line);
|
||||||
|
Matcher phonyMatcher = PHONY_PATTERN.matcher(line);
|
||||||
|
|
||||||
if (line.trim().isEmpty()) {
|
if (line.trim().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
@ -96,32 +101,35 @@ public class BakefileParser {
|
|||||||
System.exit(1);
|
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()) {
|
if (varMatcher.matches()) {
|
||||||
// Stocke la variable en enlevant les espaces en début et fin
|
|
||||||
variables.put(varMatcher.group(1), varMatcher.group(2).trim());
|
variables.put(varMatcher.group(1), varMatcher.group(2).trim());
|
||||||
} else if (targetMatcher.matches()) {
|
} else if (targetMatcher.matches()) {
|
||||||
if (currentTarget != null) {
|
if (currentTarget != null) {
|
||||||
|
String resolvedTarget = replaceVariables(currentTarget.trim());
|
||||||
rules.add(new Rule(
|
rules.add(new Rule(
|
||||||
replaceVariables(currentTarget.trim()),
|
resolvedTarget,
|
||||||
splitDependencies(dependencies.stream()
|
splitDependencies(dependencies.stream()
|
||||||
.collect(Collectors.joining(" "))),
|
.collect(Collectors.joining(" "))),
|
||||||
replaceVariablesInList(commands),
|
replaceVariablesInList(commands),
|
||||||
phonyTargets.contains(currentTarget.trim())
|
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);
|
currentTarget = targetMatcher.group(1);
|
||||||
String depStr = targetMatcher.group(2);
|
String depStr = targetMatcher.group(2);
|
||||||
dependencies = splitDependencies(depStr);
|
dependencies = splitDependencies(depStr);
|
||||||
|
|
||||||
if (firstTarget == null) {
|
|
||||||
firstTarget = replaceVariables(currentTarget.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentTarget.equals("clean")) {
|
|
||||||
phonyTargets.add(currentTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
commands = new ArrayList<>();
|
commands = new ArrayList<>();
|
||||||
} else if (commandMatcher.matches()) {
|
} else if (commandMatcher.matches()) {
|
||||||
commands.add(commandMatcher.group(1));
|
commands.add(commandMatcher.group(1));
|
||||||
@ -129,12 +137,18 @@ public class BakefileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentTarget != null) {
|
if (currentTarget != null) {
|
||||||
|
String resolvedTarget = replaceVariables(currentTarget.trim());
|
||||||
rules.add(new Rule(
|
rules.add(new Rule(
|
||||||
replaceVariables(currentTarget.trim()),
|
resolvedTarget,
|
||||||
replaceVariablesInList(dependencies),
|
replaceVariablesInList(dependencies),
|
||||||
replaceVariablesInList(commands),
|
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) {
|
} catch (IOException e) {
|
||||||
@ -143,7 +157,7 @@ public class BakefileParser {
|
|||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String replaceVariables(String input) {
|
private String replaceVariables(String input) {
|
||||||
if (input == null) return null;
|
if (input == null) return null;
|
||||||
String result = input;
|
String result = input;
|
||||||
boolean replaced;
|
boolean replaced;
|
||||||
@ -161,7 +175,7 @@ public class BakefileParser {
|
|||||||
return result.trim();
|
return result.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> replaceVariablesInList(List<String> items) {
|
private List<String> replaceVariablesInList(List<String> items) {
|
||||||
List<String> resolved = new ArrayList<>();
|
List<String> resolved = new ArrayList<>();
|
||||||
for (String item : items) {
|
for (String item : items) {
|
||||||
resolved.add(replaceVariables(item));
|
resolved.add(replaceVariables(item));
|
||||||
@ -169,10 +183,11 @@ public class BakefileParser {
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permet de récupérer la première cible trouvée dans le fichier Bakefile.
|
* Permet de récupérer la première cible trouvée dans le fichier Bakefile.
|
||||||
* @return La première cible trouvée
|
* @return La première cible trouvée
|
||||||
*/
|
*/
|
||||||
public static String getFirstTarget() { return firstTarget; }
|
public static String getFirstTarget() {
|
||||||
}
|
return firstTarget;
|
||||||
|
}
|
||||||
|
}
|
@ -3,42 +3,12 @@ package fr.monlouyan.bakefile;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
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 {
|
public class Rule {
|
||||||
/**
|
|
||||||
* Nom de la règle
|
|
||||||
*/
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/**
|
|
||||||
* Liste des dépendances de la règle
|
|
||||||
*/
|
|
||||||
private List<String> dependencies;
|
private List<String> dependencies;
|
||||||
|
|
||||||
/**
|
|
||||||
* Liste des commandes de la règle (actions à exécuter)
|
|
||||||
*/
|
|
||||||
private List<String> commands;
|
private List<String> commands;
|
||||||
|
|
||||||
/**
|
|
||||||
* Indique si la règle est une règle phony
|
|
||||||
*/
|
|
||||||
private boolean isPhony;
|
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) {
|
public Rule(String name, List<String> dependencies, List<String> commands, boolean isPhony) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.dependencies = dependencies;
|
this.dependencies = dependencies;
|
||||||
@ -46,60 +16,50 @@ public class Rule {
|
|||||||
this.isPhony = isPhony;
|
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; }
|
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; }
|
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; }
|
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; }
|
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(); }
|
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() {
|
public boolean needsUpdate() {
|
||||||
if (BakeCLI.isDebug()){
|
if (BakeCLI.isDebug()){
|
||||||
System.out.println("Debug : Checking if rule " + name + " needs update");
|
System.out.println("Debug : Checking if rule " + name + " needs update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Les règles phony sont toujours mises à jour
|
||||||
if (isPhony) {
|
if (isPhony) {
|
||||||
if (BakeCLI.isDebug()) {
|
if (BakeCLI.isDebug()) {
|
||||||
System.out.println("Debug : Rule " + name + " is phony, always needs update");
|
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()){
|
if (BakeCLI.isDebug()){
|
||||||
System.out.println("Debug : Checking if target file " + name + " exist and is up to date");
|
System.out.println("Debug : Checking if target file " + name + " exist and is up to date");
|
||||||
}
|
}
|
||||||
|
|
||||||
long targetTimestamp = targetFile.exists() ? TimestampManager.getTimestamp(targetFile) : 0;
|
long targetTimestamp = targetFile.exists() ? TimestampManager.getTimestamp(targetFile) : 0;
|
||||||
|
|
||||||
if (BakeCLI.isDebug()) {
|
if (BakeCLI.isDebug()) {
|
||||||
@ -114,6 +74,7 @@ public class Rule {
|
|||||||
System.out.println("Debug : Dependency '" + dependency + "' last modified at " + TimestampManager.formatTimestamp(depTimestamp));
|
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);
|
boolean hasRule = BakeEngine.hasRule(dependency);
|
||||||
|
|
||||||
if (!depFile.exists() && !dependency.isEmpty() && !hasRule) {
|
if (!depFile.exists() && !dependency.isEmpty() && !hasRule) {
|
||||||
@ -121,6 +82,16 @@ public class Rule {
|
|||||||
System.exit(1);
|
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 (depFile.exists() && TimestampManager.getTimestamp(depFile) > targetTimestamp) {
|
||||||
if (BakeCLI.isDebug()) {
|
if (BakeCLI.isDebug()) {
|
||||||
System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update");
|
System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update");
|
||||||
@ -130,4 +101,4 @@ public class Rule {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user