Skip to content

Commit

Permalink
Created separate class for Maven interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
rodinaarssen committed Sep 11, 2024
1 parent 0529f26 commit d30a696
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 41 deletions.
84 changes: 84 additions & 0 deletions src/org/rascalmpl/library/util/Maven.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.rascalmpl.library.util;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

import org.apache.maven.cli.CliRequest;
import org.apache.maven.cli.MavenCli;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.uri.URIUtil;

import io.usethesource.vallang.ISourceLocation;

public class Maven {

Check warning on line 18 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L18

Added line #L18 was not covered by tests
/**
* Calls maven with the provided arguments. The working directory will be set to `manifestRoot`,
* which should contain a `pom.xml` file. If `outputFile` refers to an existing file, its contents
* will the read and returned after Maven concludes.
*
* Maven's output is fully suppressed. However, it is often possible to redirect (parts of) the output
* to a file. For instance, the output of `mvn dependency:build-classpath` can be redicted to a file
* by providing an additional argument `-Dmdep.outputFile=/path/to/file`.
*/
public static List<String> runCommand(List<String> args, ISourceLocation manifestRoot, Path outputFile) {
try {
ISourceLocation pomxml = URIUtil.getChildLocation(manifestRoot, "pom.xml");
pomxml = URIResolverRegistry.getInstance().logicalToPhysical(pomxml);
manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot);

if (!"file".equals(manifestRoot.getScheme())) {
throw new IllegalArgumentException("`manifestRoot` could not be resolved");
}

if (!URIResolverRegistry.getInstance().exists(pomxml)) {
throw new IllegalArgumentException("`manifestRoot` does not contain pom.xml");

Check warning on line 39 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L39

Added line #L39 was not covered by tests
}

var maven = new MavenCli();
maven.doMain(buildRequest(args.toArray(String[]::new), manifestRoot));

if (outputFile != null && Files.exists(outputFile)) {
return Files.readAllLines(outputFile);
}
} catch (IOException | ReflectiveOperationException e) {

Check warning on line 48 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L48

Added line #L48 was not covered by tests
// Fall through to return the empty list
}

Check warning on line 50 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L50

Added line #L50 was not covered by tests

return Collections.emptyList();

Check warning on line 52 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L52

Added line #L52 was not covered by tests
}

/**
* Calls maven with the provided arguments. The working directory will be set to `manifestRoot`,
* which should contain a `pom.xml` file. Maven's output is fully suppressed.
*/
public static void runCommand(List<String> args, ISourceLocation manifestRoot) {
runCommand(args, manifestRoot, null);
}

Check warning on line 61 in src/org/rascalmpl/library/util/Maven.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/Maven.java#L60-L61

Added lines #L60 - L61 were not covered by tests

private static void setField(CliRequest req, String fieldName, Object value) throws ReflectiveOperationException {
var field = CliRequest.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(req, value);
}

private static CliRequest buildRequest(String[] args, ISourceLocation manifestRoot) throws ReflectiveOperationException {
// we need to set a field that the default class doesn't set
// it's a work around around a bug in the MavenCli code
var cons = CliRequest.class.getDeclaredConstructor(String[].class, ClassWorld.class);
cons.setAccessible(true);
var result = cons.newInstance(args, null);
var manifestRootFile = new File(manifestRoot.getPath());
setField(result, "workingDirectory", manifestRootFile.getPath());
setField(result, "multiModuleProjectDirectory", manifestRootFile);
return result;
}

public static Path getTempFile(String kind) throws IOException {
return Files.createTempFile("rascal-maven-" + kind + "-", ".tmp");
}
}
46 changes: 5 additions & 41 deletions src/org/rascalmpl/library/util/PathConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -16,9 +15,6 @@
import java.util.Objects;
import java.util.Set;

import org.apache.maven.cli.CliRequest;
import org.apache.maven.cli.MavenCli;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.rascalmpl.interpreter.Configuration;
import org.rascalmpl.interpreter.utils.RascalManifest;
import org.rascalmpl.uri.ILogicalSourceLocationResolver;
Expand Down Expand Up @@ -639,26 +635,11 @@ private static ISourceLocation setTargetScheme(ISourceLocation projectLoc) {
*/
private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) {
try {
ISourceLocation pomxml = URIUtil.getChildLocation(manifestRoot, "pom.xml");
pomxml = URIResolverRegistry.getInstance().logicalToPhysical(pomxml);
manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot);
var tempFile = Maven.getTempFile("classpath");
var mavenOutput = Maven.runCommand(List.of("-quiet", "-o", "dependency:build-classpath", "-DincludeScope=compile", "-Dmdep.outputFile=" + tempFile.toString()), manifestRoot, tempFile);

if (!"file".equals(manifestRoot.getScheme())) {
return vf.list();
}

if (!URIResolverRegistry.getInstance().exists(pomxml)) {
return vf.list();
}

var maven = new MavenCli();
var tempFile = Files.createTempFile("rascal-classpath-", ".tmp");

maven.doMain(buildRequest(new String[] {"-quiet", "-o", "dependency:build-classpath", "-DincludeScope=compile", "-Dmdep.outputFile=" + tempFile.toString()}, manifestRoot));

var foundClassPath = Files.readAllLines(tempFile).get(0);

return Arrays.stream(foundClassPath.split(File.pathSeparator))
// The classpath will be written to the temp file on a single line
return Arrays.stream(mavenOutput.get(0).split(File.pathSeparator))
.filter(fileName -> new File(fileName).exists())
.map(elem -> {

Check warning on line 644 in src/org/rascalmpl/library/util/PathConfig.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/PathConfig.java#L642-L644

Added lines #L642 - L644 were not covered by tests
try {
Expand All @@ -671,28 +652,11 @@ private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) {
.filter(Objects::nonNull)
.collect(vf.listWriter());

Check warning on line 653 in src/org/rascalmpl/library/util/PathConfig.java

View check run for this annotation

Codecov / codecov/patch

src/org/rascalmpl/library/util/PathConfig.java#L652-L653

Added lines #L652 - L653 were not covered by tests
}
catch (IOException | RuntimeException | ReflectiveOperationException e) {
catch (IOException | RuntimeException e) {
return vf.list();
}
}

private static void setField(CliRequest req, String fieldName, Object value) throws ReflectiveOperationException {
var field = CliRequest.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(req, value);
}

private static CliRequest buildRequest(String[] args, ISourceLocation manifestRoot) throws ReflectiveOperationException {
// we need to set a field that the default class doesn't set
// it's a work around around a bug in the MavenCli code
var cons = CliRequest.class.getDeclaredConstructor(String[].class, ClassWorld.class);
cons.setAccessible(true);
var result = cons.newInstance(args, null);
setField(result, "workingDirectory", new File(manifestRoot.getPath()).getPath());
setField(result, "multiModuleProjectDirectory", new File(manifestRoot.getPath()));
return result;
}

public ISourceLocation getBin() {
return bin;
}
Expand Down

0 comments on commit d30a696

Please sign in to comment.