SLING-7672 The feature model converter should not overwrite exising newer file.
diff --git a/pom.xml b/pom.xml
index 458324b..0d305ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,6 +121,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ <version>1.11.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.feature</artifactId>
<version>0.1.0</version>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
index 9896aff..6754456 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
@@ -60,8 +60,15 @@
private static final Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
- public static void convert(File file, String output, ArtifactManager am) throws IOException {
- org.apache.sling.feature.Feature feature = IOUtils.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+ public static void convert(File inputFile, File outputFile, ArtifactManager am) throws IOException {
+ if (outputFile.exists()) {
+ if (outputFile.lastModified() > inputFile.lastModified()) {
+ LOGGER.debug("Skipping the generation of {} as this file already exists and is newer.", outputFile);
+ return;
+ }
+ }
+
+ org.apache.sling.feature.Feature feature = IOUtils.getFeature(inputFile.getAbsolutePath(), am, SubstituteVariables.NONE);
Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
String featureName;
@@ -72,7 +79,8 @@
}
Feature newFeature = new Feature(featureName);
- convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
+ convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(),
+ feature.getFrameworkProperties(), feature.getExtensions(), outputFile.getAbsolutePath());
}
/*
@@ -242,7 +250,6 @@
}
}
- LOGGER.info("Writing feature...");
final String out = outputFile;
final File file = new File(out);
final Model m = new Model();
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java b/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
index 8f404e5..f53236a 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
@@ -84,12 +84,18 @@
id = bareFileName + "_" + id;
File outFile = new File(outDir, id + ".json");
- int counter = 0;
- while (outFile.exists()) {
- outFile = new File(outDir, id + "_" + (++counter) + ".json");
+ files.add(outFile);
+
+ if (outFile.exists()) {
+ if (outFile.lastModified() > file.lastModified()) {
+ LOGGER.debug("Skipping the generation of {} as this file already exists and is newer.", outFile);
+ continue;
+ } else {
+ LOGGER.debug("Deleting existing file {} as source is newer", outFile);
+ outFile.delete();
+ }
}
- files.add(outFile);
writeFeature(f, outFile.getAbsolutePath(), 0);
}
return files;
@@ -508,7 +514,6 @@
}
private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
- LOGGER.info("Writing feature...");
if ( index > 0 ) {
final int lastDot = out.lastIndexOf('.');
if ( lastDot == -1 ) {
diff --git a/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java b/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
index 7938f23..ccdcd59 100644
--- a/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
+++ b/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
@@ -50,6 +50,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -64,6 +65,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -191,6 +193,67 @@
assertFeaturesEqual(expected, actual);
}
+ @Test
+ public void testConvertToProvisioningModelOverwriteLogic() throws Exception {
+ String originalJSON = "/boot.json";
+ String expectedProvModel = "/boot.txt";
+
+ File inFile = new File(getClass().getResource(originalJSON).toURI());
+ File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
+
+ FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+ List<String> orgLines = Files.readAllLines(outFile.toPath());
+ assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1));
+
+ // Append to the output file:
+ Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND);
+
+ // Convert again and see that the output file is not modified
+ FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+
+ List<String> lines = Files.readAllLines(outFile.toPath());
+ assertEquals("modified!", lines.get(lines.size() - 1));
+
+ // Modify the modification time of the generated file to be older than the input file
+ outFile.setLastModified(inFile.lastModified() - 100000);
+ FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+
+ List<String> owLines = Files.readAllLines(outFile.toPath());
+ assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp",
+ orgLines, owLines);
+ }
+
+ @Test
+ public void testConvertToFeature() throws Exception {
+ File inFile = new File(getClass().getResource("/boot.txt").toURI());
+
+ List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+ assertEquals("The testing code expects a single output file here", 1, files.size());
+ File outFile = files.get(0);
+
+ List<String> orgLines = Files.readAllLines(outFile.toPath());
+ assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1));
+
+ // Append to the output file:
+ Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND);
+
+ // Convert again and see that the output file is not modified
+ List<File> files2 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+ assertEquals("Should return the same file list", files, files2);
+
+ List<String> lines = Files.readAllLines(outFile.toPath());
+ assertEquals("modified!", lines.get(lines.size() - 1));
+
+ // Modify the modification time of the generated file to be older than the input file
+ outFile.setLastModified(inFile.lastModified() - 100000);
+ List<File> files3 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+ assertEquals("Should return the same file list", files, files3);
+
+ List<String> owLines = Files.readAllLines(outFile.toPath());
+ assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp",
+ orgLines, owLines);
+ }
+
public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
System.out.println("*** Roundtrip converting: " + orgProvModel.getName());
List<File> allGenerateProvisioningModelFiles = new ArrayList<>();
@@ -202,7 +265,7 @@
assertFalse("File name cannot contain a colon", baseName.contains(":"));
File genFile = new File(tempDir.toFile(), baseName + ".txt");
allGenerateProvisioningModelFiles.add(genFile);
- FeatureToProvisioning.convert(f, genFile.getAbsolutePath(), artifactManager);
+ FeatureToProvisioning.convert(f, genFile, artifactManager);
}
Model expected = readProvisioningModel(orgProvModel);
@@ -227,8 +290,7 @@
File inFile = new File(getClass().getResource(originalJSON).toURI());
File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
- FeatureToProvisioning.convert(inFile, outFile.getAbsolutePath(),
- artifactManager);
+ FeatureToProvisioning.convert(inFile, outFile, artifactManager);
File expectedFile = new File(getClass().getResource(expectedProvModel).toURI());
Model expected = readProvisioningModel(expectedFile);