提交 61a52267 编写于 作者: K kohsuke

I messed up the branching. So merging the maven2 branch to the trunk. If we...

I messed up the branching. So merging the maven2 branch to the trunk. If we need a quick fix release for 1.74, I'll see if I can move this all to a branch again.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@1808 71c3de6d-444a-0410-be80-ed276b4c234a
上级 fe21d5c1
......@@ -265,7 +265,7 @@ public final class PluginWrapper {
* Returns a one-line descriptive name of this plugin.
*/
public String getLongName() {
String name = manifest.getMainAttributes().getValue("Long-Name");
String name = manifest.getMainAttributes().getValue("Long-PluginName");
if(name!=null) return name;
return shortName;
}
......
......@@ -79,6 +79,10 @@ public final class XmlFile {
this.file = file;
}
public File getFile() {
return file;
}
/**
* Loads the contents of this file into a new object.
*/
......
......@@ -30,20 +30,20 @@ import java.util.Arrays;
import java.util.Calendar;
/**
* {@link Run} for {@link MavenJob}.
* {@link Run} for {@link MavenModule}.
*
* @author Kohsuke Kawaguchi
*/
public class MavenBuild extends AbstractBuild<MavenJob,MavenBuild> {
public MavenBuild(MavenJob job) throws IOException {
public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public MavenBuild(MavenModule job) throws IOException {
super(job);
}
public MavenBuild(MavenJob job, Calendar timestamp) {
public MavenBuild(MavenModule job, Calendar timestamp) {
super(job, timestamp);
}
public MavenBuild(MavenJob project, File buildDir) throws IOException {
public MavenBuild(MavenModule project, File buildDir) throws IOException {
super(project, buildDir);
}
......
......@@ -140,7 +140,7 @@ public abstract class MavenReporter implements Describable<MavenReporter>, Exten
* Equivalent of {@link BuildStep#getProjectAction(Project)}
* for {@link MavenReporter}.
*/
public Action getProjectAction(MavenJob project) {
public Action getProjectAction(MavenModule project) {
return null;
}
}
......@@ -27,9 +27,9 @@ public final class MojoInfo {
public final MojoExecution mojoExecution;
/**
* Name of the plugin that contains this mojo.
* PluginName of the plugin that contains this mojo.
*/
public final Name pluginName;
public final PluginName pluginName;
/**
* Configuration of the mojo for the current execution.
......@@ -54,7 +54,7 @@ public final class MojoInfo {
this.mojoExecution = mojoExecution;
this.configuration = configuration;
this.expressionEvaluator = expressionEvaluator;
this.pluginName = new Name(mojoExecution.getMojoDescriptor().getPluginDescriptor());
this.pluginName = new PluginName(mojoExecution.getMojoDescriptor().getPluginDescriptor());
}
/**
......
......@@ -33,7 +33,7 @@ import java.util.Map;
public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends AbstractBuild<P,R>> extends Run<P,R> implements Runnable {
/**
* Name of the slave this project was built on.
* PluginName of the slave this project was built on.
* Null or "" if built by the master. (null happens when we read old record that didn't have this information.)
*/
private String builtOn;
......
......@@ -7,7 +7,7 @@ import hudson.model.Descriptor.FormException;
import hudson.triggers.Trigger;
import hudson.triggers.Triggers;
import hudson.Launcher.LocalLauncher;
import hudson.maven.MavenJob;
import hudson.maven.MavenModule;
import hudson.scm.NullSCM;
import hudson.scm.SCM;
import hudson.scm.SCMS;
......@@ -25,7 +25,7 @@ import java.util.Map;
/**
* Base implementation of {@link Job}s that build software.
*
* For now this is primarily the common part of {@link Project} and {@link MavenJob}.
* For now this is primarily the common part of {@link Project} and {@link MavenModule}.
*
* @author Kohsuke Kawaguchi
* @see AbstractBuild
......@@ -89,7 +89,7 @@ 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(parent, name);
super(name);
if(!parent.getSlaves().isEmpty()) {
// if a new job is configured with Hudson that already has slave nodes
......@@ -99,8 +99,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
@Override
protected void onLoad(Hudson root, String name) throws IOException {
super.onLoad(root,name);
public void onLoad(String name) throws IOException {
super.onLoad(name);
this.builds = new RunMap<R>();
this.builds.load(this,new Constructor<R>() {
......
......@@ -161,7 +161,7 @@ public final class DirectoryBrowserSupport {
*/
private final String href;
/**
* Name of this path. Just the file name portion.
* PluginName of this path. Just the file name portion.
*/
private final String title;
......
......@@ -17,7 +17,7 @@ import java.util.logging.Logger;
*
* @author Kohsuke Kawaguchi
*/
public class ExternalJob extends ViewJob<ExternalJob,ExternalRun> {
public class ExternalJob extends ViewJob<ExternalJob,ExternalRun> implements TopLevelItem {
public ExternalJob(Hudson parent,String name) {
super(parent,name);
}
......@@ -62,11 +62,11 @@ public class ExternalJob extends ViewJob<ExternalJob,ExternalRun> {
private static final Logger logger = Logger.getLogger(ExternalJob.class.getName());
public JobDescriptor<ExternalJob,ExternalRun> getDescriptor() {
public TopLevelItemDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final JobDescriptor<ExternalJob,ExternalRun> DESCRIPTOR = new JobDescriptor<ExternalJob,ExternalRun>(ExternalJob.class) {
public static final TopLevelItemDescriptor DESCRIPTOR = new TopLevelItemDescriptor(ExternalJob.class) {
public String getDisplayName() {
return "Monitoring an external job";
}
......
......@@ -13,6 +13,8 @@ import hudson.XmlFile;
import hudson.model.Descriptor.FormException;
import hudson.model.listeners.JobListener;
import hudson.model.listeners.SCMListener;
import hudson.model.listeners.ItemListener;
import hudson.model.listeners.JobListener.JobListenerAdapter;
import hudson.remoting.LocalChannel;
import hudson.remoting.VirtualChannel;
import hudson.scm.CVSSCM;
......@@ -74,7 +76,7 @@ import java.util.logging.LogRecord;
*
* @author Kohsuke Kawaguchi
*/
public final class Hudson extends View implements Node {
public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node {
private transient final Queue queue = new Queue();
/**
......@@ -104,9 +106,18 @@ public final class Hudson extends View implements Node {
/**
* All {@link Job}s keyed by their names.
* Subset of {@link #items}.
*
* @deprecated
* TODO: get rid of this in favor of {@link #items}.
*/
/*package*/ transient final Map<String,Job> jobs = new TreeMap<String,Job>();
/**
* All {@link Item}s keyed by their {@link Item#getName() name}s.
*/
/*package*/ transient final Map<String,TopLevelItem> items = new TreeMap<String,TopLevelItem>();
/**
* The sole instance.
*/
......@@ -149,7 +160,7 @@ public final class Hudson extends View implements Node {
/**
* List of registered {@link JobListener}s.
*/
private transient final CopyOnWriteList<JobListener> jobListeners = new CopyOnWriteList<JobListener>();
private transient final CopyOnWriteList<ItemListener> viewItemListeners = new CopyOnWriteList<ItemListener>();
/**
* List of registered {@link SCMListener}s.
......@@ -170,9 +181,9 @@ public final class Hudson extends View implements Node {
// load plugins.
pluginManager = new PluginManager(context);
// work around to have MavenJob register itself until we either move it to a plugin
// work around to have MavenModule register itself until we either move it to a plugin
// or make it a part of the core.
Jobs.JOBS.hashCode();
TopLevelItems.LIST.hashCode();
load();
if(slaves==null) slaves = new ArrayList<Slave>();
......@@ -180,7 +191,7 @@ public final class Hudson extends View implements Node {
getQueue().load();
for (JobListener l : jobListeners)
for (ItemListener l : viewItemListeners)
l.onLoaded();
}
......@@ -247,7 +258,7 @@ public final class Hudson extends View implements Node {
* Use {@code getJobListners().add(l)} instead.
*/
public void addListener(JobListener l) {
jobListeners.add(l);
viewItemListeners.add(new JobListenerAdapter(l));
}
/**
......@@ -257,14 +268,14 @@ public final class Hudson extends View implements Node {
* Use {@code getJobListners().remove(l)} instead.
*/
public boolean removeListener(JobListener l ) {
return jobListeners.remove(l);
return viewItemListeners.remove(new JobListenerAdapter(l));
}
/**
* Gets all the installed {@link JobListener}s.
* Gets all the installed {@link ItemListener}s.
*/
public CopyOnWriteList<JobListener> getJobListeners() {
return jobListeners;
public CopyOnWriteList<ItemListener> getJobListeners() {
return viewItemListeners;
}
/**
......@@ -364,8 +375,8 @@ public final class Hudson extends View implements Node {
return new ArrayList<Job>(jobs.values());
}
public synchronized List<ViewItem> getItems() {
return new ArrayList<ViewItem>(jobs.values());
public synchronized List<TopLevelItem> getItems() {
return new ArrayList<TopLevelItem>(items.values());
}
/**
......@@ -398,7 +409,7 @@ public final class Hudson extends View implements Node {
* why are you calling a method that always return true?
*/
@Deprecated
public boolean contains(ViewItem view) {
public boolean contains(TopLevelItem view) {
return true;
}
......@@ -524,6 +535,10 @@ public final class Hudson extends View implements Node {
return "";
}
public String getUrlChildPrefix() {
return "job";
}
/**
* Gets the absolute URL of Hudson,
* such as "http://localhost/hudson/".
......@@ -589,6 +604,13 @@ public final class Hudson extends View implements Node {
return jobs.get(name);
}
/**
* Gets the {@link TopLevelItem} of the given name.
*/
public synchronized TopLevelItem getItem(String name) {
return items.get(name);
}
/**
* Gets the user of the given name.
*
......@@ -605,11 +627,11 @@ public final class Hudson extends View implements Node {
* @throws IllegalArgumentException
* if the project of the given name already exists.
*/
public synchronized Job createProject( JobDescriptor type, String name ) throws IOException {
public synchronized TopLevelItem createProject( TopLevelItemDescriptor type, String name ) throws IOException {
if(jobs.containsKey(name))
throw new IllegalArgumentException();
Job job;
TopLevelItem job;
try {
job = type.newInstance(name);
} catch (Exception e) {
......@@ -617,7 +639,7 @@ public final class Hudson extends View implements Node {
}
job.save();
jobs.put(name,job);
items.put(name,job);
return job;
}
......@@ -625,7 +647,7 @@ public final class Hudson extends View implements Node {
* Called in response to {@link Job#doDoDelete(StaplerRequest, StaplerResponse)}
*/
/*package*/ void deleteJob(Job job) throws IOException {
for (JobListener l : jobListeners)
for (ItemListener l : viewItemListeners)
l.onDeleted(job);
jobs.remove(job.getName());
......@@ -712,11 +734,11 @@ public final class Hudson extends View implements Node {
return child.isDirectory();
}
});
jobs.clear();
items.clear();
for (File subdir : subdirs) {
try {
Job p = Job.load(this,subdir);
jobs.put(p.getName(), p);
TopLevelItem item = (TopLevelItem)ItemLoader.load(subdir);
items.put(item.getName(), item);
} catch (IOException e) {
e.printStackTrace(); // TODO: logging
}
......@@ -857,7 +879,7 @@ public final class Hudson extends View implements Node {
rsp.sendRedirect2(".");
}
public synchronized Job doCreateJob( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
public synchronized Item doCreateViewItem( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return null;
......@@ -873,7 +895,7 @@ public final class Hudson extends View implements Node {
return null;
}
if(getJob(name)!=null) {
if(getItem(name)!=null) {
sendError("A job already exists with the name '"+name+"'",req,rsp);
return null;
}
......@@ -883,7 +905,7 @@ public final class Hudson extends View implements Node {
return null;
}
Job result;
TopLevelItem result;
if(mode.equals("newJob")) {
if(jobType ==null) {
......@@ -892,26 +914,26 @@ public final class Hudson extends View implements Node {
return null;
}
// redirect to the project config screen
result = createProject(Jobs.getDescriptor(jobType), name);
result = createProject(TopLevelItems.getDescriptor(jobType), name);
} else {
Job src = getJob(req.getParameter("from"));
TopLevelItem src = getItem(req.getParameter("from"));
if(src==null) {
rsp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return null;
}
result = createProject((JobDescriptor)src.getDescriptor(),name);
result = createProject(src.getDescriptor(),name);
// copy config
Util.copyFile(src.getConfigFile(),result.getConfigFile());
Util.copyFile(ItemLoader.getConfigFile(src).getFile(),ItemLoader.getConfigFile(result).getFile());
// reload from the new config
result = Job.load(this,result.getRootDir());
result.nextBuildNumber = 1; // reset the next build number
jobs.put(name,result);
result = (TopLevelItem)ItemLoader.load(result.getRootDir());
result.onCopiedFrom(src);
items.put(name,result);
}
for (JobListener l : jobListeners)
for (ItemListener l : viewItemListeners)
l.onCreated(result);
rsp.sendRedirect2(req.getContextPath()+'/'+result.getUrl()+"configure");
......
package hudson.model;
import com.thoughtworks.xstream.XStream;
import hudson.ExtensionPoint;
import hudson.Util;
import hudson.XmlFile;
import hudson.tasks.BuildTrigger;
import hudson.tasks.LogRotator;
import hudson.util.ChartUtil;
......@@ -15,7 +13,6 @@ import hudson.util.RunList;
import hudson.util.ShiftedCategoryAxis;
import hudson.util.StackedAreaRenderer2;
import hudson.util.TextFile;
import hudson.util.XStream2;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;
import org.jfree.chart.ChartFactory;
......@@ -50,14 +47,10 @@ import java.util.SortedMap;
* <p>
* Every time it "runs", it will be recorded as a {@link Run} object.
*
* <p>
* To register a custom {@link Job} class from a plugin, add it to
* {@link Jobs#JOBS}. Also see {@link Job#XSTREAM}.
*
* @author Kohsuke Kawaguchi
*/
public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,RunT>>
extends Actionable implements Describable<Job<JobT,RunT>>, ViewItem, ExtensionPoint {
extends AbstractItem implements ExtensionPoint {
/**
* Project name.
*/
......@@ -68,11 +61,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
*/
protected String description;
/**
* Root directory for this job.
*/
protected transient File root;
/**
* Next build number.
* Kept in a separate file because this is the only information
......@@ -83,7 +71,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
* so even though this is marked as transient, don't move it around.
*/
protected transient int nextBuildNumber = 1;
private transient Hudson parent;
private LogRotator logRotator;
......@@ -94,17 +81,13 @@ 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(Hudson parent,String name) {
this.parent = parent;
protected Job(String name) {
doSetName(name);
getBuildDir().mkdirs();
}
/**
* Called when a {@link Job} is loaded from disk.
*/
protected void onLoad(Hudson root, String name) throws IOException {
this.parent = root;
public void onLoad(String name) throws IOException {
super.onLoad(name);
doSetName(name);
TextFile f = getNextBuildNumberFile();
......@@ -127,16 +110,18 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
properties = new CopyOnWriteList<JobProperty<? super JobT>>();
}
@Override
public void onCopiedFrom(Item src) {
super.onCopiedFrom(src);
this.nextBuildNumber = 1; // reset the next build number
}
/**
* Just update {@link #name} and {@link #root}, since they are linked.
*/
private void doSetName(String name) {
this.name = name;
this.root = new File(new File(parent.root,"jobs"),name);
}
public File getRootDir() {
return root;
this.root = new File(new File(Hudson.getInstance().getRootDir(),"jobs"),name);
}
private TextFile getNextBuildNumberFile() {
......@@ -148,7 +133,7 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
}
public final Hudson getParent() {
return parent;
return Hudson.getInstance();
}
public boolean isInQueue() {
......@@ -241,6 +226,7 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
*/
public void renameTo(String newName) throws IOException {
// always synchronize from bigger objects first
final Hudson parent = Hudson.getInstance();
synchronized(parent) {
synchronized(this) {
// sanity check
......@@ -378,17 +364,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
}
}
/**
* The file we save our configuration.
*/
protected static XmlFile getConfigFile(File dir) {
return new XmlFile(XSTREAM,new File(dir,"config.xml"));
}
File getConfigFile() {
return new File(root,"config.xml");
}
/**
* Directory for storing {@link Run} records.
* <p>
......@@ -402,13 +377,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
return new File(root,"builds");
}
/**
* Returns the URL of this project.
*/
public String getUrl() {
return "job/"+name+'/';
}
/**
* Gets all the runs.
*
......@@ -490,21 +458,6 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
}
/**
* Save the settings to a file.
*/
public synchronized void save() throws IOException {
getConfigFile(root).write(this);
}
/**
* Loads a project from a config file.
*/
static Job load(Hudson root, File dir) throws IOException {
Job job = (Job)getConfigFile(dir).read();
job.onLoad(root,dir.getName());
return job;
}
......@@ -737,16 +690,4 @@ public abstract class Job<JobT extends Job<JobT,RunT>, RunT extends Run<JobT,Run
RSS.forwardToRss(getDisplayName()+ suffix, getUrl(),
runs.newBuilds(), Run.FEED_ADAPTER, req, rsp );
}
/**
* Used to load/save job configuration.
*
* When you extend {@link Job} in a plugin, try to put the alias so
* that it produces a reasonable XML.
*/
protected static final XStream XSTREAM = new XStream2();
static {
XSTREAM.alias("project",Project.class);
}
}
package hudson.model;
import java.util.List;
import java.util.ArrayList;
/**
* {@link Descriptor} for {@link JobProperty}.
*
......@@ -26,4 +29,15 @@ public abstract class JobPropertyDescriptor extends Descriptor<JobProperty<?>> {
* displayed in the configuration screen of this job.
*/
public abstract boolean isApplicable(Class<? extends Job> jobType);
/**
* Gets the {@link JobPropertyDescriptor}s applicable for a given job type.
*/
public List<JobPropertyDescriptor> getPropertyDescriptors(Class<? extends Job> clazz) {
List<JobPropertyDescriptor> r = new ArrayList<JobPropertyDescriptor>();
for (JobPropertyDescriptor p : Jobs.PROPERTIES)
if(p.isApplicable(clazz))
r.add(p);
return r;
}
}
package hudson.model;
import hudson.maven.MavenJob;
import java.util.List;
import java.util.ArrayList;
/**
* List of all installed {@link Job} types.
......@@ -11,36 +8,14 @@ import java.util.ArrayList;
* @author Kohsuke Kawaguchi
*/
public class Jobs {
/**
* List of all installed job types.
*/
@SuppressWarnings("unchecked") // two typing problems here!
public static final List<JobDescriptor<?,?>> JOBS = (List)Descriptor.toList(
Project.DESCRIPTOR,
ExternalJob.DESCRIPTOR
);
public static JobDescriptor getDescriptor(String displayName) {
for (JobDescriptor<?,?> job : JOBS) {
if(job.getDisplayName().equals(displayName))
return job;
}
return null;
}
/**
* List of all installed {@link JobPropertyDescriptor} types.
*
* <p>
* Plugins can add their {@link JobPropertyDescriptor}s to this list.
*
* @see JobDescriptor#getPropertyDescriptors()
* @see JobPropertyDescriptor#getPropertyDescriptors(Class)
*/
public static final List<JobPropertyDescriptor> PROPERTIES = Descriptor.toList(
);
static {
if(Boolean.getBoolean("hudson.maven"))
JOBS.add(MavenJob.DESCRIPTOR);
}
}
......@@ -26,7 +26,7 @@ public class ListView extends View {
/*package*/ final Set<String> jobNames = new TreeSet<String>();
/**
* Name of this view.
* PluginName of this view.
*/
private String name;
......@@ -48,19 +48,19 @@ public class ListView extends View {
* This method returns a separate copy each time to avoid
* concurrent modification issue.
*/
public synchronized List<Job> getItems() {
Job[] jobs = new Job[jobNames.size()];
public synchronized List<TopLevelItem> getItems() {
TopLevelItem[] items = new TopLevelItem[jobNames.size()];
int i=0;
for (String name : jobNames)
jobs[i++] = owner.getJob(name);
return Arrays.asList(jobs);
items[i++] = owner.getItem(name);
return Arrays.asList(items);
}
public Job getJob(String name) {
return owner.getJob(name);
public TopLevelItem getJob(String name) {
return owner.getItem(name);
}
public boolean contains(ViewItem item) {
public boolean contains(TopLevelItem item) {
return jobNames.contains(item.getName());
}
......@@ -76,16 +76,16 @@ public class ListView extends View {
return name;
}
public Job doCreateJob(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
public Item doCreateViewItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return null;
Job job = owner.doCreateJob(req, rsp);
if(job!=null) {
jobNames.add(job.getName());
Item item = owner.doCreateViewItem(req, rsp);
if(item!=null) {
jobNames.add(item.getName());
owner.save();
}
return job;
return item;
}
public String getUrl() {
......
......@@ -11,7 +11,7 @@ import org.apache.commons.beanutils.ConvertUtils;
*/
public interface Node {
/**
* Name of this node.
* PluginName of this node.
*
* @return
* "" if this is master
......
......@@ -12,7 +12,7 @@ import java.util.logging.Logger;
public abstract class PeriodicWork extends TimerTask {
/**
* Name of the work.
* PluginName of the work.
*/
private final String name;
private Thread thread;
......
package hudson.model;
import hudson.FilePath;
import hudson.model.Descriptor.FormException;
import hudson.model.Fingerprint.RangeSet;
import hudson.tasks.BuildStep;
......@@ -36,7 +35,7 @@ import java.util.Vector;
*
* @author Kohsuke Kawaguchi
*/
public class Project extends AbstractProject<Project,Build> {
public class Project extends AbstractProject<Project,Build> implements TopLevelItem {
/**
* List of active {@link Builder}s configured for this project.
......@@ -69,8 +68,8 @@ public class Project extends AbstractProject<Project,Build> {
super(parent,name);
}
protected void onLoad(Hudson root, String name) throws IOException {
super.onLoad(root, name);
public void onLoad(String name) throws IOException {
super.onLoad(name);
if(buildWrappers==null)
// it didn't exist in < 1.64
......@@ -364,11 +363,11 @@ public class Project extends AbstractProject<Project,Build> {
}
};
public JobDescriptor<Project,Build> getDescriptor() {
public TopLevelItemDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final JobDescriptor<Project,Build> DESCRIPTOR = new JobDescriptor<Project,Build>(Project.class) {
public static final TopLevelItemDescriptor DESCRIPTOR = new TopLevelItemDescriptor(Project.class) {
public String getDisplayName() {
return "Building a software project";
}
......
......@@ -39,7 +39,7 @@ import java.util.logging.Logger;
*/
public final class Slave implements Node, Serializable {
/**
* Name of this slave node.
* PluginName of this slave node.
*/
protected final String name;
......@@ -82,7 +82,7 @@ public final class Slave implements Node, Serializable {
this.remoteFS = remoteFS;
if (name.equals(""))
throw new FormException("Invalid slave configuration. Name is empty", null);
throw new FormException("Invalid slave configuration. PluginName is empty", null);
// this prevents the config from being saved when slaves are offline.
// on a large deployment with a lot of slaves, some slaves are bound to be offline,
......
......@@ -19,7 +19,8 @@ import java.util.List;
import java.util.Map;
/**
* Collection of {@link ViewItem}s.
* Encapsulates the rendering of the list of {@link TopLevelItem}s
* that {@link Hudson} owns.
*
* @author Kohsuke Kawaguchi
*/
......@@ -28,12 +29,12 @@ public abstract class View extends AbstractModelObject {
/**
* Gets all the items in this collection in a read-only view.
*/
public abstract Collection<? extends ViewItem> getItems();
public abstract Collection<TopLevelItem> getItems();
/**
* Checks if the job is in this collection.
*/
public abstract boolean contains(ViewItem item);
public abstract boolean contains(TopLevelItem item);
/**
* Gets the name of all this collection.
......@@ -94,7 +95,7 @@ public abstract class View extends AbstractModelObject {
* Does this {@link View} has any associated user information recorded?
*/
public final boolean hasPeople() {
for (ViewItem item : getItems()) {
for (Item item : getItems()) {
for (Job job : item.getAllJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
......@@ -116,7 +117,7 @@ public abstract class View extends AbstractModelObject {
*/
public final List<UserInfo> getPeople() {
Map<User,UserInfo> users = new HashMap<User,UserInfo>();
for (ViewItem item : getItems()) {
for (Item item : getItems()) {
for (Job job : item.getAllJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
......@@ -145,12 +146,12 @@ public abstract class View extends AbstractModelObject {
}
/**
* Creates a job in this collection.
* Creates a new {@link Item} in this collection.
*
* @return
* null if fails.
*/
public abstract Job doCreateJob( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;
public abstract Item doCreateViewItem( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;
public void doRssAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " all builds", new RunList(this));
......
......@@ -52,7 +52,7 @@ public abstract class ViewJob<JobT extends ViewJob<JobT,RunT>, RunT extends Run<
}
protected ViewJob(Hudson parent, String name) {
super(parent, name);
super(name);
}
public boolean isBuildable() {
......@@ -60,8 +60,8 @@ public abstract class ViewJob<JobT extends ViewJob<JobT,RunT>, RunT extends Run<
}
protected void onLoad(Hudson root, String name) throws IOException {
super.onLoad(root, name);
public void onLoad(String name) throws IOException {
super.onLoad(name);
notLoaded = true;
}
......
......@@ -2,6 +2,7 @@ package hudson.model.listeners;
import hudson.model.Hudson;
import hudson.model.Job;
import hudson.model.Item;
import hudson.ExtensionPoint;
/**
......@@ -36,4 +37,39 @@ public abstract class JobListener implements ExtensionPoint {
*/
public void onDeleted(Job j) {
}
public static final class JobListenerAdapter extends ItemListener {
private final JobListener listener;
public JobListenerAdapter(JobListener listener) {
this.listener = listener;
}
public void onCreated(Item item) {
if(item instanceof Job)
listener.onCreated((Job)item);
}
public void onLoaded() {
}
public void onDeleted(Item item) {
if(item instanceof Job)
listener.onDeleted((Job)item);
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JobListenerAdapter that = (JobListenerAdapter) o;
return this.listener.equals(that.listener);
}
public int hashCode() {
return listener.hashCode();
}
}
}
......@@ -55,7 +55,7 @@ import java.util.Vector;
* <FONT color=#6a5acd>&lt;!ELEMENT</FONT> msg <FONT color=#ff00ff>(#PCDATA)</FONT><FONT color=#6a5acd>&gt;</FONT>
* <FONT color=#0000ff>&lt;!-- File changed --&gt;</FONT>
* <FONT color=#6a5acd>&lt;!ELEMENT</FONT> file <FONT color=#ff00ff>(name,revision,prevrevision</FONT><FONT color=#ff00ff>?</FONT><FONT color=#ff00ff>)</FONT><FONT color=#6a5acd>&gt;</FONT>
* <FONT color=#0000ff>&lt;!-- Name of the file --&gt;</FONT>
* <FONT color=#0000ff>&lt;!-- PluginName of the file --&gt;</FONT>
* <FONT color=#6a5acd>&lt;!ELEMENT</FONT> name <FONT color=#ff00ff>(#PCDATA)</FONT><FONT color=#6a5acd>&gt;</FONT>
* <FONT color=#0000ff>&lt;!-- Revision number --&gt;</FONT>
* <FONT color=#6a5acd>&lt;!ELEMENT</FONT> revision <FONT color=#ff00ff>(#PCDATA)</FONT><FONT color=#6a5acd>&gt;</FONT>
......
......@@ -7,27 +7,27 @@ import hudson.Proc;
import hudson.Util;
import static hudson.Util.fixEmpty;
import hudson.model.AbstractBuild;
import hudson.model.AbstractModelObject;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Job;
import hudson.model.LargeText;
import hudson.model.ModelObject;
import hudson.model.TaskListener;
import hudson.model.Build;
import hudson.model.Project;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.AbstractModelObject;
import hudson.model.LargeText;
import hudson.model.TaskListener;
import hudson.org.apache.tools.ant.taskdefs.cvslib.ChangeLogTask;
import hudson.remoting.RemoteOutputStream;
import hudson.remoting.VirtualChannel;
import hudson.util.ArgumentListBuilder;
import hudson.util.ByteBuffer;
import hudson.util.ForkOutputStream;
import hudson.util.FormFieldValidator;
import hudson.util.StreamTaskListener;
import hudson.util.ByteBuffer;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.zip.ZipEntry;
......@@ -36,6 +36,7 @@ import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
......@@ -52,24 +53,25 @@ import java.io.PrintWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.OutputStreamWriter;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.ref.WeakReference;
/**
* CVS.
......@@ -187,7 +189,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
dir.deleteContents();
ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add("cvs",debugLogging?"-t":"-Q","-z9","-d",cvsroot,"co");
cmd.add(getDescriptor().getCvsExe(),debugLogging?"-t":"-Q","-z9","-d",cvsroot,"co");
if(branch!=null)
cmd.add("-r",branch);
if(flatten)
......@@ -320,7 +322,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
List<String> changedFileNames = new ArrayList<String>(); // file names relative to the workspace
ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add("cvs","-q","-z9");
cmd.add(getDescriptor().getCvsExe(),"-q","-z9");
if(dryRun)
cmd.add("-n");
cmd.add("update","-PdC");
......@@ -675,6 +677,11 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
*/
private String cvsPassFile;
/**
* Path to cvs executable. Null to just use "cvs".
*/
private String cvsExe;
/**
* Copy-on-write.
*/
......@@ -716,6 +723,11 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
return value;
}
public String getCvsExe() {
if(cvsExe==null) return "cvs";
else return cvsExe;
}
public void setCvspassFile(String value) {
cvsPassFile = value;
save();
......@@ -732,7 +744,8 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
}
public boolean configure( StaplerRequest req ) {
setCvspassFile(req.getParameter("cvs_cvspass"));
cvsPassFile = fixEmpty(req.getParameter("cvs_cvspass").trim());
cvsExe = fixEmpty(req.getParameter("cvs_exe").trim());
Map<String,RepositoryBrowser> browsers = new HashMap<String, RepositoryBrowser>();
int i=0;
......@@ -780,14 +793,54 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
}.process();
}
/**
* Checks if cvs executable exists.
*/
public void doCvsExeCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
// this method can be used to check if a file exists anywhere in the file system,
// so it should be protected.
new FormFieldValidator(req,rsp,true) {
protected void check() throws IOException, ServletException {
String cvsExe = fixEmpty(request.getParameter("value"));
if(cvsExe==null) {
ok();
return;
}
if(cvsExe.indexOf(File.separatorChar)>=0) {
// this is full path
if(new File(cvsExe).exists()) {
ok();
} else {
error("There's no such file: "+cvsExe);
}
} else {
// can't really check
ok();
}
}
}.process();
}
/**
* Displays "cvs --version" for trouble shooting.
*/
public void doVersion(StaplerRequest req, StaplerResponse rsp) throws IOException {
rsp.setContentType("text/plain");
Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch(
new String[]{"cvs", "--version"}, new String[0], rsp.getOutputStream(), null);
proc.join();
ServletOutputStream os = rsp.getOutputStream();
try {
Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch(
new String[]{getCvsExe(), "--version"}, new String[0], os, null);
proc.join();
} catch (IOException e) {
PrintWriter w = new PrintWriter(os);
w.println("Failed to launch "+getCvsExe());
String msg = Util.getWin32ErrorMessage(e);
if(msg!=null)
w.println(msg);
e.printStackTrace(w);
}
}
/**
......@@ -895,7 +948,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
rsp.setContentType("text/plain");
Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch(
new String[]{"cvs", "-d",cvsroot,"login"}, new String[0],
new String[]{getCvsExe(), "-d",cvsroot,"login"}, new String[0],
new ByteArrayInputStream((password+"\n").getBytes()),
rsp.getOutputStream());
proc.join();
......@@ -1062,7 +1115,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable {
boolean isDir = path.isDirectory();
ArgumentListBuilder cmd = new ArgumentListBuilder();
cmd.add("cvs","tag");
cmd.add(getDescriptor().getCvsExe(),"tag");
if(isDir) {
cmd.add("-R");
}
......
......@@ -4,7 +4,7 @@ import hudson.model.Job;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.View;
import hudson.model.ViewItem;
import hudson.model.Item;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -29,7 +29,7 @@ public class RunList extends ArrayList<Run> {
}
public RunList(View view) {
for (ViewItem item : view.getItems())
for (Item item : view.getItems())
for (Job<?,?> j : item.getAllJobs())
addAll(j.getBuilds());
Collections.sort(this,Run.ORDER_BY_DATE);
......
<!--
New Project page
"New Project" page.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:layout norefresh="true">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<s:form method="post" action="createJob">
<s:form method="post" action="createViewItem">
<s:entry title="Job name">
<input type="text" name="name" class="setting-input" />
</s:entry>
......
......@@ -5,6 +5,12 @@
<a href="${rootURL}/scm/CVSSCM/version">Check CVS version</a>
</div>
</f:description>
<f:entry title="cvs executable"
description="location of cvs executable"
help="/help/_cvs/cvsexe.html">
<f:textbox name="cvs_exe" value="${descriptor.cvsExe}"
checkUrl="'${rootURL}/scm/CVSSCM/cvsExeCheck?value='+this.value" />
</f:entry>
<f:entry title=".cvspass file"
description=".cvspass file to load passwords from. Leave it empty to read from $HOME/.cvspass"
help="/help/_cvs/cvspass.jelly">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册