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

made the location of Maven local repositories pluggable

上级 44c3253f
......@@ -80,6 +80,9 @@ Upcoming changes</a>
<li class="rfe">
Added the Reploy-To header support.
(<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">
Jobs now support display name separate from its unique name
<a href="https://issues.jenkins-ci.org/browse/JENKINS-11762">issue 11762</a>
......
......@@ -25,6 +25,7 @@ package hudson.maven;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.maven.local_repo.LocalRepositoryLocator;
import hudson.maven.reporters.MavenArtifactRecord;
import hudson.maven.reporters.SurefireArchiver;
import hudson.slaves.WorkspaceList;
......@@ -687,10 +688,10 @@ public class MavenBuild extends AbstractMavenBuild<MavenModule,MavenBuild> {
getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null ));
ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B");
if(mms.usesPrivateRepository())
// use the per-project repository. should it be per-module? But that would cost too much in terms of disk
FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this);
if(localRepo!=null)
// 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 (IOUtils.isAbsolute(mms.getAlternateSettings())) {
......
......@@ -24,7 +24,7 @@
*/
package hudson.maven;
import static hudson.Util.fixEmpty;
import static hudson.Util.*;
import static hudson.model.ItemGroupMixIn.loadChildren;
import hudson.CopyOnWrite;
import hudson.EnvVars;
......@@ -34,6 +34,9 @@ import hudson.FilePath;
import hudson.Functions;
import hudson.Indenter;
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.model.AbstractProject;
import hudson.model.Action;
......@@ -183,8 +186,20 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
* from multiple Maven process, so this helps there too.
*
* @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.
......@@ -440,8 +455,12 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
return aggregatorStyleBuild;
}
/**
* @deprecated as of 1.448
* Use {@link #getLocalRepository()}
*/
public boolean usesPrivateRepository() {
return usePrivateRepository;
return !(getLocalRepository() instanceof DefaultLocalRepositoryLocator);
}
public boolean isPerModuleEmail() {
......@@ -468,8 +487,31 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
this.aggregatorStyleBuild = aggregatorStyleBuild;
}
/**
* @deprecated as of 1.448.
* Use {@link #setLocalRepository(LocalRepositoryLocator)} instead
*/
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) {
......@@ -681,6 +723,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
perModuleEmail = Boolean.TRUE;
}
if (Boolean.TRUE.equals(usePrivateRepository)) {
this.localRepository = new PerJobLocalRepositoryLocator();
usePrivateRepository = null;
}
updateTransientActions();
}
......@@ -1002,7 +1049,10 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
mavenOpts = Util.fixEmpty(req.getParameter("mavenOpts").trim());
mavenName = req.getParameter("maven_version");
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");
ignoreUpstremChanges = !json.has("triggerByDependency");
runHeadless = req.hasParameter("maven.runHeadless");
......@@ -1085,6 +1135,11 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
*/
private Map<String, Integer> mavenValidationLevels = new LinkedHashMap<String, Integer>();
/**
* @since 1.448
*/
private LocalRepositoryLocator localRepository = new DefaultLocalRepositoryLocator();
public DescriptorImpl() {
super();
load();
......@@ -1105,6 +1160,18 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
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() {
return Messages.MavenModuleSet_DiplayName();
}
......@@ -1128,6 +1195,7 @@ public class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,MavenMod
@Override
public boolean configure( StaplerRequest req, JSONObject o ) {
globalMavenOpts = Util.fixEmptyAndTrim(o.getString("globalMavenOpts"));
localRepository = req.bindJSON(LocalRepositoryLocator.class,o.getJSONObject("localRepository"));
save();
return true;
......
......@@ -719,8 +719,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
pom.getParent() ) );
}
ArgumentListBuilder margs = new ArgumentListBuilder().add("-B").add("-f", pom.getRemote());
if(project.usesPrivateRepository())
margs.add("-Dmaven.repo.local="+getWorkspace().child(".repository"));
FilePath localRepo = project.getLocalRepository().locate(MavenModuleSetBuild.this);
if(localRepo!=null)
margs.add("-Dmaven.repo.local="+localRepo.getRemote());
if (project.globalSettingConfigPath != null)
margs.add("-gs" , project.globalSettingConfigPath);
......@@ -910,7 +911,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
List<PomInfo> poms;
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) {
if (project.isIncrementalBuild()) {
// If POM parsing failed we should do a full build next time.
......@@ -1074,8 +1075,9 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
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.
MavenModuleSet project = build.getProject();
this.listener = listener;
this.mavenHome = mavenHome;
this.rootPOM = project.getRootPOM();
......@@ -1100,10 +1102,11 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
this.nonRecursive = project.isNonRecursive();
this.workspaceProper = workspace.getRemote();
this.workspaceProper = build.getWorkspace().getRemote();
LOGGER.fine("Workspace is " + workspaceProper);
if (project.usesPrivateRepository()) {
this.privateRepository = workspace.child(".repository").getRemote();
FilePath localRepo = project.getLocalRepository().locate(build);
if (localRepo!=null) {
this.privateRepository = localRepo.getRemote();
} else {
this.privateRepository = null;
}
......@@ -1115,7 +1118,7 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
this.processPlugins = project.isProcessPlugins();
this.moduleRootPath =
project.getScm().getModuleRoot( workspace, project.getLastBuild() ).getRemote();
project.getScm().getModuleRoot( build.getWorkspace(), project.getLastBuild() ).getRemote();
this.mavenValidationLevel = project.getMavenValidationLevel();
this.globalSetings = project.globalSettingConfigPath;
......
......@@ -24,6 +24,7 @@
package hudson.maven;
import hudson.AbortException;
import hudson.FilePath;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
......@@ -102,8 +103,9 @@ public class MavenUtil {
settingsLoc = (altSet == null) ? null
: new File(build.getWorkspace().child(altSet).getRemote());
if (((MavenModuleSet) project).usesPrivateRepository()) {
privateRepository = build.getWorkspace().child(".repository").getRemote();
FilePath localRepo = ((MavenModuleSet) project).getLocalRepository().locate((MavenModuleSetBuild) build);
if (localRepo!=null) {
privateRepository = localRepo.getRemote();
}
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.
<f:optionalBlock name="maven.perModuleBuild" title="${%Build modules in parallel}" help="/plugin/maven-plugin/aggregator.html"
checked="${!it.aggregatorStyleBuild}" />
<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"
checked="${it.isPerModuleEmail()}" />
<f:optionalBlock name="maven.resolveDependencies" title="${%Resolve Dependencies during Pom parsing}"
......
......@@ -31,5 +31,6 @@ THE SOFTWARE.
<f:entry title="${%Global MAVEN_OPTS}" help="/plugin/maven-plugin/maven-opts.html">
<f:expandableTextbox name="globalMavenOpts" value="${descriptor.globalMavenOpts}" />
</f:entry>
<f:dropdownDescriptorSelector title="${%Local Maven Repository}" field="localRepository" />
</f:section>
</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.
先完成此消息的编辑!
想要评论请 注册