提交 60e9d410 编写于 作者: K kohsuke

expanded SCM a bit to make it usable from MavenModuleSet.

This doesn't seem like a good abstraction, so will check back later if there's any other way.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@1857 71c3de6d-444a-0410-be80-ed276b4c234a
上级 839e1266
......@@ -6,7 +6,9 @@ import hudson.model.Descriptor.FormException;
import hudson.model.Hudson;
import hudson.model.Items;
import hudson.model.Job;
import hudson.model.ItemGroup;
import hudson.util.DescribableList;
import hudson.FilePath;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -36,6 +38,17 @@ public final class MavenModule extends AbstractProject<MavenModule,MavenBuild> i
reporters.setOwner(this);
}
@Override
public FilePath getWorkspace() {
// TODO: implement this method later
throw new UnsupportedOperationException();
}
public MavenModuleSet getParent() {
return (MavenModuleSet)super.getParent();
}
@Override
public MavenBuild newBuild() throws IOException {
MavenBuild lastBuild = new MavenBuild(this);
......
package hudson.maven;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractItem;
import hudson.model.Descriptor.FormException;
import hudson.model.Hudson;
import hudson.model.ItemGroup;
import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import hudson.model.Items;
import hudson.model.JDK;
import hudson.model.Project;
import hudson.model.Descriptor.FormException;
import hudson.util.CopyOnWriteMap;
import hudson.scm.SCM;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import hudson.scm.NullSCM;
import hudson.scm.SCM;
import hudson.scm.SCMS;
import hudson.util.CopyOnWriteMap;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
/**
* Group of {@link MavenModule}s.
*
......@@ -61,7 +62,7 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr
private boolean disabled;
public MavenModuleSet(String name) {
super(name);
super(Hudson.getInstance(),name);
}
public String getUrlChildPrefix() {
......@@ -100,6 +101,14 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr
return getItems();
}
/**
* Gets the workspace of this job.
*/
public FilePath getWorkspace() {
// TODO: support roaming and etc
return Hudson.getInstance().getWorkspaceFor(this);
}
public void onLoad(String name) throws IOException {
super.onLoad(name);
......@@ -123,6 +132,22 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr
}
}
/**
* Obtains a workspace.
*/
public boolean checkout(Launcher launcher, TaskListener listener) throws IOException {
try {
FilePath workspace = getWorkspace();
workspace.mkdirs();
return scm.checkout(launcher, workspace, listener);
} catch (InterruptedException e) {
e.printStackTrace(listener.fatalError("SCM check out aborted"));
return false;
}
}
public synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return;
......
......@@ -35,8 +35,11 @@ public abstract class AbstractItem extends Actionable implements Item {
*/
protected transient File root;
protected AbstractItem(String name) {
private ItemGroup parent;
protected AbstractItem(ItemGroup parent, String name) {
doSetName(name);
this.parent = parent;
}
public String getName() {
......@@ -51,6 +54,11 @@ public abstract class AbstractItem extends Actionable implements Item {
return root;
}
public ItemGroup getParent() {
assert parent!=null;
return parent;
}
/**
* Gets the project description HTML.
*/
......
......@@ -94,10 +94,10 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
protected List<Trigger> triggers = new Vector<Trigger>();
protected AbstractProject(Hudson parent, String name) {
super(name);
protected AbstractProject(ItemGroup parent, String name) {
super(parent,name);
if(!parent.getSlaves().isEmpty()) {
if(!Hudson.getInstance().getSlaves().isEmpty()) {
// if a new job is configured with Hudson that already has slave nodes
// make it roamable by default
canRoam = true;
......@@ -132,23 +132,13 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
if(assignedNode ==null)
return Hudson.getInstance();
return getParent().getSlave(assignedNode);
return Hudson.getInstance().getSlave(assignedNode);
}
/**
* Gets the directory where the module is checked out.
*/
public FilePath getWorkspace() {
Node node = getLastBuiltOn();
if(node==null)
node = getParent();
if(node instanceof Slave)
return ((Slave)node).getWorkspaceRoot().child(getName());
else
return new FilePath(new File(getRootDir(),"workspace"));
}
public abstract FilePath getWorkspace();
/**
* Returns the root directory of the checked-out module.
......@@ -161,7 +151,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
public int getQuietPeriod() {
return quietPeriod!=null ? quietPeriod : getParent().getQuietPeriod();
return quietPeriod!=null ? quietPeriod : Hudson.getInstance().getQuietPeriod();
}
// ugly name because of EL
......@@ -182,7 +172,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
public void scheduleBuild() {
if(!disabled)
getParent().getQueue().add(this);
Hudson.getInstance().getQueue().add(this);
}
/**
......@@ -190,11 +180,11 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
@Override
public boolean isInQueue() {
return getParent().getQueue().contains(this);
return Hudson.getInstance().getQueue().contains(this);
}
public JDK getJDK() {
return getParent().getJDK(jdk);
return Hudson.getInstance().getJDK(jdk);
}
/**
......@@ -444,7 +434,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
if(!Hudson.adminCheck(req,rsp))
return;
getParent().getQueue().cancel(this);
Hudson.getInstance().getQueue().cancel(this);
rsp.forwardToPreviousPage(req);
}
......
......@@ -22,6 +22,11 @@ public class ExternalJob extends ViewJob<ExternalJob,ExternalRun> implements Top
super(parent,name);
}
@Override
public Hudson getParent() {
return (Hudson)super.getParent();
}
@Override
protected void reload() {
this.runs.load(this,new Constructor<ExternalRun>() {
......
......@@ -10,6 +10,7 @@ import hudson.PluginManager;
import hudson.PluginWrapper;
import hudson.Util;
import hudson.XmlFile;
import hudson.FilePath;
import hudson.model.Descriptor.FormException;
import hudson.model.listeners.ItemListener;
import hudson.model.listeners.JobListener;
......@@ -578,6 +579,10 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
return root;
}
public FilePath getWorkspaceFor(TopLevelItem item) {
return new FilePath(new File(item.getRootDir(),"workspace"));
}
public boolean isUseSecurity() {
return useSecurity;
}
......
......@@ -72,8 +72,8 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
*/
private CopyOnWriteList<JobProperty<? super JobT>> properties = new CopyOnWriteList<JobProperty<? super JobT>>();
protected Job(String name) {
super(name);
protected Job(ItemGroup parent,String name) {
super(parent,name);
getBuildDir().mkdirs();
}
......@@ -114,10 +114,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
getNextBuildNumberFile().write(String.valueOf(nextBuildNumber)+'\n');
}
public final Hudson getParent() {
return Hudson.getInstance();
}
public boolean isInQueue() {
return false;
}
......
package hudson.model;
import hudson.Launcher;
import hudson.FilePath;
import hudson.util.EnumConverter;
import org.apache.commons.beanutils.ConvertUtils;
......@@ -45,6 +46,15 @@ public interface Node {
Computer createComputer();
/**
* Returns a "workspace" directory for the given {@link TopLevelItem}.
*
* <p>
* Workspace directory is usually used for keeping out the checked out
* source code, but it can be used for anything.
*/
FilePath getWorkspaceFor(TopLevelItem item);
public enum Mode {
NORMAL("Utilize this slave as much as possible"),
EXCLUSIVE("Leave this machine for tied jobs only");
......
......@@ -9,6 +9,7 @@ import hudson.tasks.Builder;
import hudson.tasks.Fingerprinter;
import hudson.tasks.Publisher;
import hudson.triggers.Trigger;
import hudson.FilePath;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -71,6 +72,18 @@ public class Project extends AbstractProject<Project,Build> implements TopLevelI
updateTransientActions();
}
@Override
public Hudson getParent() {
return Hudson.getInstance();
}
@Override
public FilePath getWorkspace() {
Node node = getLastBuiltOn();
if(node==null) node = getParent();
return node.getWorkspaceFor(this);
}
@Override
public BallColor getIconColor() {
if(isDisabled())
......
......@@ -179,6 +179,10 @@ public final class Slave implements Node, Serializable {
return new ComputerImpl(this);
}
public FilePath getWorkspaceFor(TopLevelItem item) {
return getWorkspaceRoot().child(item.getName());
}
/**
* Root directory on this slave where all the job workspaces are laid out.
*/
......
......@@ -52,7 +52,7 @@ public abstract class ViewJob<JobT extends ViewJob<JobT,RunT>, RunT extends Run<
}
protected ViewJob(Hudson parent, String name) {
super(name);
super(parent,name);
}
public boolean isBuildable() {
......
......@@ -182,18 +182,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
if(changedFiles==null)
return false; // failed
} else {
dir.deleteContents();
ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add(getDescriptor().getCvsExe(),debugLogging?"-t":"-Q","-z9","-d",cvsroot,"co");
if(branch!=null)
cmd.add("-r",branch);
if(flatten)
cmd.add("-d",dir.getName());
configureDate(cmd, build.getTimestamp().getTime());
cmd.addTokenized(module);
if(!run(launcher,cmd,listener, flatten ? dir.getParent() : dir))
if(!checkout(launcher,dir,listener,build.getTimestamp().getTime()))
return false;
}
......@@ -241,6 +230,25 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
return calcChangeLog(build, changedFiles, changelogFile, listener);
}
public boolean checkout(Launcher launcher, FilePath dir, TaskListener listener) throws IOException, InterruptedException {
return checkout(launcher,dir,listener,new Date());
}
private boolean checkout(Launcher launcher, FilePath dir, TaskListener listener, Date dt) throws IOException, InterruptedException {
dir.deleteContents();
ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add(getDescriptor().getCvsExe(),debugLogging?"-t":"-Q","-z9","-d",cvsroot,"co");
if(branch!=null)
cmd.add("-r",branch);
if(flatten)
cmd.add("-d",dir.getName());
configureDate(cmd,dt);
cmd.addTokenized(module);
return run(launcher,cmd,listener, flatten ? dir.getParent() : dir);
}
/**
* Returns the file name used to archive the build.
*/
......
......@@ -28,6 +28,10 @@ public class NullSCM extends AbstractCVSFamilySCM /*to reuse createEmptyChangeLo
return createEmptyChangeLog(changeLogFile, listener, "log");
}
public boolean checkout(Launcher launcher, FilePath workspace, TaskListener listener) throws IOException, InterruptedException {
return true;
}
public Descriptor<SCM> getDescriptor() {
return DESCRIPTOR;
}
......
......@@ -78,6 +78,14 @@ public interface SCM extends Describable<SCM>, ExtensionPoint {
*/
boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changelogFile) throws IOException, InterruptedException;
/**
* Checks out the code into the workspace, but without computing changelog.
*
* TODO: This is an ugly abstraction.
* come back and check if this abstraction is really making much sense.
*/
boolean checkout(Launcher launcher, FilePath workspace, TaskListener listener) throws IOException, InterruptedException;
/**
* Adds environmental variables for the builds to the given map.
*/
......
......@@ -17,7 +17,6 @@ import hudson.util.FormFieldValidator;
import hudson.util.Scrambler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
......@@ -217,37 +216,11 @@ public class SubversionSCM extends AbstractCVSFamilySCM implements Serializable
}
public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, final BuildListener listener, File changelogFile) throws IOException, InterruptedException {
boolean result;
if(useUpdate && isUpdatable(workspace, listener)) {
result = update(launcher,workspace,listener);
if(!result)
if(!update(launcher,workspace,listener))
return false;
} else {
final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
result = workspace.act(new FileCallable<Boolean>() {
public Boolean invoke(File ws, VirtualChannel channel) throws IOException {
Util.deleteContentsRecursive(ws);
SVNUpdateClient svnuc = createSvnClientManager(authProvider).getUpdateClient();
svnuc.setEventHandler(new SubversionUpdateEventHandler(listener));
StringTokenizer tokens = new StringTokenizer(modules);
while(tokens.hasMoreTokens()) {
try {
SVNURL url = SVNURL.parseURIEncoded(tokens.nextToken());
listener.getLogger().println("Checking out "+url);
svnuc.doCheckout(url, new File(ws, getLastPathComponent(url.getPath())), SVNRevision.HEAD, SVNRevision.HEAD, true );
} catch (SVNException e) {
e.printStackTrace(listener.error("Error in subversion"));
return false;
}
}
return true;
}
});
if(!result)
if(!checkout(launcher,workspace, listener))
return false;
}
......@@ -265,6 +238,34 @@ public class SubversionSCM extends AbstractCVSFamilySCM implements Serializable
return calcChangeLog(build, changelogFile, listener);
}
public boolean checkout(Launcher launcher, FilePath workspace, final TaskListener listener) throws IOException, InterruptedException {
boolean result;
final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
result = workspace.act(new FileCallable<Boolean>() {
public Boolean invoke(File ws, VirtualChannel channel) throws IOException {
Util.deleteContentsRecursive(ws);
SVNUpdateClient svnuc = createSvnClientManager(authProvider).getUpdateClient();
svnuc.setEventHandler(new SubversionUpdateEventHandler(listener));
StringTokenizer tokens = new StringTokenizer(modules);
while(tokens.hasMoreTokens()) {
try {
SVNURL url = SVNURL.parseURIEncoded(tokens.nextToken());
listener.getLogger().println("Checking out "+url);
svnuc.doCheckout(url, new File(ws, getLastPathComponent(url.getPath())), SVNRevision.HEAD, SVNRevision.HEAD, true );
} catch (SVNException e) {
e.printStackTrace(listener.error("Error in subversion"));
return false;
}
}
return true;
}
});
return result;
}
/**
* Creates {@link SVNClientManager}.
*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册