diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 3a4160c2d1f..dfbecd7c2c5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -195,6 +195,11 @@ public class AutoBuild { private final String defaultEncoding; private ExecutorService threadPool; private volatile boolean seenCode = false; + private boolean installDependencies = false; + private int installDependenciesTimeout; + + /** The default timeout when running yarn, in milliseconds. */ + public static final int INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes public AutoBuild() { this.LGTM_SRC = toRealPath(getPathFromEnvVar("LGTM_SRC")); @@ -204,6 +209,10 @@ public class AutoBuild { this.typeScriptMode = getEnumFromEnvVar("LGTM_INDEX_TYPESCRIPT", TypeScriptMode.class, TypeScriptMode.FULL); this.defaultEncoding = getEnvVar("LGTM_INDEX_DEFAULT_ENCODING"); + this.installDependencies = Boolean.valueOf(getEnvVar("LGTM_TYPESCRIPT_INSTALL_DEPS")); + this.installDependenciesTimeout = + Env.systemEnv() + .getInt("LGTM_TYPESCRIPT_INSTALL_DEPS_TIMEOUT", INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT); setupFileTypes(); setupXmlMode(); setupMatchers(); @@ -533,6 +542,10 @@ public class AutoBuild { List tsconfigFiles = new ArrayList<>(); findFilesToExtract(defaultExtractor, filesToExtract, tsconfigFiles); + if (!tsconfigFiles.isEmpty() && this.installDependencies) { + this.installDependencies(filesToExtract); + } + // extract TypeScript projects and files Set extractedFiles = extractTypeScript(defaultExtractor, filesToExtract, tsconfigFiles); @@ -549,6 +562,34 @@ public class AutoBuild { } } + protected void installDependencies(Set filesToExtract) { + for (Path file : filesToExtract) { + if (file.getFileName().toString().equals("package.json")) { + System.out.println("Installing dependencies from " + file); + ProcessBuilder pb = + new ProcessBuilder( + Arrays.asList( + "yarn", + "install", + "--verbose", + "--ignore-scripts", + "--ignore-platform", + "--ignore-engines", + "--ignore-optional", + "--no-bin-links", + "--pure-lockfile")); + pb.directory(file.getParent().toFile()); + pb.redirectOutput(Redirect.INHERIT); + pb.redirectError(Redirect.INHERIT); + try { + pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS); + } catch (IOException | InterruptedException ex) { + throw new ResourceError("Could not install dependencies from " + file, ex); + } + } + } + } + private ExtractorConfig mkExtractorConfig() { ExtractorConfig config = new ExtractorConfig(true); config = config.withSourceType(getSourceType()); diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 8db4ca22da5..3e39cfc6706 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -128,6 +128,11 @@ public class AutoBuildTests { } } + @Override + protected void installDependencies(Set filesToExtract) { + // never install dependencies during testing + } + @Override protected void extractXml() throws IOException { Files.walkFileTree(