From 30ee6b9ea7895f6e3da9e32b60bc2d179682b90f Mon Sep 17 00:00:00 2001 From: lgrignon Date: Sun, 14 Feb 2016 04:24:02 +0100 Subject: [PATCH] candies js extraction support --- .classpath | 12 +++- .project | 13 ++++ .../org/jsweet/JSweetCommandLineLauncher.java | 16 ++++- .../jsweet/transpiler/JSweetTranspiler.java | 25 +++++-- .../transpiler/candies/CandiesProcessor.java | 67 ++++++++++++++++--- .../transpiler/candies/CandyDescriptor.java | 49 ++++++++++++-- .../transpiler/util/AbstractTreePrinter.java | 2 +- .../jsweet/test/transpiler/AbstractTest.java | 2 +- 8 files changed, 160 insertions(+), 26 deletions(-) diff --git a/.classpath b/.classpath index d37a077d..8dcd5f96 100644 --- a/.classpath +++ b/.classpath @@ -25,9 +25,19 @@ + - + + + + + + + + + + diff --git a/.project b/.project index f935951f..8fdd1e6d 100644 --- a/.project +++ b/.project @@ -5,6 +5,11 @@ + + org.eclipse.wst.common.project.facet.core.builder + + + org.eclipse.jdt.core.javabuilder @@ -15,9 +20,17 @@ + + org.eclipse.wst.validation.validationbuilder + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature diff --git a/src/main/java/org/jsweet/JSweetCommandLineLauncher.java b/src/main/java/org/jsweet/JSweetCommandLineLauncher.java index e954c7cf..ff4934d0 100644 --- a/src/main/java/org/jsweet/JSweetCommandLineLauncher.java +++ b/src/main/java/org/jsweet/JSweetCommandLineLauncher.java @@ -96,6 +96,11 @@ public class JSweetCommandLineLauncher { if (jsapArgs.getFile("dtsout") != null) { dtsOutputDir = jsapArgs.getFile("dtsout"); } + + File candiesJsOutputDir = null; + if (jsapArgs.getFile("candiesJsOut") != null) { + candiesJsOutputDir = jsapArgs.getFile("candiesJsOut"); + } File inputDir = new File(jsapArgs.getString("input")); logger.info("input dir: " + inputDir); @@ -103,7 +108,7 @@ public class JSweetCommandLineLauncher { LinkedList files = new LinkedList(); Util.addFiles(".java", inputDir, files); - JSweetTranspiler transpiler = new JSweetTranspiler(tsOutputDir, jsOutputDir, classPath); + JSweetTranspiler transpiler = new JSweetTranspiler(tsOutputDir, jsOutputDir, candiesJsOutputDir, classPath); transpiler.setBundle(jsapArgs.getBoolean("bundle")); transpiler.setNoRootDirectories(jsapArgs.getBoolean("noRootDirectories")); @@ -232,6 +237,15 @@ public class JSweetCommandLineLauncher { optionArg.setStringParser(FileStringParser.getParser()); optionArg.setRequired(false); jsap.registerParameter(optionArg); + + // Candies javascript output directory + optionArg = new FlaggedOption("candiesJsOut"); + optionArg.setLongFlag("candiesJsOut"); + optionArg.setDefault("js/candies"); + optionArg.setHelp("Specify where to place extracted JavaScript files from candies."); + optionArg.setStringParser(FileStringParser.getParser()); + optionArg.setRequired(false); + jsap.registerParameter(optionArg); // Classpath optionArg = new FlaggedOption("classpath"); diff --git a/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java b/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java index 5186848e..c5f7c4a2 100644 --- a/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java +++ b/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java @@ -153,7 +153,7 @@ public class JSweetTranspiler implements JSweetOptions { * to System.getProperty("java.class.path"). */ public JSweetTranspiler() { - this(new File(System.getProperty("java.io.tmpdir")), null, System.getProperty("java.class.path")); + this(new File(System.getProperty("java.io.tmpdir")), null, null, System.getProperty("java.class.path")); } /** @@ -163,12 +163,14 @@ public class JSweetTranspiler implements JSweetOptions { * the directory where TypeScript files are written * @param jsOutputDir * the directory where JavaScript files are written + * @param extractedCandiesJavascriptDir + * see {@link #getExtractedCandyJavascriptDir()} * @param classPath * the classpath as a string (check out system-specific * requirements for Java classpathes) */ - public JSweetTranspiler(File tsOutputDir, File jsOutputDir, String classPath) { - this(new File(TMP_WORKING_DIR_NAME), tsOutputDir, jsOutputDir, classPath); + public JSweetTranspiler(File tsOutputDir, File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) { + this(new File(TMP_WORKING_DIR_NAME), tsOutputDir, jsOutputDir, extractedCandiesJavascriptDir, classPath); } /** @@ -180,12 +182,15 @@ public class JSweetTranspiler implements JSweetOptions { * the directory where TypeScript files are written * @param jsOutputDir * the directory where JavaScript files are written + * @param extractedCandiesJavascriptDir + * see {@link #getExtractedCandyJavascriptDir()} * @param classPath * the classpath as a string (check out system-specific * requirements for Java classpaths) */ - public JSweetTranspiler(File workingDir, File tsOutputDir, File jsOutputDir, String classPath) { + public JSweetTranspiler(File workingDir, File tsOutputDir, File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) { this.workingDir = workingDir.getAbsoluteFile(); + this.extractedCandyJavascriptDir = extractedCandiesJavascriptDir; try { tsOutputDir.mkdirs(); this.tsOutputDir = tsOutputDir.getCanonicalFile(); @@ -204,7 +209,7 @@ public class JSweetTranspiler implements JSweetOptions { logger.info("jsOut: " + jsOutputDir + (jsOutputDir == null ? "" : " - " + jsOutputDir.getAbsolutePath())); logger.debug("compile classpath: " + classPath); logger.debug("runtime classpath: " + System.getProperty("java.class.path")); - this.candiesProcessor = new CandiesProcessor(workingDir, classPath); + this.candiesProcessor = new CandiesProcessor(workingDir, classPath, extractedCandyJavascriptDir); } /** @@ -872,6 +877,8 @@ public class JSweetTranspiler implements JSweetOptions { private Process tsCompilationProcess; private SourceFile[] watchedFiles; + private File extractedCandyJavascriptDir; + private Path relativizeTsFile(File file) { try { return getTsOutputDir().getAbsoluteFile().getCanonicalFile().toPath().relativize(file.getAbsoluteFile().getCanonicalFile().toPath()); @@ -1379,4 +1386,12 @@ public class JSweetTranspiler implements JSweetOptions { this.declarationsOutputDir = declarationsOutputDir; } + /** + * The directory where the transpiler should put the extracted javascript + * files from candies. Candies could bundle one or more javascript files + * which will be extracted to this directory. + */ + public File getExtractedCandyJavascriptDir() { + return extractedCandyJavascriptDir; + } } diff --git a/src/main/java/org/jsweet/transpiler/candies/CandiesProcessor.java b/src/main/java/org/jsweet/transpiler/candies/CandiesProcessor.java index e8099740..2afa1356 100644 --- a/src/main/java/org/jsweet/transpiler/candies/CandiesProcessor.java +++ b/src/main/java/org/jsweet/transpiler/candies/CandiesProcessor.java @@ -76,11 +76,17 @@ public class CandiesProcessor { * The name of the directory that contains the TypeScript source files. */ public static final String CANDIES_TSDEFS_DIR_NAME = CANDIES_DIR_NAME + File.separator + JSweetConfig.TS_LIBS_DIR_NAME; + /** + * Default directory for extracted candies' javascript. + */ + private static final String CANDIES_DEFAULT_JS_DIR_NAME = CANDIES_DIR_NAME + File.separator + "js"; private File candiesSourceDir; private File candiesProcessedDir; private File candiesStoreFile; private File candiesTsdefsDir; + private File candiesJavascriptOutDir; + private File workingDir; /** * Create a candies processor. @@ -90,8 +96,11 @@ public class CandiesProcessor { * temporary data for processing * @param classPath * the classpath where the processor will seek for JSweet candies + * @param extractedCandiesJavascriptDir + * see JSweetTranspiler.extractedCandyJavascriptDir */ - public CandiesProcessor(File workingDir, String classPath) { + public CandiesProcessor(File workingDir, String classPath, File extractedCandiesJavascriptDir) { + this.workingDir = workingDir; this.classPath = (classPath == null ? System.getProperty("java.class.path") : classPath); String[] cp = this.classPath.split(File.pathSeparator); int[] indices = new int[0]; @@ -109,6 +118,17 @@ public class CandiesProcessor { candiesStoreFile = new File(workingDir, CANDIES_STORE_FILE_NAME); candiesTsdefsDir = new File(workingDir, CANDIES_TSDEFS_DIR_NAME); logger.debug("processed classes dir: " + getCandiesProcessedDir() + " - " + getCandiesProcessedDir().getAbsolutePath()); + + setCandiesJavascriptOutDir(extractedCandiesJavascriptDir); + } + + private void setCandiesJavascriptOutDir(File extractedCandiesJavascriptDir) { + this.candiesJavascriptOutDir = extractedCandiesJavascriptDir; + if (this.candiesJavascriptOutDir == null) { + this.candiesJavascriptOutDir = new File(workingDir, CANDIES_DEFAULT_JS_DIR_NAME); + } + logger.info("extracted candies directory: " + extractedCandiesJavascriptDir); + this.candiesJavascriptOutDir.mkdirs(); } /** @@ -215,16 +235,29 @@ public class CandiesProcessor { String candyName = candyDescriptor.name; boolean isCore = "jsweet-core".equals(candyName); try (JarFile jarFileHandle = new JarFile(jarFile)) { + String candyJarName = FilenameUtils.getBaseName(jarFile.getName()); + File candyExtractedSourcesDir = new File(extractedSourcesDir, candyJarName); + File candyExtractedJsDir = new File(candiesJavascriptOutDir, candyJarName); + extractCandy( // + candyDescriptor, // jarFileHandle, // - new File(extractedSourcesDir, FilenameUtils.getBaseName(jarFile.getName())), // + candyExtractedSourcesDir, // extractedTsDefsDir, // - isCore ? tsDefName -> false : null, extractedClassesDir); + candyExtractedJsDir, // + isCore ? tsDefName -> false : null, // + extractedClassesDir); } } } - private void extractCandy(JarFile jarFile, File javaOutputDirectory, File tsDefOutputDirectory, Predicate isTsDefToBeExtracted, + private void extractCandy( // + CandyDescriptor descriptor, // + JarFile jarFile, // + File javaOutputDirectory, // + File tsDefOutputDirectory, // + File jsOutputDirectory, // + Predicate isTsDefToBeExtracted, // File classesOutputDirectory) { logger.info("extract candy: " + jarFile.getName() + " javaOutputDirectory=" + javaOutputDirectory + " tsDefOutputDirectory=" + tsDefOutputDirectory + " classesOutputDirectory=" + classesOutputDirectory); @@ -232,6 +265,7 @@ public class CandiesProcessor { jarFile.stream() .filter(entry -> entry.getName().endsWith(".d.ts") && entry.getName().startsWith("src/") || entry.getName().endsWith("package-info.class")) // .forEach(entry -> { + File out; if (entry.getName().endsWith(".java")) { out = new File(javaOutputDirectory + "/" + entry.getName().substring(4)); @@ -244,13 +278,26 @@ public class CandiesProcessor { } else { out = new File(classesOutputDirectory + "/" + entry.getName()); } - out.getParentFile().mkdirs(); - try { - FileUtils.copyInputStreamToFile(jarFile.getInputStream(entry), out); - } catch (Exception e) { - throw new RuntimeException(e); - } + extractEntry(jarFile, entry, out); }); + + for (String jsFilePath : descriptor.jsFilesPaths) { + JarEntry entry = jarFile.getJarEntry(jsFilePath); + String relativeJsPath = jsFilePath.substring(descriptor.jsDirPath.length()); + + File out = new File(jsOutputDirectory, relativeJsPath); + extractEntry(jarFile, entry, out); + } + } + + private void extractEntry(JarFile jarFile, JarEntry entry, File out) { + logger.info("extract " + entry.getName() + " to " + out); + out.getParentFile().mkdirs(); + try { + FileUtils.copyInputStreamToFile(jarFile.getInputStream(entry), out); + } catch (Exception e) { + throw new RuntimeException(e); + } } private void extractSourcesForClasses(Map candies, Collection> classes) { diff --git a/src/main/java/org/jsweet/transpiler/candies/CandyDescriptor.java b/src/main/java/org/jsweet/transpiler/candies/CandyDescriptor.java index e54b8562..b3b7f8b6 100644 --- a/src/main/java/org/jsweet/transpiler/candies/CandyDescriptor.java +++ b/src/main/java/org/jsweet/transpiler/candies/CandyDescriptor.java @@ -18,6 +18,8 @@ package org.jsweet.transpiler.candies; import java.io.IOException; import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -36,18 +38,33 @@ import com.google.gson.GsonBuilder; * @see CandiesStore */ class CandyDescriptor { - String name; - String version; - long lastUpdateTimestamp; - String modelVersion; - String transpilerVersion; + final String name; + final String version; + final long lastUpdateTimestamp; + final String modelVersion; + final String transpilerVersion; + final String jsDirPath; + final List jsFilesPaths; - public CandyDescriptor(String name, String version, long lastUpdateTimestamp, String modelVersion, String transpilerVersion) { + public CandyDescriptor( // + String name, // + String version, // + long lastUpdateTimestamp, // + String modelVersion, // + String transpilerVersion, // + String jsDirPath, // + List jsFilesPaths) { this.name = name; this.version = version; this.lastUpdateTimestamp = lastUpdateTimestamp; this.modelVersion = modelVersion; this.transpilerVersion = transpilerVersion; + this.jsDirPath = jsDirPath; + this.jsFilesPaths = jsFilesPaths; + } + + public boolean hasJsFiles() { + return jsFilesPaths.size() > 0; } @Override @@ -122,7 +139,25 @@ class CandyDescriptor { transpilerVersion = (String) metadata.get("transpilerVersion"); } - return new CandyDescriptor(name, version, lastUpdateTimestamp, modelVersion, transpilerVersion); + String jsDirPath = "META-INF/resources/webjars/" + name + "/" + version; + ZipEntry jsDirEntry = jarFile.getEntry(jsDirPath); + List jsFilesPaths = new LinkedList<>(); + if (jsDirEntry != null) { + // collects js files + jarFile.stream() // + .filter(entry -> entry.getName().startsWith(jsDirPath) && entry.getName().endsWith(".js")) // + .map(entry -> entry.getName()) // + .forEach(jsFilesPaths::add); + } + + return new CandyDescriptor( // + name, // + version, // + lastUpdateTimestamp, // + modelVersion, // + transpilerVersion, // + jsDirPath, // + jsFilesPaths); } @Override diff --git a/src/main/java/org/jsweet/transpiler/util/AbstractTreePrinter.java b/src/main/java/org/jsweet/transpiler/util/AbstractTreePrinter.java index 9d8834b8..f307b5b6 100644 --- a/src/main/java/org/jsweet/transpiler/util/AbstractTreePrinter.java +++ b/src/main/java/org/jsweet/transpiler/util/AbstractTreePrinter.java @@ -164,7 +164,7 @@ public abstract class AbstractTreePrinter extends AbstractTreeScanner { currentLine--; } if (currentLine != line) { - logger.warn("cannot adjust line for: " + tree.getClass() + " at line " + line); + logger.warn ("cannot adjust line for: " + tree.getClass() + " at line " + line); } // adjusting columns... (TODO: does not work) // int column = diff --git a/src/test/java/org/jsweet/test/transpiler/AbstractTest.java b/src/test/java/org/jsweet/test/transpiler/AbstractTest.java index d5b509f5..fa267755 100644 --- a/src/test/java/org/jsweet/test/transpiler/AbstractTest.java +++ b/src/test/java/org/jsweet/test/transpiler/AbstractTest.java @@ -95,7 +95,7 @@ public class AbstractTest { staticLogger.info("*** test suite initialization ***"); FileUtils.deleteQuietly(outDir); staticLogger.info("*** create tranpiler ***"); - transpiler = new JSweetTranspiler(outDir, null, System.getProperty("java.class.path")); + transpiler = new JSweetTranspiler(outDir, null, null, System.getProperty("java.class.path")); transpiler.setModuleKind(ModuleKind.none); transpiler.cleanWorkingDirectory(); testSuiteInitialized = true;