提交 5c0b36da 编写于 作者: K Kohsuke Kawaguchi

made the location of Maven local repositories pluggable

上级 44c3253f
...@@ -80,6 +80,9 @@ Upcoming changes</a> ...@@ -80,6 +80,9 @@ Upcoming changes</a>
<li class="rfe"> <li class="rfe">
Added the Reploy-To header support. Added the Reploy-To header support.
(<a href="https://github.com/jenkinsci/jenkins/pull/306">pull #306</a>) (<a href="https://github.com/jenkinsci/jenkins/pull/306">pull #306</a>)
<li class="rfe">
The location of Maven local repository is now pluggable, and supported per-executor configuration out of the box.
(<a href="https://github.com/jenkinsci/jenkins/pull/293">pull #293</a>)
<li class="rfe"> <li class="rfe">
Jobs now support display name separate from its unique name Jobs now support display name separate from its unique name
<a href="https://issues.jenkins-ci.org/browse/JENKINS-11762">issue 11762</a> <a href="https://issues.jenkins-ci.org/browse/JENKINS-11762">issue 11762</a>
......
...@@ -25,6 +25,7 @@ package hudson.maven; ...@@ -25,6 +25,7 @@ package hudson.maven;
import hudson.EnvVars; import hudson.EnvVars;
import hudson.FilePath; import hudson.FilePath;
import hudson.maven.local_repo.LocalRepositoryLocator;
import hudson.maven.reporters.MavenArtifactRecord; import hudson.maven.reporters.MavenArtifactRecord;
import hudson.maven.reporters.SurefireArchiver; import hudson.maven.reporters.SurefireArchiver;
import hudson.slaves.WorkspaceList; import hudson.slaves.WorkspaceList;
...@@ -687,10 +688,10 @@ public class MavenBuild extends AbstractMavenBuild<MavenModule,MavenBuild> { ...@@ -687,10 +688,10 @@ public class MavenBuild extends AbstractMavenBuild<MavenModule,MavenBuild> {
getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null )); getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null ));
ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B"); ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B");
if(mms.usesPrivateRepository()) FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this);
// use the per-project repository. should it be per-module? But that would cost too much in terms of disk if(localRepo!=null)
// the workspace must be on this node, so getRemote() is safe. // the workspace must be on this node, so getRemote() is safe.
margs.add("-Dmaven.repo.local="+getWorkspace().child(".repository").getRemote()); margs.add("-Dmaven.repo.local="+localRepo.getRemote());
if (mms.getAlternateSettings() != null) { if (mms.getAlternateSettings() != null) {
if (IOUtils.isAbsolute(mms.getAlternateSettings())) { if (IOUtils.isAbsolute(mms.getAlternateSettings())) {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
*/ */
package hudson.maven; package hudson.maven;
import static hudson.Util.fixEmpty; import static hudson.Util.*;
import static hudson.model.ItemGroupMixIn.loadChildren; import static hudson.model.ItemGroupMixIn.loadChildren;
import hudson.CopyOnWrite; import hudson.CopyOnWrite;
import hudson.EnvVars; import hudson.EnvVars;
...@@ -34,6 +34,9 @@ import hudson.FilePath; ...@@ -34,6 +34,9 @@ import hudson.FilePath;
import hudson.Functions; import hudson.Functions;
import hudson.Indenter; import hudson.Indenter;
import hudson.Util; import hudson.Util;
import hudson.maven.local_repo.DefaultLocalRepositoryLocator;
import hudson.maven.local_repo.LocalRepositoryLocator;
import hudson.maven.local_repo.PerJobLocalRepositoryLocator;
import hudson.maven.settings.SettingsProviderUtils; import hudson.maven.settings.SettingsProviderUtils;
import hudson.model.AbstractProject; import hudson.model.AbstractProject;
import hudson.model.Action; import hudson.model.Action;
...@@ -183,8 +186,20 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -183,8 +186,20 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
* from multiple Maven process, so this helps there too. * from multiple Maven process, so this helps there too.
* *
* @since 1.223 * @since 1.223
* @deprecated as of 1.448
* Subsumed by {@link #localRepository}. false maps to {@link DefaultLocalRepositoryLocator},
* and true maps to {@link PerJobLocalRepositoryLocator}
*/ */
private boolean usePrivateRepository = false; private transient Boolean usePrivateRepository;
/**
* Encapsulates where to run the local repository.
*
* If null, inherited from the global configuration.
*
* @since 1.448
*/
private LocalRepositoryLocator localRepository = null;
/** /**
* If true, the build will send a failure e-mail for each failing maven module. * If true, the build will send a failure e-mail for each failing maven module.
...@@ -440,8 +455,12 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -440,8 +455,12 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
return aggregatorStyleBuild; return aggregatorStyleBuild;
} }
/**
* @deprecated as of 1.448
* Use {@link #getLocalRepository()}
*/
public boolean usesPrivateRepository() { public boolean usesPrivateRepository() {
return usePrivateRepository; return !(getLocalRepository() instanceof DefaultLocalRepositoryLocator);
} }
public boolean isPerModuleEmail() { public boolean isPerModuleEmail() {
...@@ -468,8 +487,31 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -468,8 +487,31 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
this.aggregatorStyleBuild = aggregatorStyleBuild; this.aggregatorStyleBuild = aggregatorStyleBuild;
} }
/**
* @deprecated as of 1.448.
* Use {@link #setLocalRepository(LocalRepositoryLocator)} instead
*/
public void setUsePrivateRepository(boolean usePrivateRepository) { public void setUsePrivateRepository(boolean usePrivateRepository) {
this.usePrivateRepository = usePrivateRepository; setLocalRepository(usePrivateRepository?new PerJobLocalRepositoryLocator() : new DefaultLocalRepositoryLocator());
}
/**
* @return
* never null
*/
public LocalRepositoryLocator getLocalRepository() {
return localRepository!=null ? localRepository : getDescriptor().getLocalRepository();
}
/**
* Undefaulted locally configured value with taking inheritance from the global configuration into account.
*/
public LocalRepositoryLocator getExplicitLocalRepository() {
return localRepository;
}
public void setLocalRepository(LocalRepositoryLocator localRepository) {
this.localRepository = localRepository;
} }
public void setIgnoreUpstremChanges(boolean ignoreUpstremChanges) { public void setIgnoreUpstremChanges(boolean ignoreUpstremChanges) {
...@@ -681,6 +723,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -681,6 +723,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
perModuleEmail = Boolean.TRUE; perModuleEmail = Boolean.TRUE;
} }
if (Boolean.TRUE.equals(usePrivateRepository)) {
this.localRepository = new PerJobLocalRepositoryLocator();
usePrivateRepository = null;
}
updateTransientActions(); updateTransientActions();
} }
...@@ -1002,7 +1049,10 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -1002,7 +1049,10 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
mavenOpts = Util.fixEmpty(req.getParameter("mavenOpts").trim()); mavenOpts = Util.fixEmpty(req.getParameter("mavenOpts").trim());
mavenName = req.getParameter("maven_version"); mavenName = req.getParameter("maven_version");
aggregatorStyleBuild = !req.hasParameter("maven.perModuleBuild"); aggregatorStyleBuild = !req.hasParameter("maven.perModuleBuild");
usePrivateRepository = req.hasParameter("maven.usePrivateRepository"); if (json.optBoolean("usePrivateRepository"))
localRepository = req.bindJSON(LocalRepositoryLocator.class,json.getJSONObject("explicitLocalRepository"));
else
localRepository = null;
perModuleEmail = req.hasParameter("maven.perModuleEmail"); perModuleEmail = req.hasParameter("maven.perModuleEmail");
ignoreUpstremChanges = !json.has("triggerByDependency"); ignoreUpstremChanges = !json.has("triggerByDependency");
runHeadless = req.hasParameter("maven.runHeadless"); runHeadless = req.hasParameter("maven.runHeadless");
...@@ -1085,6 +1135,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -1085,6 +1135,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
*/ */
private Map<String, Integer> mavenValidationLevels = new LinkedHashMap<String, Integer>(); private Map<String, Integer> mavenValidationLevels = new LinkedHashMap<String, Integer>();
/**
* @since 1.448
*/
private LocalRepositoryLocator localRepository = new DefaultLocalRepositoryLocator();
public DescriptorImpl() { public DescriptorImpl() {
super(); super();
load(); load();
...@@ -1105,6 +1160,18 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -1105,6 +1160,18 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
save(); save();
} }
/**
* @return never null.
*/
public LocalRepositoryLocator getLocalRepository() {
return localRepository!=null ? localRepository : new DefaultLocalRepositoryLocator();
}
public void setLocalRepository(LocalRepositoryLocator localRepository) {
this.localRepository = localRepository;
save();
}
public String getDisplayName() { public String getDisplayName() {
return Messages.MavenModuleSet_DiplayName(); return Messages.MavenModuleSet_DiplayName();
} }
...@@ -1128,6 +1195,7 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod ...@@ -1128,6 +1195,7 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
@Override @Override
public boolean configure( StaplerRequest req, JSONObject o ) { public boolean configure( StaplerRequest req, JSONObject o ) {
globalMavenOpts = Util.fixEmptyAndTrim(o.getString("globalMavenOpts")); globalMavenOpts = Util.fixEmptyAndTrim(o.getString("globalMavenOpts"));
localRepository = req.bindJSON(LocalRepositoryLocator.class,o.getJSONObject("localRepository"));
save(); save();
return true; return true;
......
...@@ -719,8 +719,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven ...@@ -719,8 +719,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
pom.getParent() ) ); pom.getParent() ) );
} }
ArgumentListBuilder margs = new ArgumentListBuilder().add("-B").add("-f", pom.getRemote()); ArgumentListBuilder margs = new ArgumentListBuilder().add("-B").add("-f", pom.getRemote());
if(project.usesPrivateRepository()) FilePath localRepo = project.getLocalRepository().locate(MavenModuleSetBuild.this);
margs.add("-Dmaven.repo.local="+getWorkspace().child(".repository")); if(localRepo!=null)
margs.add("-Dmaven.repo.local="+localRepo.getRemote());
if (project.globalSettingConfigPath != null) if (project.globalSettingConfigPath != null)
margs.add("-gs" , project.globalSettingConfigPath); margs.add("-gs" , project.globalSettingConfigPath);
...@@ -910,7 +911,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven ...@@ -910,7 +911,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
List<PomInfo> poms; List<PomInfo> poms;
try { try {
poms = getModuleRoot().act(new PomParser(listener, mvn, project, mavenVersion, envVars, getWorkspace())); poms = getModuleRoot().act(new PomParser(listener, mvn, mavenVersion, envVars, MavenModuleSetBuild.this));
} catch (IOException e) { } catch (IOException e) {
if (project.isIncrementalBuild()) { if (project.isIncrementalBuild()) {
// If POM parsing failed we should do a full build next time. // If POM parsing failed we should do a full build next time.
...@@ -1074,8 +1075,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven ...@@ -1074,8 +1075,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
String rootPOMRelPrefix; String rootPOMRelPrefix;
public PomParser(BuildListener listener, MavenInstallation mavenHome, MavenModuleSet project, String mavenVersion, EnvVars envVars, FilePath workspace) { public PomParser(BuildListener listener, MavenInstallation mavenHome, String mavenVersion, EnvVars envVars, MavenModuleSetBuild build) {
// project cannot be shipped to the remote JVM, so all the relevant properties need to be captured now. // project cannot be shipped to the remote JVM, so all the relevant properties need to be captured now.
MavenModuleSet project = build.getProject();
this.listener = listener; this.listener = listener;
this.mavenHome = mavenHome; this.mavenHome = mavenHome;
this.rootPOM = project.getRootPOM(); this.rootPOM = project.getRootPOM();
...@@ -1100,10 +1102,11 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven ...@@ -1100,10 +1102,11 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
this.nonRecursive = project.isNonRecursive(); this.nonRecursive = project.isNonRecursive();
this.workspaceProper = workspace.getRemote(); this.workspaceProper = build.getWorkspace().getRemote();
LOGGER.fine("Workspace is " + workspaceProper); LOGGER.fine("Workspace is " + workspaceProper);
if (project.usesPrivateRepository()) { FilePath localRepo = project.getLocalRepository().locate(build);
this.privateRepository = workspace.child(".repository").getRemote(); if (localRepo!=null) {
this.privateRepository = localRepo.getRemote();
} else { } else {
this.privateRepository = null; this.privateRepository = null;
} }
...@@ -1115,7 +1118,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven ...@@ -1115,7 +1118,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
this.processPlugins = project.isProcessPlugins(); this.processPlugins = project.isProcessPlugins();
this.moduleRootPath = this.moduleRootPath =
project.getScm().getModuleRoot( workspace, project.getLastBuild() ).getRemote(); project.getScm().getModuleRoot( build.getWorkspace(), project.getLastBuild() ).getRemote();
this.mavenValidationLevel = project.getMavenValidationLevel(); this.mavenValidationLevel = project.getMavenValidationLevel();
this.globalSetings = project.globalSettingConfigPath; this.globalSetings = project.globalSettingConfigPath;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
package hudson.maven; package hudson.maven;
import hudson.AbortException; import hudson.AbortException;
import hudson.FilePath;
import hudson.Util; import hudson.Util;
import hudson.model.AbstractBuild; import hudson.model.AbstractBuild;
import hudson.model.AbstractProject; import hudson.model.AbstractProject;
...@@ -102,8 +103,9 @@ public class MavenUtil { ...@@ -102,8 +103,9 @@ public class MavenUtil {
settingsLoc = (altSet == null) ? null settingsLoc = (altSet == null) ? null
: new File(build.getWorkspace().child(altSet).getRemote()); : new File(build.getWorkspace().child(altSet).getRemote());
if (((MavenModuleSet) project).usesPrivateRepository()) { FilePath localRepo = ((MavenModuleSet) project).getLocalRepository().locate((MavenModuleSetBuild) build);
privateRepository = build.getWorkspace().child(".repository").getRemote(); if (localRepo!=null) {
privateRepository = localRepo.getRemote();
} }
profiles = ((MavenModuleSet) project).getProfiles(); profiles = ((MavenModuleSet) project).getProfiles();
......
package hudson.maven.local_repo;
import hudson.Extension;
import hudson.FilePath;
import hudson.maven.AbstractMavenBuild;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Uses Maven's default local repository, which is actually <tt>~/.m2/repository</tt>
*
* @author Kohsuke Kawaguchi
*/
public class DefaultLocalRepositoryLocator extends LocalRepositoryLocator {
@DataBoundConstructor
public DefaultLocalRepositoryLocator() {
}
@Override
public FilePath locate(AbstractMavenBuild build) {
return null;
}
@Extension
public static class DescriptorImpl extends LocalRepositoryLocatorDescriptor {
@Override
public String getDisplayName() {
return "Default (~/.m2/repository)";
}
}
}
package hudson.maven.local_repo;
import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.maven.AbstractMavenBuild;
import hudson.model.AbstractDescribableImpl;
/**
* Strategy pattern that decides the location of the Maven local repository for a build.
*
* @author Kohsuke Kawaguchi
* @since 1.448
* @see LocalRepositoryLocatorDescriptor
*/
public abstract class LocalRepositoryLocator extends AbstractDescribableImpl<LocalRepositoryLocator> implements ExtensionPoint {
/**
* Called during the build on the master to determine the location of the local Maven repository.
*
* @return
* null to let Maven uses its default location. Otherwise this must be located on the same
* node as {@link AbstractMavenBuild#getWorkspace()} does.
*/
public abstract FilePath locate(AbstractMavenBuild build);
@Override
public LocalRepositoryLocatorDescriptor getDescriptor() {
return (LocalRepositoryLocatorDescriptor)super.getDescriptor();
}
}
package hudson.maven.local_repo;
import hudson.model.Descriptor;
/**
* @author Kohsuke Kawaguchi
* @since 1.448
* @see LocalRepositoryLocator
*/
public abstract class LocalRepositoryLocatorDescriptor extends Descriptor<LocalRepositoryLocator> {
}
package hudson.maven.local_repo;
import hudson.Extension;
import hudson.FilePath;
import hudson.maven.AbstractMavenBuild;
import hudson.model.Executor;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* @author Kohsuke Kawaguchi
*/
public class PerExecutorLocalRepositoryLocator extends LocalRepositoryLocator {
@DataBoundConstructor
public PerExecutorLocalRepositoryLocator() {}
@Override
public FilePath locate(AbstractMavenBuild build) {
return build.getBuiltOn().getRootPath().child("maven-repositories/"+ Executor.currentExecutor().getNumber());
}
@Extension
public static class DescriptorImpl extends LocalRepositoryLocatorDescriptor {
@Override
public String getDisplayName() {
return "Local to the executor";
}
}
}
package hudson.maven.local_repo;
import hudson.Extension;
import hudson.FilePath;
import hudson.maven.AbstractMavenBuild;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Uses a local repository isolated per job.
*
* @author Kohsuke Kawaguchi
*/
public class PerJobLocalRepositoryLocator extends LocalRepositoryLocator {
@DataBoundConstructor
public PerJobLocalRepositoryLocator() {
}
@Override
public FilePath locate(AbstractMavenBuild build) {
return build.getWorkspace().child(".repository");
}
@Extension
public static class DescriptorImpl extends LocalRepositoryLocatorDescriptor {
@Override
public String getDisplayName() {
return "Local to the workspace";
}
}
}
...@@ -97,7 +97,9 @@ THE SOFTWARE. ...@@ -97,7 +97,9 @@ THE SOFTWARE.
<f:optionalBlock name="maven.perModuleBuild" title="${%Build modules in parallel}" help="/plugin/maven-plugin/aggregator.html" <f:optionalBlock name="maven.perModuleBuild" title="${%Build modules in parallel}" help="/plugin/maven-plugin/aggregator.html"
checked="${!it.aggregatorStyleBuild}" /> checked="${!it.aggregatorStyleBuild}" />
<f:optionalBlock name="maven.usePrivateRepository" title="${%Use private Maven repository}" help="/plugin/maven-plugin/private-repository.html" <f:optionalBlock name="maven.usePrivateRepository" title="${%Use private Maven repository}" help="/plugin/maven-plugin/private-repository.html"
checked="${it.usesPrivateRepository()}" /> checked="${it.getExplicitLocalRepository()!=null}" inline="true">
<f:dropdownDescriptorSelector title="${%Strategy}" field="explicitLocalRepository" />
</f:optionalBlock>
<f:optionalBlock name="maven.perModuleEmail" title="${%Send e-mail for each failed module}" help="/plugin/maven-plugin/per-module-email.html" <f:optionalBlock name="maven.perModuleEmail" title="${%Send e-mail for each failed module}" help="/plugin/maven-plugin/per-module-email.html"
checked="${it.isPerModuleEmail()}" /> checked="${it.isPerModuleEmail()}" />
<f:optionalBlock name="maven.resolveDependencies" title="${%Resolve Dependencies during Pom parsing}" <f:optionalBlock name="maven.resolveDependencies" title="${%Resolve Dependencies during Pom parsing}"
......
...@@ -31,5 +31,6 @@ THE SOFTWARE. ...@@ -31,5 +31,6 @@ THE SOFTWARE.
<f:entry title="${%Global MAVEN_OPTS}" help="/plugin/maven-plugin/maven-opts.html"> <f:entry title="${%Global MAVEN_OPTS}" help="/plugin/maven-plugin/maven-opts.html">
<f:expandableTextbox name="globalMavenOpts" value="${descriptor.globalMavenOpts}" /> <f:expandableTextbox name="globalMavenOpts" value="${descriptor.globalMavenOpts}" />
</f:entry> </f:entry>
<f:dropdownDescriptorSelector title="${%Local Maven Repository}" field="localRepository" />
</f:section> </f:section>
</j:jelly> </j:jelly>
\ No newline at end of file
<div>
Specifies the default setting of the local repository location when jobs do not specify one.
See the per-job configuration of this (under the "Advanced" button) for more discussion
of what this option means.
</div>
\ No newline at end of file
package hudson.maven.local_repo.LocalRepositoryLocator;
// default no-op config fragment
\ No newline at end of file
package hudson.maven;
import hudson.maven.local_repo.PerJobLocalRepositoryLocator;
import org.jvnet.hudson.test.HudsonTestCase;
/**
* @author Kohsuke Kawaguchi
*/
public class MavenModuleSetTest extends HudsonTestCase {
public void testConfigRoundtripLocalRepository() throws Exception {
MavenModuleSet p = createMavenProject();
configRoundtrip(p);
assertNull(p.getExplicitLocalRepository());
// make sure it roundtrips
PerJobLocalRepositoryLocator before = new PerJobLocalRepositoryLocator();
p.setLocalRepository(before);
configRoundtrip(p);
assertEqualDataBoundBeans(p.getLocalRepository(),before);
assertTrue(before!=p.getLocalRepository());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册