diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index ec51bc18f8..2ae40b0286 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -5,6 +5,7 @@ import hudson.model.ModelObject; import hudson.model.Node; import hudson.model.Project; import hudson.model.Run; +import hudson.model.Items; import org.kohsuke.stapler.Ancestor; import org.kohsuke.stapler.StaplerRequest; @@ -162,7 +163,7 @@ public class Functions { } public static String getProjectListString(List projects) { - return Project.toNameList(projects); + return Items.toNameList(projects); } public static Object ifThenElse(boolean cond, Object thenValue, Object elseValue) { diff --git a/core/src/main/java/hudson/Main.java b/core/src/main/java/hudson/Main.java index e634add6e3..8125bea83f 100644 --- a/core/src/main/java/hudson/Main.java +++ b/core/src/main/java/hudson/Main.java @@ -3,8 +3,8 @@ package hudson; import hudson.model.ExternalJob; import hudson.model.ExternalRun; import hudson.model.Hudson; -import hudson.model.Job; import hudson.model.Result; +import hudson.model.TopLevelItem; import hudson.util.DualOutputStream; import hudson.util.EncodingStream; @@ -60,12 +60,12 @@ public class Main { public static int localPost(String[] args) throws Exception { Hudson app = new Hudson(new File(getHudsonHome()),null); - Job job = app.getJob(args[0]); - if(!(job instanceof ExternalJob)) { + TopLevelItem item = app.getItem(args[0]); + if(!(item instanceof ExternalJob)) { System.err.println(args[0]+" is not a valid external job name in Hudson"); return -1; } - ExternalJob ejob = (ExternalJob) job; + ExternalJob ejob = (ExternalJob) item; ExternalRun run = ejob.newBuild(); diff --git a/core/src/main/java/hudson/maven/MavenBuild.java b/core/src/main/java/hudson/maven/MavenBuild.java index ed54b24d76..fb5f1d1a2f 100644 --- a/core/src/main/java/hudson/maven/MavenBuild.java +++ b/core/src/main/java/hudson/maven/MavenBuild.java @@ -5,6 +5,8 @@ import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.model.Result; import hudson.model.Run; +import hudson.model.AbstractProject; +import hudson.model.Fingerprint.RangeSet; import hudson.remoting.VirtualChannel; import hudson.remoting.Channel; import hudson.util.IOException2; @@ -52,6 +54,11 @@ public class MavenBuild extends AbstractBuild { run(new RunnerImpl()); } + public RangeSet getDownstreamRelationship(AbstractProject that) { + // TODO + throw new UnsupportedOperationException(); + } + /** * Runs Maven and builds the project. * diff --git a/core/src/main/java/hudson/maven/MavenModule.java b/core/src/main/java/hudson/maven/MavenModule.java index ae12108bf4..3682f9990f 100644 --- a/core/src/main/java/hudson/maven/MavenModule.java +++ b/core/src/main/java/hudson/maven/MavenModule.java @@ -2,11 +2,10 @@ package hudson.maven; import hudson.model.AbstractProject; import hudson.model.Descriptor; -import hudson.model.Hudson; -import hudson.model.Job; -import hudson.model.TopLevelItemDescriptor; -import hudson.model.ItemLoader; import hudson.model.Descriptor.FormException; +import hudson.model.Hudson; +import hudson.model.Items; +import hudson.model.Job; import hudson.util.DescribableList; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -14,6 +13,7 @@ import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.File; import java.io.IOException; +import java.util.List; /** * {@link Job} that builds projects based on Maven2. @@ -48,6 +48,16 @@ public final class MavenModule extends AbstractProject i return new MavenBuild(this,dir); } + @Override + public boolean isFingerprintConfigured() { + return true; + } + + public List getDownstreamProjects() { + // TODO + throw new UnsupportedOperationException(); + } + /** * List of active {@link MavenReporter}s configured for this project. */ @@ -68,6 +78,6 @@ public final class MavenModule extends AbstractProject i } static { - ItemLoader.XSTREAM.alias("maven2", MavenModule.class); + Items.XSTREAM.alias("maven2", MavenModule.class); } } diff --git a/core/src/main/java/hudson/maven/MavenModuleSet.java b/core/src/main/java/hudson/maven/MavenModuleSet.java index 29115bb214..ee47d949aa 100644 --- a/core/src/main/java/hudson/maven/MavenModuleSet.java +++ b/core/src/main/java/hudson/maven/MavenModuleSet.java @@ -3,17 +3,16 @@ package hudson.maven; import hudson.model.AbstractItem; import hudson.model.Hudson; import hudson.model.ItemGroup; -import hudson.model.ItemLoader; import hudson.model.TopLevelItem; import hudson.model.TopLevelItemDescriptor; +import hudson.model.Items; +import hudson.util.CopyOnWriteMap; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.Map; -import java.util.TreeMap; /** * Group of {@link MavenModule}s. @@ -31,7 +30,7 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr /** * All {@link MavenModule}s. */ - transient final Map modules = new TreeMap(); + transient final Map modules = new CopyOnWriteMap.Tree(); public MavenModuleSet(String name) { this.name = name; @@ -53,12 +52,12 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr return Hudson.getInstance(); } - public synchronized Collection getItems() { - return new ArrayList(modules.values()); + public Collection getItems() { + return modules.values(); } - public synchronized boolean contains(MavenModule item) { - return modules.containsKey(item.getName()); + public MavenModule getItem(String name) { + return modules.get(name); } public Collection getAllJobs() { @@ -80,7 +79,7 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr modules.clear(); for (File subdir : subdirs) { try { - MavenModule item = (MavenModule)ItemLoader.load(subdir); + MavenModule item = (MavenModule) Items.load(subdir); modules.put(item.getName(), item); } catch (IOException e) { e.printStackTrace(); // TODO: logging @@ -103,6 +102,6 @@ public class MavenModuleSet extends AbstractItem implements TopLevelItem, ItemGr }; static { - ItemLoader.XSTREAM.alias("maven2-module-set", MavenModule.class); + Items.XSTREAM.alias("maven2-module-set", MavenModule.class); } } diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java index f31a3282d7..5dbf6d9f58 100644 --- a/core/src/main/java/hudson/model/AbstractBuild.java +++ b/core/src/main/java/hudson/model/AbstractBuild.java @@ -6,6 +6,7 @@ import hudson.Util; import hudson.maven.MavenBuild; import static hudson.model.Hudson.isWindows; import hudson.model.listeners.SCMListener; +import hudson.model.Fingerprint.RangeSet; import hudson.scm.CVSChangeLogParser; import hudson.scm.ChangeLogParser; import hudson.scm.ChangeLogSet; @@ -21,6 +22,7 @@ import java.io.IOException; import java.io.PrintStream; import java.util.Calendar; import java.util.Map; +import java.util.HashMap; /** * Base implementation of {@link Run}s that build software. @@ -200,6 +202,61 @@ public abstract class AbstractBuild

,R extends Abs */ public abstract void run(); +// +// +// fingerprint related stuff +// +// + /** + * Gets the downstream builds of this build, which are the builds of the + * downstream projects that use artifacts of this build. + * + * @return + * For each project with fingerprinting enabled, returns the range + * of builds (which can be empty if no build uses the artifact from this build.) + */ + public Map getDownstreamBuilds() { + Map r = new HashMap(); + for (AbstractProject p : getParent().getDownstreamProjects()) { + if(p.isFingerprintConfigured()) + r.put(p,getDownstreamRelationship(p)); + } + return r; + } + + @Override + public String getWhyKeepLog() { + // if any of the downstream project is configured with 'keep dependency component', + // we need to keep this log + for (Map.Entry e : getDownstreamBuilds().entrySet()) { + AbstractProject p = e.getKey(); + if(!p.isKeepDependencies()) continue; + + // is there any active build that depends on us? + for (AbstractBuild build : p.getBuilds()) { + if(e.getValue().includes(build.getNumber())) + return "kept because of "+build; + } + } + + return super.getWhyKeepLog(); + } + + /** + * Gets the dependency relationship from this build (as the source) + * and that project (as the sink.) + * + * @return + * range of build numbers that represent which downstream builds are using this build. + * The range will be empty if no build of that project matches this. + */ + public abstract RangeSet getDownstreamRelationship(AbstractProject that); + +// +// +// web methods +// +// /** * Stops this build if it's still going. * diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index 2ec00aee7b..5e3ea6d196 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -38,6 +38,13 @@ public abstract class AbstractItem extends Actionable implements Item { */ public abstract String getName(); + + public final String getFullName() { + String n = getParent().getFullName(); + if(n.length()==0) return getName(); + else return n+'/'+getName(); + } + /** * Called right after when a {@link Item} is loaded from disk. * This is an opporunity to do a post load processing. @@ -66,6 +73,6 @@ public abstract class AbstractItem extends Actionable implements Item { } protected final XmlFile getConfigFile() { - return ItemLoader.getConfigFile(this); + return Items.getConfigFile(this); } } diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index f3430c5d08..14a616a18c 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -2,6 +2,7 @@ package hudson.model; import hudson.FilePath; import hudson.Launcher; +import hudson.util.EditDistance; import hudson.model.RunMap.Constructor; import hudson.model.Descriptor.FormException; import hudson.triggers.Trigger; @@ -227,7 +228,6 @@ public abstract class AbstractProject

,R extends A */ protected abstract R loadBuild(File dir) throws IOException; - /** * Gets the {@link Node} where this project was last built on. * @@ -342,6 +342,22 @@ public abstract class AbstractProject

,R extends A return Descriptor.toMap(triggers); } +// +// +// fingerprint related +// +// + /** + * True if the builds of this project produces {@link Fingerprint} records. + */ + public abstract boolean isFingerprintConfigured(); + + /** + * Gets the other {@link AbstractProject}s that should be built + * when a build of this project is completed. + */ + public abstract List getDownstreamProjects(); + // // // actions @@ -450,4 +466,17 @@ public abstract class AbstractProject

,R extends A new DirectoryBrowserSupport(this).serveFile(req, rsp, ws, "folder.gif", true); } } + + /** + * Finds a {@link AbstractProject} that has the name closest to the given name. + */ + public static AbstractProject findNearest(String name) { + List projects = Hudson.getInstance().getAllItems(AbstractProject.class); + String[] names = new String[projects.size()]; + for( int i=0; i { super(project,buildDir); } - @Override - public String getWhyKeepLog() { - // if any of the downstream project is configured with 'keep dependency component', - // we need to keep this log - for (Map.Entry e : getDownstreamBuilds().entrySet()) { - Project p = e.getKey(); - if(!p.isKeepDependencies()) continue; - - // is there any active build that depends on us? - for (Build build : p.getBuilds()) { - if(e.getValue().includes(build.getNumber())) - return "kept because of "+build; - } - } - - return super.getWhyKeepLog(); - } - public Calendar due() { return timestamp; } @@ -70,15 +52,8 @@ public final class Build extends AbstractBuild { return getAction(AbstractTestResultAction.class); } - /** - * Gets the dependency relationship from this build (as the source) - * and that project (as the sink.) - * - * @return - * range of build numbers that represent which downstream builds are using this build. - * The range will be empty if no build of that project matches this. - */ - public RangeSet getDownstreamRelationship(Project that) { + @Override + public RangeSet getDownstreamRelationship(AbstractProject that) { RangeSet rs = new RangeSet(); FingerprintAction f = getAction(FingerprintAction.class); @@ -94,23 +69,6 @@ public final class Build extends AbstractBuild { return rs; } - /** - * Gets the downstream builds of this build, which are the builds of the - * downstream projects that use artifacts of this build. - * - * @return - * For each project with fingerprinting enabled, returns the range - * of builds (which can be empty if no build uses the artifact from this build.) - */ - public Map getDownstreamBuilds() { - Map r = new HashMap(); - for (Project p : getParent().getDownstreamProjects()) { - if(p.isFingerprintConfigured()) - r.put(p,getDownstreamRelationship(p)); - } - return r; - } - /** * Gets the dependency relationship from this build (as the sink) * and that project (as the source.) diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index 9477bb2fce..9360f3a031 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -61,7 +61,7 @@ public class Fingerprint implements ModelObject { * or null if such a job no longer exists. */ public Job getJob() { - return Hudson.getInstance().getJob(name); + return Hudson.getInstance().getItemByFullName(name,Job.class); } /** @@ -461,7 +461,7 @@ public class Fingerprint implements ModelObject { return true; for (Entry e : usages.entrySet()) { - Job j = Hudson.getInstance().getJob(e.getKey()); + Job j = Hudson.getInstance().getItemByFullName(e.getKey(),Job.class); if(j==null) continue; diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 39f7f32996..8a8f6d6cb5 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -68,6 +68,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.Vector; +import java.util.StringTokenizer; +import java.util.Stack; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -364,10 +366,37 @@ public final class Hudson extends View implements ItemGroup, Node return Util.createSubList(items.values(),Job.class); } + public String getFullName() { + return ""; + } + public List getItems() { return new ArrayList(items.values()); } + /** + * Gets all the {@link Item}s recursively in the {@link ItemGroup} tree + * and filter them by the given type. + */ + public List getAllItems(Class type) { + List r = new ArrayList(); + + Stack q = new Stack(); + q.push(this); + + while(!q.isEmpty()) { + ItemGroup parent = q.pop(); + for (Item i : parent.getItems()) { + if(type.isInstance(i)) + r.add(type.cast(r)); + if(i instanceof ItemGroup) + q.push((ItemGroup)i); + } + } + + return r; + } + /** * Gets the snapshot of all the projects. */ @@ -576,17 +605,12 @@ public final class Hudson extends View implements ItemGroup, Node } /** - * Gets the job of the given name. - * - * @return null - * if such a project doesn't exist. + * @deprecated + * Left only for the compatibility of URLs. + * Should not be invoked for any other purpose. */ - public Job getJob(String name) { - TopLevelItem item = items.get(name); - if(item instanceof Job) - return (Job)item; - else - return null; + public TopLevelItem getJob(String name) { + return getItem(name); } /** @@ -596,6 +620,35 @@ public final class Hudson extends View implements ItemGroup, Node return items.get(name); } + /** + * Gets the {@link Item} object by its full name. + * Full names are like path names, where each name of {@link Item} is + * combined by '/'. + * + * @return + * null if either such {@link Item} doesn't exist under the given full name, + * or it exists but it's no an instance of the given type. + */ + public T getItemByFullName(String fullName, Class type) { + StringTokenizer tokens = new StringTokenizer(fullName,"/"); + ItemGroup parent = this; + + while(true) { + Item item = parent.getItem(tokens.nextToken()); + if(!tokens.hasMoreTokens()) { + if(type.isInstance(item)) + return type.cast(item); + else + return null; + } + + if(!(item instanceof ItemGroup)) + return null; // this item can't have any children + + parent = (ItemGroup) item; + } + } + /** * Gets the user of the given name. * @@ -722,7 +775,7 @@ public final class Hudson extends View implements ItemGroup, Node items.clear(); for (File subdir : subdirs) { try { - TopLevelItem item = (TopLevelItem)ItemLoader.load(subdir); + TopLevelItem item = (TopLevelItem)Items.load(subdir); items.put(item.getName(), item); } catch (IOException e) { e.printStackTrace(); // TODO: logging @@ -908,10 +961,10 @@ public final class Hudson extends View implements ItemGroup, Node result = createProject(src.getDescriptor(),name); // copy config - Util.copyFile(ItemLoader.getConfigFile(src).getFile(),ItemLoader.getConfigFile(result).getFile()); + Util.copyFile(Items.getConfigFile(src).getFile(),Items.getConfigFile(result).getFile()); // reload from the new config - result = (TopLevelItem)ItemLoader.load(result.getRootDir()); + result = (TopLevelItem)Items.load(result.getRootDir()); result.onCopiedFrom(src); items.put(name,result); } diff --git a/core/src/main/java/hudson/model/Item.java b/core/src/main/java/hudson/model/Item.java index 09c46bb50b..0090a5dadd 100644 --- a/core/src/main/java/hudson/model/Item.java +++ b/core/src/main/java/hudson/model/Item.java @@ -4,15 +4,32 @@ import java.io.IOException; import java.util.Collection; /** - * Object that can be displayed in a {@link ListView}. + * Basic configuration unit in Hudson. * - * {@link Item}s are allowed to show up in multiple {@link View}s, - * so they need to have unique names among all {@link Item}s. - * This uniqueness is also used for allocating file system storage - * for each {@link Item}. + *

+ * Every {@link Item} is hosted in an {@link ItemGroup} called "parent", + * and some {@link Item}s are {@link ItemGroup}s. This form a tree + * structure, which is rooted at {@link Hudson}. + * + *

+ * Unlike file systems, where a file can be moved from one directory + * to another, {@link Item} inherently belongs to a single {@link ItemGroup} + * and that relationship will not change. + * Think of + * Windows device manager + * — an HDD always show up under 'Disk drives' and it can never be moved to another parent. + * + * Similarly, {@link ItemGroup} is not a generic container. Each subclass + * of {@link ItemGroup} can usually only host a certain limited kinds of + * {@link Item}s. + * + *

+ * {@link Item}s have unique {@link #getName() name}s that distinguish themselves + * among their siblings uniquely. The names can be combined by '/' to form an + * item full name, which uniquely identifies an {@link Item} inside the whole {@link Hudson}. * * @author Kohsuke Kawaguchi - * @see ItemLoader + * @see Items */ public interface Item extends PersistenceRoot { /** @@ -29,16 +46,32 @@ public interface Item extends PersistenceRoot { * Gets the name of the item. * *

- * The name must be unique among all {@link Item}s in this Hudson, - * because we allow a single {@link Item} to show up in multiple - * {@link View}s. + * The name must be unique among other {@link Item}s that belong + * to the same parent. + * + *

+ * This name is also used for directory name, so it cannot contain + * any character that's not allowed on the file system. */ String getName(); + /** + * Gets the full name of this item, like "abc/def/ghi". + * + *

+ * Full name consists of {@link #getName() name}s of {@link Item}s + * that lead from the root {@link Hudson} to this {@link Item}, + * separated by '/'. This is the unique name that identifies this + * {@link Item} inside the whole {@link Hudson}. + * + * @see Hudson#getItemByFullName(String,Class) + */ + String getFullName(); + /** * Returns the URL of this project relative to the context root of the application. * - * @see AbstractItem#getUrl() for how to implement this + * @see AbstractItem#getUrl() for how to implement this. */ String getUrl(); diff --git a/core/src/main/java/hudson/model/ItemGroup.java b/core/src/main/java/hudson/model/ItemGroup.java index 0074ae1ba0..6902c8e34c 100644 --- a/core/src/main/java/hudson/model/ItemGroup.java +++ b/core/src/main/java/hudson/model/ItemGroup.java @@ -8,6 +8,12 @@ import java.util.Collection; * @author Kohsuke Kawaguchi */ public interface ItemGroup extends PersistenceRoot, ModelObject { + /** + * Gets the full name of this {@link ItemGroup}. + * + * @see Item#getFullName() + */ + String getFullName(); /** * Gets all the items in this collection in a read-only view. @@ -25,4 +31,9 @@ public interface ItemGroup extends PersistenceRoot, ModelObject * Like "job", "item", etc. */ String getUrlChildPrefix(); + + /** + * Gets the {@link Item} inside this group that has a given name. + */ + T getItem(String name); } diff --git a/core/src/main/java/hudson/model/ItemLoader.java b/core/src/main/java/hudson/model/Items.java similarity index 51% rename from core/src/main/java/hudson/model/ItemLoader.java rename to core/src/main/java/hudson/model/Items.java index 6052963f09..b6afba690b 100644 --- a/core/src/main/java/hudson/model/ItemLoader.java +++ b/core/src/main/java/hudson/model/Items.java @@ -1,18 +1,53 @@ package hudson.model; -import com.thoughtworks.xstream.XStream; -import hudson.util.XStream2; import hudson.XmlFile; +import hudson.util.XStream2; +import java.util.Collection; +import java.util.List; +import java.util.ArrayList; +import java.util.StringTokenizer; import java.io.File; import java.io.IOException; +import com.thoughtworks.xstream.XStream; + /** - * Used to load {@link Item} implementation. - * + * Convenience methods related to {@link Item}. + * * @author Kohsuke Kawaguchi */ -public final class ItemLoader { +public class Items { + /** + * Converts a list of items into a camma-separated full names. + */ + public static String toNameList(Collection items) { + StringBuilder buf = new StringBuilder(); + for (Item item : items) { + if(buf.length()>0) + buf.append(", "); + buf.append(item.getFullName()); + } + return buf.toString(); + } + + /** + * Does the opposite of {@link #toNameList(Collection)}. + */ + public static List fromNameList(String list,Class type) { + Hudson hudson = Hudson.getInstance(); + + List r = new ArrayList(); + StringTokenizer tokens = new StringTokenizer(list,","); + while(tokens.hasMoreTokens()) { + String fullName = tokens.nextToken().trim(); + T item = hudson.getItemByFullName(fullName,type); + if(item!=null) + r.add(item); + } + return r; + } + /** * Loads a {@link Item} from a config file. * diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 7f0b295a1b..beb5d97910 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -237,7 +237,7 @@ public abstract class Job, RunT extends Run implements TopLevelI return r; } - public List getDownstreamProjects() { + public List getDownstreamProjects() { BuildTrigger buildTrigger = (BuildTrigger) getPublishers().get(BuildTrigger.DESCRIPTOR); if(buildTrigger==null) - return new ArrayList(); + return new ArrayList(); else return buildTrigger.getChildProjects(); } @@ -187,9 +185,7 @@ public class Project extends AbstractProject implements TopLevelI } } - /** - * Returns true if the fingerprint record is configured in this project. - */ + @Override public boolean isFingerprintConfigured() { synchronized(publishers) { for (Publisher p : publishers) { @@ -212,7 +208,7 @@ public class Project extends AbstractProject implements TopLevelI */ public void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { - Set upstream = Collections.emptySet(); + Set upstream = Collections.emptySet(); synchronized(this) { try { @@ -234,7 +230,7 @@ public class Project extends AbstractProject implements TopLevelI } if(req.getParameter("pseudoUpstreamTrigger")!=null) { - upstream = new HashSet(Project.fromNameList(req.getParameter("upstreamProjects"))); + upstream = new HashSet(Items.fromNameList(req.getParameter("upstreamProjects"),AbstractProject.class)); } // this needs to be done after we release the lock on this, @@ -242,7 +238,7 @@ public class Project extends AbstractProject implements TopLevelI for (Project p : Hudson.getInstance().getProjects()) { boolean isUpstream = upstream.contains(p); synchronized(p) { - List newChildProjects = p.getDownstreamProjects(); + List newChildProjects = p.getDownstreamProjects(); if(isUpstream) { if(!newChildProjects.contains(this)) @@ -312,51 +308,6 @@ public class Project extends AbstractProject implements TopLevelI @Deprecated private transient String slave; - /** - * Converts a list of projects into a camma-separated names. - */ - public static String toNameList(Collection projects) { - StringBuilder buf = new StringBuilder(); - for (Project project : projects) { - if(buf.length()>0) - buf.append(", "); - buf.append(project.getName()); - } - return buf.toString(); - } - - /** - * Does the opposite of {@link #toNameList(Collection)}. - */ - public static List fromNameList(String list) { - Hudson hudson = Hudson.getInstance(); - - List r = new ArrayList(); - StringTokenizer tokens = new StringTokenizer(list,","); - while(tokens.hasMoreTokens()) { - String projectName = tokens.nextToken().trim(); - Job job = hudson.getJob(projectName); - if(!(job instanceof Project)) { - continue; // ignore this token - } - r.add((Project) job); - } - return r; - } - - /** - * Finds a {@link Project} that has the name closest to the given name. - */ - public static Project findNearest(String name) { - List projects = Hudson.getInstance().getProjects(); - String[] names = new String[projects.size()]; - for( int i=0; i REVERSE_INTEGER_COMPARATOR = new Comparator() { public int compare(Integer o1, Integer o2) { return o2-o1; diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 1461a41361..1dab104d2a 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -124,9 +124,9 @@ public class Queue { BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(queueFile))); String line; while((line=in.readLine())!=null) { - Job j = Hudson.getInstance().getJob(line); - if(j instanceof Project) - ((Project)j).scheduleBuild(); + AbstractProject j = Hudson.getInstance().getItemByFullName(line,AbstractProject.class); + if(j!=null) + j.scheduleBuild(); } in.close(); // discard the queue file now that we are done diff --git a/core/src/main/java/hudson/model/TopLevelItem.java b/core/src/main/java/hudson/model/TopLevelItem.java index 84a7b8a981..54dfe470b3 100644 --- a/core/src/main/java/hudson/model/TopLevelItem.java +++ b/core/src/main/java/hudson/model/TopLevelItem.java @@ -7,7 +7,7 @@ import hudson.ExtensionPoint; * *

* To register a custom {@link TopLevelItem} class from a plugin, add it to - * {@link TopLevelItems#LIST}. Also see {@link ItemLoader#XSTREAM}. + * {@link TopLevelItems#LIST}. Also see {@link Items#XSTREAM}. * * @author Kohsuke Kawaguchi */ diff --git a/core/src/main/java/hudson/model/WorkspaceCleanupThread.java b/core/src/main/java/hudson/model/WorkspaceCleanupThread.java index 20d31120ca..a839ad061b 100644 --- a/core/src/main/java/hudson/model/WorkspaceCleanupThread.java +++ b/core/src/main/java/hudson/model/WorkspaceCleanupThread.java @@ -70,16 +70,16 @@ public class WorkspaceCleanupThread extends PeriodicWork { private boolean shouldBeDeleted(String jobName, FilePath dir, Node n) throws IOException, InterruptedException { // TODO: the use of remoting is not optimal. // One remoting can execute "exists", "lastModified", and "delete" all at once. - Job job = Hudson.getInstance().getJob(jobName); - if(job==null) + TopLevelItem item = Hudson.getInstance().getItem(jobName); + if(item==null) // no such project anymore return true; if(!dir.exists()) return false; - if (job instanceof Project) { - Project p = (Project) job; + if (item instanceof Project) { + Project p = (Project) item; Node lb = p.getLastBuiltOn(); if(lb!=null && lb.equals(n)) // this is the active workspace. keep it. diff --git a/core/src/main/java/hudson/scm/CVSSCM.java b/core/src/main/java/hudson/scm/CVSSCM.java index 35009e48b1..7128815651 100644 --- a/core/src/main/java/hudson/scm/CVSSCM.java +++ b/core/src/main/java/hudson/scm/CVSSCM.java @@ -1049,7 +1049,7 @@ public class CVSSCM extends AbstractCVSFamilySCM implements Serializable { } upName = upName.substring(9); // trim off 'upstream.' - Job p = Hudson.getInstance().getJob(upName); + Job p = Hudson.getInstance().getItemByFullName(upName,Job.class); Run build = p.getBuildByNumber(upstreams.get(p)); tagSet.put((AbstractBuild) build,tag); diff --git a/core/src/main/java/hudson/tasks/BuildTrigger.java b/core/src/main/java/hudson/tasks/BuildTrigger.java index b722140d69..21ca17ff5f 100644 --- a/core/src/main/java/hudson/tasks/BuildTrigger.java +++ b/core/src/main/java/hudson/tasks/BuildTrigger.java @@ -1,12 +1,14 @@ package hudson.tasks; import hudson.Launcher; +import hudson.model.AbstractProject; import hudson.model.Build; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Hudson; +import hudson.model.Item; +import hudson.model.Items; import hudson.model.Job; -import hudson.model.Project; import hudson.model.Result; import hudson.util.FormFieldValidator; import org.kohsuke.stapler.StaplerRequest; @@ -33,21 +35,21 @@ public class BuildTrigger extends Publisher { this.childProjects = childProjects; } - public BuildTrigger(List childProjects) { - this(Project.toNameList(childProjects)); + public BuildTrigger(List childProjects) { + this(Items.toNameList(childProjects)); } public String getChildProjectsValue() { return childProjects; } - public List getChildProjects() { - return Project.fromNameList(childProjects); + public List getChildProjects() { + return Items.fromNameList(childProjects,AbstractProject.class); } public boolean perform(Build build, Launcher launcher, BuildListener listener) { if(build.getResult()== Result.SUCCESS) { - for (Project p : getChildProjects()) { + for (AbstractProject p : getChildProjects()) { listener.getLogger().println("Triggering a new build of "+p.getName()); p.scheduleBuild(); } @@ -121,14 +123,14 @@ public class BuildTrigger extends Publisher { StringTokenizer tokens = new StringTokenizer(list,","); while(tokens.hasMoreTokens()) { String projectName = tokens.nextToken().trim(); - Job job = Hudson.getInstance().getJob(projectName); - if(job==null) { + Item item = Hudson.getInstance().getItemByFullName(projectName,Item.class); + if(item==null) { error("No such project '"+projectName+"'. Did you mean '"+ - Project.findNearest(projectName).getName()+"'?"); + AbstractProject.findNearest(projectName).getName()+"'?"); return; } - if(!(job instanceof Project)) { - error(projectName+" is not a software build"); + if(!(item instanceof AbstractProject)) { + error(projectName+" is not buildable"); return; } }