From 34f7e29284b7c8512365665f2531530f3213a007 Mon Sep 17 00:00:00 2001 From: Ville Oikarinen Date: Tue, 19 Nov 2024 20:32:49 +0200 Subject: [PATCH] No more unnecessary textfile rewrites: only ensure --- .../fluentjava/iwant/wsdef/Descripted.java | 8 ++-- .../iwant/wsdef/ExtendedIwantEnums.java | 3 +- .../org/fluentjava/iwant/entry/Iwant.java | 27 ++++++++++- .../api/bash/TargetImplementedInBash.java | 3 +- .../iwant/api/core/ClassNameList.java | 2 +- .../iwant/api/core/ScriptGenerated.java | 2 +- .../api/javamodules/KotlinAndJavaClasses.java | 4 +- .../iwant/api/javamodules/ScalaClasses.java | 2 +- .../api/javamodules/JavaClassesTest.java | 23 ++++++---- .../iwant/core/download/DownloadedTest.java | 2 +- .../iwant/coreservices/FileUtil.java | 4 +- .../EclipseSettingsWriter.java | 3 +- .../embedded/AsEmbeddedIwantUserTest.java | 2 +- .../org/fluentjava/iwant/entry/Iwant.java | 27 ++++++++++- .../org/fluentjava/iwant/entry2/Iwant2.java | 2 +- .../fluentjava/iwant/entry2/Iwant2Test.java | 8 ++-- .../org/fluentjava/iwant/entry3/Iwant3.java | 12 ++--- .../iwant/entry3/TargetRefreshTask.java | 3 +- .../entry3/ConcurrencyControllableTarget.java | 2 +- .../fluentjava/iwant/entry3/Iwant3Test.java | 3 +- .../iwant/entry3/TargetRefreshTaskTest.java | 6 +-- ...argetThatForgetsToDeclareAnIngredient.java | 2 +- .../iwant/entry3/WishEvaluatorTest.java | 5 +- .../iwant/plugin/jacoco/JacocoTestBase.java | 4 +- .../fluentjava/iwant/plugin/war/WarTest.java | 19 ++++---- private/iwant-docs/backlog.txt | 7 ++- .../iwant/entry/tests/DownloadingTest.java | 4 +- .../iwant/entry/tests/IwantTest.java | 46 ++++++++++++++++--- .../iwant/entry/tests/UnzippingTest.java | 3 +- 29 files changed, 167 insertions(+), 71 deletions(-) diff --git a/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/Descripted.java b/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/Descripted.java index 767383d2..4f839f46 100644 --- a/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/Descripted.java +++ b/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/Descripted.java @@ -140,8 +140,8 @@ public void path(TargetEvaluationContext ctx) throws Exception { sh.append("cat '" + htmlHeader + "' '" + htmlBodyContent + "' '" + htmlFooter + "' > '" + fullHtml + "'\n"); - File script = Iwant.newTextFile(new File(dest, name() + ".sh"), - sh.toString()); + File script = Iwant.textFileEnsuredToHaveContent( + new File(dest, name() + ".sh"), sh.toString()); script.setExecutable(true); ScriptGenerated.execute(ctx, dest, script, new String[] {}); } @@ -158,7 +158,7 @@ private File newHtmlHeaderFile(File dest) { html.append("\n"); html.append("\n"); appendNavigationLinkPanelPlaceholder(html); - return Iwant.newTextFile(new File(dest, "header.html"), + return Iwant.textFileEnsuredToHaveContent(new File(dest, "header.html"), html.toString()); } @@ -171,7 +171,7 @@ private static File newHtmlFooterFile(File dest) { StringBuilder html = new StringBuilder(); appendNavigationLinkPanelPlaceholder(html); html.append("\n"); - return Iwant.newTextFile(new File(dest, "footer.html"), + return Iwant.textFileEnsuredToHaveContent(new File(dest, "footer.html"), html.toString()); } diff --git a/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/ExtendedIwantEnums.java b/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/ExtendedIwantEnums.java index a1d5ca98..62f93558 100644 --- a/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/ExtendedIwantEnums.java +++ b/as-iwant-developer/i-have/wsdef/src/main/java/org/fluentjava/iwant/wsdef/ExtendedIwantEnums.java @@ -38,7 +38,8 @@ public void path(TargetEvaluationContext ctx) throws Exception { private static void extend(TargetEvaluationContext ctx, EnumSrc enumSrc) { String content = FileUtil.contentAsString(ctx.cached(enumSrc.source())); content = content.replaceFirst("([A-Z_]*,)", "_ILLEGAL_, $1"); - FileUtil.newTextFile(enumSrc.destination(ctx), content); + FileUtil.textFileEnsuredToHaveContent(enumSrc.destination(ctx), + content); } private class EnumSrc { diff --git a/as-iwant-developer/with/java/org/fluentjava/iwant/entry/Iwant.java b/as-iwant-developer/with/java/org/fluentjava/iwant/entry/Iwant.java index de80807d..ace6c0c7 100644 --- a/as-iwant-developer/with/java/org/fluentjava/iwant/entry/Iwant.java +++ b/as-iwant-developer/with/java/org/fluentjava/iwant/entry/Iwant.java @@ -21,6 +21,7 @@ import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.security.Permission; import java.util.ArrayList; import java.util.Arrays; @@ -345,7 +346,7 @@ private static Properties iwantFromProperties(File asSomeone) mkdirs(iwantFromParent); } if (!iwantFrom.exists()) { - newTextFile(iwantFrom, EXAMPLE_IWANT_FROM_CONTENT); + textFileEnsuredToHaveContent(iwantFrom, EXAMPLE_IWANT_FROM_CONTENT); throw new IwantException("I created " + iwantFrom + "\nPlease edit and uncomment the properties in it and rerun me."); } @@ -371,7 +372,8 @@ private static File tryToWriteTextFile(File file, String content) } } - public static File newTextFile(File file, String content) { + public static File textFileEnsuredToHaveContentAndBeTouched(File file, + String content) { try { return tryToWriteTextFile(file, content); } catch (IOException e) { @@ -379,6 +381,27 @@ public static File newTextFile(File file, String content) { } } + public static synchronized File textFileEnsuredToHaveContent(File file, + String content) { + try { + if (existsAndHasContent(file, content)) { + return file; + } + return tryToWriteTextFile(file, content); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static boolean existsAndHasContent(File file, String content) + throws IOException { + if (!file.exists()) { + return false; + } + String currentContent = Files.readString(file.toPath()); + return content.equals(currentContent); + } + private File iwantBootstrapperClasses(File iwantEssential) { File classes = network.cacheOfContentFrom( new UnmodifiableIwantBootstrapperClassesFromIwantWsRoot( diff --git a/essential/iwant-api-bash/src/main/java/org/fluentjava/iwant/api/bash/TargetImplementedInBash.java b/essential/iwant-api-bash/src/main/java/org/fluentjava/iwant/api/bash/TargetImplementedInBash.java index 1f3bde1e..f2b5ede2 100644 --- a/essential/iwant-api-bash/src/main/java/org/fluentjava/iwant/api/bash/TargetImplementedInBash.java +++ b/essential/iwant-api-bash/src/main/java/org/fluentjava/iwant/api/bash/TargetImplementedInBash.java @@ -286,7 +286,8 @@ public void path(TargetEvaluationContext ctx) throws Exception { deprefsContent.append(ctx.cached(ingr).getCanonicalPath()); deprefsContent.append("\n"); } - FileUtil.newTextFile(deprefs, deprefsContent.toString()); + FileUtil.textFileEnsuredToHaveContent(deprefs, + deprefsContent.toString()); File runDir = new File(tmpDir, "rundir"); Iwant.mkdirs(runDir); diff --git a/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ClassNameList.java b/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ClassNameList.java index 7e7a2874..a40b1cc5 100644 --- a/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ClassNameList.java +++ b/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ClassNameList.java @@ -67,7 +67,7 @@ public void path(TargetEvaluationContext ctx) throws Exception { } } - Iwant.newTextFile(ctx.cached(this), out.toString()); + Iwant.textFileEnsuredToHaveContent(ctx.cached(this), out.toString()); } private boolean isAcceptedByFilter(String className) { diff --git a/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ScriptGenerated.java b/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ScriptGenerated.java index 013f658d..b3dd11a3 100644 --- a/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ScriptGenerated.java +++ b/essential/iwant-api-core/src/main/java/org/fluentjava/iwant/api/core/ScriptGenerated.java @@ -78,7 +78,7 @@ private static ExecutionEnvironment prepareExecutionEnvironment( executable = cygwinBashExe; File wrapper = FileUtil - .newTextFile( + .textFileEnsuredToHaveContent( new File(dir, userExecutable.getName() + "-cygwinwrapper.sh"), diff --git a/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/KotlinAndJavaClasses.java b/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/KotlinAndJavaClasses.java index 480d8a0c..d3784568 100644 --- a/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/KotlinAndJavaClasses.java +++ b/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/KotlinAndJavaClasses.java @@ -56,9 +56,9 @@ protected IngredientsAndParametersDefined ingredientsAndParameters( public void path(TargetEvaluationContext ctx) throws Exception { File tmp = ctx.freshTemporaryDirectory(); File buildXml = new File(tmp, "build.xml"); - FileUtil.newTextFile(buildXml, buildXml(ctx)); + FileUtil.textFileEnsuredToHaveContent(buildXml, buildXml(ctx)); File buildSh = new File(tmp, "build.sh"); - FileUtil.newTextFile(buildSh, buildSh()); + FileUtil.textFileEnsuredToHaveContent(buildSh, buildSh()); buildSh.setExecutable(true); ScriptGenerated.execute(tmp, Arrays.asList("./build.sh")); diff --git a/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/ScalaClasses.java b/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/ScalaClasses.java index d125bbb9..8746fc7d 100644 --- a/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/ScalaClasses.java +++ b/essential/iwant-api-javamodules/src/main/java/org/fluentjava/iwant/api/javamodules/ScalaClasses.java @@ -96,7 +96,7 @@ public void path(TargetEvaluationContext ctx) throws Exception { File tmp = ctx.freshTemporaryDirectory(); File buildXml = new File(tmp, "build.xml"); - FileUtil.newTextFile(buildXml, antScript(ctx)); + FileUtil.textFileEnsuredToHaveContent(buildXml, antScript(ctx)); List antJars = Arrays.asList(ctx.cached(antJar), ctx.cached(antLauncherJar)); diff --git a/essential/iwant-api-javamodules/src/test/java/org/fluentjava/iwant/api/javamodules/JavaClassesTest.java b/essential/iwant-api-javamodules/src/test/java/org/fluentjava/iwant/api/javamodules/JavaClassesTest.java index 5d3a6d36..2cb3a991 100644 --- a/essential/iwant-api-javamodules/src/test/java/org/fluentjava/iwant/api/javamodules/JavaClassesTest.java +++ b/essential/iwant-api-javamodules/src/test/java/org/fluentjava/iwant/api/javamodules/JavaClassesTest.java @@ -180,14 +180,16 @@ public void toPathCompilesFromMultiplePackages() throws Exception { @Test public void toPathCompilesFromMultipleSrcDirs() throws Exception { File srcDir1 = new File(wsRoot, "src1"); - Iwant.newTextFile(new File(srcDir1, "Caller.java"), + Iwant.textFileEnsuredToHaveContent(new File(srcDir1, "Caller.java"), "class Caller {pak1.Callee1 callee1;pak2.Callee2 callee2;}"); File srcDir2 = new File(wsRoot, "src2"); - Iwant.newTextFile(new File(srcDir2, "pak1/Callee1.java"), + Iwant.textFileEnsuredToHaveContent( + new File(srcDir2, "pak1/Callee1.java"), "package pak1;\npublic class Callee1 {}"); File srcDir3 = new File(wsRoot, "src3"); - Iwant.newTextFile(new File(srcDir3, "pak2/Callee2.java"), + Iwant.textFileEnsuredToHaveContent( + new File(srcDir3, "pak2/Callee2.java"), "package pak2;\npublic class Callee2 {}"); Target target = JavaClasses @@ -208,7 +210,7 @@ public void classWithDepToClassesCompiles() throws Exception { File superClassFile = new File(getClass() .getResource(superClass.getSimpleName() + ".class").toURI()); File srcDir = new File(wsRoot, "src"); - Iwant.newTextFile(new File(srcDir, "Subclass.java"), + Iwant.textFileEnsuredToHaveContent(new File(srcDir, "Subclass.java"), "class Subclass extends " + superClass.getCanonicalName() + "{}"); Source src = Source.underWsroot("src"); @@ -298,7 +300,7 @@ public void usingNonDirectoryAsSourceDirectoryCausesFriendlyError() throws Exception { Iwant.mkdirs(wsRoot); File srcFile = new File(wsRoot, "Valid.java"); - Iwant.newTextFile(srcFile, "class Valid {}"); + Iwant.textFileEnsuredToHaveContent(srcFile, "class Valid {}"); Source src = Source.underWsroot("Valid.java"); Target target = JavaClasses.with().name("non-dir").srcDirs(src) .classLocations().end(); @@ -316,7 +318,8 @@ public void usingNonDirectoryAsSourceDirectoryCausesFriendlyError() public void debugInformationIsIncludedIffRequested() throws Exception { String srcDirName = "src"; Path src = Source.underWsroot(srcDirName); - Iwant.newTextFile(new File(new File(wsRoot, srcDirName), "Foo.java"), + Iwant.textFileEnsuredToHaveContent( + new File(new File(wsRoot, srcDirName), "Foo.java"), "public class Foo {\n" + " public String hello(String message) {\n" + " final String greeting = \"Moi \";\n" @@ -397,10 +400,10 @@ public void missingResourceDirectoryIsIgnoredWithWarningAndWithoutThrowing() @Test public void twoResourceDirsAndNoSrc() throws Exception { - Iwant.newTextFile(new File(wsRoot, "res1/pak1/res1.txt"), - "res1.txt content"); - Iwant.newTextFile(new File(wsRoot, "res2/pak2/res2.txt"), - "res2.txt content"); + Iwant.textFileEnsuredToHaveContent( + new File(wsRoot, "res1/pak1/res1.txt"), "res1.txt content"); + Iwant.textFileEnsuredToHaveContent( + new File(wsRoot, "res2/pak2/res2.txt"), "res2.txt content"); JavaClasses classes = JavaClasses.with().name("classes").resourceDirs( Source.underWsroot("res1"), Source.underWsroot("res2")).end(); diff --git a/essential/iwant-core-download/src/test/java/org/fluentjava/iwant/core/download/DownloadedTest.java b/essential/iwant-core-download/src/test/java/org/fluentjava/iwant/core/download/DownloadedTest.java index f1a8706b..6e31c61b 100644 --- a/essential/iwant-core-download/src/test/java/org/fluentjava/iwant/core/download/DownloadedTest.java +++ b/essential/iwant-core-download/src/test/java/org/fluentjava/iwant/core/download/DownloadedTest.java @@ -160,7 +160,7 @@ public void downloaded(URL from, File to) { throw new IllegalStateException( "You forgot to teach content of " + from); } - Iwant.newTextFile(to, content); + Iwant.textFileEnsuredToHaveContent(to, content); } public void shallDownloadContent(URL from, String content) { diff --git a/essential/iwant-coreservices/src/main/java/org/fluentjava/iwant/coreservices/FileUtil.java b/essential/iwant-coreservices/src/main/java/org/fluentjava/iwant/coreservices/FileUtil.java index 2e667b94..a0633e18 100644 --- a/essential/iwant-coreservices/src/main/java/org/fluentjava/iwant/coreservices/FileUtil.java +++ b/essential/iwant-coreservices/src/main/java/org/fluentjava/iwant/coreservices/FileUtil.java @@ -83,8 +83,8 @@ public static String contentAsString(File file) { return Iwant2.contentAsString(file); } - public static File newTextFile(File file, String content) { - return Iwant.newTextFile(file, content); + public static File textFileEnsuredToHaveContent(File file, String content) { + return Iwant.textFileEnsuredToHaveContent(file, content); } public static int copyMissingFiles(File from, File to) throws IOException { diff --git a/essential/iwant-eclipse-settings/src/main/java/org/fluentjava/iwant/eclipsesettings/EclipseSettingsWriter.java b/essential/iwant-eclipse-settings/src/main/java/org/fluentjava/iwant/eclipsesettings/EclipseSettingsWriter.java index 26525a4e..63079eeb 100644 --- a/essential/iwant-eclipse-settings/src/main/java/org/fluentjava/iwant/eclipsesettings/EclipseSettingsWriter.java +++ b/essential/iwant-eclipse-settings/src/main/java/org/fluentjava/iwant/eclipsesettings/EclipseSettingsWriter.java @@ -111,7 +111,8 @@ private void write(JavaSrcModule module) { private static void writeFile(File modDir, String fileName, String fileContent) { System.err.println("( " + fileName + ")"); - Iwant.newTextFile(new File(modDir, fileName), fileContent); + Iwant.textFileEnsuredToHaveContent(new File(modDir, fileName), + fileContent); } } diff --git a/essential/iwant-embedded/src/test/java/org/fluentjava/iwant/embedded/AsEmbeddedIwantUserTest.java b/essential/iwant-embedded/src/test/java/org/fluentjava/iwant/embedded/AsEmbeddedIwantUserTest.java index 48f74165..af290e72 100644 --- a/essential/iwant-embedded/src/test/java/org/fluentjava/iwant/embedded/AsEmbeddedIwantUserTest.java +++ b/essential/iwant-embedded/src/test/java/org/fluentjava/iwant/embedded/AsEmbeddedIwantUserTest.java @@ -63,7 +63,7 @@ protected IngredientsAndParametersDefined ingredientsAndParameters( @Override public void path(TargetEvaluationContext ctx) throws Exception { File dest = ctx.cached(this); - FileUtil.newTextFile(dest, name()); + FileUtil.textFileEnsuredToHaveContent(dest, name()); threadName.set(Thread.currentThread().getName()); } diff --git a/essential/iwant-entry/as-some-developer/with/java/org/fluentjava/iwant/entry/Iwant.java b/essential/iwant-entry/as-some-developer/with/java/org/fluentjava/iwant/entry/Iwant.java index de80807d..ace6c0c7 100644 --- a/essential/iwant-entry/as-some-developer/with/java/org/fluentjava/iwant/entry/Iwant.java +++ b/essential/iwant-entry/as-some-developer/with/java/org/fluentjava/iwant/entry/Iwant.java @@ -21,6 +21,7 @@ import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.security.Permission; import java.util.ArrayList; import java.util.Arrays; @@ -345,7 +346,7 @@ private static Properties iwantFromProperties(File asSomeone) mkdirs(iwantFromParent); } if (!iwantFrom.exists()) { - newTextFile(iwantFrom, EXAMPLE_IWANT_FROM_CONTENT); + textFileEnsuredToHaveContent(iwantFrom, EXAMPLE_IWANT_FROM_CONTENT); throw new IwantException("I created " + iwantFrom + "\nPlease edit and uncomment the properties in it and rerun me."); } @@ -371,7 +372,8 @@ private static File tryToWriteTextFile(File file, String content) } } - public static File newTextFile(File file, String content) { + public static File textFileEnsuredToHaveContentAndBeTouched(File file, + String content) { try { return tryToWriteTextFile(file, content); } catch (IOException e) { @@ -379,6 +381,27 @@ public static File newTextFile(File file, String content) { } } + public static synchronized File textFileEnsuredToHaveContent(File file, + String content) { + try { + if (existsAndHasContent(file, content)) { + return file; + } + return tryToWriteTextFile(file, content); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static boolean existsAndHasContent(File file, String content) + throws IOException { + if (!file.exists()) { + return false; + } + String currentContent = Files.readString(file.toPath()); + return content.equals(currentContent); + } + private File iwantBootstrapperClasses(File iwantEssential) { File classes = network.cacheOfContentFrom( new UnmodifiableIwantBootstrapperClassesFromIwantWsRoot( diff --git a/essential/iwant-entry2/src/main/java/org/fluentjava/iwant/entry2/Iwant2.java b/essential/iwant-entry2/src/main/java/org/fluentjava/iwant/entry2/Iwant2.java index 0638ed03..4deb3bac 100644 --- a/essential/iwant-entry2/src/main/java/org/fluentjava/iwant/entry2/Iwant2.java +++ b/essential/iwant-entry2/src/main/java/org/fluentjava/iwant/entry2/Iwant2.java @@ -241,7 +241,7 @@ public TimestampHandler(File cachedTarget, File sourceDescriptor, void markFresh() { Iwant.fileLog("Writing " + sourceDescriptor); - Iwant.newTextFile(sourceDescriptor, + Iwant.textFileEnsuredToHaveContentAndBeTouched(sourceDescriptor, currentSourceDescriptorContent()); } diff --git a/essential/iwant-entry2/src/test/java/org/fluentjava/iwant/entry2/Iwant2Test.java b/essential/iwant-entry2/src/test/java/org/fluentjava/iwant/entry2/Iwant2Test.java index d9791611..c3190491 100644 --- a/essential/iwant-entry2/src/test/java/org/fluentjava/iwant/entry2/Iwant2Test.java +++ b/essential/iwant-entry2/src/test/java/org/fluentjava/iwant/entry2/Iwant2Test.java @@ -209,12 +209,14 @@ public void iwant2CompilesIwantWithDebugInformation() throws Exception { public void findingJavaFilesUnderSrcDirThatContainsNonJavaAndSvnMetadata() { File src = testArea.newDir("src"); Iwant.mkdirs(new File(src, ".svn")); - File aJava = Iwant.newTextFile(new File(src, "A.java"), ""); + File aJava = Iwant.textFileEnsuredToHaveContent(new File(src, "A.java"), + ""); File pak1 = new File(src, "pak1"); Iwant.mkdirs(new File(pak1, ".svn")); - File bJava = Iwant.newTextFile(new File(pak1, "B.java"), ""); - Iwant.newTextFile(new File(pak1, "crap.notjava"), ""); + File bJava = Iwant + .textFileEnsuredToHaveContent(new File(pak1, "B.java"), ""); + Iwant.textFileEnsuredToHaveContent(new File(pak1, "crap.notjava"), ""); assertEquals("[" + aJava + ", " + bJava + "]", Iwant2.javaFilesRecursivelyUnder(src).toString()); diff --git a/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/Iwant3.java b/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/Iwant3.java index e805d7c6..907d808b 100644 --- a/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/Iwant3.java +++ b/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/Iwant3.java @@ -229,7 +229,7 @@ private static IwantException createExampleWsdefdefAndWsdefAndWs( .proposedWsdefPackage(wsInfo.wsdefdefPackage()); String wsDefName = ExampleWsDefGenerator .proposedWsdefSimpleName(wsInfo.wsName()); - FileUtil.newTextFile(wsInfo.wsdefdefJava(), + FileUtil.textFileEnsuredToHaveContent(wsInfo.wsdefdefJava(), ExampleWsDefGenerator.exampleWsdefdef(essential, wsInfo.wsdefdefPackage(), wsInfo.wsdefdefClassSimpleName(), wsInfo.wsName(), @@ -237,12 +237,12 @@ private static IwantException createExampleWsdefdefAndWsdefAndWs( File wsDefJava = new File(iHave, "/wsdef/src/main/java" + "/" + wsDefPackage.replace(".", "/") + "/" + wsDefName + "Factory.java"); - FileUtil.newTextFile(wsDefJava, ExampleWsDefGenerator + FileUtil.textFileEnsuredToHaveContent(wsDefJava, ExampleWsDefGenerator .exampleWsdef(essential, wsDefPackage, wsDefName)); File wsJava = new File(iHave, "/wsdef/src/main/java" + "/" + wsDefPackage.replace(".", "/") + "/" + wsDefName + ".java"); - FileUtil.newTextFile(wsJava, ExampleWsDefGenerator.exampleWs(essential, - wsDefPackage, wsDefName)); + FileUtil.textFileEnsuredToHaveContent(wsJava, ExampleWsDefGenerator + .exampleWs(essential, wsDefPackage, wsDefName)); // TODO it's a bit ugly to create dummy target and side-effect just to // get proper names for wish scripts: HelloSideEffect stubEclipseSettingsSe = new HelloSideEffect( @@ -399,7 +399,7 @@ private static WsInfo parseWsInfo(File wsInfoFile, File asSomeone) } private static void createExampleWsInfo(File wsInfo) { - FileUtil.newTextFile(wsInfo, + FileUtil.textFileEnsuredToHaveContent(wsInfo, "# paths are relative to this file's directory\n" + "WSNAME=example\n" + "WSROOT=../../..\n" + "WSDEFDEF_MODULE=../wsdefdef\n" @@ -407,7 +407,7 @@ private static void createExampleWsInfo(File wsInfo) { } private static void createScript(File file, String content) { - FileUtil.newTextFile(file, content); + FileUtil.textFileEnsuredToHaveContent(file, content); file.setExecutable(true); } diff --git a/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/TargetRefreshTask.java b/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/TargetRefreshTask.java index 748ba33e..d2d9a44a 100644 --- a/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/TargetRefreshTask.java +++ b/essential/iwant-entry3/src/main/java/org/fluentjava/iwant/entry3/TargetRefreshTask.java @@ -70,7 +70,8 @@ public void refresh(Map allocatedResources) { try { target.path(new IngredientCheckingTargetEvaluationContext(target, ctx, refLegalityCheckCache)); - Iwant.newTextFile(cachedDescriptor, target.contentDescriptor()); + Iwant.textFileEnsuredToHaveContent(cachedDescriptor, + target.contentDescriptor()); } catch (RuntimeException e) { throw e; } catch (Exception e) { diff --git a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/ConcurrencyControllableTarget.java b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/ConcurrencyControllableTarget.java index ea33af88..e6b45a40 100644 --- a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/ConcurrencyControllableTarget.java +++ b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/ConcurrencyControllableTarget.java @@ -34,7 +34,7 @@ private static void log(Object... msg) { public void path(TargetEvaluationContext ctx) throws Exception { log(this, "path starting"); task.refresh(Collections. emptyMap()); - Iwant.newTextFile(ctx.cached(this), name()); + Iwant.textFileEnsuredToHaveContent(ctx.cached(this), name()); log(this, "path returning"); } diff --git a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/Iwant3Test.java b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/Iwant3Test.java index e7d55ecf..fb6545b4 100644 --- a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/Iwant3Test.java +++ b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/Iwant3Test.java @@ -772,7 +772,8 @@ public void emptyWishAfterCreationOfUserPreferencesFiles() emptyWishAfterCreationOfExampleWsDef(); startOfOutAndErrCapture(); - Iwant.newTextFile(new File(asTest, "i-have/conf/user-preferences"), + Iwant.textFileEnsuredToHaveContent( + new File(asTest, "i-have/conf/user-preferences"), "workerCount=3"); try { diff --git a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetRefreshTaskTest.java b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetRefreshTaskTest.java index f31a111c..8a80bae6 100644 --- a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetRefreshTaskTest.java +++ b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetRefreshTaskTest.java @@ -74,8 +74,8 @@ private void cacheContainsFreshDescriptor(Target target) { private File cacheContainsDescriptor(Target target, String cachedDescriptor) { - return Iwant.newTextFile(new File(cachedDescriptors, target.name()), - cachedDescriptor); + return Iwant.textFileEnsuredToHaveContent( + new File(cachedDescriptors, target.name()), cachedDescriptor); } private TargetRefreshTask task(Target target) { @@ -459,7 +459,7 @@ public synchronized void path(TargetEvaluationContext ctx) fail("Parent of " + dest + " should exist."); } File subFile = new File(dest, fileNameToCreateUnderDirectory); - Iwant.newTextFile(subFile, + Iwant.textFileEnsuredToHaveContentAndBeTouched(subFile, fileNameToCreateUnderDirectory + " content"); } diff --git a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetThatForgetsToDeclareAnIngredient.java b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetThatForgetsToDeclareAnIngredient.java index 4d2b8acf..9bfde0bc 100644 --- a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetThatForgetsToDeclareAnIngredient.java +++ b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/TargetThatForgetsToDeclareAnIngredient.java @@ -30,7 +30,7 @@ public void path(TargetEvaluationContext ctx) throws Exception { // this reference shall cause a failure: File cachedIngredient = ctx.cached(implicitIngredient); // this shall never be run: - Iwant.newTextFile(ctx.cached(this), + Iwant.textFileEnsuredToHaveContentAndBeTouched(ctx.cached(this), cachedIngredient.getCanonicalPath()); } diff --git a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/WishEvaluatorTest.java b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/WishEvaluatorTest.java index d93f10ee..349efdf5 100644 --- a/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/WishEvaluatorTest.java +++ b/essential/iwant-entry3/src/test/java/org/fluentjava/iwant/entry3/WishEvaluatorTest.java @@ -437,10 +437,11 @@ public void hello2EffectiveOfTwoSideEffects() { @Test public void deletionOfJavaFileIsDetectedAndCompilationIsRetriedAndFailed() { File srcDir = new File(wsRoot, "src"); - Iwant.newTextFile(new File(srcDir, "pak1/Caller.java"), + Iwant.textFileEnsuredToHaveContent(new File(srcDir, "pak1/Caller.java"), "package pak1;\npublic class Caller {pak2.Callee callee;}"); File calleeJava = new File(srcDir, "pak2/Callee.java"); - Iwant.newTextFile(calleeJava, "package pak2;\npublic class Callee {}"); + Iwant.textFileEnsuredToHaveContent(calleeJava, + "package pak2;\npublic class Callee {}"); Source src = Source.underWsroot("src"); Target target = JavaClasses.with().name("multiple").srcDirs(src) .classLocations().end(); diff --git a/optional/iwant-plugin-jacoco/src/test/java/org/fluentjava/iwant/plugin/jacoco/JacocoTestBase.java b/optional/iwant-plugin-jacoco/src/test/java/org/fluentjava/iwant/plugin/jacoco/JacocoTestBase.java index 755e52b2..315d651f 100644 --- a/optional/iwant-plugin-jacoco/src/test/java/org/fluentjava/iwant/plugin/jacoco/JacocoTestBase.java +++ b/optional/iwant-plugin-jacoco/src/test/java/org/fluentjava/iwant/plugin/jacoco/JacocoTestBase.java @@ -65,8 +65,8 @@ protected JavaClassesAndSources newJavaClassesAndSources(String name, code.append(" }\n"); code.append("}\n"); - Iwant.newTextFile(new File(srcDir, className + ".java"), - code.toString()); + Iwant.textFileEnsuredToHaveContent( + new File(srcDir, className + ".java"), code.toString()); JavaClasses classes = JavaClasses.with().name(name + "-classes") .srcDirs(Source.underWsroot(srcDirString)).classLocations() .end(); diff --git a/optional/iwant-plugin-war/src/test/java/org/fluentjava/iwant/plugin/war/WarTest.java b/optional/iwant-plugin-war/src/test/java/org/fluentjava/iwant/plugin/war/WarTest.java index 7a5d947a..a3a639d4 100644 --- a/optional/iwant-plugin-war/src/test/java/org/fluentjava/iwant/plugin/war/WarTest.java +++ b/optional/iwant-plugin-war/src/test/java/org/fluentjava/iwant/plugin/war/WarTest.java @@ -23,7 +23,7 @@ private File newTmpDirWithUnzippedContentOf(War war) { private Source sourceWithContent(String path, String content) { File file = new File(wsRoot, path); Iwant.mkdirs(file.getParentFile()); - Iwant.newTextFile(file, content); + Iwant.textFileEnsuredToHaveContent(file, content); return Source.underWsroot(path); } @@ -92,7 +92,8 @@ public void explicitWebXml() throws Exception { public void webXmlUnderGivenDirectory() throws Exception { File generatedConfs = new File(wsRoot, "generated-confs"); Iwant.mkdirs(generatedConfs); - Iwant.newTextFile(new File(generatedConfs, "generated-web.xml"), + Iwant.textFileEnsuredToHaveContent( + new File(generatedConfs, "generated-web.xml"), "generated web.xml content"); File baseDir = new File(wsRoot, "empty-basedir"); Iwant.mkdirs(baseDir); @@ -114,16 +115,18 @@ public void webXmlUnderGivenDirectory() throws Exception { public void nonEmptyBasedirWithFilesToExclude() throws Exception { File web = new File(wsRoot, "web"); Iwant.mkdirs(web); - Iwant.newTextFile(new File(web, "index.html"), "index.html content"); - Iwant.newTextFile(new File(web, "file-to-exclude"), + Iwant.textFileEnsuredToHaveContent(new File(web, "index.html"), + "index.html content"); + Iwant.textFileEnsuredToHaveContent(new File(web, "file-to-exclude"), "file-to-exclude content"); - Iwant.newTextFile(new File(web, "subdir/another-file-to-exclude"), + Iwant.textFileEnsuredToHaveContent( + new File(web, "subdir/another-file-to-exclude"), "file-to-exclude content"); - Iwant.newTextFile(new File(web, "subdir/file.html"), + Iwant.textFileEnsuredToHaveContent(new File(web, "subdir/file.html"), "file.html content"); - Iwant.newTextFile(new File(web, "WEB-INF/web.xml"), + Iwant.textFileEnsuredToHaveContent(new File(web, "WEB-INF/web.xml"), "web.xml content to exclude"); - Iwant.newTextFile(new File(wsRoot, "correct-web.xml"), + Iwant.textFileEnsuredToHaveContent(new File(wsRoot, "correct-web.xml"), "web.xml content to use"); War war = War.with().name("test.war").basedir(Source.underWsroot("web")) diff --git a/private/iwant-docs/backlog.txt b/private/iwant-docs/backlog.txt index 466a2f17..661fdbdb 100644 --- a/private/iwant-docs/backlog.txt +++ b/private/iwant-docs/backlog.txt @@ -13,6 +13,8 @@ - deprecate and even remove commonSettins - ha, maybe even force by defining abstract myModule method +- now with newer java simplify file IO, what else? + - fix local website: broken since who know when - fix - make part of continuous practice (maybe after the /tmp usage story) @@ -20,13 +22,14 @@ - all core and plugin dependencies to exactly one place, usable for users, too - conf: *all* possible caches under /tmp, to save SSD and time. Also to force testing against internet rot. - - iwant-test-area especially! + + iwant-test-area especially! + + target temp dirs - global setting to only use global cache for downloads, nothing else, TODO how? - maybe: user can tell something is so slow it needs to be cached permanently - empty intermediate caches success TODO how to define intermediate? user? - personal projects (c compilation!), imagemagick, all scripts - iwant's all caches (unzipped local etc) - - eclipse settings, wish script writing: only write if changes + + eclipse settings, wish script writing: only write if changes * also may improve laziness with some (future) features - what else diff --git a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/DownloadingTest.java b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/DownloadingTest.java index 76fba23d..0c500051 100644 --- a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/DownloadingTest.java +++ b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/DownloadingTest.java @@ -28,12 +28,12 @@ public void before() { private void cachedFileContains(URL url, String content) { File cached = iwant.network() .cacheOfContentFrom(new UnmodifiableUrl(url)); - Iwant.newTextFile(cached, content); + Iwant.textFileEnsuredToHaveContent(cached, content); } private File remoteFileContains(String path, String content) { File remoteFile = new File(testArea.root(), path); - Iwant.newTextFile(remoteFile, content); + Iwant.textFileEnsuredToHaveContent(remoteFile, content); return remoteFile; } diff --git a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/IwantTest.java b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/IwantTest.java index 7e36812e..54ebc2ca 100644 --- a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/IwantTest.java +++ b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/IwantTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -234,7 +235,8 @@ public void userGetsFriendlyErrorIfIwantFromFileDoesNotSpecifyIwantFrom() startOfOutAndErrCapture(); File asSomeone = testArea.newDir("as-test"); - Iwant.newTextFile(new File(asSomeone, "/i-have/conf/iwant-from"), + Iwant.textFileEnsuredToHaveContent( + new File(asSomeone, "/i-have/conf/iwant-from"), "just-something=else\n"); try { Iwant.main(new String[] { asSomeone.getCanonicalPath() }); @@ -255,7 +257,8 @@ public void userGetsFriendlyErrorIfIwantFromFileContainsInvalidIwantFromUrl() startOfOutAndErrCapture(); File asSomeone = testArea.newDir("as-test"); - Iwant.newTextFile(new File(asSomeone, "/i-have/conf/iwant-from"), + Iwant.textFileEnsuredToHaveContent( + new File(asSomeone, "/i-have/conf/iwant-from"), "iwant-from=crap\n"); try { Iwant.main(new String[] { asSomeone.getCanonicalPath() }); @@ -276,7 +279,7 @@ public void iwantSourceZipIsAcquiredWhenItDoesntExist() { File iHaveConf = testArea.newDir("as-test/i-have/conf"); File iwantZip = mockWsRootZip(); URL iwantFromUrl = Iwant.fileToUrl(iwantZip); - Iwant.newTextFile(new File(iHaveConf, "iwant-from"), + Iwant.textFileEnsuredToHaveContent(new File(iHaveConf, "iwant-from"), "iwant-from=" + iwantFromUrl + "\n"); IwantNetworkMock network = new IwantNetworkMock(testArea); @@ -295,7 +298,7 @@ public void iwantSourceIsAcquiredWhenItDoesntExist() { File iHaveConf = testArea.newDir("as-test/i-have/conf"); File iwantZip = mockWsRootZip(); URL iwantFromUrl = Iwant.fileToUrl(iwantZip); - Iwant.newTextFile(new File(iHaveConf, "iwant-from"), + Iwant.textFileEnsuredToHaveContent(new File(iHaveConf, "iwant-from"), "iwant-from=" + iwantFromUrl + "\n"); IwantNetworkMock network = new IwantNetworkMock(testArea); @@ -323,7 +326,7 @@ public void iwantBootstrapsWhenNothingHasBeenDownloadedAndJustIwantFromFileIsGiv File iHaveConf = testArea.newDir("as-test/i-have/conf"); File iwantZip = mockWsRootZip(); URL iwantFromUrl = Iwant.fileToUrl(iwantZip); - Iwant.newTextFile(new File(iHaveConf, "iwant-from"), + Iwant.textFileEnsuredToHaveContent(new File(iHaveConf, "iwant-from"), "iwant-from=" + iwantFromUrl + "\n"); IwantNetworkMock network = new IwantNetworkMock(testArea); @@ -385,7 +388,7 @@ public void iwantGivesNiceErrorMessageIfSystemJavaCompilerIsNotFound() File iHaveConf = testArea.newDir("as-test/i-have/conf"); File iwantZip = mockWsRootZip(); URL iwantFromUrl = Iwant.fileToUrl(iwantZip); - Iwant.newTextFile(new File(iHaveConf, "iwant-from"), + Iwant.textFileEnsuredToHaveContent(new File(iHaveConf, "iwant-from"), "iwant-from=" + iwantFromUrl + "\n"); IwantNetworkMock network = new IwantNetworkMock(testArea); @@ -420,7 +423,7 @@ public void bootstrapperIsNotCompiledIfNotNecessary() throws Exception { File iHaveConf = testArea.newDir("as-test/i-have/conf"); File iwantZip = mockWsRootZip(); URL iwantFromUrl = Iwant.fileToUrl(iwantZip); - Iwant.newTextFile(new File(iHaveConf, "iwant-from"), + Iwant.textFileEnsuredToHaveContent(new File(iHaveConf, "iwant-from"), "iwant-from=" + iwantFromUrl + "\n"); IwantNetworkMock network = new IwantNetworkMock(testArea); @@ -558,4 +561,33 @@ public void delWorksEvenWithBrokenSymlinkUnderDirToDelete() assertFalse(parent.exists()); } + @Test + public void textFileEnsuredToHaveContent() throws InterruptedException { + File a = new File(testArea.root(), "someDir/a"); + assertFalse(a.exists()); + + // 1. creation + + assertSame(a, Iwant.textFileEnsuredToHaveContent(a, "a\nä\n1")); + assertTrue(a.exists()); + assertEquals("a\nä\n1", testArea.contentOf(a)); + long aModTime = a.lastModified(); + + // 2. ensure same content => no write happens + + while (System.currentTimeMillis() <= aModTime) { + Thread.sleep(1L); + } + + assertSame(a, Iwant.textFileEnsuredToHaveContent(a, "a\nä\n1")); + assertEquals(aModTime, a.lastModified()); + assertTrue(a.exists()); + assertEquals("a\nä\n1", testArea.contentOf(a)); + + // 3. ensure new content => write happens + + assertSame(a, Iwant.textFileEnsuredToHaveContent(a, "a\nä\n2")); + assertEquals("a\nä\n2", testArea.contentOf(a)); + } + } diff --git a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/UnzippingTest.java b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/UnzippingTest.java index 89564d41..f56ae153 100644 --- a/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/UnzippingTest.java +++ b/private/iwant-entry-tests/src/test/java/org/fluentjava/iwant/entry/tests/UnzippingTest.java @@ -59,7 +59,8 @@ public void cacheIsReturnedWithoutUnzippingWhenCacheExists() { URL zip = Iwant .fileToUrl(new File(testArea.root(), "not-to-be-accessed")); File unzipped = network.cachesZipAt(zip, "unzipped"); - Iwant.newTextFile(new File(unzipped, "file"), "unzipped content"); + Iwant.textFileEnsuredToHaveContent(new File(unzipped, "file"), + "unzipped content"); File unzippedAgain = iwant .unmodifiableZipUnzipped(new UnmodifiableZip(zip));