package fitnesse.wikitext.widgets;
import hudson.maven.MavenEmbedderException;
import hudson.maven.MavenEmbedderUtils;
import hudson.maven.MavenRequest;
import org.apache.maven.DefaultMaven;
import org.apache.maven.Maven;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.cli.MavenCli;
import org.apache.maven.execution.*;
import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.*;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.*;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuilder;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsBuildingRequest;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.sonatype.aether.RepositorySystemSession;
import java.io.*;
import java.util.*;
/**
* Copied from Hudson's Maven Embedded which hides most of this behind private methods, making it impossible to change
* it's behavior. Only change is the addition of buildProject which builds the project using dependency resolution.
*/
public class DependencyResolvingMavenEmbedder {
public static final String userHome = System.getProperty("user.home");
private MavenXpp3Reader modelReader;
private MavenXpp3Writer modelWriter;
private final File mavenHome;
private final PlexusContainer plexusContainer;
private final MavenRequest mavenRequest;
private MavenExecutionRequest mavenExecutionRequest;
private final MavenSession mavenSession;
public DependencyResolvingMavenEmbedder(File mavenHome, MavenRequest mavenRequest) throws MavenEmbedderException {
this(mavenHome, mavenRequest, MavenEmbedderUtils.buildPlexusContainer(mavenHome, mavenRequest));
}
public DependencyResolvingMavenEmbedder(ClassLoader mavenClassLoader, ClassLoader parent, MavenRequest mavenRequest) throws MavenEmbedderException {
this(null, mavenRequest, MavenEmbedderUtils.buildPlexusContainer(mavenClassLoader, parent, mavenRequest));
}
private DependencyResolvingMavenEmbedder(File mavenHome, MavenRequest mavenRequest, PlexusContainer plexusContainer)
throws MavenEmbedderException {
this.mavenHome = mavenHome;
this.mavenRequest = mavenRequest;
this.plexusContainer = plexusContainer;
try {
this.buildMavenExecutionRequest();
RepositorySystemSession rss = ((DefaultMaven) lookup(Maven.class)).newRepositorySession(mavenExecutionRequest);
mavenSession = new MavenSession(plexusContainer, rss, mavenExecutionRequest, new DefaultMavenExecutionResult());
lookup(LegacySupport.class).setSession(mavenSession);
} catch (MavenEmbedderException e) {
throw new MavenEmbedderException(e.getMessage(), e);
} catch (ComponentLookupException e) {
throw new MavenEmbedderException(e.getMessage(), e);
}
}
public DependencyResolvingMavenEmbedder(ClassLoader mavenClassLoader, MavenRequest mavenRequest) throws MavenEmbedderException {
this(mavenClassLoader, null, mavenRequest);
}
private void buildMavenExecutionRequest()
throws MavenEmbedderException, ComponentLookupException {
this.mavenExecutionRequest = new DefaultMavenExecutionRequest();
if (this.mavenRequest.getGlobalSettingsFile() != null) {
this.mavenExecutionRequest.setGlobalSettingsFile(this.mavenExecutionRequest.getGlobalSettingsFile());
}
if (this.mavenExecutionRequest.getUserSettingsFile() != null) {
this.mavenExecutionRequest.setUserSettingsFile(new File(mavenRequest.getUserSettingsFile()));
}
try {
lookup(MavenExecutionRequestPopulator.class).populateFromSettings(this.mavenExecutionRequest,
getSettings());
lookup(MavenExecutionRequestPopulator.class).populateDefaults(mavenExecutionRequest);
} catch (MavenExecutionRequestPopulationException e) {
throw new MavenEmbedderException(e.getMessage(), e);
}
ArtifactRepository localRepository = getLocalRepository();
this.mavenExecutionRequest.setLocalRepository(localRepository);
this.mavenExecutionRequest.setLocalRepositoryPath(localRepository.getBasedir());
this.mavenExecutionRequest.setOffline(this.mavenExecutionRequest.isOffline());
this.mavenExecutionRequest.setUpdateSnapshots(this.mavenRequest.isUpdateSnapshots());
// TODO check null and create a console one ?
this.mavenExecutionRequest.setTransferListener(this.mavenRequest.getTransferListener());
this.mavenExecutionRequest.setCacheNotFound(this.mavenRequest.isCacheNotFound());
this.mavenExecutionRequest.setCacheTransferError(true);
this.mavenExecutionRequest.setUserProperties(this.mavenRequest.getUserProperties());
this.mavenExecutionRequest.getSystemProperties().putAll(System.getProperties());
if (this.mavenRequest.getSystemProperties() != null) {
this.mavenExecutionRequest.getSystemProperties().putAll(this.mavenRequest.getSystemProperties());
}
this.mavenExecutionRequest.getSystemProperties().putAll(getEnvVars());
if (this.mavenHome != null) {
this.mavenExecutionRequest.getSystemProperties().put("maven.home", this.mavenHome.getAbsolutePath());
}
if (this.mavenRequest.getProfiles() != null && !this.mavenRequest.getProfiles().isEmpty()) {
for (String id : this.mavenRequest.getProfiles()) {
Profile p = new Profile();
p.setId(id);
p.setSource("cli");
this.mavenExecutionRequest.addProfile(p);
this.mavenExecutionRequest.addActiveProfile(id);
}
}
this.mavenExecutionRequest.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_WARN);
lookup(Logger.class).setThreshold(Logger.LEVEL_WARN);
this.mavenExecutionRequest.setExecutionListener(this.mavenRequest.getExecutionListener())
.setInteractiveMode(this.mavenRequest.isInteractive())
.setGlobalChecksumPolicy(this.mavenRequest.getGlobalChecksumPolicy())
.setGoals(this.mavenRequest.getGoals());
if (this.mavenRequest.getPom() != null) {
this.mavenExecutionRequest.setPom(new File(this.mavenRequest.getPom()));
}
if (this.mavenRequest.getWorkspaceReader() != null) {
this.mavenExecutionRequest.setWorkspaceReader(this.mavenRequest.getWorkspaceReader());
}
}
private Properties getEnvVars() {
Properties envVars = new Properties();
boolean caseSensitive = !Os.isFamily(Os.FAMILY_WINDOWS);
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
String key = "env." + (caseSensitive ? entry.getKey() : entry.getKey().toUpperCase(Locale.ENGLISH));
envVars.setProperty(key, entry.getValue());
}
return envVars;
}
public Settings getSettings()
throws MavenEmbedderException, ComponentLookupException {
SettingsBuildingRequest settingsBuildingRequest = new DefaultSettingsBuildingRequest();
if (this.mavenRequest.getGlobalSettingsFile() != null) {
settingsBuildingRequest.setGlobalSettingsFile(new File(this.mavenRequest.getGlobalSettingsFile()));
} else {
settingsBuildingRequest.setGlobalSettingsFile(MavenCli.DEFAULT_GLOBAL_SETTINGS_FILE);
}
if (this.mavenRequest.getUserSettingsFile() != null) {
settingsBuildingRequest.setUserSettingsFile(new File(this.mavenRequest.getUserSettingsFile()));
} else {
settingsBuildingRequest.setUserSettingsFile(MavenCli.DEFAULT_USER_SETTINGS_FILE);
}
settingsBuildingRequest.setUserProperties(this.mavenRequest.getUserProperties());
settingsBuildingRequest.getSystemProperties().putAll(System.getProperties());
settingsBuildingRequest.getSystemProperties().putAll(this.mavenRequest.getSystemProperties());
settingsBuildingRequest.getSystemProperties().putAll(getEnvVars());
try {
return lookup(SettingsBuilder.class).build(settingsBuildingRequest).getEffectiveSettings();
} catch (SettingsBuildingException e) {
throw new MavenEmbedderException(e.getMessage(), e);
}
}
public ArtifactRepository getLocalRepository() throws ComponentLookupException {
try {
String localRepositoryPath = getLocalRepositoryPath();
if (localRepositoryPath != null) {
return lookup(RepositorySystem.class).createLocalRepository(new File(localRepositoryPath));
}
return lookup(RepositorySystem.class).createLocalRepository(RepositorySystem.defaultUserLocalRepository);
} catch (InvalidRepositoryException e) {
// never happened
throw new IllegalStateException(e);
}
}
public String getLocalRepositoryPath() {
String path = null;
try {
Settings settings = getSettings();
path = settings.getLocalRepository();
} catch (MavenEmbedderException e) {
// ignore
} catch (ComponentLookupException e) {
// ignore
}
if (this.mavenRequest.getLocalRepositoryPath() != null) {
path = this.mavenRequest.getLocalRepositoryPath();
}
if (path == null) {
path = RepositorySystem.defaultUserLocalRepository.getAbsolutePath();
}
return path;
}
// ----------------------------------------------------------------------
// Model
// ----------------------------------------------------------------------
public Model readModel(File model)
throws XmlPullParserException, FileNotFoundException, IOException {
return modelReader.read(new FileReader(model));
}
public void writeModel(Writer writer, Model model)
throws IOException {
modelWriter.write(writer, model);
}
// ----------------------------------------------------------------------
// Project
// ----------------------------------------------------------------------
public MavenProject readProject(File mavenProject)
throws ProjectBuildingException, MavenEmbedderException {
List<MavenProject> projects = readProjects(mavenProject, false);
return projects == null || projects.isEmpty() ? null : projects.get(0);
}
public List<MavenProject> readProjects(File mavenProject, boolean recursive)
throws ProjectBuildingException, MavenEmbedderException {
ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
try {
List<ProjectBuildingResult> results = buildProjects(mavenProject, recursive);
List<MavenProject> projects = new ArrayList<MavenProject>(results.size());
for (ProjectBuildingResult result : results) {
projects.add(result.getProject());
}
return projects;
} finally {
Thread.currentThread().setContextClassLoader(originalCl);
}
}
public ProjectBuildingResult buildProject(File mavenProject) throws ProjectBuildingException, MavenEmbedderException {
ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.plexusContainer.getContainerRealm());
ProjectBuilder projectBuilder = lookup(ProjectBuilder.class);
ProjectBuildingRequest projectBuildingRequest = this.mavenExecutionRequest.getProjectBuildingRequest();
projectBuildingRequest.setValidationLevel(this.mavenRequest.getValidationLevel());
RepositorySystemSession repositorySystemSession = buildRepositorySystemSession();
projectBuildingRequest.setRepositorySession(repositorySystemSession);
projectBuildingRequest.setProcessPlugins(this.mavenRequest.isProcessPlugins());
projectBuildingRequest.setResolveDependencies(this.mavenRequest.isResolveDependencies());
return projectBuilder.build(mavenProject, projectBuildingRequest);
} catch (ComponentLookupException e) {
throw new MavenEmbedderException(e.getMessage(), e);
} finally {
Thread.currentThread().setContextClassLoader(originalCl);
}
}
public List<ProjectBuildingResult> buildProjects(File mavenProject, boolean recursive)
throws ProjectBuildingException, MavenEmbedderException {
ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.plexusContainer.getContainerRealm());
ProjectBuilder projectBuilder = lookup(ProjectBuilder.class);
ProjectBuildingRequest projectBuildingRequest = this.mavenExecutionRequest.getProjectBuildingRequest();
projectBuildingRequest.setValidationLevel(this.mavenRequest.getValidationLevel());
RepositorySystemSession repositorySystemSession = buildRepositorySystemSession();
projectBuildingRequest.setRepositorySession(repositorySystemSession);
projectBuildingRequest.setProcessPlugins(this.mavenRequest.isProcessPlugins());
projectBuildingRequest.setResolveDependencies(this.mavenRequest.isResolveDependencies());
List<ProjectBuildingResult> results = projectBuilder.build(Arrays.asList(mavenProject), recursive, projectBuildingRequest);
return results;
} catch (ComponentLookupException e) {
throw new MavenEmbedderException(e.getMessage(), e);
} finally {
Thread.currentThread().setContextClassLoader(originalCl);
}
}
private RepositorySystemSession buildRepositorySystemSession() throws ComponentLookupException {
DefaultMaven defaultMaven = (DefaultMaven) plexusContainer.lookup(Maven.class);
return defaultMaven.newRepositorySession(mavenExecutionRequest);
}
public List<MavenProject> collectProjects(File basedir, String[] includes, String[] excludes)
throws MojoExecutionException, MavenEmbedderException {
List<MavenProject> projects = new ArrayList<MavenProject>();
List<File> poms = getPomFiles(basedir, includes, excludes);
for (File pom : poms) {
try {
MavenProject p = readProject(pom);
projects.add(p);
} catch (ProjectBuildingException e) {
throw new MojoExecutionException("Error loading " + pom, e);
}
}
return projects;
}
// ----------------------------------------------------------------------
// Artifacts
// ----------------------------------------------------------------------
public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type)
throws MavenEmbedderException {
try {
RepositorySystem repositorySystem = lookup(RepositorySystem.class);
return repositorySystem.createArtifact(groupId, artifactId, version, scope, type);
} catch (ComponentLookupException e) {
throw new MavenEmbedderException(e.getMessage(), e);
}
}
public Artifact createArtifactWithClassifier(String groupId, String artifactId, String version, String type, String classifier)
throws MavenEmbedderException {
try {
RepositorySystem repositorySystem = lookup(RepositorySystem.class);
return repositorySystem.createArtifactWithClassifier(groupId, artifactId, version, type, classifier);
} catch (ComponentLookupException e) {
throw new MavenEmbedderException(e.getMessage(), e);
}
}
public void resolve(Artifact artifact, List remoteRepositories, ArtifactRepository localRepository)
throws ArtifactResolutionException, ArtifactNotFoundException {
// FIXME ?
}
// ----------------------------------------------------------------------
// Execution of phases/goals
// ----------------------------------------------------------------------
public MavenExecutionResult execute(MavenRequest mavenRequest)
throws ComponentLookupException {
Maven maven = lookup(Maven.class);
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.plexusContainer.getContainerRealm());
return maven.execute(mavenExecutionRequest);
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
// ----------------------------------------------------------------------
// Local Repository
// ----------------------------------------------------------------------
public static final String DEFAULT_LOCAL_REPO_ID = "local";
public static final String DEFAULT_LAYOUT_ID = "default";
public ArtifactRepository createLocalRepository(File localRepository)
throws ComponentLookupException {
return createLocalRepository(localRepository.getAbsolutePath(), DEFAULT_LOCAL_REPO_ID);
}
public ArtifactRepository createLocalRepository(Settings settings)
throws ComponentLookupException {
return createLocalRepository(settings.getLocalRepository(), DEFAULT_LOCAL_REPO_ID);
}
public ArtifactRepository createLocalRepository(String url, String repositoryId)
throws ComponentLookupException {
if (!url.startsWith("file:")) {
url = "file://" + url;
}
return createRepository(url, repositoryId);
}
public ArtifactRepository createRepository(String url, String repositoryId)
throws ComponentLookupException {
// snapshots vs releases
// offline = to turning the update policy off
//TODO: we'll need to allow finer grained creation of repositories but this will do for now
String updatePolicyFlag = ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS;
String checksumPolicyFlag = ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN;
ArtifactRepositoryPolicy snapshotsPolicy = new ArtifactRepositoryPolicy(true, updatePolicyFlag, checksumPolicyFlag);
ArtifactRepositoryPolicy releasesPolicy = new ArtifactRepositoryPolicy(true, updatePolicyFlag, checksumPolicyFlag);
RepositorySystem repositorySystem = lookup(RepositorySystem.class);
ArtifactRepositoryLayout repositoryLayout = lookup(ArtifactRepositoryLayout.class, "default");
return repositorySystem.createArtifactRepository(repositoryId, url, repositoryLayout, snapshotsPolicy, releasesPolicy);
}
// ----------------------------------------------------------------------
// Internal utility code
// ----------------------------------------------------------------------
private List<File> getPomFiles(File basedir, String[] includes, String[] excludes) {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(basedir);
scanner.setIncludes(includes);
scanner.setExcludes(excludes);
scanner.scan();
List<File> poms = new ArrayList<File>();
for (int i = 0; i < scanner.getIncludedFiles().length; i++) {
poms.add(new File(basedir, scanner.getIncludedFiles()[i]));
}
return poms;
}
/**
* {@link org.apache.maven.artifact.manager.WagonManager} can't configure itself from {@link Settings}, so we need to baby-sit them.
* So much for dependency injection.
*/
private void resolveParameters(WagonManager wagonManager, Settings settings)
throws ComponentLookupException, ComponentLifecycleException, SettingsConfigurationException {
// TODO todo or not todo ?
Proxy proxy = settings.getActiveProxy();
if (proxy != null) {
if (proxy.getHost() == null) {
throw new SettingsConfigurationException("Proxy in settings.xml has no host");
}
//wagonManager.addProxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), proxy.getUsername(),
// proxy.getPassword(), proxy.getNonProxyHosts());
}
for (Server server : (List<Server>) settings.getServers()) {
//wagonManager.addAuthenticationInfo(server.getId(), server.getUsername(), server.getPassword(),
// server.getPrivateKey(), server.getPassphrase());
//wagonManager.addPermissionInfo(server.getId(), server.getFilePermissions(),
// server.getDirectoryPermissions());
if (server.getConfiguration() != null) {
//wagonManager.addConfiguration(server.getId(), (Xpp3Dom) server.getConfiguration());
}
}
for (Mirror mirror : (List<Mirror>) settings.getMirrors()) {
//wagonManager.addMirror(mirror.getId(), mirror.getMirrorOf(), mirror.getUrl());
}
}
public <T> T lookup(Class<T> clazz) throws ComponentLookupException {
return plexusContainer.lookup(clazz);
}
public <T> T lookup(Class<T> clazz, String hint) throws ComponentLookupException {
return plexusContainer.lookup(clazz, hint);
}
public Object lookup(String role, String hint) throws ComponentLookupException {
return plexusContainer.lookup(role, hint);
}
public Object lookup(String role) throws ComponentLookupException {
return plexusContainer.lookup(role);
}
private Map<String, String> propertiesToMap(Properties properties) {
if (properties == null || properties.isEmpty()) {
return new HashMap<String, String>(0);
}
Map<String, String> result = new HashMap<String, String>(properties.size());
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
result.put((String) entry.getKey(), (String) entry.getValue());
}
return result;
}
public MavenRequest getMavenRequest() {
return mavenRequest;
}
}