diff options
author | tricktron <tgagnaux@gmail.com> | 2021-12-21 15:54:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-21 15:54:51 +0100 |
commit | 2eeb5f4fe33f325d07988c99c758909c4aaad957 (patch) | |
tree | 1edffe9354d85cc4ce4717cda443be17ee1cf8a7 | |
parent | 3c4bfaeb12fc7480782efd5f2f78831ab0761bbb (diff) | |
parent | 6fe74444e80d68dffa61e2e57b78092e50a54772 (diff) | |
download | frege-gradle-plugin-2eeb5f4fe33f325d07988c99c758909c4aaad957.tar.gz frege-gradle-plugin-2eeb5f4fe33f325d07988c99c758909c4aaad957.tar.bz2 frege-gradle-plugin-2eeb5f4fe33f325d07988c99c758909c4aaad957.zip |
Merge pull request #17 from tricktron/f-repl-with-source-deps
Repl with all Source Dependencies
14 files changed, 814 insertions, 493 deletions
@@ -12,13 +12,14 @@ git clone https://github.com/tricktron/frege-gradle-plugin.git ``` ## How to Use -1. Specify the frege compiler release, version and main module in your `build.gradle`: +1. Specify the frege compiler release, version, main module and repl source file in your `build.gradle`: ```groovy frege { version = '3.25.84' release = '3.25alpha' - mainModule = 'my.mod.Name' + mainModule = 'my.mod.Name' // see runFrege task + replSource = 'Name.fr' // see replFrege task } ``` @@ -35,7 +36,7 @@ Optional configuration parameters inside `build.gradle`: - **setupFrege**: Downloads the specified version of the Frege compiler. - **compileFrege**: All your `*.fr` files in `mainSourceDir` get compiled to `outputDir`. - **runFrege**: Runs the Frege module specified by `mainModule`. Alternatively you can also pass the main module by command line, e.g: `gradle runFrege --mainModule=my.mod.Name`. -- **replFrege**: Takes care of all project dependencies and prints the command to start the Frege REPL, e.g: `java -cp <your-correct-classpath-with-all-dependencies> frege.repl.FregeRepl`. +- **replFrege**: Takes care of all project dependencies of the specified filename by `replSource` and prints the command to start the Frege REPL, e.g: `java -cp <your-correct-classpath-with-all-dependencies> frege.repl.FregeRepl`. Afterwards you can load your file into the repl with `:l <absolute path to replSource>`. ### Dependencies diff --git a/gradle.properties b/gradle.properties index 4e2b9ee..8fca547 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group = ch.fhnw.thga -version = 1.5.0-alpha
\ No newline at end of file +version = 1.6.0-alpha
\ No newline at end of file diff --git a/src/functionalTest/java/ch/fhnw/thga/gradleplugins/FregePluginFunctionalTest.java b/src/functionalTest/java/ch/fhnw/thga/gradleplugins/FregePluginFunctionalTest.java index f94469c..a7c2b35 100644 --- a/src/functionalTest/java/ch/fhnw/thga/gradleplugins/FregePluginFunctionalTest.java +++ b/src/functionalTest/java/ch/fhnw/thga/gradleplugins/FregePluginFunctionalTest.java @@ -2,18 +2,19 @@ package ch.fhnw.thga.gradleplugins; import static ch.fhnw.thga.gradleplugins.FregeExtension.DEFAULT_DOWNLOAD_DIRECTORY; import static ch.fhnw.thga.gradleplugins.FregePlugin.COMPILE_FREGE_TASK_NAME; +import static ch.fhnw.thga.gradleplugins.FregePlugin.DEPS_FREGE_TASK_NAME; import static ch.fhnw.thga.gradleplugins.FregePlugin.FREGE_EXTENSION_NAME; import static ch.fhnw.thga.gradleplugins.FregePlugin.FREGE_PLUGIN_ID; -import static ch.fhnw.thga.gradleplugins.FregePlugin.DEPS_FREGE_TASK_NAME; +import static ch.fhnw.thga.gradleplugins.FregePlugin.REPL_FREGE_TASK_NAME; import static ch.fhnw.thga.gradleplugins.FregePlugin.RUN_FREGE_TASK_NAME; import static ch.fhnw.thga.gradleplugins.FregePlugin.SETUP_FREGE_TASK_NAME; -import static ch.fhnw.thga.gradleplugins.FregePlugin.REPL_FREGE_TASK_NAME; import static ch.fhnw.thga.gradleplugins.GradleBuildFileConversionTest.createPluginsSection; import static org.gradle.testkit.runner.TaskOutcome.FAILED; import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE; import static org.gradle.testkit.runner.TaskOutcome.SUCCESS; import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.BufferedWriter; @@ -44,403 +45,512 @@ import ch.fhnw.thga.gradleplugins.internal.DependencyFregeTask; @TestInstance(Lifecycle.PER_CLASS) public class FregePluginFunctionalTest { - private static final String NEW_LINE = System.lineSeparator(); - private static final String SIMPLE_FREGE_CODE = String.join(NEW_LINE, "module ch.fhnw.thga.Completion where", - NEW_LINE, NEW_LINE, " complete :: Int -> (Int, String)", NEW_LINE, - " complete i = (i, \"Frege rocks\")", - NEW_LINE); - - private static FregeDTOBuilder fregeBuilder; - - @TempDir - File testProjectDir; - private File buildFile; - private File settingsFile; - private Project project; - - private void writeFile(File destination, String content, boolean append) throws IOException { - try (BufferedWriter output = new BufferedWriter(new FileWriter(destination, append))) { - output.write(content); - } - } - - private void writeToFile(File destination, String content) throws IOException { - writeFile(destination, content, false); - } - - private void appendToFile(File destination, String content) throws IOException { - writeFile(destination, "\n" + content, true); - } - - private static String createFregeSection(FregeDTO fregeDTO) { - return String.format("%s {\n %s\n}", FREGE_EXTENSION_NAME, fregeDTO.toBuildFile()); - } - - private BuildResult runGradleTask(String... taskName) { - return GradleRunner.create().withProjectDir(testProjectDir).withPluginClasspath() - .withArguments(taskName) - .build(); - } - - private BuildResult runAndFailGradleTask(String taskName, String... args) { - return GradleRunner.create().withProjectDir(testProjectDir).withPluginClasspath() - .withArguments(taskName) - .buildAndFail(); - } - - private void setupDefaultFregeProjectStructure(String fregeCode, String fregeFileName, String buildFileConfig) - throws Exception { - Files.createDirectories(testProjectDir.toPath().resolve(Paths.get("src", "main", "frege"))); - File fregeFile = testProjectDir.toPath().resolve(Paths.get("src", "main", "frege", fregeFileName)) - .toFile(); - writeToFile(fregeFile, fregeCode); - appendToFile(buildFile, buildFileConfig); - } - - @BeforeAll - void beforeAll() throws Exception { - settingsFile = new File(testProjectDir, "settings.gradle"); - writeToFile(settingsFile, "rootProject.name='frege-plugin'"); - project = ProjectBuilder.builder().withProjectDir(testProjectDir).build(); - project.getPluginManager().apply(FREGE_PLUGIN_ID); - + private static final String NEW_LINE = System.lineSeparator(); + private static final String SIMPLE_FREGE_CODE = String.join(NEW_LINE, "module ch.fhnw.thga.Completion where", + NEW_LINE, NEW_LINE, " complete :: Int -> (Int, String)", NEW_LINE, + " complete i = (i, \"Frege rocks\")", + NEW_LINE); + + private static FregeDTOBuilder fregeBuilder; + + @TempDir + File testProjectDir; + private File buildFile; + private File settingsFile; + private Project project; + + private void writeFile(File destination, String content, boolean append) throws IOException { + try (BufferedWriter output = new BufferedWriter(new FileWriter(destination, append))) { + output.write(content); + } + } + + private void writeToFile(File destination, String content) throws IOException { + writeFile(destination, content, false); + } + + private void appendToFile(File destination, String content) throws IOException { + writeFile(destination, System.lineSeparator() + content, true); + } + + private static String createFregeSection(FregeDTO fregeDTO) { + return String.format( + "%s {%s %s%s}", + FREGE_EXTENSION_NAME, + System.lineSeparator(), + fregeDTO.toBuildFile(), + System.lineSeparator()); + } + + private BuildResult runGradleTask(String... taskName) { + return GradleRunner.create().withProjectDir(testProjectDir).withPluginClasspath() + .withArguments(taskName) + .build(); + } + + private BuildResult runAndFailGradleTask(String taskName, String... args) { + return GradleRunner.create().withProjectDir(testProjectDir).withPluginClasspath() + .withArguments(taskName) + .buildAndFail(); + } + + private void setupDefaultFregeProjectStructure(String fregeCode, String fregeFileName, String buildFileConfig) + throws Exception { + Files.createDirectories(testProjectDir.toPath().resolve(Paths.get("src", "main", "frege"))); + File fregeFile = testProjectDir.toPath().resolve(Paths.get("src", "main", "frege", fregeFileName)) + .toFile(); + writeToFile(fregeFile, fregeCode); + appendToFile(buildFile, buildFileConfig); + } + + @BeforeAll + void beforeAll() throws Exception { + settingsFile = new File(testProjectDir, "settings.gradle"); + writeToFile(settingsFile, "rootProject.name='frege-plugin'"); + project = ProjectBuilder.builder().withProjectDir(testProjectDir).build(); + project.getPluginManager().apply(FREGE_PLUGIN_ID); + + } + + @BeforeEach + void setup() throws Exception { + buildFile = new File(testProjectDir, "build.gradle"); + writeToFile(buildFile, createPluginsSection(Stream.of(FREGE_PLUGIN_ID))); + fregeBuilder = FregeDTOBuilder.getInstance(); + } + + @AfterEach + void cleanup() { + testProjectDir.delete(); + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Setup_frege_task_works { + + @Test + void given_minimal_build_file_config() throws Exception { + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + appendToFile(buildFile, minimalBuildFileConfig); + + BuildResult result = runGradleTask(SETUP_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(SETUP_FREGE_TASK_NAME) instanceof SetupFregeTask); + assertEquals(SUCCESS, result.task(":" + SETUP_FREGE_TASK_NAME).getOutcome()); + assertTrue(testProjectDir.toPath() + .resolve(Paths.get(DEFAULT_DOWNLOAD_DIRECTORY, "frege3.25.84.jar")) + .toFile().exists()); + } + + @Test + void given_custom_frege_compiler_download_directory_in_build_file_config() throws Exception { + String buildFileConfigWithCustomDownloadDir = createFregeSection(fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'") + .compilerDownloadDir("layout.projectDirectory.dir('dist')").build()); + appendToFile(buildFile, buildFileConfigWithCustomDownloadDir); + + BuildResult result = runGradleTask(SETUP_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(SETUP_FREGE_TASK_NAME) instanceof SetupFregeTask); + assertEquals(SUCCESS, result.task(":" + SETUP_FREGE_TASK_NAME).getOutcome()); + assertTrue(testProjectDir.toPath().resolve(Paths.get("dist", "frege3.25.84.jar")).toFile() + .exists()); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Compile_frege_task_works { + + @Test + void given_frege_code_in_default_source_dir_and_minimal_build_file_config() throws Exception { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); + + BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") + .exists()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") + .exists()); + } + + @Test + void given_frege_code_and_many_compiler_flags() throws Exception { + String completionFr = "Completion.fr"; + String buildConfigWithCompilerFlags = createFregeSection(fregeBuilder.version("'3.25.84'") + .release("'3.25alpha'").compilerFlags("['-v', '-make', '-O', '-hints']") + .build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, + buildConfigWithCompilerFlags); + + BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") + .exists()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") + .exists()); + } + + @Test + void given_frege_code_in_custom_source_dir_and_custom_output_dir_and_minimal_build_file_config() + throws Exception { + Path customMainSourceDir = testProjectDir.toPath().resolve(Paths.get("src", "frege")); + Files.createDirectories(customMainSourceDir); + File completionFr = customMainSourceDir.resolve("Completion.fr").toFile(); + writeToFile(completionFr, SIMPLE_FREGE_CODE); + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'") + .mainSourceDir("layout.projectDirectory.dir('src/frege')") + .outputDir("layout.buildDirectory.dir('frege')").build()); + appendToFile(buildFile, minimalBuildFileConfig); + + BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + assertTrue( + new File(testProjectDir.getAbsolutePath() + + "/build/frege/ch/fhnw/thga/Completion.java").exists()); + assertTrue( + new File(testProjectDir.getAbsolutePath() + + "/build/frege/ch/fhnw/thga/Completion.class").exists()); + } + + @Test + void and_is_up_to_date_given_no_code_changes() throws Exception { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); + + BuildResult first = runGradleTask(COMPILE_FREGE_TASK_NAME); + assertEquals(SUCCESS, first.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + + BuildResult second = runGradleTask(COMPILE_FREGE_TASK_NAME); + assertEquals(UP_TO_DATE, second.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + } + + @Test + void and_is_cached_given_cache_hit() throws Exception { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); + + BuildResult first = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); + assertEquals(SUCCESS, first.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + + String codeChange = String.join(NEW_LINE, "module ch.fhnw.thga.Completion where", NEW_LINE, + NEW_LINE, + " frob :: Int -> (Int, String)", NEW_LINE, " frob i = (i, \"Frege rocks\")", + NEW_LINE); + setupDefaultFregeProjectStructure(codeChange, completionFr, ""); + + BuildResult second = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); + assertEquals(SUCCESS, second.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, ""); + BuildResult third = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); + assertEquals(FROM_CACHE, third.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + } + + @Test + void given_two_dependent_frege_files_in_default_source_dir_and_minimal_build_file_config() + throws Exception { + String completionFr = "Completion.fr"; + String frobFr = "Frob.fr"; + String frobCode = String.join(NEW_LINE, "module ch.fhnw.thga.Frob where", NEW_LINE, NEW_LINE, + "import ch.fhnw.thga.Completion (complete)", NEW_LINE, + "frob i = complete $ i + i", NEW_LINE); + + String minimalBuildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); + setupDefaultFregeProjectStructure(frobCode, frobFr, ""); + + BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") + .exists()); + assertTrue(new File( + testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") + .exists()); + assertTrue(new File(testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Frob.java") + .exists()); + assertTrue(new File(testProjectDir.getAbsolutePath() + + "/build/classes/main/frege/ch/fhnw/thga/Frob.class") + .exists()); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Compile_frege_task_fails { + @Test + void given_frege_code_and_illegal_compiler_flags() throws Exception { + String completionFr = "Completion.fr"; + String buildConfigWithIllegalCompilerFlags = createFregeSection(fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'").compilerFlags("['-make', '-bla']").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, + buildConfigWithIllegalCompilerFlags); + + BuildResult result = runAndFailGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(FAILED, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + } + + @Test + void given_two_dependent_frege_files_in_default_source_dir_and_without_make_compiler_flag() + throws Exception { + String completionFr = "Completion.fr"; + String frobFr = "Frob.fr"; + String frobCode = String.join(NEW_LINE, "module ch.fhnw.thga.Frob where", NEW_LINE, NEW_LINE, + "import ch.fhnw.thga.Completion (complete)", NEW_LINE, + "frob i = complete $ i + i", NEW_LINE); + + String minimalBuildFileConfigWithoutMake = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").compilerFlags("['-v']") + .build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, + minimalBuildFileConfigWithoutMake); + setupDefaultFregeProjectStructure(frobCode, frobFr, ""); + + BuildResult result = runAndFailGradleTask(COMPILE_FREGE_TASK_NAME); + + assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); + assertEquals(FAILED, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Run_frege_task_works { + @Test + void given_frege_file_with_main_function_and_main_module_config() throws Exception { + String fregeCode = String.join(NEW_LINE, "module ch.fhnw.thga.Main where", NEW_LINE, NEW_LINE, + " main = do", NEW_LINE, " println \"Frege rocks\"", NEW_LINE); + String mainFr = "Main.fr"; + String buildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'") + .mainModule("'ch.fhnw.thga.Main'").build()); + setupDefaultFregeProjectStructure(fregeCode, mainFr, buildFileConfig); + + BuildResult result = runGradleTask(RUN_FREGE_TASK_NAME); + assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); + assertEquals(SUCCESS, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("Frege rocks")); + } + + @Test + void given_frege_file_without_main_function() throws Exception { + String completionFr = "Completion.fr"; + String buildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'") + .mainModule("'ch.fhnw.thga.Completion'").build()); + setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, buildFileConfig); + + BuildResult result = runAndFailGradleTask(RUN_FREGE_TASK_NAME); + assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); + assertEquals(FAILED, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("Main method not found")); + } + + @Test + void given_frege_file_with_main_function_and_main_module_command_line_option() throws Exception { + String fregeCode = String.join(NEW_LINE, "module ch.fhnw.thga.Main where", NEW_LINE, NEW_LINE, + " main = do", NEW_LINE, " println \"Frege rocks\"", NEW_LINE); + String mainFr = "Main.fr"; + String buildFileConfig = createFregeSection( + fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); + setupDefaultFregeProjectStructure(fregeCode, mainFr, buildFileConfig); + + BuildResult result = runGradleTask(RUN_FREGE_TASK_NAME, "--mainModule=ch.fhnw.thga.Main"); + assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); + assertEquals(SUCCESS, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("Frege rocks")); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration( + separator = " -> ", + generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Deps_frege_task_works { + @Test + void given_minimal_build_file_config() throws Exception { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'") + .build()); + setupDefaultFregeProjectStructure( + SIMPLE_FREGE_CODE, + completionFr, + minimalBuildFileConfig); + + BuildResult result = runGradleTask( + DEPS_FREGE_TASK_NAME, + "-q", + String.format("--replSource=%s", completionFr)); + + assertTrue( + project.getTasks().getByName(DEPS_FREGE_TASK_NAME) + instanceof DependencyFregeTask); + assertEquals(SUCCESS, result.task(":" + DEPS_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("frege3.25.84.jar")); + assertFalse(result.getOutput().contains("Completion.java")); + assertFalse( + testProjectDir + .toPath() + .resolve("/build/classes/main/frege/ch/fhnw/thga/Completion.java").toFile() + .exists()); } - @BeforeEach - void setup() throws Exception { - buildFile = new File(testProjectDir, "build.gradle"); - writeToFile(buildFile, createPluginsSection(Stream.of(FREGE_PLUGIN_ID))); - fregeBuilder = FregeDTOBuilder.getInstance(); - } - - @AfterEach - void cleanup() { - testProjectDir.delete(); - } - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Setup_frege_task_works { - - @Test - void given_minimal_build_file_config() throws Exception { - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - appendToFile(buildFile, minimalBuildFileConfig); - - BuildResult result = runGradleTask(SETUP_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(SETUP_FREGE_TASK_NAME) instanceof SetupFregeTask); - assertEquals(SUCCESS, result.task(":" + SETUP_FREGE_TASK_NAME).getOutcome()); - assertTrue(testProjectDir.toPath() - .resolve(Paths.get(DEFAULT_DOWNLOAD_DIRECTORY, "frege3.25.84.jar")) - .toFile().exists()); - } - - @Test - void given_custom_frege_compiler_download_directory_in_build_file_config() throws Exception { - String buildFileConfigWithCustomDownloadDir = createFregeSection(fregeBuilder - .version("'3.25.84'") - .release("'3.25alpha'") - .compilerDownloadDir("layout.projectDirectory.dir('dist')").build()); - appendToFile(buildFile, buildFileConfigWithCustomDownloadDir); - - BuildResult result = runGradleTask(SETUP_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(SETUP_FREGE_TASK_NAME) instanceof SetupFregeTask); - assertEquals(SUCCESS, result.task(":" + SETUP_FREGE_TASK_NAME).getOutcome()); - assertTrue(testProjectDir.toPath().resolve(Paths.get("dist", "frege3.25.84.jar")).toFile() - .exists()); - } + @Test + void given_build_file_config_with_dependencies() throws Exception { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'") + .build()); + setupDefaultFregeProjectStructure( + SIMPLE_FREGE_CODE, + completionFr, + minimalBuildFileConfig); + appendToFile( + buildFile, + String.join( + System.lineSeparator(), + "repositories {", + "mavenCentral()", + "}")); + appendToFile( + buildFile, + String.join( + System.lineSeparator(), + "dependencies {", + "implementation group: 'org.json', name: 'json', version: '20211205'", + "}")); + + BuildResult result = runGradleTask( + DEPS_FREGE_TASK_NAME, + "-q", + String.format("--replSource=%s", completionFr)); + + assertTrue( + project.getTasks().getByName(DEPS_FREGE_TASK_NAME) + instanceof DependencyFregeTask); + assertEquals(SUCCESS, result.task(":" + DEPS_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("frege3.25.84.jar")); + assertTrue(result.getOutput().contains("org.json")); + assertFalse(result.getOutput().contains("Completion.java")); + assertFalse( + testProjectDir + .toPath() + .resolve("/build/classes/main/frege/ch/fhnw/thga/Completion.java").toFile() + .exists()); } - - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Compile_frege_task_works { - - @Test - void given_frege_code_in_default_source_dir_and_minimal_build_file_config() throws Exception { - String completionFr = "Completion.fr"; - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); - - BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") - .exists()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") - .exists()); - } - - @Test - void given_frege_code_and_many_compiler_flags() throws Exception { - String completionFr = "Completion.fr"; - String buildConfigWithCompilerFlags = createFregeSection(fregeBuilder.version("'3.25.84'") - .release("'3.25alpha'").compilerFlags("['-v', '-make', '-O', '-hints']") - .build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, - buildConfigWithCompilerFlags); - - BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") - .exists()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") - .exists()); - } - - @Test - void given_frege_code_in_custom_source_dir_and_custom_output_dir_and_minimal_build_file_config() - throws Exception { - Path customMainSourceDir = testProjectDir.toPath().resolve(Paths.get("src", "frege")); - Files.createDirectories(customMainSourceDir); - File completionFr = customMainSourceDir.resolve("Completion.fr").toFile(); - writeToFile(completionFr, SIMPLE_FREGE_CODE); - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'") - .mainSourceDir("layout.projectDirectory.dir('src/frege')") - .outputDir("layout.buildDirectory.dir('frege')").build()); - appendToFile(buildFile, minimalBuildFileConfig); - - BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - assertTrue( - new File(testProjectDir.getAbsolutePath() - + "/build/frege/ch/fhnw/thga/Completion.java").exists()); - assertTrue( - new File(testProjectDir.getAbsolutePath() - + "/build/frege/ch/fhnw/thga/Completion.class").exists()); - } - - @Test - void and_is_up_to_date_given_no_code_changes() throws Exception { - String completionFr = "Completion.fr"; - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); - - BuildResult first = runGradleTask(COMPILE_FREGE_TASK_NAME); - assertEquals(SUCCESS, first.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - - BuildResult second = runGradleTask(COMPILE_FREGE_TASK_NAME); - assertEquals(UP_TO_DATE, second.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - } - - @Test - void and_is_cached_given_cache_hit() throws Exception { - String completionFr = "Completion.fr"; - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); - - BuildResult first = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); - assertEquals(SUCCESS, first.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - - String codeChange = String.join(NEW_LINE, "module ch.fhnw.thga.Completion where", NEW_LINE, - NEW_LINE, - " frob :: Int -> (Int, String)", NEW_LINE, " frob i = (i, \"Frege rocks\")", - NEW_LINE); - setupDefaultFregeProjectStructure(codeChange, completionFr, ""); - - BuildResult second = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); - assertEquals(SUCCESS, second.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, ""); - BuildResult third = runGradleTask(COMPILE_FREGE_TASK_NAME, "--build-cache"); - assertEquals(FROM_CACHE, third.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - } - - @Test - void given_two_dependent_frege_files_in_default_source_dir_and_minimal_build_file_config() - throws Exception { - String completionFr = "Completion.fr"; - String frobFr = "Frob.fr"; - String frobCode = String.join(NEW_LINE, "module ch.fhnw.thga.Frob where", NEW_LINE, NEW_LINE, - "import ch.fhnw.thga.Completion (complete)", NEW_LINE, - "frob i = complete $ i + i", NEW_LINE); - - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, minimalBuildFileConfig); - setupDefaultFregeProjectStructure(frobCode, frobFr, ""); - - BuildResult result = runGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(SUCCESS, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.java") - .exists()); - assertTrue(new File( - testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Completion.class") - .exists()); - assertTrue(new File(testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Frob.java") - .exists()); - assertTrue(new File(testProjectDir.getAbsolutePath() - + "/build/classes/main/frege/ch/fhnw/thga/Frob.class") - .exists()); - } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration( + separator = " -> ", + generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Repl_frege_task_works + { + @Test + void given_minimal_build_file_config_with_replModule() throws Exception + { + String completionFr = "Completion.fr"; + String minimalReplModuleConfig = createFregeSection( + fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'") + .replSource(String.format("'%s'", completionFr)) + .build()); + setupDefaultFregeProjectStructure( + SIMPLE_FREGE_CODE, + completionFr, + minimalReplModuleConfig); + + BuildResult result = runGradleTask(REPL_FREGE_TASK_NAME); + + assertTrue( + project.getTasks().getByName(REPL_FREGE_TASK_NAME) + instanceof ReplFregeTask); + assertEquals(SUCCESS, result.task(":" + REPL_FREGE_TASK_NAME).getOutcome()); + assertTrue(result.getOutput().contains("java -cp")); + assertTrue(result.getOutput().contains("frege3.25.84.jar")); + assertFalse(result.getOutput().contains("Completion.java")); + assertFalse( + testProjectDir + .toPath() + .resolve("/build/classes/main/frege/ch/fhnw/thga/Completion.java").toFile() + .exists()); } - - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Compile_frege_task_fails { - @Test - void given_frege_code_and_illegal_compiler_flags() throws Exception { - String completionFr = "Completion.fr"; - String buildConfigWithIllegalCompilerFlags = createFregeSection(fregeBuilder - .version("'3.25.84'") - .release("'3.25alpha'").compilerFlags("['-make', '-bla']").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, - buildConfigWithIllegalCompilerFlags); - - BuildResult result = runAndFailGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(FAILED, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - } - - @Test - void given_two_dependent_frege_files_in_default_source_dir_and_without_make_compiler_flag() - throws Exception { - String completionFr = "Completion.fr"; - String frobFr = "Frob.fr"; - String frobCode = String.join(NEW_LINE, "module ch.fhnw.thga.Frob where", NEW_LINE, NEW_LINE, - "import ch.fhnw.thga.Completion (complete)", NEW_LINE, - "frob i = complete $ i + i", NEW_LINE); - - String minimalBuildFileConfigWithoutMake = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").compilerFlags("['-v']") - .build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, - minimalBuildFileConfigWithoutMake); - setupDefaultFregeProjectStructure(frobCode, frobFr, ""); - - BuildResult result = runAndFailGradleTask(COMPILE_FREGE_TASK_NAME); - - assertTrue(project.getTasks().getByName(COMPILE_FREGE_TASK_NAME) instanceof CompileFregeTask); - assertEquals(FAILED, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); - } - } - - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Run_frege_task_works { - @Test - void given_frege_file_with_main_function_and_main_module_config() throws Exception { - String fregeCode = String.join(NEW_LINE, "module ch.fhnw.thga.Main where", NEW_LINE, NEW_LINE, - " main = do", NEW_LINE, " println \"Frege rocks\"", NEW_LINE); - String mainFr = "Main.fr"; - String buildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'") - .mainModule("'ch.fhnw.thga.Main'").build()); - setupDefaultFregeProjectStructure(fregeCode, mainFr, buildFileConfig); - - BuildResult result = runGradleTask(RUN_FREGE_TASK_NAME); - assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); - assertEquals(SUCCESS, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("Frege rocks")); - } - - @Test - void given_frege_file_without_main_function() throws Exception { - String completionFr = "Completion.fr"; - String buildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'") - .mainModule("'ch.fhnw.thga.Completion'").build()); - setupDefaultFregeProjectStructure(SIMPLE_FREGE_CODE, completionFr, buildFileConfig); - - BuildResult result = runAndFailGradleTask(RUN_FREGE_TASK_NAME); - assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); - assertEquals(FAILED, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("Main method not found")); - } - - @Test - void given_frege_file_with_main_function_and_main_module_command_line_option() throws Exception { - String fregeCode = String.join(NEW_LINE, "module ch.fhnw.thga.Main where", NEW_LINE, NEW_LINE, - " main = do", NEW_LINE, " println \"Frege rocks\"", NEW_LINE); - String mainFr = "Main.fr"; - String buildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - setupDefaultFregeProjectStructure(fregeCode, mainFr, buildFileConfig); - - BuildResult result = runGradleTask(RUN_FREGE_TASK_NAME, "--mainModule=ch.fhnw.thga.Main"); - assertTrue(project.getTasks().getByName(RUN_FREGE_TASK_NAME) instanceof RunFregeTask); - assertEquals(SUCCESS, result.task(":" + RUN_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("Frege rocks")); - } - } - - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Deps_frege_task_works { - @Test - void given_minimal_build_file_config() throws Exception { - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - appendToFile(buildFile, minimalBuildFileConfig); - - BuildResult result = runGradleTask(DEPS_FREGE_TASK_NAME, "-q"); - assertTrue(project.getTasks().getByName(DEPS_FREGE_TASK_NAME) instanceof DependencyFregeTask); - assertEquals(SUCCESS, result.task(":" + DEPS_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("frege3.25.84.jar")); - } - - @Test - void given_build_file_config_with_dependencies() throws Exception { - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - appendToFile(buildFile, minimalBuildFileConfig); - appendToFile(buildFile, String.join("\n", "repositories {", "mavenCentral()", "}")); - appendToFile(buildFile, String.join("\n", "dependencies {", - "implementation group: 'org.json', name: 'json', version: '20211205'", "}")); - BuildResult result = runGradleTask(DEPS_FREGE_TASK_NAME, "-q"); - assertTrue(project.getTasks().getByName(DEPS_FREGE_TASK_NAME) instanceof DependencyFregeTask); - assertEquals(SUCCESS, result.task(":" + DEPS_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("frege3.25.84.jar")); - assertTrue(result.getOutput().contains("org.json")); - } - } - - @Nested - @TestInstance(Lifecycle.PER_CLASS) - @IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class) - class Repl_frege_task_works { - @Test - void given_minimal_build_file_config() throws Exception { - String minimalBuildFileConfig = createFregeSection( - fregeBuilder.version("'3.25.84'").release("'3.25alpha'").build()); - appendToFile(buildFile, minimalBuildFileConfig); - - BuildResult result = runGradleTask(REPL_FREGE_TASK_NAME, "-q"); - assertTrue(project.getTasks().getByName(REPL_FREGE_TASK_NAME) instanceof ReplFregeTask); - assertEquals(SUCCESS, result.task(":" + REPL_FREGE_TASK_NAME).getOutcome()); - assertTrue(result.getOutput().contains("java -cp")); - assertTrue(result.getOutput().contains("frege3.25.84.jar")); - } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @IndicativeSentencesGeneration( + separator = " -> ", + generator = DisplayNameGenerator.ReplaceUnderscores.class) + class Repl_frege_task_fails + { + @Test + void given_minimal_build_file_config_without_repl_module() throws Exception + { + String completionFr = "Completion.fr"; + String minimalBuildFileConfig = createFregeSection( + fregeBuilder + .version("'3.25.84'") + .release("'3.25alpha'") + .build()); + setupDefaultFregeProjectStructure( + SIMPLE_FREGE_CODE, + completionFr, + minimalBuildFileConfig); + + BuildResult result = runAndFailGradleTask(REPL_FREGE_TASK_NAME); + + assertTrue( + project.getTasks().getByName(REPL_FREGE_TASK_NAME) + instanceof ReplFregeTask); + assertEquals(FAILED, result.task(":" + COMPILE_FREGE_TASK_NAME).getOutcome()); } + } }
\ No newline at end of file diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/CompileFregeTask.java b/src/main/java/ch/fhnw/thga/gradleplugins/CompileFregeTask.java index e81fe76..bc3c8f7 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/CompileFregeTask.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/CompileFregeTask.java @@ -3,13 +3,16 @@ package ch.fhnw.thga.gradleplugins; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; import org.gradle.api.DefaultTask; +import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileTree; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; @@ -29,6 +32,24 @@ import org.gradle.api.tasks.TaskAction; @CacheableTask public abstract class CompileFregeTask extends DefaultTask { private final JavaExec javaExec; + private static final String FREGE_FILES_GLOB_PATTERN = "**/*.fr"; + private static final BiFunction<String, Directory, FileTree> + excludeReplSourceFile = + (String replSource, + Directory srcDir) -> + { + if (replSource.isEmpty()) return srcDir.getAsFileTree(); + return srcDir.getAsFileTree().matching( + pattern -> + { + pattern.exclude( + String.format( + "**/%s", + replSource) + ); + } + ); + }; @InputFile @PathSensitive(PathSensitivity.RELATIVE) @@ -44,6 +65,9 @@ public abstract class CompileFregeTask extends DefaultTask { @Input public abstract Property<String> getFregeDependencies(); + @Input + public abstract Property<String> getReplSource(); + @OutputDirectory public abstract DirectoryProperty getFregeOutputDir(); @@ -58,9 +82,27 @@ public abstract class CompileFregeTask extends DefaultTask { } @Internal + public final Provider<FileTree> getSourceFileTree() { + return getReplSource().zip( + getFregeMainSourceDir(), + excludeReplSourceFile); + } + + @Internal + public final Provider<List<String>> getSourceFiles() { + return getSourceFileTree() + .map(tree -> tree.matching(pattern -> pattern.include(FREGE_FILES_GLOB_PATTERN))) + .map(tree -> tree.getFiles().stream() + .map(file -> file.getAbsolutePath()) + .collect(Collectors.toList()) + ); + } + + @Internal public final Provider<List<String>> getDependencyArg() { return getFregeDependencies().map(depsClasspath -> { - return depsClasspath.isEmpty() ? Collections.emptyList() : List.of("-fp", depsClasspath); + return depsClasspath.isEmpty() ? Collections.emptyList() + : List.of("-fp", depsClasspath); }); } @@ -69,16 +111,25 @@ public abstract class CompileFregeTask extends DefaultTask { javaExec = objectFactory.newInstance(JavaExec.class); } - private List<String> buildCompilerArgsFromProperties(List<String> directoryArg) { - return Stream - .of(getDependencyArg().get(), getFregeCompilerFlags().get(), directoryArg, getSourcePathArg().get(), - List.of(getFregeMainSourcePath().get())) - .filter(lists -> !lists.isEmpty()).flatMap(Collection::stream).collect(Collectors.toList()); + private List<String> buildCompilerArgsFromProperties(List<String> directoryArg) + { + return Stream.of( + getDependencyArg().get(), + getFregeCompilerFlags().get(), + directoryArg, + getSourcePathArg().get(), + getSourceFiles().get()) + .filter(lists -> !lists.isEmpty()) + .flatMap(Collection::stream) + .collect(Collectors.toList()); } @TaskAction public void compileFrege() { - List<String> directoryArg = List.of("-d", getFregeOutputDir().getAsFile().get().getAbsolutePath()); + List<String> directoryArg = List.of( + "-d", + getFregeOutputDir().getAsFile().get().getAbsolutePath()); + javaExec.setClasspath(getProject().files(getFregeCompilerJar())) .setArgs(buildCompilerArgsFromProperties(directoryArg)).exec(); } diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/FregeExtension.java b/src/main/java/ch/fhnw/thga/gradleplugins/FregeExtension.java index ea02493..5bcbf3d 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/FregeExtension.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/FregeExtension.java @@ -10,9 +10,9 @@ import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; public abstract class FregeExtension { - public static final String DEFAULT_DOWNLOAD_DIRECTORY = "lib"; - public static final String DEFAULT_RELATIVE_OUTPUT_DIR = "classes/main/frege"; - public static final String DEFAULT_RELATIVE_SOURCE_DIR = "src/main/frege"; + public static final String DEFAULT_DOWNLOAD_DIRECTORY = "lib"; + public static final String DEFAULT_RELATIVE_OUTPUT_DIR = "classes/main/frege"; + public static final String DEFAULT_RELATIVE_SOURCE_DIR = "src/main/frege"; public static final List<String> DEFAULT_COMPILER_FLAGS = List.of("-O", "-make"); public abstract Property<String> getVersion(); @@ -29,11 +29,19 @@ public abstract class FregeExtension { public abstract ListProperty<String> getCompilerFlags(); + public abstract Property<String> getReplSource(); + @Inject public FregeExtension(ProjectLayout projectLayout) { - getCompilerDownloadDir().convention(projectLayout.getProjectDirectory().dir(DEFAULT_DOWNLOAD_DIRECTORY)); - getMainSourceDir().convention(projectLayout.getProjectDirectory().dir(DEFAULT_RELATIVE_SOURCE_DIR)); - getOutputDir().convention(projectLayout.getBuildDirectory().dir(DEFAULT_RELATIVE_OUTPUT_DIR)); + getCompilerDownloadDir() + .convention(projectLayout.getProjectDirectory().dir(DEFAULT_DOWNLOAD_DIRECTORY)); + + getMainSourceDir() + .convention(projectLayout.getProjectDirectory().dir(DEFAULT_RELATIVE_SOURCE_DIR)); + + getOutputDir() + .convention(projectLayout.getBuildDirectory().dir(DEFAULT_RELATIVE_OUTPUT_DIR)); + getCompilerFlags().convention(DEFAULT_COMPILER_FLAGS); } } diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/FregePlugin.java b/src/main/java/ch/fhnw/thga/gradleplugins/FregePlugin.java index 18016f3..a318b81 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/FregePlugin.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/FregePlugin.java @@ -3,69 +3,113 @@ package ch.fhnw.thga.gradleplugins; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.file.FileCollection; -import org.gradle.api.file.RegularFile; -import org.gradle.api.provider.Provider; import org.gradle.api.tasks.TaskProvider; import ch.fhnw.thga.gradleplugins.internal.DependencyFregeTask; -public class FregePlugin implements Plugin<Project> { - public static final String SETUP_FREGE_TASK_NAME = "setupFrege"; - public static final String COMPILE_FREGE_TASK_NAME = "compileFrege"; - public static final String RUN_FREGE_TASK_NAME = "runFrege"; - public static final String REPL_FREGE_TASK_NAME = "replFrege"; - public static final String DEPS_FREGE_TASK_NAME = "depsFrege"; - public static final String FREGE_PLUGIN_ID = "ch.fhnw.thga.frege"; - public static final String FREGE_EXTENSION_NAME = "frege"; +public class FregePlugin implements Plugin<Project> +{ + public static final String SETUP_FREGE_TASK_NAME = "setupFrege"; + public static final String COMPILE_FREGE_TASK_NAME = "compileFrege"; + public static final String RUN_FREGE_TASK_NAME = "runFrege"; + public static final String REPL_FREGE_TASK_NAME = "replFrege"; + public static final String DEPS_FREGE_TASK_NAME = "depsFrege"; + public static final String FREGE_PLUGIN_ID = "ch.fhnw.thga.frege"; + public static final String FREGE_EXTENSION_NAME = "frege"; public static final String FREGE_IMPLEMENTATION_SCOPE = "implementation"; - private FileCollection setupClasspath(Project project, Configuration dependencies, - Provider<RegularFile> fregeCompilerJar) { - if (dependencies.isEmpty()) { - return project.files(fregeCompilerJar); - } else { - return project.files(fregeCompilerJar, dependencies.getAsPath()); - } - } - @Override public void apply(Project project) { - Configuration implementation = project.getConfigurations().create(FREGE_IMPLEMENTATION_SCOPE); - FregeExtension extension = project.getExtensions().create(FREGE_EXTENSION_NAME, FregeExtension.class); - TaskProvider<SetupFregeTask> setupFregeCompilerTask = project.getTasks().register(SETUP_FREGE_TASK_NAME, - SetupFregeTask.class, task -> { + Configuration implementation = project + .getConfigurations() + .create(FREGE_IMPLEMENTATION_SCOPE); + + FregeExtension extension = project + .getExtensions() + .create( + FREGE_EXTENSION_NAME, + FregeExtension.class); + + TaskProvider<SetupFregeTask> setupFregeCompilerTask = + project.getTasks().register( + SETUP_FREGE_TASK_NAME, + SetupFregeTask.class, + task -> + { task.getVersion().set(extension.getVersion()); task.getRelease().set(extension.getRelease()); task.getDownloadDir().set(extension.getCompilerDownloadDir()); }); - TaskProvider<CompileFregeTask> compileFregeTask = project.getTasks().register(COMPILE_FREGE_TASK_NAME, - CompileFregeTask.class, task -> { + TaskProvider<CompileFregeTask> compileFregeTask = + project.getTasks().register( + COMPILE_FREGE_TASK_NAME, + CompileFregeTask.class, + task -> + { task.dependsOn(setupFregeCompilerTask); - task.getFregeCompilerJar().set(setupFregeCompilerTask.get().getFregeCompilerOutputPath()); + task.getFregeCompilerJar().set( + setupFregeCompilerTask.get().getFregeCompilerOutputPath()); task.getFregeMainSourceDir().set(extension.getMainSourceDir()); task.getFregeOutputDir().set(extension.getOutputDir()); task.getFregeCompilerFlags().set(extension.getCompilerFlags()); task.getFregeDependencies().set(implementation.getAsPath()); - }); - project.getTasks().register(RUN_FREGE_TASK_NAME, RunFregeTask.class, task -> { - task.dependsOn(compileFregeTask); - task.getFregeCompilerJar().set(setupFregeCompilerTask.get().getFregeCompilerOutputPath()); - task.getFregeOutputDir().set(extension.getOutputDir()); - task.getMainModule().set(extension.getMainModule()); - task.getFregeDependencies().set(implementation.getAsPath()); - }); - project.getTasks().register(DEPS_FREGE_TASK_NAME, - DependencyFregeTask.class, task -> { - task.dependsOn(setupFregeCompilerTask); - task.getClasspath().setFrom(setupClasspath(project, implementation, - setupFregeCompilerTask.get().getFregeCompilerOutputPath())); - }); - project.getTasks().register(REPL_FREGE_TASK_NAME, ReplFregeTask.class, task -> { - task.dependsOn(setupFregeCompilerTask); - task.getFregeClasspath().setFrom(setupClasspath(project, implementation, - setupFregeCompilerTask.get().getFregeCompilerOutputPath())); - }); + task.getReplSource().set(""); + } + ); + + project.getTasks().register( + RUN_FREGE_TASK_NAME, + RunFregeTask.class, + task -> + { + task.dependsOn(compileFregeTask); + task.getFregeCompilerJar().set( + setupFregeCompilerTask.get().getFregeCompilerOutputPath()); + task.getFregeOutputDir().set(extension.getOutputDir()); + task.getMainModule().set(extension.getMainModule()); + task.getFregeDependencies().set(implementation.getAsPath()); + } + ); + + project.getTasks().register( + DEPS_FREGE_TASK_NAME, + DependencyFregeTask.class, + task -> + { + task.dependsOn(compileFregeTask.map( + compileTask -> + { + compileTask.getReplSource().set(task.getReplSource()); + return compileTask; + }) + .get()); + task.dependsOn(compileFregeTask); + task.getFregeCompilerJar().set( + setupFregeCompilerTask.get().getFregeCompilerOutputPath()); + task.getFregeOutputDir().set(extension.getOutputDir()); + task.getFregeDependencies().set(implementation.getAsPath()); + } + ); + + project.getTasks().register( + REPL_FREGE_TASK_NAME, + ReplFregeTask.class, + task -> + { + task.getReplSource().set(extension.getReplSource()); + task.dependsOn(compileFregeTask.map( + compileTask -> + { + compileTask.getReplSource().set(task.getReplSource()); + return compileTask; + }) + .get()); + task.getFregeCompilerJar().set( + setupFregeCompilerTask.get().getFregeCompilerOutputPath()); + task.getFregeOutputDir().set(extension.getOutputDir()); + task.getFregeDependencies().set(implementation.getAsPath()); + } + ); } } diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/ReplFregeTask.java b/src/main/java/ch/fhnw/thga/gradleplugins/ReplFregeTask.java index 81da1cd..dd18270 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/ReplFregeTask.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/ReplFregeTask.java @@ -1,19 +1,43 @@ package ch.fhnw.thga.gradleplugins; import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.tasks.InputFiles; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; public abstract class ReplFregeTask extends DefaultTask { public static final String REPL_MAIN_CLASS = "frege.repl.FregeRepl"; - @InputFiles - public abstract ConfigurableFileCollection getFregeClasspath(); + @InputFile + public abstract RegularFileProperty getFregeCompilerJar(); + + @Input + public abstract Property<String> getFregeDependencies(); + + @InputDirectory + public abstract DirectoryProperty getFregeOutputDir(); + + @Input + @Option(option = "replSource", + description = "The filename which you want to load into the repl, e.g. 'myFregeFile.fr'") + public abstract Property<String> getReplSource(); @TaskAction public void printStartFregeReplCommand() { System.out.println("Execute the following command to start the Frege Repl:"); - System.out.println(String.format("java -cp %s %s", getFregeClasspath().getAsPath(), REPL_MAIN_CLASS)); + System.out.println(String.format( + "java -cp %s %s", + SharedTaskLogic.setupClasspath( + getProject(), + getFregeDependencies(), + getFregeCompilerJar(), + getFregeOutputDir()) + .get().getAsPath(), + REPL_MAIN_CLASS)); } } diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/RunFregeTask.java b/src/main/java/ch/fhnw/thga/gradleplugins/RunFregeTask.java index 41ac2a3..f993af4 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/RunFregeTask.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/RunFregeTask.java @@ -4,17 +4,14 @@ import javax.inject.Inject; import org.gradle.api.DefaultTask; import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.FileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.Property; -import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -30,20 +27,13 @@ public abstract class RunFregeTask extends DefaultTask { public abstract DirectoryProperty getFregeOutputDir(); @Input - @Option(option = "mainModule", description = "The full name of the Frege module with a main function, e.g. 'my.mod.Name'") + @Option(option = "mainModule", + description = "The full name of the Frege module with a main function, e.g. 'my.mod.Name'") public abstract Property<String> getMainModule(); @Input public abstract Property<String> getFregeDependencies(); - @Internal - public final Provider<FileCollection> getClasspath() { - return getFregeDependencies().map(depsClasspath -> { - return depsClasspath.isEmpty() ? getProject().files(getFregeCompilerJar(), getFregeOutputDir()) - : getProject().files(getFregeCompilerJar(), getFregeOutputDir(), depsClasspath); - }); - } - @Inject public RunFregeTask(ObjectFactory objectFactory) { javaExec = objectFactory.newInstance(JavaExec.class); @@ -52,6 +42,12 @@ public abstract class RunFregeTask extends DefaultTask { @TaskAction public void runFrege() { javaExec.getMainClass().set(getMainModule()); - javaExec.setClasspath(getClasspath().get()).exec(); + javaExec.setClasspath( + SharedTaskLogic.setupClasspath( + getProject(), + getFregeDependencies(), + getFregeCompilerJar(), + getFregeOutputDir()) + .get()).exec(); } } diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/SetupFregeTask.java b/src/main/java/ch/fhnw/thga/gradleplugins/SetupFregeTask.java index 1b12f56..6bfe72d 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/SetupFregeTask.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/SetupFregeTask.java @@ -21,9 +21,10 @@ import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; public abstract class SetupFregeTask extends DefaultTask { - public static final Logger LOGGER = Logging.getLogger(SetupFregeTask.class); + public static final Logger LOGGER = Logging.getLogger(SetupFregeTask.class); - private static final String FREGE_GITHUB_URL_PREFIX = "https://github.com/Frege/frege/releases/download"; + private static final String FREGE_GITHUB_URL_PREFIX = + "https://github.com/Frege/frege/releases/download"; @Input public abstract Property<String> getVersion(); diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/SharedTaskLogic.java b/src/main/java/ch/fhnw/thga/gradleplugins/SharedTaskLogic.java new file mode 100644 index 0000000..57af617 --- /dev/null +++ b/src/main/java/ch/fhnw/thga/gradleplugins/SharedTaskLogic.java @@ -0,0 +1,22 @@ +package ch.fhnw.thga.gradleplugins; + +import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; +import org.gradle.api.provider.Provider; +import org.gradle.api.provider.Property; + +public final class SharedTaskLogic { + private SharedTaskLogic() {}; + + public static final Provider<FileCollection> setupClasspath( + Project project, + Property<String> dependencies, + Object... paths) + { + return dependencies.map(depsClasspath -> + { + return depsClasspath.isEmpty() ? project.files(paths) + : project.files(depsClasspath, paths); + }); + } +} diff --git a/src/main/java/ch/fhnw/thga/gradleplugins/internal/DependencyFregeTask.java b/src/main/java/ch/fhnw/thga/gradleplugins/internal/DependencyFregeTask.java index 34b33a2..87f4d2b 100644 --- a/src/main/java/ch/fhnw/thga/gradleplugins/internal/DependencyFregeTask.java +++ b/src/main/java/ch/fhnw/thga/gradleplugins/internal/DependencyFregeTask.java @@ -1,16 +1,41 @@ package ch.fhnw.thga.gradleplugins.internal; import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.tasks.InputFiles; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; + +import ch.fhnw.thga.gradleplugins.SharedTaskLogic; public abstract class DependencyFregeTask extends DefaultTask { - @InputFiles - public abstract ConfigurableFileCollection getClasspath(); + @InputFile + public abstract RegularFileProperty getFregeCompilerJar(); + + @Input + public abstract Property<String> getFregeDependencies(); + + @InputDirectory + public abstract DirectoryProperty getFregeOutputDir(); + + @Input + @Option(option = "replSource", + description = "The filename which you want to load into the repl, e.g. 'myFregeFile.fr'") + public abstract Property<String> getReplSource(); + @TaskAction public void fregeDependencies() { - System.out.println(getClasspath().getAsPath()); + System.out.println( + SharedTaskLogic.setupClasspath( + getProject(), + getFregeDependencies(), + getFregeCompilerJar(), + getFregeOutputDir()) + .get().getAsPath()); } } diff --git a/src/test/java/ch/fhnw/thga/gradleplugins/Builder.java b/src/test/java/ch/fhnw/thga/gradleplugins/Builder.java index 9293e44..df070a2 100644 --- a/src/test/java/ch/fhnw/thga/gradleplugins/Builder.java +++ b/src/test/java/ch/fhnw/thga/gradleplugins/Builder.java @@ -15,5 +15,7 @@ public interface Builder { Builder compilerFlags(String compilerFlags); + Builder replSource(String replSource); + FregeDTO build(); } diff --git a/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTO.java b/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTO.java index a09bd27..e092eac 100644 --- a/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTO.java +++ b/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTO.java @@ -14,9 +14,17 @@ public class FregeDTO { public final String outputDir; public final String mainModule; public final String compilerFlags; - - public FregeDTO(String version, String release, String compilerDownloadDir, String mainSourceDir, - String outputDir, String mainModule, String compilerFlags) { + public final String replSource; + + public FregeDTO( + String version, + String release, + String compilerDownloadDir, + String mainSourceDir, + String outputDir, + String mainModule, + String compilerFlags, + String replSource) { this.version = version; this.release = release; this.compilerDownloadDir = compilerDownloadDir; @@ -24,6 +32,7 @@ public class FregeDTO { this.outputDir = outputDir; this.mainModule = mainModule; this.compilerFlags = compilerFlags; + this.replSource = replSource; } public String getVersion() { @@ -54,6 +63,10 @@ public class FregeDTO { return compilerFlags; } + public String getReplSource() { + return replSource; + } + private String getFieldValue(Field field) { try { return field.get(this).toString(); @@ -67,7 +80,9 @@ public class FregeDTO { return FregeDTO.class.getField(fieldName); } catch (NoSuchFieldException e) { throw new RuntimeException( - String.format("Field %s not found in class %s", e.getMessage(), FregeDTO.class.getName()), + String.format( + "Field %s not found in class %s", + e.getMessage(), FregeDTO.class.getName()), e.getCause()); } } @@ -81,7 +96,8 @@ public class FregeDTO { } private boolean isGetterProperty(Method method) { - return method.getName().startsWith("get") && method.getReturnType().getName().contains("Property"); + return method.getName().startsWith("get") && + method.getReturnType().getName().contains("Property"); } private String stripGetPrefixAndDecapitalize(String s) { @@ -89,9 +105,14 @@ public class FregeDTO { } public String toBuildFile() { - Stream<Method> methods = Arrays.stream(FregeExtension.class.getMethods()); - Stream<Field> fields = methods.filter(m -> isGetterProperty(m)) - .map(m -> stripGetPrefixAndDecapitalize(m.getName())).map(name -> getField(name)); - return fields.filter(f -> !isEmpty(f)).map(f -> toKeyValuePairs(f)).collect(Collectors.joining("\n ")); + Stream<Field> fields = + Arrays.stream(FregeExtension.class.getMethods()) + .filter(m -> isGetterProperty(m)) + .map(m -> stripGetPrefixAndDecapitalize(m.getName())) + .map(name -> getField(name)); + return fields + .filter(f -> !isEmpty(f)) + .map(f -> toKeyValuePairs(f)) + .collect(Collectors.joining("\n ")); } } diff --git a/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTOBuilder.java b/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTOBuilder.java index 910114e..cae01d5 100644 --- a/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTOBuilder.java +++ b/src/test/java/ch/fhnw/thga/gradleplugins/FregeDTOBuilder.java @@ -8,6 +8,7 @@ public final class FregeDTOBuilder implements Builder { private String outputDir = ""; private String mainModule = ""; private String compilerFlags = ""; + private String replSource = ""; private static volatile FregeDTOBuilder instance; @@ -72,7 +73,22 @@ public final class FregeDTOBuilder implements Builder { return this; } + @Override + public Builder replSource(String replSource) + { + this.replSource = replSource; + return this; + } + public FregeDTO build() { - return new FregeDTO(version, release, compilerDownloadDir, mainSourceDir, outputDir, mainModule, compilerFlags); + return new FregeDTO( + version, + release, + compilerDownloadDir, + mainSourceDir, + outputDir, + mainModule, + compilerFlags, + replSource); } } |