Retour à une version plus stable
This commit is contained in:
@@ -26,10 +26,9 @@ public class BakefileParser {
|
||||
/**
|
||||
* Regex pour détecter les targets et leurs dépendances.
|
||||
* Format : "nom1 nom2 nom3 : dépendance1 dépendance2"
|
||||
* La nouvelle regex assure que la ligne ne commence pas par une tabulation
|
||||
* et vérifie que le premier caractère non-espace n'est pas un symbole de commentaire
|
||||
* La nouvelle regex gère plusieurs cibles séparées par des espaces
|
||||
*/
|
||||
private static final Pattern TARGET_PATTERN = Pattern.compile("^([^\\t:#][^:#]+?)\\s*:\\s*([^#]*?)\\s*(?:#.*)?$");
|
||||
private static final Pattern TARGET_PATTERN = Pattern.compile("^([^:#]+?)\\s*:\\s*([^#]*?)\\s*(?:#.*)?$");
|
||||
|
||||
/**
|
||||
* Regex pour détecter les lignes de commande associées à une target.
|
||||
@@ -87,71 +86,68 @@ public class BakefileParser {
|
||||
* @return La ligne combinée
|
||||
*/
|
||||
private String handleContinuationLines(List<String> lines, int startIndex) {
|
||||
StringBuilder combinedLine = new StringBuilder();
|
||||
int i = startIndex;
|
||||
|
||||
while (i < lines.size()) {
|
||||
String line = lines.get(i);
|
||||
Matcher contMatcher = CONTINUATION_PATTERN.matcher(line);
|
||||
|
||||
if (contMatcher.matches()) {
|
||||
// Ajouter la ligne sans le backslash mais conserver le contenu entier
|
||||
// Ne pas ajouter d'espace après certains opérateurs comme &&
|
||||
String content = contMatcher.group(1);
|
||||
combinedLine.append(content);
|
||||
|
||||
// Si la ligne ne se termine pas déjà par un opérateur tel que &&, ajouter un espace
|
||||
if (!content.trim().endsWith("&&") && !content.trim().endsWith("|") &&
|
||||
!content.trim().endsWith(";")) {
|
||||
combinedLine.append(" ");
|
||||
} else {
|
||||
// Si elle se termine par &&, |, ou ;, ajouter juste un espace après
|
||||
combinedLine.append(" ");
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
// Ajouter la dernière ligne et sortir
|
||||
combinedLine.append(line.trim());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return combinedLine.toString();
|
||||
}
|
||||
StringBuilder combinedLine = new StringBuilder();
|
||||
int i = startIndex;
|
||||
|
||||
while (i < lines.size()) {
|
||||
String line = lines.get(i);
|
||||
Matcher contMatcher = CONTINUATION_PATTERN.matcher(line);
|
||||
|
||||
if (contMatcher.matches()) {
|
||||
// Ajouter la ligne sans le backslash
|
||||
combinedLine.append(contMatcher.group(1).trim()).append(" ");
|
||||
i++;
|
||||
} else {
|
||||
// Ajouter la dernière ligne et sortir
|
||||
combinedLine.append(line.trim());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return combinedLine.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplacer les variables dans une chaîne.
|
||||
* Cette méthode remplace toutes les références de variables (${VAR} ou $(VAR))
|
||||
* par leur valeur. Si une variable n'est pas définie, elle est remplacée par une chaîne vide.
|
||||
*
|
||||
* @param input Chaîne à traiter
|
||||
* @return Chaîne avec les variables remplacées
|
||||
*/
|
||||
private String replaceVariables(String input) {
|
||||
if (input == null) return null;
|
||||
|
||||
String result = input;
|
||||
|
||||
// Détecter et remplacer toutes les occurrences de variables
|
||||
Matcher matcher = VARIABLE_REFERENCE.matcher(result);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
while (matcher.find()) {
|
||||
String varName = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
|
||||
// Remplacer par la valeur de la variable si elle existe, sinon par une chaîne vide
|
||||
String replacement = variables.containsKey(varName) ? variables.get(varName) : "";
|
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
result = sb.toString();
|
||||
|
||||
// Vérifier les références imbriquées de variables et continuer à remplacer si nécessaire
|
||||
if (VARIABLE_REFERENCE.matcher(result).find()) {
|
||||
result = replaceVariables(result); // Appel récursif pour gérer les variables imbriquées
|
||||
}
|
||||
|
||||
return result.trim();
|
||||
}
|
||||
private String replaceVariables(String input) {
|
||||
if (input == null) return null;
|
||||
|
||||
String result = input;
|
||||
Set<String> processedVars = new HashSet<>();
|
||||
boolean changed;
|
||||
|
||||
do {
|
||||
changed = false;
|
||||
Matcher matcher = VARIABLE_REFERENCE.matcher(result);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
while (matcher.find()) {
|
||||
String varName = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
|
||||
if (!processedVars.contains(varName) && variables.containsKey(varName)) {
|
||||
String replacement = variables.get(varName);
|
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||
changed = true;
|
||||
processedVars.add(varName);
|
||||
}
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
result = sb.toString();
|
||||
|
||||
// Si aucun changement n'a été fait dans ce passage, arrêter
|
||||
if (!changed) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Réinitialiser processedVars pour le prochain passage si nécessaire
|
||||
processedVars.clear();
|
||||
|
||||
} while (changed);
|
||||
|
||||
return result.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplacer les variables dans une liste de chaînes.
|
||||
@@ -205,10 +201,9 @@ public class BakefileParser {
|
||||
public List<Rule> parse() {
|
||||
List<Rule> rules = new ArrayList<>();
|
||||
Set<String> phonyTargets = new HashSet<>();
|
||||
List<String> allTargetNames = new ArrayList<>(); // Pour suivre l'ordre des cibles
|
||||
|
||||
if (!Files.exists(Paths.get(filename))) {
|
||||
System.out.println("*** No targets specified and no bakefile found. Stop.");
|
||||
System.out.println("*** No targets specified and no makefile found. Stop.");
|
||||
System.exit(2);
|
||||
}
|
||||
|
||||
@@ -218,18 +213,6 @@ public class BakefileParser {
|
||||
List<String> dependencies = new ArrayList<>();
|
||||
List<String> commands = new ArrayList<>();
|
||||
|
||||
// Première passe : collecter toutes les cibles PHONY
|
||||
for (String line : lines) {
|
||||
if (line.trim().isEmpty()) continue;
|
||||
|
||||
Matcher phonyMatcher = PHONY_PATTERN.matcher(line);
|
||||
if (phonyMatcher.matches()) {
|
||||
String[] phonies = phonyMatcher.group(1).trim().split("\\s+");
|
||||
Collections.addAll(phonyTargets, phonies);
|
||||
}
|
||||
}
|
||||
|
||||
// Deuxième passe : analyser les règles en tenant compte des PHONY
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
|
||||
@@ -260,7 +243,8 @@ public class BakefileParser {
|
||||
Matcher phonyMatcher = PHONY_PATTERN.matcher(line);
|
||||
|
||||
if (phonyMatcher.matches()) {
|
||||
// Déjà traité dans la première passe
|
||||
String[] phonies = phonyMatcher.group(1).trim().split("\\s+");
|
||||
Collections.addAll(phonyTargets, phonies);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -283,8 +267,9 @@ public class BakefileParser {
|
||||
phonyTargets.contains(resolvedTarget)
|
||||
));
|
||||
|
||||
// Enregistrer le nom de la cible pour suivre l'ordre
|
||||
allTargetNames.add(resolvedTarget);
|
||||
if (firstTarget == null && !phonyTargets.contains(resolvedTarget)) {
|
||||
firstTarget = resolvedTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,32 +294,15 @@ public class BakefileParser {
|
||||
phonyTargets.contains(resolvedTarget)
|
||||
));
|
||||
|
||||
// Enregistrer le nom de la cible pour suivre l'ordre
|
||||
allTargetNames.add(resolvedTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Définir la première cible (similaire à Make)
|
||||
// Make prend la première cible non-PHONY, ou la première cible si toutes sont PHONY
|
||||
if (!allTargetNames.isEmpty()) {
|
||||
// Chercher d'abord une cible non-PHONY dans l'ordre d'apparition
|
||||
for (String targetName : allTargetNames) {
|
||||
if (!phonyTargets.contains(targetName)) {
|
||||
firstTarget = targetName;
|
||||
break;
|
||||
if (firstTarget == null && !phonyTargets.contains(resolvedTarget)) {
|
||||
firstTarget = resolvedTarget;
|
||||
}
|
||||
}
|
||||
|
||||
// Si toutes les cibles sont PHONY, prendre simplement la première
|
||||
if (firstTarget == null) {
|
||||
firstTarget = allTargetNames.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user