Améliorations du code + Du mode debug
This commit is contained in:
parent
238a02796b
commit
0af4eb8f1b
bakefile.jar
src/fr/monlouyan/bakefile
BakeCLI.javaBakeEngine.javaBakefileParser.javaCommandExecutor.javaDependencyResolver.javaRule.javaTarget.javaTimestampManager.java
tests
BIN
bakefile.jar
Normal file
BIN
bakefile.jar
Normal file
Binary file not shown.
@ -15,7 +15,7 @@ public class BakeCLI {
|
||||
/*
|
||||
* Mode debug activé ou non
|
||||
*/
|
||||
private boolean debug;
|
||||
private static boolean debug;
|
||||
|
||||
/*
|
||||
* Liste des arguments passés en ligne de commande
|
||||
@ -30,7 +30,7 @@ public class BakeCLI {
|
||||
* @see Main
|
||||
*/
|
||||
public BakeCLI(String[] args){
|
||||
this.debug = false;
|
||||
debug = false;
|
||||
this.targets = new ArrayList<>();
|
||||
parseArgs(args);
|
||||
}
|
||||
@ -54,7 +54,7 @@ public class BakeCLI {
|
||||
* Permet de savoir si le mode debug est activé ou non.
|
||||
* @return true si le mode debug est activé, false sinon
|
||||
*/
|
||||
public boolean isDebug(){ return debug; }
|
||||
public static boolean isDebug(){ return debug; }
|
||||
|
||||
/**
|
||||
* Permet de récupérer les arguments autres que "-d" passés en ligne de commande
|
||||
|
@ -2,7 +2,6 @@ package fr.monlouyan.bakefile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class BakeEngine {
|
||||
private BakeCLI cli;
|
||||
private BakefileParser parser;
|
||||
@ -12,15 +11,16 @@ public class BakeEngine {
|
||||
public BakeEngine(BakeCLI cli) {
|
||||
this.cli = cli;
|
||||
this.parser = new BakefileParser("Bakefile");
|
||||
this.resolver = new DependencyResolver(cli.isDebug());
|
||||
this.executor = new CommandExecutor(cli.isDebug());
|
||||
this.resolver = new DependencyResolver(BakeCLI.isDebug());
|
||||
this.executor = new CommandExecutor(BakeCLI.isDebug());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
List<Target> targets = parser.parse();
|
||||
List<Target> targetsToBuild = resolver.resolve(targets, cli.getTargets());
|
||||
for (Target target : targetsToBuild) {
|
||||
executor.execute(target);
|
||||
List<Rule> rules = parser.parse();
|
||||
List<Rule> rulesToBuild = resolver.resolve(rules, cli.getTargets());
|
||||
|
||||
for (Rule rule : rulesToBuild) {
|
||||
executor.execute(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ public class BakefileParser {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public List<Target> parse() {
|
||||
List<Target> targets = new ArrayList<>();
|
||||
public List<Rule> parse() {
|
||||
List<Rule> rules = new ArrayList<>();
|
||||
Set<String> phonyTargets = new HashSet<>();
|
||||
|
||||
if (!Files.exists(Paths.get(filename))) {
|
||||
System.out.println("*** No targets specified and no makefile found. Stop.");
|
||||
System.exit(1);
|
||||
@ -44,30 +46,29 @@ public class BakefileParser {
|
||||
Matcher commandMatcher = COMMAND_PATTERN.matcher(line);
|
||||
|
||||
if (targetMatcher.matches()) {
|
||||
// Sauvegarde de la précédente target si elle existe
|
||||
// Sauvegarde de la règle précédente si elle existe
|
||||
if (currentTarget != null) {
|
||||
targets.add(new Target(currentTarget, dependencies, String.join(" && ", commands)));
|
||||
rules.add(new Rule(currentTarget, dependencies, commands, phonyTargets.contains(currentTarget)));
|
||||
}
|
||||
|
||||
// Nouvelle target détectée
|
||||
// Nouvelle cible détectée
|
||||
currentTarget = targetMatcher.group(1);
|
||||
dependencies = new ArrayList<>(Arrays.asList(targetMatcher.group(2).trim().split("\\s+")));
|
||||
commands = new ArrayList<>();
|
||||
|
||||
} else if (commandMatcher.matches()) {
|
||||
// Ligne de commande associée à la dernière target trouvée
|
||||
// Ligne de commande associée à la dernière cible trouvée
|
||||
commands.add(commandMatcher.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
// Ajout de la dernière target après la boucle
|
||||
// Ajout de la dernière règle après la boucle
|
||||
if (currentTarget != null) {
|
||||
targets.add(new Target(currentTarget, dependencies, String.join(" && ", commands)));
|
||||
rules.add(new Rule(currentTarget, dependencies, commands, phonyTargets.contains(currentTarget)));
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return targets;
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
|
@ -9,20 +9,31 @@ public class CommandExecutor {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public void execute(Target target) {
|
||||
if (!target.needsUpdate()){
|
||||
System.out.println("bake: '" + target.getName() + "' is up to date.");
|
||||
public void execute(Rule rule) {
|
||||
if (rule.getCommands().isEmpty()) {
|
||||
System.out.println("bake: Nothing to be done for '" + rule.getName() + "'.");
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
if (!rule.needsUpdate()){
|
||||
System.out.println("bake: '" + rule.getName() + "' is up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println(target.getCommand());
|
||||
ProcessBuilder pb = new ProcessBuilder("sh", "-c", target.getCommand());
|
||||
Process process = pb.start();
|
||||
int exitCode = process.waitFor();
|
||||
if (debug) System.out.println("Executed: " + target.getCommand() + " with exit code " + exitCode);
|
||||
if (exitCode != 0) System.err.println("Error executing " + target.getName());
|
||||
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;
|
||||
}
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,16 +10,17 @@ public class DependencyResolver {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public List<Target> resolve(List<Target> allTargets, List<String> requestedTargets) {
|
||||
List<Target> targetsToBuild = new ArrayList<>();
|
||||
for (Target target : allTargets) {
|
||||
if (requestedTargets.isEmpty() || requestedTargets.contains(target.getName())) {
|
||||
public List<Rule> resolve(List<Rule> allRules, List<String> requestedRules) {
|
||||
List<Rule> rulesToBuild = new ArrayList<>();
|
||||
|
||||
for (Rule rule : allRules) {
|
||||
if (requestedRules.isEmpty() || requestedRules.contains(rule.getName()) || rule.isPhony()) {
|
||||
if (debug){
|
||||
System.out.println("Target " + target.getName() + " is requested");
|
||||
System.out.println("Rule " + rule.getName() + " is requested");
|
||||
}
|
||||
targetsToBuild.add(target);
|
||||
rulesToBuild.add(rule);
|
||||
}
|
||||
}
|
||||
return targetsToBuild;
|
||||
return rulesToBuild;
|
||||
}
|
||||
}
|
116
src/fr/monlouyan/bakefile/Rule.java
Normal file
116
src/fr/monlouyan/bakefile/Rule.java
Normal file
@ -0,0 +1,116 @@
|
||||
package fr.monlouyan.bakefile;
|
||||
|
||||
import java.io.File;
|
||||
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 {
|
||||
/**
|
||||
* Nom de la règle
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Liste des dépendances de la règle
|
||||
*/
|
||||
private List<String> dependencies;
|
||||
|
||||
/**
|
||||
* Liste des commandes de la règle (actions à exécuter)
|
||||
*/
|
||||
private List<String> commands;
|
||||
|
||||
/**
|
||||
* Indique si la règle est une règle phony
|
||||
*/
|
||||
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) {
|
||||
this.name = name;
|
||||
this.dependencies = dependencies;
|
||||
this.commands = commands;
|
||||
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; }
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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(); }
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
if (BakeCLI.isDebug()){
|
||||
System.out.println("Debug : Checking if rule " + name + " needs update");
|
||||
}
|
||||
|
||||
if (isPhony) {
|
||||
if (BakeCLI.isDebug()) {
|
||||
System.out.println("Debug : Rule " + name + " is phony, always needs update");
|
||||
}
|
||||
return true; // Les règles phony sont toujours mises à jour
|
||||
}
|
||||
|
||||
File targetFile = new File(name);
|
||||
|
||||
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;
|
||||
|
||||
for (String dependency : dependencies) {
|
||||
File depFile = new File(dependency);
|
||||
if (depFile.exists() && TimestampManager.getTimestamp(depFile) > targetTimestamp) {
|
||||
if (BakeCLI.isDebug()) {
|
||||
System.out.println("Debug : Dependency " + dependency + " is newer than target file " + name + ", needs update");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package fr.monlouyan.bakefile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class Target {
|
||||
private String name;
|
||||
private List<String> dependencies;
|
||||
private String command;
|
||||
|
||||
public Target(String name, List<String> dependencies, String command) {
|
||||
this.name = name;
|
||||
this.dependencies = dependencies;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public boolean needsUpdate() {
|
||||
File targetFile = new File(name);
|
||||
if (!targetFile.exists()) return true;
|
||||
long lastModified = targetFile.lastModified();
|
||||
for (String dep : dependencies) {
|
||||
File depFile = new File(dep);
|
||||
if (depFile.exists() && depFile.lastModified() > lastModified) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getCommand() { return command; }
|
||||
public String getName() { return name; }
|
||||
}
|
39
src/fr/monlouyan/bakefile/TimestampManager.java
Normal file
39
src/fr/monlouyan/bakefile/TimestampManager.java
Normal file
@ -0,0 +1,39 @@
|
||||
package fr.monlouyan.bakefile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Classe utilitaire pour la gestion des timestamps des fichiers.
|
||||
* Dernière modification : 04/02/2025
|
||||
*
|
||||
* @author Moncef STITI, Yanis HAMOUDI
|
||||
* @version 1.0
|
||||
* @date 04/02/2025
|
||||
*/
|
||||
public class TimestampManager {
|
||||
|
||||
/**
|
||||
* Récupère le timestamp d'un fichier.
|
||||
* @param filePath Le chemin du fichier.
|
||||
* @return Le timestamp du fichier, ou 0 si le fichier n'existe pas.
|
||||
*/
|
||||
public static long getTimestamp(File file) {
|
||||
if (file.exists()) {
|
||||
return file.lastModified(); // Récupère le timestamp du fichier
|
||||
}
|
||||
return 0; // Le fichier n'existe pas
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare deux fichiers en fonction de leurs timestamps de modification.
|
||||
*
|
||||
* @param file1 Premier fichier
|
||||
* @param file2 Deuxième fichier
|
||||
* @return 1 si file1 est plus récent, -1 si file2 est plus récent, 0 s'ils ont le même timestamp
|
||||
*/
|
||||
public static int compareTimestamps(File file1, File file2) {
|
||||
long time1 = getTimestamp(file1);
|
||||
long time2 = getTimestamp(file2);
|
||||
return Long.compare(time1, time2);
|
||||
}
|
||||
}
|
BIN
tests/bakefile.jar
Normal file
BIN
tests/bakefile.jar
Normal file
Binary file not shown.
BIN
tests/test-01-depuis-rien/bakefile.jar
Normal file
BIN
tests/test-01-depuis-rien/bakefile.jar
Normal file
Binary file not shown.
BIN
tests/test-02-existe-deja/bakefile.jar
Normal file
BIN
tests/test-02-existe-deja/bakefile.jar
Normal file
Binary file not shown.
@ -1,14 +1,11 @@
|
||||
main: a.o b.o c.o
|
||||
gcc a.o b.o c.o -o main
|
||||
main: a b c
|
||||
gcc a b c -o main
|
||||
|
||||
a.o: a.c a.h b.h
|
||||
gcc -Wall -Werror -Wextra -c a.c -o a.o
|
||||
a: a.c a.h b.h
|
||||
gcc -Wall -Werror -Wextra -Pendatic -c a.c -o a
|
||||
|
||||
b.o: b.c b.h c.h
|
||||
gcc -Wall -Werror -Wextra -c b.c -o b.o
|
||||
b: b.c b.h c.h
|
||||
gcc -Wall -Werror -Wextra -Pendatic -c b.c -o b
|
||||
|
||||
c.o: c.c c.h a.h
|
||||
gcc -Wall -Werror -Wextra -c c.c -o c.o
|
||||
|
||||
clean:
|
||||
rm -f a.o b.o c.o main
|
||||
c: c.c c.h a.h
|
||||
gcc -Wall -Werror -Wextra -Pendatic -c c.c -o c
|
||||
|
BIN
tests/test-03-circulaire/bakefile.jar
Normal file
BIN
tests/test-03-circulaire/bakefile.jar
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user