From 3040970b846901da0b7cb5c8274fdfffe18b9ddc Mon Sep 17 00:00:00 2001 From: Modest Machnicki Date: Fri, 24 Oct 2025 09:47:12 +0200 Subject: [PATCH] feat: blue-preprocessor --- build.gradle | 18 ++ .../FileSystemDependencyGraphBuilder.java | 40 ++++- .../contract/packager/model/BluePackage.java | 15 +- .../packager/utils/BluePreprocessor.java | 170 ++++++++++++++++++ 4 files changed, 237 insertions(+), 6 deletions(-) create mode 100644 src/main/java/blue/contract/packager/utils/BluePreprocessor.java diff --git a/build.gradle b/build.gradle index da226bd..e3dac39 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,24 @@ task exportBlueFiles { } } +jar { + manifest { + attributes( + 'Main-Class': 'blue.contract.packager.utils.BluePreprocessor' + ) + } + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + zip64 = true + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' +} + test { useJUnitPlatform() reports { diff --git a/src/main/java/blue/contract/packager/graphbuilder/FileSystemDependencyGraphBuilder.java b/src/main/java/blue/contract/packager/graphbuilder/FileSystemDependencyGraphBuilder.java index dccb095..69470a6 100644 --- a/src/main/java/blue/contract/packager/graphbuilder/FileSystemDependencyGraphBuilder.java +++ b/src/main/java/blue/contract/packager/graphbuilder/FileSystemDependencyGraphBuilder.java @@ -1,5 +1,6 @@ package blue.contract.packager.graphbuilder; +import blue.contract.packager.BluePackageExporter; import blue.contract.packager.model.DependencyGraph; import blue.language.model.Node; @@ -7,6 +8,8 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; import static blue.contract.packager.BluePackageExporter.EXTENDS_FILE_NAME; import static blue.language.utils.UncheckedObjectMapper.YAML_MAPPER; @@ -14,8 +17,15 @@ public class FileSystemDependencyGraphBuilder implements DependencyGraphBuilder { private final Path rootPath; - public FileSystemDependencyGraphBuilder(Path rootPath) { + private final Set ignorePatterns; + + public FileSystemDependencyGraphBuilder(Path rootPath, Set ignorePatterns) { this.rootPath = rootPath; + this.ignorePatterns = ignorePatterns; + } + + public FileSystemDependencyGraphBuilder(Path rootPath) { + this(rootPath, new HashSet<>()); } @Override @@ -29,11 +39,19 @@ public DependencyGraph buildDependencyGraph(String rootDir) throws IOException { try (DirectoryStream stream = Files.newDirectoryStream(fullPath)) { for (Path path : stream) { - if (Files.isDirectory(path)) { + if (Files.isDirectory(path) && !shouldIgnore(path)) { String dirName = path.getFileName().toString(); - String dependency = readDependency(path.resolve(EXTENDS_FILE_NAME)); - graph.addDirectory(dirName, dependency); - processFiles(path, dirName, graph); + + // Check if this directory contains any .blue files + if (containsBlueFiles(path)) { + Path extendsFile = path.resolve(EXTENDS_FILE_NAME); + String dependency = Files.exists(extendsFile) ? + readDependency(extendsFile) : + BluePackageExporter.ROOT_DEPENDENCY; + + graph.addDirectory(dirName, dependency); + processFiles(path, dirName, graph); + } } } } @@ -41,6 +59,18 @@ public DependencyGraph buildDependencyGraph(String rootDir) throws IOException { return graph; } + private boolean shouldIgnore(Path path) { + String pathName = path.getFileName().toString(); + return ignorePatterns.stream().anyMatch(pattern -> + pathName.matches(pattern.replace("*", ".*").replace("?", ".?"))); + } + + private boolean containsBlueFiles(Path directory) throws IOException { + try (DirectoryStream stream = Files.newDirectoryStream(directory, "*.blue")) { + return stream.iterator().hasNext(); + } + } + private String readDependency(Path path) throws IOException { if (!Files.exists(path)) { throw new IOException("Dependency file not found: " + path); diff --git a/src/main/java/blue/contract/packager/model/BluePackage.java b/src/main/java/blue/contract/packager/model/BluePackage.java index ba4bda7..9abbcfd 100644 --- a/src/main/java/blue/contract/packager/model/BluePackage.java +++ b/src/main/java/blue/contract/packager/model/BluePackage.java @@ -28,7 +28,20 @@ public Node getPackageContent() { } public Map getMappings() { - return new HashMap<>(mappings); + // Extract mappings from packageContent if they're not already in the mappings map + if (mappings.isEmpty() && packageContent != null) { + Node mappingsNode = packageContent.getItems() + .get(1) // Second item contains mappings + .getProperties() + .get("mappings"); + + if (mappingsNode != null && mappingsNode.getProperties() != null) { + mappingsNode.getProperties().forEach((key, valueNode) -> { + mappings.put(key, valueNode.getValue().toString()); + }); + } + } + return mappings; } public Map getPreprocessedNodes() { diff --git a/src/main/java/blue/contract/packager/utils/BluePreprocessor.java b/src/main/java/blue/contract/packager/utils/BluePreprocessor.java new file mode 100644 index 0000000..3cc31e1 --- /dev/null +++ b/src/main/java/blue/contract/packager/utils/BluePreprocessor.java @@ -0,0 +1,170 @@ +package blue.contract.packager.utils; + +import blue.contract.packager.BluePackageExporter; +import blue.contract.packager.graphbuilder.FileSystemDependencyGraphBuilder; +import blue.contract.packager.model.BluePackage; +import blue.language.model.Node; +import blue.language.utils.BlueIdCalculator; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Arrays; + +import static blue.language.utils.UncheckedObjectMapper.YAML_MAPPER; + +public class BluePreprocessor { + public static void main(String[] args) { + if (args.length < 2 || args[0].equals("-h") || args[0].equals("--help")) { + printUsage(); + System.exit(args.length < 2 ? 1 : 0); + } + + try { + String inputDir = args[0]; + String outputDir = args[1]; + Set ignorePatterns = new HashSet<>(); + boolean verbose = false; + + // Parse additional arguments + for (int i = 2; i < args.length; i++) { + if (args[i].equals("--ignore") && i + 1 < args.length) { + String[] patterns = args[i + 1].split(","); + ignorePatterns.addAll(Arrays.asList(patterns)); + i++; // Skip the next argument as we've already processed it + } else if (args[i].equals("--verbose")) { + verbose = true; + } + } + + // Add default ignore patterns + ignorePatterns.addAll(Arrays.asList( + ".git", + ".github", + "node_modules", + "build", + ".gradle", + "blue-preprocessed" + )); + + if (verbose) { + System.out.println("Input directory: " + inputDir); + System.out.println("Output directory: " + outputDir); + System.out.println("Ignored patterns: " + String.join(", ", ignorePatterns)); + } + + Path inputPath = Paths.get(inputDir); + Path outputPath = Paths.get(outputDir); + + if (!Files.exists(inputPath)) { + System.err.println("Input directory does not exist: " + inputPath); + System.exit(1); + } + + // Create output directory if it doesn't exist + Files.createDirectories(outputPath); + + // Create builder with ignore patterns + FileSystemDependencyGraphBuilder builder = new FileSystemDependencyGraphBuilder(inputPath, ignorePatterns); + List packages = BluePackageExporter.exportPackages("", builder); + + writePreprocessedFiles(packages, outputPath); + + System.out.println("Preprocessing completed successfully."); + System.out.println("Preprocessed files written to: " + outputPath.toAbsolutePath()); + + } catch (Exception e) { + System.err.println("Error during preprocessing: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } + + private static void printUsage() { + System.out.println("Usage: blue-preprocessor [options]"); + System.out.println("Options:"); + System.out.println(" --ignore Comma-separated list of directory patterns to ignore"); + System.out.println(" --verbose Print detailed processing information"); + System.out.println(" --help Show this help message"); + System.out.println("\nDefault ignored patterns: .git, .github, node_modules, build, .gradle"); + } + + private static void writePreprocessedFiles(List packages, Path outputPath) throws Exception { + System.out.println("Writing preprocessed files..."); + + // Write package-specific files + for (BluePackage pkg : packages) { + String pkgName = pkg.getDirectoryName(); + System.out.println("Processing package: " + pkgName); + + Path packageDir = outputPath.resolve(pkgName); + Files.createDirectories(packageDir); + + // Write preprocessed nodes + for (Map.Entry entry : pkg.getPreprocessedNodes().entrySet()) { + String fileName = entry.getKey() + ".blue"; + Path filePath = packageDir.resolve(fileName); + String yaml = YAML_MAPPER.writeValueAsString(entry.getValue()); + Files.writeString(filePath, yaml); + //System.out.println(" - Wrote: " + fileName); + } + + // Write package.blue + Path packageBluePath = packageDir.resolve("package.blue"); + String packageBlueYaml = YAML_MAPPER.writeValueAsString(pkg.getPackageContent()); + Files.writeString(packageBluePath, packageBlueYaml); + //System.out.println(" - Wrote: package.blue"); + + // Extract and write package-specific blue-ids.yaml + Map packageMappings = extractMappingsFromPackage(pkg); + if (!packageMappings.isEmpty()) { + Path packageBlueIdsPath = packageDir.resolve("blue-ids.yaml"); + String blueIdsYaml = YAML_MAPPER.writeValueAsString(packageMappings); + Files.writeString(packageBlueIdsPath, blueIdsYaml); + //System.out.println(" - Wrote: blue-ids.yaml with " + packageMappings.size() + " mappings"); + } + } + + // Write root blue-ids.yaml with package blueIds + Map packageBlueIds = new HashMap<>(); + for (BluePackage pkg : packages) { + String packageBlueId = extractPackageBlueId(pkg); + if (packageBlueId != null) { + packageBlueIds.put(pkg.getDirectoryName(), packageBlueId); + } + } + + Path rootBlueIdsPath = outputPath.resolve("blue-ids.yaml"); + String rootBlueIdsYaml = YAML_MAPPER.writeValueAsString(packageBlueIds); + Files.writeString(rootBlueIdsPath, rootBlueIdsYaml); + System.out.println("Wrote root blue-ids.yaml with " + packageBlueIds.size() + " package IDs"); + } + + private static String extractPackageBlueId(BluePackage pkg) { + Node packageContent = pkg.getPackageContent(); + return BlueIdCalculator.calculateBlueId(packageContent); + } + + private static Map extractMappingsFromPackage(BluePackage pkg) { + Node packageContent = pkg.getPackageContent(); + if (packageContent != null && packageContent.getItems() != null && packageContent.getItems().size() > 1) { + Node mappingsContainer = packageContent.getItems().get(1); + if (mappingsContainer.getProperties() != null) { + Node mappingsNode = mappingsContainer.getProperties().get("mappings"); + if (mappingsNode != null && mappingsNode.getProperties() != null) { + Map mappings = new HashMap<>(); + mappingsNode.getProperties().forEach((key, valueNode) -> { + mappings.put(key, valueNode.getValue().toString()); + }); + return mappings; + } + } + } + return new HashMap<>(); + } +} \ No newline at end of file