From c605eeaf9bca94fb0c6c037f75d81bd8dea5b99f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 2 May 2023 15:18:31 -0700 Subject: [PATCH 01/19] Bugfixes --- .github/workflows/ci.yml | 1 - .../org/lflang/generator/c/CGenerator.java | 12 +-- .../org/lflang/generator/cpp/CppGenerator.kt | 7 +- .../generator/python/PythonGenerator.java | 8 +- .../org/lflang/generator/ts/TSGenerator.kt | 2 +- org.lflang/src/org/lflang/util/FileUtil.java | 94 +++++++------------ 6 files changed, 45 insertions(+), 79 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6dd56ae40..c2e1513fe7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,6 @@ jobs: with: target: 'C' benchmarks-ref: main - compiler-ref: master needs: cancel # Run language server tests. diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index fbedb23253..bbd0007961 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -883,7 +883,7 @@ private void generateReactorDefinitions() throws IOException { /** Generate user-visible header files for all reactors instantiated. */ private void generateHeaders() throws IOException { FileUtil.deleteDirectory(fileConfig.getIncludePath()); - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( fileConfig.getRuntimeIncludePath(), fileConfig.getIncludePath(), false @@ -962,12 +962,12 @@ protected void copyTargetFiles() throws IOException { if (coreLib != null) { FileUtil.copyDirectory(Path.of(coreLib), dest, true); } else { - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/c/reactor-c/core", dest.resolve("core"), true ); - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/c/reactor-c/lib", dest.resolve("lib"), true @@ -976,18 +976,18 @@ protected void copyTargetFiles() throws IOException { // For the Zephyr target, copy default config and board files. if (targetConfig.platformOptions.platform == Platform.ZEPHYR) { - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath().resolve("boards"), false ); - FileUtil.copyFileFromClassPath( + FileUtil.copyFromClassPath( "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath().resolve("prj_lf.conf"), true ); - FileUtil.copyFileFromClassPath( + FileUtil.copyFromClassPath( "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath().resolve("Kconfig"), true diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index 5001fe9ac7..805846caec 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -27,7 +27,6 @@ package org.lflang.generator.cpp import org.eclipse.emf.ecore.resource.Resource -import org.lflang.ErrorReporter import org.lflang.Target import org.lflang.generator.CodeMap import org.lflang.generator.GeneratorBase @@ -127,9 +126,9 @@ class CppGenerator( // copy static library files over to the src-gen directory val genIncludeDir = srcGenPath.resolve("__include__") listOf("lfutil.hh", "time_parser.hh").forEach { - FileUtil.copyFileFromClassPath("$libDir/$it", genIncludeDir.resolve(it), true) + FileUtil.copyFromClassPath("$libDir/$it", genIncludeDir.resolve(it), true) } - FileUtil.copyFileFromClassPath( + FileUtil.copyFromClassPath( "$libDir/3rd-party/cxxopts.hpp", genIncludeDir.resolve("CLI").resolve("cxxopts.hpp"), true @@ -140,7 +139,7 @@ class CppGenerator( if (targetConfig.runtimeVersion != null) { fetchReactorCpp() } else { - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "$libDir/reactor-cpp", fileConfig.srcGenBasePath.resolve("reactor-cpp-default"), true diff --git a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java index 020954be80..361e06e285 100644 --- a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java +++ b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java @@ -35,7 +35,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.xbase.lib.Exceptions; @@ -56,7 +55,6 @@ import org.lflang.generator.c.CGenerator; import org.lflang.generator.c.CUtil; import org.lflang.lf.Action; -import org.lflang.lf.Code; import org.lflang.lf.Input; import org.lflang.lf.Model; import org.lflang.lf.Output; @@ -661,17 +659,17 @@ private static String generatePythonFileName(String lfModuleName) { @Override protected void copyTargetFiles() throws IOException { super.copyTargetFiles(); - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/include", fileConfig.getSrcGenPath().resolve("include"), true ); - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/lib", fileConfig.getSrcGenPath().resolve("lib"), true ); - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/LinguaFrancaBase", fileConfig.getSrcGenPath().resolve("LinguaFrancaBase"), true diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index bd92a144ce..0514a46a9c 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -235,7 +235,7 @@ class TSGenerator( "No '" + configFile + "' exists in " + fileConfig.srcPath + ". Using default configuration." ) - FileUtil.copyFileFromClassPath("$LIB_PATH/$configFile", configFileDest) + FileUtil.copyFromClassPath("$LIB_PATH/$configFile", configFileDest, true) } } } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index a2cfb81e4d..746835f7cb 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -38,7 +38,6 @@ import org.lflang.ErrorReporter; import org.lflang.FileConfig; -import org.lflang.generator.LFGeneratorContext; public class FileUtil { @@ -262,27 +261,26 @@ public static void copyFiles( var found = FileUtil.findInPackage(path, fileConfig); if (found != null) { try { - FileUtil.copyFileOrDirectory(found, destination.resolve(found.getFileName())); + FileUtil.copyFromFileSystem(found, destination.resolve(path.getFileName())); + System.out.println("Copied '" + fileOrDirectory + "' from the file system."); } catch (IOException e) { errorReporter.reportError( "Unable to copy '" + fileOrDirectory + "' from the file system." ); } } else { - // Attempt to copy from the classpath instead. - // If the filename is not a directory, it will - // just be copied without further recursion. try { - FileUtil.copyDirectoryFromClassPath( + FileUtil.copyFromClassPath( fileOrDirectory, destination, false ); - } catch (IOException e) { + } catch(IOException e) { errorReporter.reportError( "Unable to copy '" + fileOrDirectory + "' from the class path." ); } + System.out.println("Copied '" + fileOrDirectory + "' from the class path."); } } } @@ -294,7 +292,7 @@ public static void copyFiles( * @param destination A directory to copy the file(s) at the source to. * @throws IOException */ - public static void copyFileOrDirectory(Path source, Path destination) throws IOException { + public static void copyFromFileSystem(Path source, Path destination) throws IOException { if (Files.isDirectory(source)) { copyDirectory(source, destination); } else if (Files.isRegularFile(source)) { @@ -315,60 +313,26 @@ public static void copyFileOrDirectory(Path source, Path destination) throws IOE * @throws IOException if copy fails. */ private static void copyInputStream(InputStream source, Path destination, boolean skipIfUnchanged) throws IOException { - Files.createDirectories(destination.getParent()); - // Read the stream once and keep a copy of all bytes. This is required as a stream cannot be read twice. final var bytes = source.readAllBytes(); - // abort if the destination file does not change - if(skipIfUnchanged && Files.isRegularFile(destination)) { - if (Arrays.equals(bytes, Files.readAllBytes(destination))) { - return; + final var parent = destination.getParent(); + if (Files.isRegularFile(destination)) { + if (skipIfUnchanged) { + if (Arrays.equals(bytes, Files.readAllBytes(destination))) { + // Abort if the file contents are the same. + return; + } + } else { + // Delete the file exists but the contents don't match. + Files.delete(destination); } + } else if (!Files.exists(parent)) { + Files.createDirectories(parent); } Files.write(destination, bytes); } - /** - * Lookup a file in the classpath and copy its contents to a destination path - * in the filesystem. - * - * This also creates new directories for any directories on the destination - * path that do not yet exist. - * - * @param source The source file as a path relative to the classpath. - * @param destination The file system path that the source file is copied to. - * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed - * @throws IOException If the given source cannot be copied. - */ - public static void copyFileFromClassPath(final String source, final Path destination, final boolean skipIfUnchanged) throws IOException { - InputStream sourceStream = FileConfig.class.getResourceAsStream(source); - - // Copy the file. - if (sourceStream == null) { - throw new TargetResourceNotFoundException(source); - } else { - try (sourceStream) { - copyInputStream(sourceStream, destination, skipIfUnchanged); - } - } - } - - /** - * Lookup a file in the classpath and copy its contents to a destination path - * in the filesystem. - * - * This also creates new directories for any directories on the destination - * path that do not yet exist. - * - * @param source The source file as a path relative to the classpath. - * @param destination The file system path that the source file is copied to. - * @throws IOException If the given source cannot be copied. - */ - public static void copyFileFromClassPath(final String source, final Path destination) throws IOException { - copyFileFromClassPath(source, destination, false); - } - /** * Lookup a directory in the classpath and copy its contents to a destination path * in the filesystem. @@ -381,22 +345,27 @@ public static void copyFileFromClassPath(final String source, final Path destina * @param skipIfUnchanged If true, don't overwrite the file if its content would not be changed * @throws IOException If the given source cannot be copied. */ - public static void copyDirectoryFromClassPath(final String source, final Path destination, final boolean skipIfUnchanged) throws IOException { + public static void copyFromClassPath(final String source, final Path destination, final boolean skipIfUnchanged) throws IOException { final URL resource = FileConfig.class.getResource(source); + if (resource == null) { throw new TargetResourceNotFoundException(source); } final URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { - boolean copiedFiles = copyDirectoryFromJar((JarURLConnection) connection, destination, skipIfUnchanged); + boolean copiedFiles = copyFromJar((JarURLConnection) connection, destination, skipIfUnchanged); if (!copiedFiles) { throw new TargetResourceNotFoundException(source); } } else { try { Path dir = Paths.get(FileLocator.toFileURL(resource).toURI()); - copyDirectory(dir, destination, skipIfUnchanged); + if (dir.toFile().isDirectory()) { + copyFile(dir, destination, skipIfUnchanged); + } else { + copyDirectory(dir, destination, skipIfUnchanged); + } } catch(URISyntaxException e) { // This should never happen as toFileURL should always return a valid URL throw new IOException("Unexpected error while resolving " + source + " on the classpath"); @@ -418,7 +387,7 @@ public static void copyDirectoryFromClassPath(final String source, final Path de * @return true if any files were copied * @throws IOException If the given source cannot be copied. */ - private static boolean copyDirectoryFromJar(JarURLConnection connection, final Path destination, final boolean skipIfUnchanged) throws IOException { + private static boolean copyFromJar(JarURLConnection connection, final Path destination, final boolean skipIfUnchanged) throws IOException { final JarFile jar = connection.getJarFile(); final String connectionEntryName = connection.getEntryName(); @@ -431,9 +400,10 @@ private static boolean copyDirectoryFromJar(JarURLConnection connection, final P // Extract files only if they match the given source path. if (entryName.startsWith(connectionEntryName)) { - String filename = entryName.equals(connectionEntryName) ? - connectionEntryName : - entryName.substring(connectionEntryName.length() + 1); + // Gobble up the separator only if there is one. + String filename = entryName.equals(connectionEntryName) ? entryName : + entry.getName().substring(connectionEntryName.length() + 1); + Path currentFile = destination.resolve(filename); if (entry.isDirectory()) { Files.createDirectories(currentFile); @@ -610,7 +580,7 @@ public static Path findInPackage(Path fileOrDirectory, FileConfig fileConfig) { loc -> Files.exists(loc.resolve(relPath)) ).findFirst(); if (found.isPresent()) { - return found.get().resolve(relPath); + return found.get().resolve(relPath).toAbsolutePath(); } } return null; From c8c2bf08dd6209dad3da2cb88c33225879f81d1f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 2 May 2023 23:24:20 -0700 Subject: [PATCH 02/19] More fixes --- org.lflang/src/org/lflang/util/FileUtil.java | 48 ++++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index 746835f7cb..2cb66d6c67 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -261,7 +261,7 @@ public static void copyFiles( var found = FileUtil.findInPackage(path, fileConfig); if (found != null) { try { - FileUtil.copyFromFileSystem(found, destination.resolve(path.getFileName())); + FileUtil.copyFromFileSystem(found, destination); System.out.println("Copied '" + fileOrDirectory + "' from the file system."); } catch (IOException e) { errorReporter.reportError( @@ -296,7 +296,7 @@ public static void copyFromFileSystem(Path source, Path destination) throws IOEx if (Files.isDirectory(source)) { copyDirectory(source, destination); } else if (Files.isRegularFile(source)) { - copyFile(source, destination); + copyFile(source, destination.resolve(source.getFileName())); // FIXME: should copyFile have the same API and have a directory as the second argument? } else { throw new IllegalArgumentException("Source is neither a directory nor a regular file."); } @@ -360,11 +360,11 @@ public static void copyFromClassPath(final String source, final Path destination } } else { try { - Path dir = Paths.get(FileLocator.toFileURL(resource).toURI()); - if (dir.toFile().isDirectory()) { - copyFile(dir, destination, skipIfUnchanged); + Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); + if (path.toFile().isDirectory()) { + copyDirectory(path, destination, skipIfUnchanged); } else { - copyDirectory(dir, destination, skipIfUnchanged); + copyFile(path, destination.resolve(path.getFileName()), skipIfUnchanged); } } catch(URISyntaxException e) { // This should never happen as toFileURL should always return a valid URL @@ -373,6 +373,26 @@ public static void copyFromClassPath(final String source, final Path destination } } + /** + * Return true if the given connection points to a file. + * @param connection A connection to a JAR file. + * @throws IOException If the connection is faulty. + */ + private static boolean isFileInJar(JarURLConnection connection) throws IOException { + return connection.getJarFile().stream().filter( + it -> it.getName().equals(connection.getEntryName()) + ).findFirst().isPresent(); + } + + private static void copyFileFromJar(JarFile jar, String source, Path destination, boolean skipIfUnchanged) throws IOException { + var entry = jar.getJarEntry(source); + var filename = Paths.get(entry.getName()).getFileName(); + InputStream is = jar.getInputStream(entry); + try (is) { + copyInputStream(is, destination.resolve(filename), skipIfUnchanged); + } + } + /** * Copy a directory from a jar to a destination path in the filesystem. * @@ -389,7 +409,12 @@ public static void copyFromClassPath(final String source, final Path destination */ private static boolean copyFromJar(JarURLConnection connection, final Path destination, final boolean skipIfUnchanged) throws IOException { final JarFile jar = connection.getJarFile(); - final String connectionEntryName = connection.getEntryName(); + final String source = connection.getEntryName(); + + if (isFileInJar(connection)) { + copyFileFromJar(jar, source, destination, skipIfUnchanged); + return true; + } boolean copiedFiles = false; @@ -397,13 +422,8 @@ private static boolean copyFromJar(JarURLConnection connection, final Path desti for (Enumeration e = jar.entries(); e.hasMoreElements(); ) { final JarEntry entry = e.nextElement(); final String entryName = entry.getName(); - - // Extract files only if they match the given source path. - if (entryName.startsWith(connectionEntryName)) { - // Gobble up the separator only if there is one. - String filename = entryName.equals(connectionEntryName) ? entryName : - entry.getName().substring(connectionEntryName.length() + 1); - + if (entryName.startsWith(source)) { + String filename = entry.getName().substring(source.length() + 1); Path currentFile = destination.resolve(filename); if (entry.isDirectory()) { Files.createDirectories(currentFile); From b0de39de9b16a4d6e92b20ee105eea13e484ef65 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 3 May 2023 12:49:27 -0700 Subject: [PATCH 03/19] Clarifications in docs and API --- .../org/lflang/generator/GeneratorBase.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 6 +- .../org/lflang/generator/rust/RustEmitter.kt | 2 +- org.lflang/src/org/lflang/util/FileUtil.java | 77 ++++++++++--------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 15d703bcbf..992ce5e1a5 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -350,7 +350,7 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - FileUtil.copyFiles(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); + FileUtil.copyFilesOrDirectories(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); } /** diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index bbd0007961..8bc7566608 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -830,7 +830,7 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - FileUtil.copyFiles(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); + FileUtil.copyFilesOrDirectories(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { @@ -904,7 +904,7 @@ private void generateHeaders() throws IOException { }, this::generateTopLevelPreambles); } - FileUtil.copyDirectory(fileConfig.getIncludePath(), fileConfig.getSrcGenPath().resolve("include"), false); + FileUtil.copyDirectoryContents(fileConfig.getIncludePath(), fileConfig.getSrcGenPath().resolve("include"), false); } /** @@ -960,7 +960,7 @@ protected void copyTargetFiles() throws IOException { Path dest = fileConfig.getSrcGenPath(); if (targetConfig.platformOptions.platform == Platform.ARDUINO) dest = dest.resolve("src"); if (coreLib != null) { - FileUtil.copyDirectory(Path.of(coreLib), dest, true); + FileUtil.copyDirectoryContents(Path.of(coreLib), dest, true); } else { FileUtil.copyFromClassPath( "/lib/c/reactor-c/core", diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 7a36bce23e..525acd3dc3 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -73,7 +73,7 @@ object RustEmitter : RustEmitterBase() { for (modPath in gen.crate.modulesToIncludeInMain) { val target = fileConfig.srcGenPath.resolve("src").resolve(modPath.fileName) if (Files.isDirectory(modPath)) { - FileUtil.copyDirectory(modPath, target) + FileUtil.copyDirectoryContents(modPath, target) } else { FileUtil.copyFile(modPath, target) } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index 2cb66d6c67..bec2118ecf 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -163,17 +163,16 @@ public static java.net.URI locateFile(String path, Resource resource) { } /** - * Recursively copies the contents of the given 'src' - * directory to 'dest'. Existing files of the destination - * may be overwritten. + * Recursively copy the contents of the given 'srcDir' into the given 'dstDir'. + * Existing files of the destination may be overwritten. * - * @param src The source directory path. - * @param dest The destination directory path. + * @param srcDir The source directory path. + * @param dstDir The destination directory path. * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed * @throws IOException if copy fails. */ - public static void copyDirectory(final Path src, final Path dest, final boolean skipIfUnchanged) throws IOException { - try (Stream stream = Files.walk(src)) { + public static void copyDirectoryContents(final Path srcDir, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + try (Stream stream = Files.walk(srcDir)) { stream.forEach(source -> { // Handling checked exceptions in lambda expressions is // hard. See @@ -182,7 +181,7 @@ public static void copyDirectory(final Path src, final Path dest, final boolean // here. if (Files.isRegularFile(source)) { // do not copy directories try { - Path target = dest.resolve(src.relativize(source)); + Path target = dstDir.resolve(srcDir.relativize(source)); Files.createDirectories(target.getParent()); copyFile(source, target, skipIfUnchanged); } catch (IOException e) { @@ -195,68 +194,72 @@ public static void copyDirectory(final Path src, final Path dest, final boolean } } + public static void copyDirectory(final Path srcDir, final Path dstDir) throws IOException { + copyDirectoryContents(srcDir, dstDir.resolve(srcDir.getFileName()), false); + } + /** - * Recursively copies the contents of the given 'src' - * directory to 'dest'. Existing files of the destination - * may be overwritten. + * Recursively copy the contents of the given 'srcDir' + * to 'dstDir'. + * Existing files of the destination may be overwritten. * - * @param src The source directory path. - * @param dest The destination directory path. + * @param srcDir The directory to copy files from. + * @param dstDir The directory to copy files to. * @throws IOException if copy fails. */ - public static void copyDirectory(final Path src, final Path dest) throws IOException { - copyDirectory(src, dest, false); + public static void copyDirectoryContents(final Path srcDir, final Path dstDir) throws IOException { + copyDirectoryContents(srcDir, dstDir, false); } /** - * Copy a given file from 'source' to 'destination'. + * Copy a given file from 'srcFile' to 'dstFile'. * - * This also creates new directories for any directories on the destination - * path that do not yet exist. + * This also creates new directories for any directories + * on the path to `dstFile` that do not yet exist. * - * @param source The source file path. - * @param destination The destination file path. + * @param srcFile The source file path. + * @param dstFile The destination file path. * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed * @throws IOException if copy fails. */ - public static void copyFile(Path source, Path destination, boolean skipIfUnchanged) throws IOException { - BufferedInputStream stream = new BufferedInputStream(new FileInputStream(source.toFile())); + public static void copyFile(Path srcFile, Path dstFile, boolean skipIfUnchanged) throws IOException { + BufferedInputStream stream = new BufferedInputStream(new FileInputStream(srcFile.toFile())); try (stream) { - copyInputStream(stream, destination, skipIfUnchanged); + copyInputStream(stream, dstFile, skipIfUnchanged); } } /** - * Copy a given file from 'source' to 'destination'. + * Copy a 'srcFile' to 'dstFile'. * - * This also creates new directories for any directories on the destination - * path that do not yet exist. + * This also creates new directories for any directories + * on the path to `dstFile` that do not yet exist. * - * @param source The source file path. - * @param destination The destination file path. + * @param srcFile The source file path. + * @param dstFile The destination file path. * @throws IOException if copy fails. */ - public static void copyFile(Path source, Path destination) throws IOException { - copyFile(source, destination, false); + public static void copyFile(Path srcFile, Path dstFile) throws IOException { + copyFile(srcFile, dstFile, false); } /** * Given a list of files or directories, attempt to find them based on the given generator - * context, and copy then to the destination. Files are searched for in the file system first. - * Files that cannot be found in the file system are looked for on the class path. + * context, and copy them to the destination. Entries are searched for in the file system first. + * Entries that cannot be found in the file system are looked for on the class path. * - * @param filesOrDirectories The files or directories to copy. + * @param entries The files or directories to copy. * @param destination The location to copy them to. * @param fileConfig The file configuration that specifies where the files must be found. * @param errorReporter An error reporter to report problems. */ - public static void copyFiles( - List filesOrDirectories, + public static void copyFilesOrDirectories( + List entries, Path destination, FileConfig fileConfig, ErrorReporter errorReporter ) { - for (String fileOrDirectory : filesOrDirectories) { + for (String fileOrDirectory : entries) { var path = Paths.get(fileOrDirectory); var found = FileUtil.findInPackage(path, fileConfig); if (found != null) { @@ -362,7 +365,7 @@ public static void copyFromClassPath(final String source, final Path destination try { Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); if (path.toFile().isDirectory()) { - copyDirectory(path, destination, skipIfUnchanged); + copyDirectoryContents(path, destination, skipIfUnchanged); } else { copyFile(path, destination.resolve(path.getFileName()), skipIfUnchanged); } From 931ed6c003b9dd2d9b5b7a835997f215207e0284 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 3 May 2023 13:26:15 -0700 Subject: [PATCH 04/19] Fix and simplify TS file dealings --- .../org/lflang/generator/ts/TSGenerator.kt | 29 ++++--------------- org.lflang/src/org/lflang/util/FileUtil.java | 24 +++++++-------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 0514a46a9c..7e11b6597a 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -38,7 +38,6 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path -import java.nio.file.StandardCopyOption import java.util.* private const val NO_NPM_MESSAGE = "The TypeScript target requires npm >= 6.14.4. " + @@ -61,19 +60,13 @@ class TSGenerator( val fileConfig: TSFileConfig = context.fileConfig as TSFileConfig - var devMode = false; + private var devMode = false companion object { /** Path to the TS lib directory (relative to class path) */ const val LIB_PATH = "/lib/ts" - /** - * Names of the configuration files to check for and copy to the generated - * source package root if they cannot be found in the source directory. - */ - val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", ".eslintrc.json") - const val RUNTIME_URL = "git://github.com/lf-lang/reactor-ts.git" fun timeInTargetLanguage(value: TimeValue): String { @@ -223,21 +216,11 @@ class TSGenerator( * as the source file, copy a default version from $LIB_PATH/. */ private fun copyConfigFiles() { - for (configFile in CONFIG_FILES) { - val configFileDest = fileConfig.srcGenPath.resolve(configFile) - val configFileInSrc = fileConfig.srcPath.resolve(configFile) - if (configFileInSrc.toFile().exists()) { - println("Copying $configFileInSrc to $configFileDest") - Files.createDirectories(configFileDest.parent) - Files.copy(configFileInSrc, configFileDest, StandardCopyOption.REPLACE_EXISTING) - } else { - println( - "No '" + configFile + "' exists in " + fileConfig.srcPath + - ". Using default configuration." - ) - FileUtil.copyFromClassPath("$LIB_PATH/$configFile", configFileDest, true) - } - } + FileUtil.copyFromClassPath( + LIB_PATH, + fileConfig.srcGenPath, + true + ) } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index bec2118ecf..aff553c28e 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -337,41 +337,41 @@ private static void copyInputStream(InputStream source, Path destination, boolea } /** - * Lookup a directory in the classpath and copy its contents to a destination path - * in the filesystem. + * Look up the given entry in the classpath. If it is a file, copy it into the destination + * directory. If it is a directory, copy its contents to the destination directory. * * This also creates new directories for any directories on the destination * path that do not yet exist. * - * @param source The source directory as a path relative to the classpath. - * @param destination The file system path that the source directory is copied to. + * @param entry The entry to be found on the class path and copied to the given destination. + * @param dstDir The file system path that found files are to be copied to. * @param skipIfUnchanged If true, don't overwrite the file if its content would not be changed * @throws IOException If the given source cannot be copied. */ - public static void copyFromClassPath(final String source, final Path destination, final boolean skipIfUnchanged) throws IOException { - final URL resource = FileConfig.class.getResource(source); + public static void copyFromClassPath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + final URL resource = FileConfig.class.getResource(entry); if (resource == null) { - throw new TargetResourceNotFoundException(source); + throw new TargetResourceNotFoundException(entry); } final URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { - boolean copiedFiles = copyFromJar((JarURLConnection) connection, destination, skipIfUnchanged); + boolean copiedFiles = copyFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged); if (!copiedFiles) { - throw new TargetResourceNotFoundException(source); + throw new TargetResourceNotFoundException(entry); } } else { try { Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); if (path.toFile().isDirectory()) { - copyDirectoryContents(path, destination, skipIfUnchanged); + copyDirectoryContents(path, dstDir, skipIfUnchanged); } else { - copyFile(path, destination.resolve(path.getFileName()), skipIfUnchanged); + copyFile(path, dstDir.resolve(path.getFileName()), skipIfUnchanged); } } catch(URISyntaxException e) { // This should never happen as toFileURL should always return a valid URL - throw new IOException("Unexpected error while resolving " + source + " on the classpath"); + throw new IOException("Unexpected error while resolving " + entry + " on the classpath"); } } } From d2e09ae8ea8203bf1462965f2702a9e2969b1990 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 3 May 2023 13:28:06 -0700 Subject: [PATCH 05/19] Remove FIXME associated with closed issue --- org.lflang/src/org/lflang/generator/ts/TSGenerator.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 7e11b6597a..7776c21d76 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -181,8 +181,6 @@ class TSGenerator( val manifest = fileConfig.srcGenPath.resolve("package.json"); val rtRegex = Regex("(\"@lf-lang/reactor-ts\")(.+)") if (rtPath != null) rtPath = formatRuntimePath(rtPath) - // FIXME: do better CLI arg validation upstream - // https://github.com/lf-lang/lingua-franca/issues/1429 if (rtPath != null || rtVersion != null) { devMode = true; } From 02311338f630d0eb839119a387e120375091b27e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 3 May 2023 16:04:12 -0700 Subject: [PATCH 06/19] Get the Cpp tests to compile again --- .../org/lflang/generator/GeneratorBase.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 2 +- .../org/lflang/generator/cpp/CppGenerator.kt | 4 ++-- org.lflang/src/org/lflang/util/FileUtil.java | 23 ++++++++++++++----- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 992ce5e1a5..01a86b6d96 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -350,7 +350,7 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - FileUtil.copyFilesOrDirectories(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); + FileUtil.copyFilesOrDirectoryContents(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); } /** diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 8bc7566608..79349efe6d 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -830,7 +830,7 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - FileUtil.copyFilesOrDirectories(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); + FileUtil.copyFilesOrDirectoryContents(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index 805846caec..de600900bb 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -126,11 +126,11 @@ class CppGenerator( // copy static library files over to the src-gen directory val genIncludeDir = srcGenPath.resolve("__include__") listOf("lfutil.hh", "time_parser.hh").forEach { - FileUtil.copyFromClassPath("$libDir/$it", genIncludeDir.resolve(it), true) + FileUtil.copyFromClassPath("$libDir/$it", genIncludeDir, true) } FileUtil.copyFromClassPath( "$libDir/3rd-party/cxxopts.hpp", - genIncludeDir.resolve("CLI").resolve("cxxopts.hpp"), + genIncludeDir.resolve("CLI"), true ) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index aff553c28e..ed945a5a37 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -253,7 +253,7 @@ public static void copyFile(Path srcFile, Path dstFile) throws IOException { * @param fileConfig The file configuration that specifies where the files must be found. * @param errorReporter An error reporter to report problems. */ - public static void copyFilesOrDirectories( + public static void copyFilesOrDirectoryContents( List entries, Path destination, FileConfig fileConfig, @@ -297,9 +297,9 @@ public static void copyFilesOrDirectories( */ public static void copyFromFileSystem(Path source, Path destination) throws IOException { if (Files.isDirectory(source)) { - copyDirectory(source, destination); + copyDirectoryContents(source, destination); } else if (Files.isRegularFile(source)) { - copyFile(source, destination.resolve(source.getFileName())); // FIXME: should copyFile have the same API and have a directory as the second argument? + copyFile(source, destination.resolve(source.getFileName())); } else { throw new IllegalArgumentException("Source is neither a directory nor a regular file."); } @@ -329,6 +329,8 @@ private static void copyInputStream(InputStream source, Path destination, boolea // Delete the file exists but the contents don't match. Files.delete(destination); } + } else if (Files.isDirectory(destination)) { + deleteDirectory(destination); } else if (!Files.exists(parent)) { Files.createDirectories(parent); } @@ -387,12 +389,12 @@ private static boolean isFileInJar(JarURLConnection connection) throws IOExcepti ).findFirst().isPresent(); } - private static void copyFileFromJar(JarFile jar, String source, Path destination, boolean skipIfUnchanged) throws IOException { - var entry = jar.getJarEntry(source); + private static void copyFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { + var entry = jar.getJarEntry(srcFile); var filename = Paths.get(entry.getName()).getFileName(); InputStream is = jar.getInputStream(entry); try (is) { - copyInputStream(is, destination.resolve(filename), skipIfUnchanged); + copyInputStream(is, dstDir.resolve(filename), skipIfUnchanged); } } @@ -553,6 +555,15 @@ public static void relativeIncludeHelper(Path dir, Path includePath) throws IOEx } } + public static void delete(Path fileOrDirectory) throws IOException { + if (Files.isRegularFile(fileOrDirectory)) { + Files.deleteIfExists(fileOrDirectory); + } + if (Files.isDirectory(fileOrDirectory)) { + deleteDirectory(fileOrDirectory); + } + } + /** * Recursively delete a directory if it exists. * From c77388e9d5a88e8acd5b16c279d7b81a5e505a5d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 3 May 2023 16:22:54 -0700 Subject: [PATCH 07/19] Fix Zephyr tests --- org.lflang/src/org/lflang/generator/c/CGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 79349efe6d..962ba6cfda 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -983,13 +983,13 @@ protected void copyTargetFiles() throws IOException { ); FileUtil.copyFromClassPath( "/lib/platform/zephyr/prj_lf.conf", - fileConfig.getSrcGenPath().resolve("prj_lf.conf"), + fileConfig.getSrcGenPath(), true ); FileUtil.copyFromClassPath( "/lib/platform/zephyr/Kconfig", - fileConfig.getSrcGenPath().resolve("Kconfig"), + fileConfig.getSrcGenPath(), true ); } From 71ed7af63749a03d06b5247161fe80c9fe61f00f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 13:40:26 -0700 Subject: [PATCH 08/19] Ready for CI run. Docs and cleanup will follow --- .../org/lflang/generator/GeneratorBase.java | 7 +- .../org/lflang/generator/c/CGenerator.java | 23 ++- .../org/lflang/generator/cpp/CppGenerator.kt | 8 +- .../generator/python/PythonGenerator.java | 15 +- .../org/lflang/generator/ts/TSGenerator.kt | 1 + org.lflang/src/org/lflang/util/FileUtil.java | 155 +++++++++++++----- 6 files changed, 149 insertions(+), 60 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 01a86b6d96..407b1c501a 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -350,7 +350,12 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - FileUtil.copyFilesOrDirectoryContents(targetConfig.files, this.context.getFileConfig().getSrcGenPath(), fileConfig, errorReporter); + FileUtil.copyFilesOrDirectories( + targetConfig.files, + this.context.getFileConfig().getSrcGenPath(), + fileConfig, + errorReporter, + false); } /** diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 962ba6cfda..6ec5e80226 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -830,7 +830,8 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - FileUtil.copyFilesOrDirectoryContents(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter); + // NOTE: All entries should be files, but we are not checking this. + FileUtil.copyFilesOrDirectories(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter, true); // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { @@ -886,7 +887,8 @@ private void generateHeaders() throws IOException { FileUtil.copyFromClassPath( fileConfig.getRuntimeIncludePath(), fileConfig.getIncludePath(), - false + false, + true ); for (Reactor r : reactors) { CReactorHeaderFileGenerator.doGenerate( @@ -964,13 +966,15 @@ protected void copyTargetFiles() throws IOException { } else { FileUtil.copyFromClassPath( "/lib/c/reactor-c/core", - dest.resolve("core"), - true + dest, + true, + false ); FileUtil.copyFromClassPath( "/lib/c/reactor-c/lib", - dest.resolve("lib"), - true + dest, + true, + false ); } @@ -978,16 +982,17 @@ protected void copyTargetFiles() throws IOException { if (targetConfig.platformOptions.platform == Platform.ZEPHYR) { FileUtil.copyFromClassPath( "/lib/platform/zephyr/boards", - fileConfig.getSrcGenPath().resolve("boards"), + fileConfig.getSrcGenPath(), + false, false ); - FileUtil.copyFromClassPath( + FileUtil.copySingleFileFromClasspath( "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath(), true ); - FileUtil.copyFromClassPath( + FileUtil.copySingleFileFromClasspath( "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index de600900bb..60b450d2c2 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -126,13 +126,12 @@ class CppGenerator( // copy static library files over to the src-gen directory val genIncludeDir = srcGenPath.resolve("__include__") listOf("lfutil.hh", "time_parser.hh").forEach { - FileUtil.copyFromClassPath("$libDir/$it", genIncludeDir, true) + FileUtil.copySingleFileFromClasspath("$libDir/$it", genIncludeDir, true) } - FileUtil.copyFromClassPath( + FileUtil.copySingleFileFromClasspath( "$libDir/3rd-party/cxxopts.hpp", genIncludeDir.resolve("CLI"), - true - ) + true) // copy or download reactor-cpp if (targetConfig.externalRuntimePath == null) { @@ -142,6 +141,7 @@ class CppGenerator( FileUtil.copyFromClassPath( "$libDir/reactor-cpp", fileConfig.srcGenBasePath.resolve("reactor-cpp-default"), + true, true ) } diff --git a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java index 361e06e285..2686c98539 100644 --- a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java +++ b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java @@ -661,18 +661,21 @@ protected void copyTargetFiles() throws IOException { super.copyTargetFiles(); FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/include", - fileConfig.getSrcGenPath().resolve("include"), - true + fileConfig.getSrcGenPath(), + true, + false ); FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/lib", - fileConfig.getSrcGenPath().resolve("lib"), - true + fileConfig.getSrcGenPath(), + true, + false ); FileUtil.copyFromClassPath( "/lib/py/reactor-c-py/LinguaFrancaBase", - fileConfig.getSrcGenPath().resolve("LinguaFrancaBase"), - true + fileConfig.getSrcGenPath(), + true, + false ); } diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 7776c21d76..49dd3444e1 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -217,6 +217,7 @@ class TSGenerator( FileUtil.copyFromClassPath( LIB_PATH, fileConfig.srcGenPath, + true, true ) } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index ed945a5a37..bbd4a5439f 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -194,8 +194,8 @@ public static void copyDirectoryContents(final Path srcDir, final Path dstDir, f } } - public static void copyDirectory(final Path srcDir, final Path dstDir) throws IOException { - copyDirectoryContents(srcDir, dstDir.resolve(srcDir.getFileName()), false); + public static void copyDirectory(final Path srcDir, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + copyDirectoryContents(srcDir, dstDir.resolve(srcDir.getFileName()), skipIfUnchanged); } /** @@ -243,28 +243,30 @@ public static void copyFile(Path srcFile, Path dstFile) throws IOException { copyFile(srcFile, dstFile, false); } + /** - * Given a list of files or directories, attempt to find them based on the given generator + * Given a list of files or directories, attempt to find them using the given generator * context, and copy them to the destination. Entries are searched for in the file system first. * Entries that cannot be found in the file system are looked for on the class path. * - * @param entries The files or directories to copy. - * @param destination The location to copy them to. + * @param entries The files or directory contents to copy. + * @param dstDir The location to copy the files to. * @param fileConfig The file configuration that specifies where the files must be found. * @param errorReporter An error reporter to report problems. */ - public static void copyFilesOrDirectoryContents( + public static void copyFilesOrDirectories( List entries, - Path destination, + Path dstDir, FileConfig fileConfig, - ErrorReporter errorReporter + ErrorReporter errorReporter, + boolean contentsOnly ) { for (String fileOrDirectory : entries) { var path = Paths.get(fileOrDirectory); var found = FileUtil.findInPackage(path, fileConfig); if (found != null) { try { - FileUtil.copyFromFileSystem(found, destination); + FileUtil.copyFromFileSystem(found, dstDir, contentsOnly); System.out.println("Copied '" + fileOrDirectory + "' from the file system."); } catch (IOException e) { errorReporter.reportError( @@ -275,8 +277,9 @@ public static void copyFilesOrDirectoryContents( try { FileUtil.copyFromClassPath( fileOrDirectory, - destination, - false + dstDir, + false, + contentsOnly ); } catch(IOException e) { errorReporter.reportError( @@ -295,11 +298,15 @@ public static void copyFilesOrDirectoryContents( * @param destination A directory to copy the file(s) at the source to. * @throws IOException */ - public static void copyFromFileSystem(Path source, Path destination) throws IOException { + public static void copyFromFileSystem(Path source, Path destination, boolean contentsOnly) throws IOException { if (Files.isDirectory(source)) { - copyDirectoryContents(source, destination); + if (contentsOnly) { + copyDirectoryContents(source, destination); + } else { + copyDirectory(source, destination, false); + } } else if (Files.isRegularFile(source)) { - copyFile(source, destination.resolve(source.getFileName())); + FileUtil.copyFile(source, destination.resolve(source.getFileName())); } else { throw new IllegalArgumentException("Source is neither a directory nor a regular file."); } @@ -338,19 +345,46 @@ private static void copyInputStream(InputStream source, Path destination, boolea Files.write(destination, bytes); } + public static void copySingleFileFromClasspath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + final URL resource = FileConfig.class.getResource(entry); + + if (resource == null) { + throw new TargetResourceNotFoundException(entry); + } + + final URLConnection connection = resource.openConnection(); + if (connection instanceof JarURLConnection) { + copySingleFileFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged); + } else { + try { + Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); + copyFile(path, dstDir.resolve(path.getFileName()), skipIfUnchanged); + } catch(URISyntaxException e) { + // This should never happen as toFileURL should always return a valid URL + throw new IOException("Unexpected error while resolving " + entry + " on the classpath"); + } + } + } + /** - * Look up the given entry in the classpath. If it is a file, copy it into the destination - * directory. If it is a directory, copy its contents to the destination directory. + * Look up the given entry in the classpath. If it is a file, copy it into the destination + * directory. If it is a directory, copy its contents to the destination directory. * - * This also creates new directories for any directories on the destination - * path that do not yet exist. + * This also creates new directories for any directories on the destination + * path that do not yet exist. * - * @param entry The entry to be found on the class path and copied to the given destination. - * @param dstDir The file system path that found files are to be copied to. - * @param skipIfUnchanged If true, don't overwrite the file if its content would not be changed - * @throws IOException If the given source cannot be copied. + * @param entry The entry to be found on the class path and copied to the given destination. + * @param dstDir The file system path that found files are to be copied to. + * @param skipIfUnchanged If true, don't overwrite the file or directory if its content would not be changed + * @param contentsOnly If true and the entry is a directory, then copy its contents but not the directory itself. + * @throws IOException If the given source cannot be copied. */ - public static void copyFromClassPath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + public static void copyFromClassPath( + final String entry, + final Path dstDir, + final boolean skipIfUnchanged, + final boolean contentsOnly + ) throws IOException { final URL resource = FileConfig.class.getResource(entry); if (resource == null) { @@ -359,7 +393,7 @@ public static void copyFromClassPath(final String entry, final Path dstDir, fina final URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { - boolean copiedFiles = copyFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged); + boolean copiedFiles = copyFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged, contentsOnly); if (!copiedFiles) { throw new TargetResourceNotFoundException(entry); } @@ -367,7 +401,12 @@ public static void copyFromClassPath(final String entry, final Path dstDir, fina try { Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); if (path.toFile().isDirectory()) { - copyDirectoryContents(path, dstDir, skipIfUnchanged); + if (contentsOnly) { + copyDirectoryContents(path, dstDir, skipIfUnchanged); + } else { + copyDirectory(path, dstDir, skipIfUnchanged); + } + } else { copyFile(path, dstDir.resolve(path.getFileName()), skipIfUnchanged); } @@ -389,7 +428,7 @@ private static boolean isFileInJar(JarURLConnection connection) throws IOExcepti ).findFirst().isPresent(); } - private static void copyFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { + private static void copySingleFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { var entry = jar.getJarEntry(srcFile); var filename = Paths.get(entry.getName()).getFileName(); InputStream is = jar.getInputStream(entry); @@ -399,37 +438,57 @@ private static void copyFileFromJar(JarFile jar, String srcFile, Path dstDir, bo } /** - * Copy a directory from a jar to a destination path in the filesystem. + * Copy the contents from an entry in a JAR to destination directory in the filesystem. The entry + * may be a file, in which case it will be copied under the same name into the destination + * directory. If the entry is a directory, then if the 'contentsOnly' flag is set, only the + * contents of the directory will be copied into the destination directory (not the directory + * itself). A directory will be copied as a whole, including its contents, if 'contentsOnly' is + * set to false. * * This method should only be used in standalone mode (lfc). * - * This also creates new directories for any directories on the destination - * path that do not yet exist + * This also creates new directories for any directories on + * the destination path that do not yet exist. * - * @param connection a URLConnection to the source directory within the jar - * @param destination The file system path that the source directory is copied to. - * @param skipIfUnchanged If true, don't overwrite the file if its content would not be changed + * @param connection a URLConnection to the source entry within the jar + * @param dstDir The file system path that entries are copied to. + * @param skipIfUnchanged If true, don't overwrite the file if its content would not be changed. + * @param contentsOnly If true, and the connection points to a directory, copy its contents only + * (not the directory itself). * @return true if any files were copied * @throws IOException If the given source cannot be copied. */ - private static boolean copyFromJar(JarURLConnection connection, final Path destination, final boolean skipIfUnchanged) throws IOException { - final JarFile jar = connection.getJarFile(); - final String source = connection.getEntryName(); - - if (isFileInJar(connection)) { - copyFileFromJar(jar, source, destination, skipIfUnchanged); + private static boolean copyFromJar( + JarURLConnection connection, + Path dstDir, + final boolean skipIfUnchanged, + final boolean contentsOnly + ) throws IOException { + + if (copySingleFileFromJar(connection, dstDir, skipIfUnchanged)) { return true; } + return copyMultipleFilesFromJar(connection, dstDir, skipIfUnchanged, contentsOnly); + } - boolean copiedFiles = false; + private static boolean copyMultipleFilesFromJar(JarURLConnection connection, + Path dstDir, + final boolean skipIfUnchanged, + final boolean contentsOnly) throws IOException { + final JarFile jar = connection.getJarFile(); + final String source = connection.getEntryName(); + boolean copiedFiles = false; + if (!contentsOnly) { + dstDir = dstDir.resolve(Paths.get(source).getFileName()); + } // Iterate all entries in the jar file. for (Enumeration e = jar.entries(); e.hasMoreElements(); ) { final JarEntry entry = e.nextElement(); final String entryName = entry.getName(); if (entryName.startsWith(source)) { String filename = entry.getName().substring(source.length() + 1); - Path currentFile = destination.resolve(filename); + Path currentFile = dstDir.resolve(filename); if (entry.isDirectory()) { Files.createDirectories(currentFile); } else { @@ -444,6 +503,22 @@ private static boolean copyFromJar(JarURLConnection connection, final Path desti return copiedFiles; } + private static boolean copySingleFileFromJar( + JarURLConnection connection, + Path dstDir, + final boolean skipIfUnchanged + ) throws IOException { + final JarFile jar = connection.getJarFile(); + final String source = connection.getEntryName(); + + if (!isFileInJar(connection)) { + return false; + } + copySingleFileFromJar(jar, source, dstDir, skipIfUnchanged); + + return true; + } + /** * Delete unused Files from Arduino-CLI based compilation. * From 5f2c187bccffe6c282d9ecda865d8d473f176063 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 18:05:14 -0700 Subject: [PATCH 09/19] Again, mostly comments --- .../org/lflang/generator/GeneratorBase.java | 8 +- .../org/lflang/generator/c/CGenerator.java | 2 +- org.lflang/src/org/lflang/util/FileUtil.java | 161 +++++++++++++----- 3 files changed, 124 insertions(+), 47 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 407b1c501a..461f571333 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -350,12 +350,8 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - FileUtil.copyFilesOrDirectories( - targetConfig.files, - this.context.getFileConfig().getSrcGenPath(), - fileConfig, - errorReporter, - false); + var dst = this.context.getFileConfig().getSrcGenPath(); + FileUtil.copyFilesOrDirectories(targetConfig.files, dst, fileConfig, errorReporter, false); } /** diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 6ec5e80226..cdf6e4d2f6 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -906,7 +906,7 @@ private void generateHeaders() throws IOException { }, this::generateTopLevelPreambles); } - FileUtil.copyDirectoryContents(fileConfig.getIncludePath(), fileConfig.getSrcGenPath().resolve("include"), false); + FileUtil.copyDirectory(fileConfig.getIncludePath(), fileConfig.getSrcGenPath(), false); } /** diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index bbd4a5439f..a876e90940 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -163,13 +163,14 @@ public static java.net.URI locateFile(String path, Resource resource) { } /** - * Recursively copy the contents of the given 'srcDir' into the given 'dstDir'. - * Existing files of the destination may be overwritten. + * Recursively copy the contents of the given source directory into the given destination + * directory. Existing files of the destination may be overwritten. * * @param srcDir The source directory path. * @param dstDir The destination directory path. - * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed - * @throws IOException if copy fails. + * @param skipIfUnchanged If true, don't overwrite anything in the destination if its content + * would not be changed. + * @throws IOException If the operation fails. */ public static void copyDirectoryContents(final Path srcDir, final Path dstDir, final boolean skipIfUnchanged) throws IOException { try (Stream stream = Files.walk(srcDir)) { @@ -194,14 +195,24 @@ public static void copyDirectoryContents(final Path srcDir, final Path dstDir, f } } - public static void copyDirectory(final Path srcDir, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + /** + * Copy the given source directory into the given destination directory. For example, if the + * source directory is {@code foo/bar} and the destination is {@code baz}, then copies of the + * contents of {@code foo/bar} will be located in {@code baz/bar}. + * @param srcDir The source directory path. + * @param dstDir The destination directory path. + * @param skipIfUnchanged If true, don't overwrite anything in the destination if its content + * would not be changed. + * @throws IOException If the operation fails. + */ + public static void copyDirectory( + final Path srcDir, final Path dstDir, final boolean skipIfUnchanged) throws IOException { copyDirectoryContents(srcDir, dstDir.resolve(srcDir.getFileName()), skipIfUnchanged); } /** - * Recursively copy the contents of the given 'srcDir' - * to 'dstDir'. - * Existing files of the destination may be overwritten. + * Recursively copy the contents of the given source directory into the given destination + * directory. Existing files of the destination may be overwritten. * * @param srcDir The directory to copy files from. * @param dstDir The directory to copy files to. @@ -212,15 +223,15 @@ public static void copyDirectoryContents(final Path srcDir, final Path dstDir) t } /** - * Copy a given file from 'srcFile' to 'dstFile'. + * Copy a given source file to a given destination file. * - * This also creates new directories for any directories - * on the path to `dstFile` that do not yet exist. + * This also creates new directories on the path to {@code dstFile} that do not yet exist. * * @param srcFile The source file path. * @param dstFile The destination file path. - * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed - * @throws IOException if copy fails. + * @param skipIfUnchanged If true, don't overwrite the destination file if its content + * would not be changed. + * @throws IOException If the operation fails. */ public static void copyFile(Path srcFile, Path dstFile, boolean skipIfUnchanged) throws IOException { BufferedInputStream stream = new BufferedInputStream(new FileInputStream(srcFile.toFile())); @@ -230,10 +241,10 @@ public static void copyFile(Path srcFile, Path dstFile, boolean skipIfUnchanged) } /** - * Copy a 'srcFile' to 'dstFile'. + * Copy a given source file to a given destination file. * * This also creates new directories for any directories - * on the path to `dstFile` that do not yet exist. + * on the path to {@code dstFile} that do not yet exist. * * @param srcFile The source file path. * @param dstFile The destination file path. @@ -245,13 +256,21 @@ public static void copyFile(Path srcFile, Path dstFile) throws IOException { /** - * Given a list of files or directories, attempt to find them using the given generator - * context, and copy them to the destination. Entries are searched for in the file system first. - * Entries that cannot be found in the file system are looked for on the class path. + * Given a list of files or directories, attempt to find each entry based on the given generator + * context and copy it to the destination directory. Entries are searched for in the file system + * first, relative to the source file and relative to the package root. Entries that cannot be + * found in the file system are looked for on the class path. + *

+ * If {@code contentsOnly} is true, then for each entry that is a directory, only its contents + * are copied, not the directory itself. + * For example, if the entry is a directory {@code foo/bar} and the destination is {@code baz}, + * then copies of the contents of {@code foo/bar} will be located directly in {@code baz}. + * If {@code contentsOnly} is false, then copies of the contents of {@code foo/bar} will be + * located in {@code baz/bar}. * - * @param entries The files or directory contents to copy. + * @param entries The files or directories to copy from. * @param dstDir The location to copy the files to. - * @param fileConfig The file configuration that specifies where the files must be found. + * @param fileConfig The file configuration that specifies where the find entries the given entries. * @param errorReporter An error reporter to report problems. */ public static void copyFilesOrDirectories( @@ -292,21 +311,26 @@ public static void copyFilesOrDirectories( } /** - * If the source is a directory, then copy the contents of the directory to the destination. - * If the source is a file, then copy the file to the destination. - * @param source A file or directory to copy to the destination. - * @param destination A directory to copy the file(s) at the source to. - * @throws IOException + * If the given {@code entry} is a file, then copy it into the destination. If the {@code entry} + * is a directory and {@code contentsOnly} is true, then copy its contents to the destination + * directory. If the {@code entry} is a directory and {@code contentsOnly} is true, then copy it + * including its contents to the destination directory. + * + * @param entry A file or directory to copy to the destination directory. + * @param dstDir A directory to copy the entry or its contents to. + * @param contentsOnly If true and {@code entry} is a directory, then copy its contents but not + * the directory itself. + * @throws IOException If the operation fails. */ - public static void copyFromFileSystem(Path source, Path destination, boolean contentsOnly) throws IOException { - if (Files.isDirectory(source)) { + public static void copyFromFileSystem(Path entry, Path dstDir, boolean contentsOnly) throws IOException { + if (Files.isDirectory(entry)) { if (contentsOnly) { - copyDirectoryContents(source, destination); + copyDirectoryContents(entry, dstDir); } else { - copyDirectory(source, destination, false); + copyDirectory(entry, dstDir, false); } - } else if (Files.isRegularFile(source)) { - FileUtil.copyFile(source, destination.resolve(source.getFileName())); + } else if (Files.isRegularFile(entry)) { + FileUtil.copyFile(entry, dstDir.resolve(entry.getFileName())); } else { throw new IllegalArgumentException("Source is neither a directory nor a regular file."); } @@ -319,8 +343,9 @@ public static void copyFromFileSystem(Path source, Path destination, boolean con * * @param source The source input stream. * @param destination The destination file path. - * @param skipIfUnchanged If true, don't overwrite the destination file if its content would not be changed - * @throws IOException if copy fails. + * @param skipIfUnchanged If true, don't overwrite the destination file if its content would + * not be changed. + * @throws IOException If the operation fails. */ private static void copyInputStream(InputStream source, Path destination, boolean skipIfUnchanged) throws IOException { // Read the stream once and keep a copy of all bytes. This is required as a stream cannot be read twice. @@ -345,6 +370,16 @@ private static void copyInputStream(InputStream source, Path destination, boolea Files.write(destination, bytes); } + /** + * Look up the given {@code entry} in the classpath. If it is found and is a file, copy it into + * the destination directory. If the entry is not found or not a file, throw an exception. + * + * @param entry A file copy to the destination directory. + * @param dstDir A directory to copy the entry to. + * @param skipIfUnchanged If true, don't overwrite the destination file if its content would + * not be changed. + * @throws IOException If the operation failed. + */ public static void copySingleFileFromClasspath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { final URL resource = FileConfig.class.getResource(entry); @@ -354,7 +389,9 @@ public static void copySingleFileFromClasspath(final String entry, final Path ds final URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { - copySingleFileFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged); + if (!copySingleFileFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged)) { + throw new IOException("'" + entry + "' is not a file"); + } } else { try { Path path = Paths.get(FileLocator.toFileURL(resource).toURI()); @@ -367,8 +404,11 @@ public static void copySingleFileFromClasspath(final String entry, final Path ds } /** - * Look up the given entry in the classpath. If it is a file, copy it into the destination - * directory. If it is a directory, copy its contents to the destination directory. + * Look up the given {@code entry} in the classpath. If it is a file, copy it into the destination + * directory. + * If the {@code entry} is a directory and {@code contentsOnly} is true, then copy its contents + * to the destination directory. If the {@code entry} is a directory and {@code contentsOnly} is + * true, then copy it including its contents to the destination directory. * * This also creates new directories for any directories on the destination * path that do not yet exist. @@ -377,7 +417,7 @@ public static void copySingleFileFromClasspath(final String entry, final Path ds * @param dstDir The file system path that found files are to be copied to. * @param skipIfUnchanged If true, don't overwrite the file or directory if its content would not be changed * @param contentsOnly If true and the entry is a directory, then copy its contents but not the directory itself. - * @throws IOException If the given source cannot be copied. + * @throws IOException If the operation failed. */ public static void copyFromClassPath( final String entry, @@ -428,6 +468,16 @@ private static boolean isFileInJar(JarURLConnection connection) throws IOExcepti ).findFirst().isPresent(); } + /** + * Given a JAR file and a {@code srcFile} entry, copy it into the given destination directory. + * + * @param jar The JAR file from which to copy {@code srcFile}. + * @param srcFile The source file to copy from the given {@code jar}. + * @param dstDir The directory to top the source file into. + * @param skipIfUnchanged If true, don't overwrite the destination file if its content would + * * not be changed. + * @throws IOException If the operation fails. + */ private static void copySingleFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { var entry = jar.getJarEntry(srcFile); var filename = Paths.get(entry.getName()).getFileName(); @@ -440,10 +490,10 @@ private static void copySingleFileFromJar(JarFile jar, String srcFile, Path dstD /** * Copy the contents from an entry in a JAR to destination directory in the filesystem. The entry * may be a file, in which case it will be copied under the same name into the destination - * directory. If the entry is a directory, then if the 'contentsOnly' flag is set, only the + * directory. If the entry is a directory, then if {@code contentsOnly} is true, only the * contents of the directory will be copied into the destination directory (not the directory - * itself). A directory will be copied as a whole, including its contents, if 'contentsOnly' is - * set to false. + * itself). A directory will be copied as a whole, including its contents, if + * {@code contentsOnly} is false. * * This method should only be used in standalone mode (lfc). * @@ -471,6 +521,20 @@ private static boolean copyFromJar( return copyMultipleFilesFromJar(connection, dstDir, skipIfUnchanged, contentsOnly); } + /** + * Given a connection to a JAR file that points to an entry that is a directory, copy all entries + * located in that directory or its subdirectories into the given {@code dstDir}. + *

+ * If {@code contentsOnly} is true, only the contents of the directory will be copied into the + * destination directory (not the directory itself). The directory will be copied as a whole, + * including its contents, if {@code contentsOnly} is false. + * @param connection A connection to a JAR file that points to a directory entry. + * @param dstDir The destination directory to copy the matching entries to. + * @param skipIfUnchanged + * @param contentsOnly + * @return + * @throws IOException + */ private static boolean copyMultipleFilesFromJar(JarURLConnection connection, Path dstDir, final boolean skipIfUnchanged, @@ -503,6 +567,16 @@ private static boolean copyMultipleFilesFromJar(JarURLConnection connection, return copiedFiles; } + /** + * Given a connection to a JAR file that points to an entry that is a file, copy the file into the + * given {@code dstDir}. + * @param connection A connection to a JAR file that points to a directory entry. + * @param dstDir The destination directory to copy the file to. + * @param skipIfUnchanged + * @return {@code true} the connection entry is a file, and it was copied successfully; + * {@code false} if the connection entry is not a file and the copy operation was aborted. + * @throws IOException If the operation failed. + */ private static boolean copySingleFileFromJar( JarURLConnection connection, Path dstDir, @@ -630,6 +704,13 @@ public static void relativeIncludeHelper(Path dir, Path includePath) throws IOEx } } + /** + * Delete the given file or directory if it exists. If {@code fileOrDirectory} is a directory, + * deletion is recursive. + * + * @param fileOrDirectory The file or directory to delete. + * @throws IOException If the operation failed. + */ public static void delete(Path fileOrDirectory) throws IOException { if (Files.isRegularFile(fileOrDirectory)) { Files.deleteIfExists(fileOrDirectory); From d4d96662492f48d2372af88b11c50d66b8ae8fb2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 18:32:39 -0700 Subject: [PATCH 10/19] Revert suspicious change --- org.lflang/src/org/lflang/generator/c/CGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index cdf6e4d2f6..6ec5e80226 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -906,7 +906,7 @@ private void generateHeaders() throws IOException { }, this::generateTopLevelPreambles); } - FileUtil.copyDirectory(fileConfig.getIncludePath(), fileConfig.getSrcGenPath(), false); + FileUtil.copyDirectoryContents(fileConfig.getIncludePath(), fileConfig.getSrcGenPath().resolve("include"), false); } /** From bf00460022b53df54d108f3defff01215811e780 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 18:36:37 -0700 Subject: [PATCH 11/19] Remove FIXME that is not a FIXME --- org.lflang/src/org/lflang/generator/c/CGenerator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 6ec5e80226..259d146da5 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -425,8 +425,6 @@ protected boolean isOSCompatible() { "LF programs with a CCpp target are currently not supported on Windows. " + "Exiting code generation." ); - // FIXME: The incompatibility between our C runtime code and the - // Visual Studio compiler is extensive. return false; } } From 0a23a7615a2b0c838b6d660a6cb5888b82f33cef Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 19:30:08 -0700 Subject: [PATCH 12/19] Only allow files for cmake-include entries --- .../org/lflang/generator/c/CGenerator.java | 1 - org.lflang/src/org/lflang/util/FileUtil.java | 29 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 259d146da5..b5c82b5d3b 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -828,7 +828,6 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - // NOTE: All entries should be files, but we are not checking this. FileUtil.copyFilesOrDirectories(targetConfig.cmakeIncludes, destination, fileConfig, errorReporter, true); // FIXME: Unclear what the following does, but it does not appear to belong here. diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index a876e90940..2bd01cc6a9 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -278,31 +278,40 @@ public static void copyFilesOrDirectories( Path dstDir, FileConfig fileConfig, ErrorReporter errorReporter, - boolean contentsOnly + boolean fileEntriesOnly ) { for (String fileOrDirectory : entries) { var path = Paths.get(fileOrDirectory); var found = FileUtil.findInPackage(path, fileConfig); if (found != null) { try { - FileUtil.copyFromFileSystem(found, dstDir, contentsOnly); + if (fileEntriesOnly) { + FileUtil.copyFile(found, dstDir.resolve(path.getFileName())); + } else { + FileUtil.copyFromFileSystem(found, dstDir, false); + } System.out.println("Copied '" + fileOrDirectory + "' from the file system."); } catch (IOException e) { errorReporter.reportError( - "Unable to copy '" + fileOrDirectory + "' from the file system." + "Unable to copy '" + fileOrDirectory + "' from the file system. Reason: " + e.toString() ); } } else { try { - FileUtil.copyFromClassPath( - fileOrDirectory, - dstDir, - false, - contentsOnly - ); + if (fileEntriesOnly) { + copySingleFileFromClasspath(fileOrDirectory, dstDir, false); + } else { + FileUtil.copyFromClassPath( + fileOrDirectory, + dstDir, + false, + false + ); + } + } catch(IOException e) { errorReporter.reportError( - "Unable to copy '" + fileOrDirectory + "' from the class path." + "Unable to copy '" + fileOrDirectory + "' from the class path. Reason: " + e.toString() ); } System.out.println("Copied '" + fileOrDirectory + "' from the class path."); From d674900b0f1651f3ca3911ba5defb204955ca21b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 19:49:59 -0700 Subject: [PATCH 13/19] Undo unncessary rename --- org.lflang/src/org/lflang/util/FileUtil.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index 2bd01cc6a9..3ee2e6ce2d 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -398,7 +398,7 @@ public static void copySingleFileFromClasspath(final String entry, final Path ds final URLConnection connection = resource.openConnection(); if (connection instanceof JarURLConnection) { - if (!copySingleFileFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged)) { + if (!copyFileFromJar((JarURLConnection) connection, dstDir, skipIfUnchanged)) { throw new IOException("'" + entry + "' is not a file"); } } else { @@ -487,7 +487,7 @@ private static boolean isFileInJar(JarURLConnection connection) throws IOExcepti * * not be changed. * @throws IOException If the operation fails. */ - private static void copySingleFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { + private static void copyFileFromJar(JarFile jar, String srcFile, Path dstDir, boolean skipIfUnchanged) throws IOException { var entry = jar.getJarEntry(srcFile); var filename = Paths.get(entry.getName()).getFileName(); InputStream is = jar.getInputStream(entry); @@ -524,10 +524,10 @@ private static boolean copyFromJar( final boolean contentsOnly ) throws IOException { - if (copySingleFileFromJar(connection, dstDir, skipIfUnchanged)) { + if (copyFileFromJar(connection, dstDir, skipIfUnchanged)) { return true; } - return copyMultipleFilesFromJar(connection, dstDir, skipIfUnchanged, contentsOnly); + return copyDirectoryFromJar(connection, dstDir, skipIfUnchanged, contentsOnly); } /** @@ -544,7 +544,7 @@ private static boolean copyFromJar( * @return * @throws IOException */ - private static boolean copyMultipleFilesFromJar(JarURLConnection connection, + private static boolean copyDirectoryFromJar(JarURLConnection connection, Path dstDir, final boolean skipIfUnchanged, final boolean contentsOnly) throws IOException { @@ -586,7 +586,7 @@ private static boolean copyMultipleFilesFromJar(JarURLConnection connection, * {@code false} if the connection entry is not a file and the copy operation was aborted. * @throws IOException If the operation failed. */ - private static boolean copySingleFileFromJar( + private static boolean copyFileFromJar( JarURLConnection connection, Path dstDir, final boolean skipIfUnchanged @@ -597,7 +597,7 @@ private static boolean copySingleFileFromJar( if (!isFileInJar(connection)) { return false; } - copySingleFileFromJar(jar, source, dstDir, skipIfUnchanged); + copyFileFromJar(jar, source, dstDir, skipIfUnchanged); return true; } From 6fcad58151dd0441089227681b8f10a0a99b3a8c Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 20:11:13 -0700 Subject: [PATCH 14/19] Another rename undone --- org.lflang/src/org/lflang/generator/c/CGenerator.java | 4 ++-- org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt | 4 ++-- org.lflang/src/org/lflang/util/FileUtil.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index b5c82b5d3b..14af96038d 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -983,13 +983,13 @@ protected void copyTargetFiles() throws IOException { false, false ); - FileUtil.copySingleFileFromClasspath( + FileUtil.copyFileFromClasspath( "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath(), true ); - FileUtil.copySingleFileFromClasspath( + FileUtil.copyFileFromClasspath( "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index 60b450d2c2..d624cfac9d 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -126,9 +126,9 @@ class CppGenerator( // copy static library files over to the src-gen directory val genIncludeDir = srcGenPath.resolve("__include__") listOf("lfutil.hh", "time_parser.hh").forEach { - FileUtil.copySingleFileFromClasspath("$libDir/$it", genIncludeDir, true) + FileUtil.copyFileFromClasspath("$libDir/$it", genIncludeDir, true) } - FileUtil.copySingleFileFromClasspath( + FileUtil.copyFileFromClasspath( "$libDir/3rd-party/cxxopts.hpp", genIncludeDir.resolve("CLI"), true) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index 3ee2e6ce2d..b2995950c2 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -299,7 +299,7 @@ public static void copyFilesOrDirectories( } else { try { if (fileEntriesOnly) { - copySingleFileFromClasspath(fileOrDirectory, dstDir, false); + copyFileFromClasspath(fileOrDirectory, dstDir, false); } else { FileUtil.copyFromClassPath( fileOrDirectory, @@ -389,7 +389,7 @@ private static void copyInputStream(InputStream source, Path destination, boolea * not be changed. * @throws IOException If the operation failed. */ - public static void copySingleFileFromClasspath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + public static void copyFileFromClasspath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { final URL resource = FileConfig.class.getResource(entry); if (resource == null) { From 6438a2c22e2771e32278ba6f1d46cf4b517713fb Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 20:19:41 -0700 Subject: [PATCH 15/19] Use proper camelCase --- org.lflang/src/org/lflang/generator/c/CGenerator.java | 4 ++-- org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt | 4 ++-- org.lflang/src/org/lflang/util/FileUtil.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index 14af96038d..c7e585e1ab 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -983,13 +983,13 @@ protected void copyTargetFiles() throws IOException { false, false ); - FileUtil.copyFileFromClasspath( + FileUtil.copyFileFromClassPath( "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath(), true ); - FileUtil.copyFileFromClasspath( + FileUtil.copyFileFromClassPath( "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index d624cfac9d..e739560ba8 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -126,9 +126,9 @@ class CppGenerator( // copy static library files over to the src-gen directory val genIncludeDir = srcGenPath.resolve("__include__") listOf("lfutil.hh", "time_parser.hh").forEach { - FileUtil.copyFileFromClasspath("$libDir/$it", genIncludeDir, true) + FileUtil.copyFileFromClassPath("$libDir/$it", genIncludeDir, true) } - FileUtil.copyFileFromClasspath( + FileUtil.copyFileFromClassPath( "$libDir/3rd-party/cxxopts.hpp", genIncludeDir.resolve("CLI"), true) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index b2995950c2..348bcd6658 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -299,7 +299,7 @@ public static void copyFilesOrDirectories( } else { try { if (fileEntriesOnly) { - copyFileFromClasspath(fileOrDirectory, dstDir, false); + copyFileFromClassPath(fileOrDirectory, dstDir, false); } else { FileUtil.copyFromClassPath( fileOrDirectory, @@ -389,7 +389,7 @@ private static void copyInputStream(InputStream source, Path destination, boolea * not be changed. * @throws IOException If the operation failed. */ - public static void copyFileFromClasspath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { + public static void copyFileFromClassPath(final String entry, final Path dstDir, final boolean skipIfUnchanged) throws IOException { final URL resource = FileConfig.class.getResource(entry); if (resource == null) { From 93c9e5b524b1eaf487e70377ba2a23cd1c87b5ef Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 20:24:30 -0700 Subject: [PATCH 16/19] Fix comment --- org.lflang/src/org/lflang/util/FileUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index 348bcd6658..a0f2e8eccc 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -531,8 +531,8 @@ private static boolean copyFromJar( } /** - * Given a connection to a JAR file that points to an entry that is a directory, copy all entries - * located in that directory or its subdirectories into the given {@code dstDir}. + * Given a connection to a JAR file that points to an entry that is a directory, recursively copy + * all entries located in that directory into the given {@code dstDir}. *

* If {@code contentsOnly} is true, only the contents of the directory will be copied into the * destination directory (not the directory itself). The directory will be copied as a whole, From 2a74c450449c7668b98b8932dea34d1f1ca4f07d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 20:51:05 -0700 Subject: [PATCH 17/19] Revive feature for copying user-specified config files --- .../org/lflang/generator/ts/TSGenerator.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 49dd3444e1..9aae97d175 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -38,6 +38,7 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path +import java.nio.file.StandardCopyOption import java.util.* private const val NO_NPM_MESSAGE = "The TypeScript target requires npm >= 6.14.4. " + @@ -67,6 +68,12 @@ class TSGenerator( /** Path to the TS lib directory (relative to class path) */ const val LIB_PATH = "/lib/ts" + /** + * Names of the configuration files to check for and copy to the generated + * source package root if they cannot be found in the source directory. + */ + val CONFIG_FILES = arrayOf("package.json", "tsconfig.json", ".eslintrc.json") + const val RUNTIME_URL = "git://github.com/lf-lang/reactor-ts.git" fun timeInTargetLanguage(value: TimeValue): String { @@ -220,6 +227,20 @@ class TSGenerator( true, true ) + for (configFile in CONFIG_FILES) { + val configFileInSrc = fileConfig.srcPath.resolve(configFile) + if (configFileInSrc.toFile().exists()) { + val configFileDest = fileConfig.srcGenPath.resolve(configFile) + println("Copying $configFileInSrc to $configFileDest") + Files.copy(configFileInSrc, configFileDest, StandardCopyOption.REPLACE_EXISTING) + } else { + println( + "No '" + configFile + "' exists in " + fileConfig.srcPath + + ". Using default configuration." + ) + FileUtil.copyFileFromClassPath("$LIB_PATH/$configFile", fileConfig.srcGenPath, true) + } + } } From d4b8238cf0b3851b2f3e16d78bc40c9b9f21d14b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 22:28:04 -0700 Subject: [PATCH 18/19] Nicer implementation of user-provided config files for TS and cleanups --- .../org/lflang/generator/ts/TSGenerator.kt | 15 ++----- org.lflang/src/org/lflang/util/FileUtil.java | 43 +++++++++++++++---- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index 9aae97d175..db5eb267a2 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -38,7 +38,6 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path -import java.nio.file.StandardCopyOption import java.util.* private const val NO_NPM_MESSAGE = "The TypeScript target requires npm >= 6.14.4. " + @@ -228,17 +227,11 @@ class TSGenerator( true ) for (configFile in CONFIG_FILES) { - val configFileInSrc = fileConfig.srcPath.resolve(configFile) - if (configFileInSrc.toFile().exists()) { - val configFileDest = fileConfig.srcGenPath.resolve(configFile) - println("Copying $configFileInSrc to $configFileDest") - Files.copy(configFileInSrc, configFileDest, StandardCopyOption.REPLACE_EXISTING) + var override = FileUtil.findAndCopyFile(configFile, fileConfig.srcGenPath, fileConfig); + if (override != null) { + System.out.println("Using user-provided '" + override + "'"); } else { - println( - "No '" + configFile + "' exists in " + fileConfig.srcPath + - ". Using default configuration." - ) - FileUtil.copyFileFromClassPath("$LIB_PATH/$configFile", fileConfig.srcGenPath, true) + System.out.println("Using default '" + configFile + "'"); } } } diff --git a/org.lflang/src/org/lflang/util/FileUtil.java b/org.lflang/src/org/lflang/util/FileUtil.java index a0f2e8eccc..eb2550127e 100644 --- a/org.lflang/src/org/lflang/util/FileUtil.java +++ b/org.lflang/src/org/lflang/util/FileUtil.java @@ -254,6 +254,33 @@ public static void copyFile(Path srcFile, Path dstFile) throws IOException { copyFile(srcFile, dstFile, false); } + /** + * Find the given {@code file} in the package and return the path to the file that was found; null + * if it was not found. + * + * @param file The file to look for. + * @param dstDir The directory to copy it to. + * @param fileConfig The file configuration that specifies where look for the file. + * @return The path to the file that was found, or null if it was not found. + */ + public static Path findAndCopyFile( + String file, + Path dstDir, + FileConfig fileConfig + ) { + var path = Paths.get(file); + var found = FileUtil.findInPackage(path, fileConfig); + if (found != null) { + try { + FileUtil.copyFile(found, dstDir.resolve(path.getFileName())); + return found; + } catch (IOException e) { + return null; + } + } else { + return null; + } + } /** * Given a list of files or directories, attempt to find each entry based on the given generator @@ -307,14 +334,13 @@ public static void copyFilesOrDirectories( false, false ); + System.out.println("Copied '" + fileOrDirectory + "' from the class path."); } - } catch(IOException e) { errorReporter.reportError( "Unable to copy '" + fileOrDirectory + "' from the class path. Reason: " + e.toString() ); } - System.out.println("Copied '" + fileOrDirectory + "' from the class path."); } } } @@ -472,9 +498,9 @@ public static void copyFromClassPath( * @throws IOException If the connection is faulty. */ private static boolean isFileInJar(JarURLConnection connection) throws IOException { - return connection.getJarFile().stream().filter( + return connection.getJarFile().stream().anyMatch( it -> it.getName().equals(connection.getEntryName()) - ).findFirst().isPresent(); + ); } /** @@ -625,7 +651,7 @@ public static void arduinoDeleteHelper(Path dir, boolean threadingOn) throws IOE List allPaths = Files.walk(dir) .sorted(Comparator.reverseOrder()) - .collect(Collectors.toList()); + .toList(); for (Path path : allPaths) { String toCheck = path.toString().toLowerCase(); if (toCheck.contains("cmake")) { @@ -680,12 +706,12 @@ public static void relativeIncludeHelper(Path dir, Path includePath) throws IOEx .filter(Files::isRegularFile) .filter(FileUtil::isCFile) .sorted(Comparator.reverseOrder()) - .collect(Collectors.toList()); + .toList(); List srcPaths = Files.walk(dir) .filter(Files::isRegularFile) .filter(FileUtil::isCFile) .sorted(Comparator.reverseOrder()) - .collect(Collectors.toList()); + .toList(); Map fileStringToFilePath = new HashMap(); for (Path path : includePaths) { String fileName = path.getFileName().toString(); @@ -696,7 +722,6 @@ public static void relativeIncludeHelper(Path dir, Path includePath) throws IOEx } Pattern regexExpression = Pattern.compile("#include\s+[\"]([^\"]+)*[\"]"); for (Path path : srcPaths) { - String fileName = path.getFileName().toString(); String fileContents = Files.readString(path); Matcher matcher = regexExpression.matcher(fileContents); int lastIndex = 0; @@ -739,7 +764,7 @@ public static void deleteDirectory(Path dir) throws IOException { System.out.println("Cleaning " + dir); List pathsToDelete = Files.walk(dir) .sorted(Comparator.reverseOrder()) - .collect(Collectors.toList()); + .toList(); for (Path path : pathsToDelete) { Files.deleteIfExists(path); } From d8a48c8b1380615dbfbddb08939a54b3e6d1c7b2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 4 May 2023 22:52:56 -0700 Subject: [PATCH 19/19] Minor formatting --- org.lflang/src/org/lflang/generator/ts/TSGenerator.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt index db5eb267a2..6bd0813531 100644 --- a/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt +++ b/org.lflang/src/org/lflang/generator/ts/TSGenerator.kt @@ -220,12 +220,7 @@ class TSGenerator( * as the source file, copy a default version from $LIB_PATH/. */ private fun copyConfigFiles() { - FileUtil.copyFromClassPath( - LIB_PATH, - fileConfig.srcGenPath, - true, - true - ) + FileUtil.copyFromClassPath(LIB_PATH, fileConfig.srcGenPath, true, true) for (configFile in CONFIG_FILES) { var override = FileUtil.findAndCopyFile(configFile, fileConfig.srcGenPath, fileConfig); if (override != null) {