diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java index c1a2b112727a..37210de9ce84 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java @@ -54,8 +54,11 @@ public interface MavenServerEmbedder extends Remote { @NotNull MavenServerExecutionResult execute(@NotNull File file, @NotNull Collection activeProfiles, - @NotNull List goals) throws RemoteException, - MavenServerProcessCanceledException; + @NotNull Collection inactiveProfiles, + @NotNull List goals, + @NotNull final List selectedProjects, + boolean alsoMake, + boolean alsoMakeDependents) throws RemoteException, MavenServerProcessCanceledException; void reset() throws RemoteException; diff --git a/plugins/maven/maven2-server-impl/lib-src/maven-embedder-1.1-SNAPSHOT-sources.jar b/plugins/maven/maven2-server-impl/lib-src/maven-embedder-1.1-SNAPSHOT-sources.jar deleted file mode 100644 index 041fce01bc86..000000000000 Binary files a/plugins/maven/maven2-server-impl/lib-src/maven-embedder-1.1-SNAPSHOT-sources.jar and /dev/null differ diff --git a/plugins/maven/maven2-server-impl/lib/maven-embedder-1.1-SNAPSHOT.jar b/plugins/maven/maven2-server-impl/lib/maven-embedder-1.1-SNAPSHOT.jar deleted file mode 100644 index c08b985459fb..000000000000 Binary files a/plugins/maven/maven2-server-impl/lib/maven-embedder-1.1-SNAPSHOT.jar and /dev/null differ diff --git a/plugins/maven/maven2-server-impl/maven2-server-impl.iml b/plugins/maven/maven2-server-impl/maven2-server-impl.iml index 364a132a931b..092e457efd1f 100644 --- a/plugins/maven/maven2-server-impl/maven2-server-impl.iml +++ b/plugins/maven/maven2-server-impl/maven2-server-impl.iml @@ -70,17 +70,6 @@ - - - - - - - - - - - diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java index 0bee080b8c84..cae29c345b98 100644 --- a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java @@ -327,13 +327,19 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven } @NotNull + @Override public MavenServerExecutionResult execute(@NotNull final File file, - @NotNull final Collection activeProfiles, - @NotNull final List goals) - throws MavenServerProcessCanceledException, RemoteException { + @NotNull final Collection activeProfiles, + @NotNull final Collection inactiveProfiles, + @NotNull final List goals, + @NotNull final List selectedProjects, + final boolean alsoMake, + final boolean alsoMakeDependents) throws RemoteException, MavenServerProcessCanceledException { return doExecute(new Executor() { public MavenServerExecutionResult execute() throws Exception { - MavenExecutionResult result = myImpl.execute(file, new ArrayList(activeProfiles), goals); + MavenExecutionResult result = myImpl + .execute(file, new ArrayList(activeProfiles), new ArrayList(inactiveProfiles), goals, selectedProjects, alsoMake, + alsoMakeDependents); return createExecutionResult(file, result, null); } }); diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/AbstractMavenLogger.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/AbstractMavenLogger.java new file mode 100644 index 000000000000..b166d1ea5d6b --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/AbstractMavenLogger.java @@ -0,0 +1,114 @@ +/* ========================================================================== + * Copyright 2006 Mevenide Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================================= + */ + +package org.jetbrains.maven.embedder; + +import org.codehaus.plexus.logging.Logger; + +public abstract class AbstractMavenLogger implements Logger { + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + private int myThreshold; + + private void doPrint(int level, String message, Throwable throwable) { + if (level < myThreshold) return; + + if (!message.endsWith(LINE_SEPARATOR)) { + message += LINE_SEPARATOR; + } + + printMessage(level, message, throwable); + } + + protected abstract void printMessage(int level, String message, Throwable throwable); + + public void debug(String string, Throwable throwable) { + doPrint(LEVEL_DEBUG, string, throwable); + } + + public void info(String string, Throwable throwable) { + doPrint(LEVEL_INFO, string, throwable); + } + + public void warn(String string, Throwable throwable) { + doPrint(LEVEL_WARN, string, throwable); + } + + public void error(String string, Throwable throwable) { + doPrint(LEVEL_ERROR, string, throwable); + } + + public void fatalError(String string, Throwable throwable) { + doPrint(LEVEL_FATAL, string, throwable); + } + + public void debug(String message) { + debug(message, null); + } + + public boolean isDebugEnabled() { + return getThreshold() <= LEVEL_DEBUG; + } + + public void info(String message) { + info(message, null); + } + + public boolean isInfoEnabled() { + return getThreshold() <= LEVEL_INFO; + } + + public void warn(String message) { + warn(message, null); + } + + public boolean isWarnEnabled() { + return getThreshold() <= LEVEL_WARN; + } + + public void error(String message) { + error(message, null); + } + + public boolean isErrorEnabled() { + return getThreshold() <= LEVEL_ERROR; + } + + public void fatalError(String message) { + fatalError(message, null); + } + + public boolean isFatalErrorEnabled() { + return getThreshold() <= LEVEL_FATAL; + } + + public void setThreshold(int threshold) { + this.myThreshold = threshold; + } + + public int getThreshold() { + return myThreshold; + } + + public Logger getChildLogger(String s) { + return null; + } + + public String getName() { + return toString(); + } +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/FieldAccessor.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/FieldAccessor.java new file mode 100644 index 000000000000..90255d1320df --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/FieldAccessor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.maven.embedder; + +import java.lang.reflect.Field; + +class FieldAccessor { + private volatile FIELD_TYPE myWagonManagerCache; + private final Class myHostClass; + private final Object myHost; + private final String myFieldName; + + public FieldAccessor(Class hostClass, T host, String fieldName) { + myHostClass = hostClass; + myHost = host; + myFieldName = fieldName; + } + + public FIELD_TYPE getField() { + if (myWagonManagerCache == null) { + Object value = getFieldValue(myHostClass, myFieldName, myHost); + //noinspection unchecked + myWagonManagerCache = (FIELD_TYPE)value; + } + return myWagonManagerCache; + } + + private Object getFieldValue(Class c, String fieldName, Object o) { + try { + Field f = c.getDeclaredField(fieldName); + f.setAccessible(true); + return f.get(o); + } + catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java new file mode 100644 index 000000000000..3926a3d1f030 --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java @@ -0,0 +1,596 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.maven.embedder; + +import org.apache.maven.DefaultMaven; +import org.apache.maven.Maven; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; +import org.apache.maven.artifact.manager.DefaultWagonManager; +import org.apache.maven.artifact.manager.WagonManager; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.DefaultArtifactRepository; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.resolver.*; +import org.apache.maven.execution.DefaultMavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.ReactorManager; +import org.apache.maven.extension.ExtensionManager; +import org.apache.maven.model.Extension; +import org.apache.maven.model.Plugin; +import org.apache.maven.monitor.event.DefaultEventDispatcher; +import org.apache.maven.monitor.event.DefaultEventMonitor; +import org.apache.maven.monitor.event.EventDispatcher; +import org.apache.maven.plugin.PluginManager; +import org.apache.maven.profiles.DefaultProfileManager; +import org.apache.maven.profiles.ProfileManager; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.project.ProjectBuilderConfiguration; +import org.apache.maven.project.interpolation.ModelInterpolationException; +import org.apache.maven.settings.*; +import org.codehaus.classworlds.ClassWorld; +import org.codehaus.plexus.DefaultPlexusContainer; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.component.repository.ComponentDescriptor; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.logging.BaseLoggerManager; +import org.codehaus.plexus.logging.Logger; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.jetbrains.annotations.NotNull; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class MavenEmbedder { + private static final String PROP_MAVEN_HOME = "maven.home"; + + private final DefaultPlexusContainer myContainer; + private final Settings mySettings; + private final Logger myLogger; + private final MavenEmbedderSettings myEmbedderSettings; + private final ArtifactRepository myLocalRepository; + + private MavenEmbedder(@NotNull DefaultPlexusContainer container, + @NotNull Settings settings, + @NotNull Logger logger, + @NotNull MavenEmbedderSettings embedderSettings) { + myContainer = container; + mySettings = settings; + myLogger = logger; + myEmbedderSettings = embedderSettings; + myLocalRepository = createLocalRepository(embedderSettings); + + loadSettings(); + } + + private void loadSettings() { + // copied from DefaultMaven.resolveParameters + // copied because using original code spoils something in the container and configuration are get messed and not picked up. + WagonManager wagonManager = getComponent(WagonManager.class); + + wagonManager.setOnline(!mySettings.isOffline()); + + if (wagonManager instanceof DefaultWagonManager) { + ((DefaultWagonManager)wagonManager).setHttpUserAgent("Apache-Maven/2.2"); + } + + Proxy proxy = mySettings.getActiveProxy(); + if (proxy != null && proxy.getHost() != null) { + String pass = decrypt(proxy.getPassword()); + wagonManager.addProxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), proxy.getUsername(), pass, proxy.getNonProxyHosts()); + } + + for (Object each : mySettings.getServers()) { + Server server = (Server)each; + + String passWord = decrypt(server.getPassword()); + String passPhrase = decrypt(server.getPassphrase()); + + wagonManager.addAuthenticationInfo(server.getId(), server.getUsername(), passWord, server.getPrivateKey(), passPhrase); + + wagonManager.addPermissionInfo(server.getId(), server.getFilePermissions(), server.getDirectoryPermissions()); + + if (server.getConfiguration() != null) { + wagonManager.addConfiguration(server.getId(), (Xpp3Dom)server.getConfiguration()); + } + } + + for (Object each : mySettings.getMirrors()) { + Mirror mirror = (Mirror)each; + if (mirror.getUrl() == null) continue; + wagonManager.addMirror(mirror.getId(), mirror.getMirrorOf(), mirror.getUrl()); + } + // end copied from DefaultMaven.resolveParameters + } + + private String decrypt(String pass) { + try { + pass = getComponent(SecDispatcher.class, "maven").decrypt(pass); + } + catch (SecDispatcherException e) { + MavenEmbedderLog.LOG.warn(e); + } + return pass; + } + + private ArtifactRepository createLocalRepository(MavenEmbedderSettings generalSettings) { + ArtifactRepositoryLayout layout = getComponent(ArtifactRepositoryLayout.class, "default"); + ArtifactRepositoryFactory factory = getComponent(ArtifactRepositoryFactory.class); + + String url = mySettings.getLocalRepository(); + if (!url.startsWith("file:")) url = "file://" + url; + + ArtifactRepository localRepository = new DefaultArtifactRepository("local", url, layout); + + boolean snapshotPolicySet = mySettings.isOffline(); + if (!snapshotPolicySet && generalSettings.getSnapshotUpdatePolicy() == MavenEmbedderSettings.UpdatePolicy.ALWAYS_UPDATE) { + factory.setGlobalUpdatePolicy(ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS); + } + factory.setGlobalChecksumPolicy(ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN); + + return localRepository; + } + + @NotNull + public ArtifactRepository getLocalRepository() { + return myLocalRepository; + } + + @NotNull + public File getLocalRepositoryFile() { + return new File(myLocalRepository.getBasedir()); + } + + public Settings getSettings() { + return mySettings; + } + + @NotNull + public MavenExecutionResult resolveProject(@NotNull final File file, @NotNull final List activeProfiles) { + return resolveProject(file, activeProfiles, Collections.emptyList()); + } + + @NotNull + public MavenExecutionResult resolveProject(@NotNull final File file, + @NotNull final List activeProfiles, + List listeners) { + MavenExecutionRequest request = createRequest(file, activeProfiles, Collections.emptyList(), Collections.emptyList()); + ProjectBuilderConfiguration config = request.getProjectBuilderConfiguration(); + + request.getGlobalProfileManager().loadSettingsProfiles(mySettings); + + ProfileManager globalProfileManager = request.getGlobalProfileManager(); + globalProfileManager.loadSettingsProfiles(request.getSettings()); + + List exceptions = new ArrayList(); + MavenProject project = null; + try { + // copied from DefaultMavenProjectBuilder.buildWithDependencies + MavenProjectBuilder builder = getComponent(MavenProjectBuilder.class); + project = builder.build(new File(file.getPath()), config); + builder.calculateConcreteState(project, config, false); + + // copied from DefaultLifecycleExecutor.execute + findExtensions(project); + // end copied from DefaultLifecycleExecutor.execute + + Artifact projectArtifact = project.getArtifact(); + Map managedVersions = project.getManagedVersionMap(); + ArtifactMetadataSource metadataSource = getComponent(ArtifactMetadataSource.class); + project.setDependencyArtifacts(project.createArtifacts(getComponent(ArtifactFactory.class), null, null)); + + ArtifactResolver resolver = getComponent(ArtifactResolver.class); + ArtifactResolutionResult result = resolver + .resolveTransitively(project.getDependencyArtifacts(), projectArtifact, managedVersions, myLocalRepository, + project.getRemoteArtifactRepositories(), metadataSource, null, listeners); + project.setArtifacts(result.getArtifacts()); + // end copied from DefaultMavenProjectBuilder.buildWithDependencies + } + catch (Exception e) { + return handleException(e); + } + + return new MavenExecutionResult(project, exceptions); + } + + private void findExtensions(MavenProject project) { + // end copied from DefaultLifecycleExecutor.findExtensions + ExtensionManager extensionManager = getComponent(ExtensionManager.class); + for (Object each : project.getBuildExtensions()) { + try { + extensionManager.addExtension((Extension)each, project, myLocalRepository); + } + catch (PlexusContainerException e) { + MavenEmbedderLog.LOG.error(e); + } + catch (ArtifactResolutionException e) { + MavenEmbedderLog.LOG.error(e); + } + catch (ArtifactNotFoundException e) { + MavenEmbedderLog.LOG.error(e); + } + } + extensionManager.registerWagons(); + + Map handlers = findArtifactTypeHandlers(project); + getComponent(ArtifactHandlerManager.class).addHandlers(handlers); + } + + @SuppressWarnings({"unchecked"}) + private Map findArtifactTypeHandlers(MavenProject project) { + // end copied from DefaultLifecycleExecutor.findExtensions + Map result = new HashMap(); + for (Object each : project.getBuildPlugins()) { + Plugin eachPlugin = (Plugin)each; + + if (eachPlugin.isExtensions()) { + try { + PluginManager pluginManager = getComponent(PluginManager.class); + pluginManager.verifyPlugin(eachPlugin, project, mySettings, myLocalRepository); + result.putAll(pluginManager.getPluginComponents(eachPlugin, ArtifactHandler.ROLE)); + } + catch (Exception e) { + MavenEmbedderLog.LOG.info(e); + continue; + } + + for (Object o : result.values()) { + ArtifactHandler handler = (ArtifactHandler)o; + if (project.getPackaging().equals(handler.getPackaging())) { + project.getArtifact().setArtifactHandler(handler); + } + } + } + } + return result; + } + + public void resolve(@NotNull final Artifact artifact, @NotNull final List repos) + throws ArtifactResolutionException, ArtifactNotFoundException { + getComponent(ArtifactResolver.class).resolve(artifact, repos, myLocalRepository); + } + + public Set resolveTransitively(@NotNull Set toResolve, @NotNull List repos) + throws ArtifactResolutionException, ArtifactNotFoundException { + Artifact project = getComponent(ArtifactFactory.class).createBuildArtifact("temp", "temp", "666", "pom"); + + return getComponent(ArtifactResolver.class) + .resolveTransitively(toResolve, project, Collections.EMPTY_MAP, myLocalRepository, repos, getComponent(ArtifactMetadataSource.class)) + .getArtifacts(); + } + + @NotNull + public MavenExecutionResult execute(@NotNull final File file, + @NotNull final List activeProfiles, + @NotNull final List inactiveProfiles, + @NotNull final List goals, + @NotNull final List selectedProjects, + boolean alsoMake, + boolean alsoMakeDependents) { + try { + MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, goals); + + if (!selectedProjects.isEmpty()) { + request.setRecursive(true); + request.setSelectedProjects(selectedProjects); + if (alsoMake && alsoMakeDependents) { + request.setMakeBehavior(ReactorManager.MAKE_BOTH_MODE); + } + else if (alsoMake) { + request.setMakeBehavior(ReactorManager.MAKE_MODE); + } + else if (alsoMakeDependents) { + request.setMakeBehavior(ReactorManager.MAKE_DEPENDENTS_MODE); + } + } + + Maven maven = getComponent(Maven.class); + Method method = maven.getClass().getDeclaredMethod("doExecute", MavenExecutionRequest.class, EventDispatcher.class); + method.setAccessible(true); + ReactorManager reactor = (ReactorManager)method.invoke(maven, request, request.getEventDispatcher()); + return new MavenExecutionResult(reactor.getTopLevelProject(), Collections.emptyList()); + } + catch (InvocationTargetException e) { + return handleException(e.getTargetException()); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); // should never happen + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); // should never happen + } + } + + @NotNull + public MavenExecutionResult readProjectWithModules(@NotNull final File file, List activeProfiles, List inactiveProfiles) { + MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.emptyList()); + request.getGlobalProfileManager().loadSettingsProfiles(mySettings); + request.setRecursive(true); + + return readProject(request); + } + + @NotNull + private MavenExecutionResult readProject(@NotNull final MavenExecutionRequest request) { + ProfileManager globalProfileManager = request.getGlobalProfileManager(); + globalProfileManager.loadSettingsProfiles(request.getSettings()); + + MavenProject rootProject = null; + final List exceptions = new ArrayList(); + Object result = null; + try { + final File pomFile = new File(request.getPomFile()); + if (!pomFile.exists()) { + throw new FileNotFoundException("File doesn't exist: " + pomFile.getPath()); + } + + final Method getProjectsMethod = DefaultMaven.class.getDeclaredMethod("getProjects", MavenExecutionRequest.class); + getProjectsMethod.setAccessible(true); + Maven maven = getComponent(Maven.class); + result = getProjectsMethod.invoke(maven, request); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + return handleException(e.getTargetException()); + } + catch (Exception e) { + return handleException(e); + } + + if (result != null) { + MavenProjectBuilder builder = getComponent(MavenProjectBuilder.class); + for (Object p : (List)result) { + MavenProject project = (MavenProject)p; + try { + builder.calculateConcreteState(project, request.getProjectBuilderConfiguration(), false); + } + catch (ModelInterpolationException e) { + exceptions.add(e); + } + + if (project.isExecutionRoot()) { + rootProject = project; + } + } + + if (rootProject == null && exceptions.isEmpty()) { + throw new RuntimeException("Could't build project for unknown reason"); + } + } + + return new MavenExecutionResult(rootProject, exceptions); + } + + @NotNull + public MavenExecutionResult readProject(@NotNull final File file, + @NotNull final List activeProfiles, + @NotNull final List inactiveProfiles) { + MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.emptyList()); + request.getGlobalProfileManager().loadSettingsProfiles(mySettings); + request.setRecursive(false); + + return readProject(request); + } + + private MavenExecutionRequest createRequest(File file, List activeProfiles, List inactiveProfiles, List goals) { + Properties executionProperties = myEmbedderSettings.getProperties(); + if (executionProperties == null) executionProperties = new Properties(); + + DefaultEventDispatcher dispatcher = new DefaultEventDispatcher(); + dispatcher.addEventMonitor(new DefaultEventMonitor(myLogger)); + + // subclassing because in DefaultMavenExecutionRequest field isRecursive is always false + MavenExecutionRequest result = new DefaultMavenExecutionRequest(myLocalRepository, mySettings, dispatcher, goals, file.getParent(), + createProfileManager(activeProfiles, inactiveProfiles, + executionProperties), executionProperties, + new Properties(), true) { + private boolean myIsRecursive; + + @Override + public boolean isRecursive() { + return myIsRecursive; + } + + @Override + public void setRecursive(final boolean recursive) { + myIsRecursive = recursive; + } + }; + + result.setPomFile(file.getPath()); + result.setRecursive(myEmbedderSettings.isRecursive()); + + return result; + } + + private MavenExecutionResult handleException(Throwable e) { + if (e instanceof RuntimeException) throw (RuntimeException)e; + if (e instanceof Error) throw (Error)e; + + return new MavenExecutionResult(null, Collections.singletonList((Exception)e)); + } + + private ProfileManager createProfileManager(List activeProfiles, List inactiveProfiles, Properties executionProperties) { + ProfileManager profileManager = new DefaultProfileManager(getContainer(), executionProperties); + profileManager.explicitlyActivate(activeProfiles); + profileManager.explicitlyDeactivate(inactiveProfiles); + return profileManager; + } + + @SuppressWarnings({"unchecked"}) + public T getComponent(Class clazz) { + try { + return (T)getContainer().lookup(clazz.getName()); + } + catch (ComponentLookupException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings({"unchecked"}) + public T getComponent(Class clazz, String roleHint) { + try { + return (T)getContainer().lookup(clazz.getName(), roleHint); + } + catch (ComponentLookupException e) { + throw new RuntimeException(e); + } + } + + public PlexusContainer getContainer() { + return myContainer; + } + + public void release() { + releaseResolverThreadExecutor(); + myContainer.dispose(); + } + + private void releaseResolverThreadExecutor() { + ArtifactResolver resolver = getComponent(ArtifactResolver.class); + @SuppressWarnings({"unchecked"}) FieldAccessor pool = new FieldAccessor(DefaultArtifactResolver.class, resolver, "resolveArtifactPool"); + try { + final Object threadPool = pool.getField(); // an instance of a hidden copy of ThreadPoolExecutor + threadPool.getClass().getMethod("shutdown").invoke(threadPool); + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + @NotNull + public static MavenEmbedder create(@NotNull final MavenEmbedderSettings embedderSettings) { + @NotNull final Logger logger = getLogger(embedderSettings); + + DefaultPlexusContainer container = new DefaultPlexusContainer(); + container.setClassWorld(new ClassWorld("plexus.core", embedderSettings.getClass().getClassLoader())); + container.setLoggerManager(new BaseLoggerManager() { + @Override + protected Logger createLogger(final String s) { + return logger; + } + }); + + try { + container.initialize(); + container.start(); + } + catch (PlexusContainerException e) { + MavenEmbedderLog.LOG.error(e); + throw new RuntimeException(e); + } + + final PlexusComponentConfigurator configurator = embedderSettings.getConfigurator(); + if (configurator != null) { + configurator.configureComponents(container); + } + + File mavenHome = embedderSettings.getMavenHome(); + if (mavenHome != null) { + System.setProperty(PROP_MAVEN_HOME, mavenHome.getPath()); + } + + Settings nativeSettings = buildSettings(container, embedderSettings); + + return new MavenEmbedder(container, nativeSettings, logger, embedderSettings); + } + + @NotNull + private static Logger getLogger(@NotNull final MavenEmbedderSettings embedderSettings) { + final Logger logger = embedderSettings.getLogger(); + return logger != null ? logger : new NullMavenLogger(); + } + + public static Settings buildSettings(PlexusContainer container, MavenEmbedderSettings embedderSettings) { + File file = embedderSettings.getGlobalSettingsFile(); + if (file != null) { + System.setProperty(MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION, file.getPath()); + } + + Settings settings = null; + + try { + MavenSettingsBuilder builder = (MavenSettingsBuilder)container.lookup(MavenSettingsBuilder.ROLE); + + File userSettingsFile = embedderSettings.getUserSettingsFile(); + if (userSettingsFile != null && userSettingsFile.exists() && !userSettingsFile.isDirectory()) { + settings = builder.buildSettings(userSettingsFile, false); + } + + if (settings == null) { + settings = builder.buildSettings(); + } + } + catch (ComponentLookupException e) { + MavenEmbedderLog.LOG.error(e); + } + catch (IOException e) { + MavenEmbedderLog.LOG.warn(e); + } + catch (XmlPullParserException e) { + MavenEmbedderLog.LOG.warn(e); + } + + if (settings == null) { + settings = new Settings(); + } + + if (embedderSettings.getLocalRepository() != null) { + settings.setLocalRepository(embedderSettings.getLocalRepository().getPath()); + } + if (settings.getLocalRepository() == null) { + settings.setLocalRepository(System.getProperty("user.home") + "/.m2/repository"); + } + + settings.setOffline(embedderSettings.isWorkOffline()); + settings.setInteractiveMode(false); + settings.setUsePluginRegistry(embedderSettings.isUsePluginRegistry()); + + RuntimeInfo runtimeInfo = new RuntimeInfo(settings); + runtimeInfo.setPluginUpdateOverride(embedderSettings.getPluginUpdatePolicy() == MavenEmbedderSettings.UpdatePolicy.ALWAYS_UPDATE); + settings.setRuntimeInfo(runtimeInfo); + + return settings; + } + + public static void setImplementation(PlexusContainer container, Class componentClass, Class implementationClass) { + ComponentDescriptor d = container.getComponentDescriptor(componentClass.getName()); + d.setImplementation(implementationClass.getName()); + } +} + diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLog.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLog.java new file mode 100644 index 000000000000..78cb538f928b --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLog.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.maven.embedder; + +import org.jetbrains.annotations.NotNull; + +public class MavenEmbedderLog { + public static final MavenEmbedderLogger LOG = new MavenEmbedderLogger() { + public void debug(final CharSequence msg) { + if (ourDelegate != null) ourDelegate.debug(msg); + } + + public void debug(final CharSequence msg, final Throwable e) { + if (ourDelegate != null) ourDelegate.debug(msg, e); + } + + public void debug(final Throwable e) { + if (ourDelegate != null) ourDelegate.debug(e); + } + + public void info(final CharSequence msg) { + if (ourDelegate != null) ourDelegate.info(msg); + } + + public void info(final CharSequence msg, final Throwable e) { + if (ourDelegate != null) ourDelegate.info(msg, e); + } + + public void info(final Throwable e) { + if (ourDelegate != null) ourDelegate.info(e); + } + + public void warn(final CharSequence msg) { + if (ourDelegate != null) ourDelegate.warn(msg); + } + + public void warn(final CharSequence msg, final Throwable e) { + if (ourDelegate != null) ourDelegate.warn(msg, e); + } + + public void warn(final Throwable e) { + if (ourDelegate != null) ourDelegate.warn(e); + } + + public void error(final CharSequence msg) { + if (ourDelegate != null) ourDelegate.error(msg); + } + + public void error(final CharSequence msg, final Throwable e) { + if (ourDelegate != null) ourDelegate.error(msg, e); + } + + public void error(final Throwable e) { + if (ourDelegate != null) ourDelegate.error(e); + } + }; + + private static MavenEmbedderLogger ourDelegate = null; + + public void setLogger(@NotNull final MavenEmbedderLogger logger) { + ourDelegate = logger; + } +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLogger.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLogger.java new file mode 100644 index 000000000000..8205236b2b69 --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderLogger.java @@ -0,0 +1,31 @@ +package org.jetbrains.maven.embedder; + +/** + * @author Sergey.Anchipolevsky + * Date: 27.01.2010 + */ +public interface MavenEmbedderLogger { + void debug(CharSequence msg); + + void debug(CharSequence msg, Throwable e); + + void debug(Throwable e); + + void info(CharSequence msg); + + void info(CharSequence msg, Throwable e); + + void info(Throwable e); + + void warn(CharSequence msg); + + void warn(CharSequence msg, Throwable e); + + void warn(Throwable e); + + void error(CharSequence msg); + + void error(CharSequence msg, Throwable e); + + void error(Throwable e); +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderSettings.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderSettings.java new file mode 100644 index 000000000000..0e9c51c3c083 --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedderSettings.java @@ -0,0 +1,151 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.maven.embedder; + +import org.codehaus.plexus.logging.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Properties; + +public class MavenEmbedderSettings { + public enum UpdatePolicy { + ALWAYS_UPDATE, DO_NOT_UPDATE + } + + private boolean workOffline = false; + private boolean isRecursive = true; + private File mavenHome; + private File userSettingsFile; + private File globalSettingsFile; + private File localRepository; + private boolean usePluginRegistry = false; + private UpdatePolicy snapshotUpdatePolicy = UpdatePolicy.ALWAYS_UPDATE; + private UpdatePolicy pluginUpdatePolicy = UpdatePolicy.DO_NOT_UPDATE; + private Properties myProperties; + + @Nullable + private Logger myLogger; + @Nullable + private PlexusComponentConfigurator myConfigurator; + + public boolean isWorkOffline() { + return workOffline; + } + + public void setWorkOffline(boolean workOffline) { + this.workOffline = workOffline; + } + + public boolean isRecursive() { + return isRecursive; + } + + public void setRecursive(boolean recursive) { + isRecursive = recursive; + } + + @Nullable + public File getMavenHome() { + return mavenHome; + } + + public void setMavenHome(@Nullable File mavenHome) { + this.mavenHome = mavenHome; + } + + @Nullable + public File getUserSettingsFile() { + return userSettingsFile; + } + + public void setUserSettingsFile(@Nullable File userSettingsFile) { + this.userSettingsFile = userSettingsFile; + } + + @Nullable + public File getGlobalSettingsFile() { + return globalSettingsFile; + } + + public void setGlobalSettingsFile(@Nullable File globalSettingsFile) { + this.globalSettingsFile = globalSettingsFile; + } + + @Nullable + public File getLocalRepository() { + return localRepository; + } + + public void setLocalRepository(@Nullable File localRepository) { + this.localRepository = localRepository; + } + + public boolean isUsePluginRegistry() { + return usePluginRegistry; + } + + public void setUsePluginRegistry(boolean usePluginRegistry) { + this.usePluginRegistry = usePluginRegistry; + } + + @NotNull + public UpdatePolicy getPluginUpdatePolicy() { + return pluginUpdatePolicy; + } + + public void setPluginUpdatePolicy(@Nullable UpdatePolicy value) { + this.pluginUpdatePolicy = value; + } + + @NotNull + public UpdatePolicy getSnapshotUpdatePolicy() { + return snapshotUpdatePolicy; + } + + public void setSnapshotUpdatePolicy(@Nullable UpdatePolicy value) { + this.snapshotUpdatePolicy = value; + } + + @Nullable + public Properties getProperties() { + return myProperties; + } + + public void setProperties(@Nullable Properties properties) { + myProperties = properties; + } + + @Nullable + public Logger getLogger() { + return myLogger; + } + + public void setLogger(@Nullable final Logger logger) { + myLogger = logger; + } + + + public void setConfigurator(@Nullable final PlexusComponentConfigurator configurator) { + myConfigurator = configurator; + } + + @Nullable + public PlexusComponentConfigurator getConfigurator() { + return myConfigurator; + } +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenExecutionResult.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenExecutionResult.java new file mode 100644 index 000000000000..bef95fd1369d --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenExecutionResult.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.maven.embedder; + +import org.apache.maven.project.MavenProject; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class MavenExecutionResult { + private final MavenProject myMavenProject; + private final List myExceptions; + + public MavenExecutionResult(@Nullable MavenProject mavenProject, List exceptions) { + myMavenProject = mavenProject; + myExceptions = exceptions; + } + + @Nullable + public MavenProject getMavenProject() { + return myMavenProject; + } + + public List getExceptions() { + return myExceptions; + } + + public boolean hasExceptions() { + return !myExceptions.isEmpty(); + } +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/NullMavenLogger.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/NullMavenLogger.java new file mode 100644 index 000000000000..17aea9782d5f --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/NullMavenLogger.java @@ -0,0 +1,12 @@ +package org.jetbrains.maven.embedder; + +/** + * @author Sergey.Anchipolevsky + * Date: 28.01.2010 + */ +class NullMavenLogger extends AbstractMavenLogger { + @Override + protected void printMessage(final int level, final String message, final Throwable throwable) { + // do nothing + } +} diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/PlexusComponentConfigurator.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/PlexusComponentConfigurator.java new file mode 100644 index 000000000000..3dc69e083c5a --- /dev/null +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/PlexusComponentConfigurator.java @@ -0,0 +1,13 @@ +package org.jetbrains.maven.embedder; + +import org.codehaus.plexus.PlexusContainer; +import org.jetbrains.annotations.NotNull; + +/** + * @author Sergey.Anchipolevsky + * Date: 21.09.2009 + */ +public interface PlexusComponentConfigurator { + void configureComponents(@NotNull PlexusContainer container); + +} diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java index f660a53c502d..c76a98c02d97 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java @@ -571,8 +571,13 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven @NotNull @Override - public MavenServerExecutionResult execute(@NotNull File file, @NotNull Collection activeProfiles, @NotNull List goals) - throws RemoteException, MavenServerProcessCanceledException { + public MavenServerExecutionResult execute(@NotNull File file, + @NotNull Collection activeProfiles, + @NotNull Collection inactiveProfiles, + @NotNull List goals, + @NotNull List selectedProjects, + boolean alsoMake, + boolean alsoMakeDependents) throws RemoteException, MavenServerProcessCanceledException { throw new UnsupportedOperationException(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java index 96ed1cff0bcd..6a90cc88bbb7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java @@ -918,6 +918,33 @@ public class MavenProjectsTree { } } + public MavenProject findRootProject(@NotNull MavenProject project) { + readLock(); + try { + MavenProject rootProject = project; + while (true) { + MavenProject aggregator = myModuleToAggregatorMapping.get(project); + if (aggregator == null) { + return rootProject; + } + rootProject = aggregator; + } + } + finally { + readUnlock(); + } + } + + public boolean isRootProject(@NotNull MavenProject project) { + readLock(); + try { + return myModuleToAggregatorMapping.get(project) == null; + } + finally { + readUnlock(); + } + } + public List getModules(MavenProject aggregator) { readLock(); try { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java index 520c3d9c4f76..3686d6f7c0e7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java @@ -157,7 +157,26 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper() { @Override public MavenServerExecutionResult execute() throws RemoteException, MavenServerProcessCanceledException { - return getOrCreateWrappee().execute(new File(file.getPath()), activeProfiles, goals); + return getOrCreateWrappee() + .execute(new File(file.getPath()), activeProfiles, Collections.emptyList(), goals, Collections.emptyList(), false, + false); + } + }); + } + + @NotNull + public MavenServerExecutionResult execute(@NotNull final VirtualFile file, + @NotNull final Collection activeProfiles, + @NotNull final Collection inactiveProfiles, + @NotNull final List goals, + @NotNull final List selectedProjects, + final boolean alsoMake, + final boolean alsoMakeDependents) throws MavenProcessCanceledException { + return perform(new RetriableCancelable() { + @Override + public MavenServerExecutionResult execute() throws RemoteException, MavenServerProcessCanceledException { + return getOrCreateWrappee() + .execute(new File(file.getPath()), activeProfiles, inactiveProfiles, goals, selectedProjects, alsoMake, alsoMakeDependents); } }); }