summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Lynggaard Hansen2012-07-08 09:33:36 (EDT)
committer Henrik Lynggaard Hansen2012-07-08 09:33:36 (EDT)
commit615596af03777514e82ad1653aa61193d5bc6741 (patch)
tree4d11c8fd7f205d8f65ad5e4b9fb42645ac3a21ec
parent6b2a021db07f935226235132973fb64223c07d91 (diff)
downloadorg.eclipse.hudson.core-615596af03777514e82ad1653aa61193d5bc6741.zip
org.eclipse.hudson.core-615596af03777514e82ad1653aa61193d5bc6741.tar.gz
org.eclipse.hudson.core-615596af03777514e82ad1653aa61193d5bc6741.tar.bz2
Run alt-shift-5 to format some of the files with most warningsrefs/changes/68/6668/2
Change-Id: I0092fbb780a85ff1145950e07c73db8afec8409b Signed-off-by: Henrik Lynggaard Hansen <henrik@hlyh.dk>
-rw-r--r--hudson-core/src/main/java/hudson/FilePath.java984
-rw-r--r--hudson-core/src/main/java/hudson/Functions.java712
-rw-r--r--hudson-core/src/main/java/hudson/PluginManager.java328
-rw-r--r--hudson-core/src/main/java/hudson/model/Queue.java1061
-rw-r--r--hudson-core/src/main/java/hudson/model/Run.java943
5 files changed, 2213 insertions, 1815 deletions
diff --git a/hudson-core/src/main/java/hudson/FilePath.java b/hudson-core/src/main/java/hudson/FilePath.java
index d0845b4..030e56a 100644
--- a/hudson-core/src/main/java/hudson/FilePath.java
+++ b/hudson-core/src/main/java/hudson/FilePath.java
@@ -7,10 +7,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
* Kohsuke Kawaguchi, Eric Lefevre-Ardant, Erik Ramfelt, Michael B. Donohue, Alan Harder, Manufacture Francaise des Pneumatiques Michelin, Romain Seguy, Winston Prakash, Anton Kozak
- *
+ *
*
*******************************************************************************/
@@ -93,38 +93,33 @@ import org.kohsuke.stapler.Stapler;
import static hudson.FilePath.TarCompression.GZIP;
import static hudson.Util.fixEmpty;
-
/**
* {@link File} like object with remoting support.
*
- * <p>
- * Unlike {@link File}, which always implies a file path on the current computer,
- * {@link FilePath} represents a file path on a specific slave or the master.
+ * <p> Unlike {@link File}, which always implies a file path on the current
+ * computer, {@link FilePath} represents a file path on a specific slave or the
+ * master.
*
* Despite that, {@link FilePath} can be used much like {@link File}. It exposes
* a bunch of operations (and we should add more operations as long as they are
- * generally useful), and when invoked against a file on a remote node, {@link FilePath}
- * executes the necessary code remotely, thereby providing semi-transparent file
- * operations.
+ * generally useful), and when invoked against a file on a remote node,
+ * {@link FilePath} executes the necessary code remotely, thereby providing
+ * semi-transparent file operations.
*
- * <h2>Using {@link FilePath} smartly</h2>
- * <p>
- * The transparency makes it easy to write plugins without worrying too much about
- * remoting, by making it works like NFS, where remoting happens at the file-system
- * layer.
+ * <h2>Using {@link FilePath} smartly</h2> <p> The transparency makes it easy to
+ * write plugins without worrying too much about remoting, by making it works
+ * like NFS, where remoting happens at the file-system layer.
*
- * <p>
- * But one should note that such use of remoting may not be optional. Sometimes,
- * it makes more sense to move some computation closer to the data, as opposed to
- * move the data to the computation. For example, if you are just computing a MD5
- * digest of a file, then it would make sense to do the digest on the host where
- * the file is located, as opposed to send the whole data to the master and do MD5
- * digesting there.
+ * <p> But one should note that such use of remoting may not be optional.
+ * Sometimes, it makes more sense to move some computation closer to the data,
+ * as opposed to move the data to the computation. For example, if you are just
+ * computing a MD5 digest of a file, then it would make sense to do the digest
+ * on the host where the file is located, as opposed to send the whole data to
+ * the master and do MD5 digesting there.
*
- * <p>
- * {@link FilePath} supports this "code migration" by in the
- * {@link #act(FileCallable)} method. One can pass in a custom implementation
- * of {@link FileCallable}, to be executed on the node where the data is located.
+ * <p> {@link FilePath} supports this "code migration" by in the
+ * {@link #act(FileCallable)} method. One can pass in a custom implementation of
+ * {@link FileCallable}, to be executed on the node where the data is located.
* The following code shows the example:
*
* <pre>
@@ -142,44 +137,43 @@ import static hudson.Util.fixEmpty;
* });
* </pre>
*
- * <p>
- * When {@link FileCallable} is transfered to a remote node, it will be done so
- * by using the same Java serialization scheme that the remoting module uses.
- * See {@link Channel} for more about this.
+ * <p> When {@link FileCallable} is transfered to a remote node, it will be done
+ * so by using the same Java serialization scheme that the remoting module uses.
+ * See {@link Channel} for more about this.
*
- * <p>
- * {@link FilePath} itself can be sent over to a remote node as a part of {@link Callable}
- * serialization. For example, sending a {@link FilePath} of a remote node to that
- * node causes {@link FilePath} to become "local". Similarly, sending a
- * {@link FilePath} that represents the local computer causes it to become "remote."
+ * <p> {@link FilePath} itself can be sent over to a remote node as a part of
+ * {@link Callable} serialization. For example, sending a {@link FilePath} of a
+ * remote node to that node causes {@link FilePath} to become "local".
+ * Similarly, sending a {@link FilePath} that represents the local computer
+ * causes it to become "remote."
*
* @author Kohsuke Kawaguchi
*/
public final class FilePath implements Serializable {
+
/**
- * When this {@link FilePath} represents the remote path,
- * this field is always non-null on master (the field represents
- * the channel to the remote slave.) When transferred to a slave via remoting,
- * this field reverts back to null, since it's transient.
+ * When this {@link FilePath} represents the remote path, this field is
+ * always non-null on master (the field represents the channel to the remote
+ * slave.) When transferred to a slave via remoting, this field reverts back
+ * to null, since it's transient.
*
- * When this {@link FilePath} represents a path on the master,
- * this field is null on master. When transferred to a slave via remoting,
- * this field becomes non-null, representing the {@link Channel}
- * back to the master.
+ * When this {@link FilePath} represents a path on the master, this field is
+ * null on master. When transferred to a slave via remoting, this field
+ * becomes non-null, representing the {@link Channel} back to the master.
*
- * This is used to determine whether we are running on the master or the slave.
+ * This is used to determine whether we are running on the master or the
+ * slave.
*/
private transient VirtualChannel channel;
-
// since the platform of the slave might be different, can't use java.io.File
private final String remote;
/**
* Creates a {@link FilePath} that represents a path on the given node.
*
- * @param channel
- * To create a path that represents a remote path, pass in a {@link Channel}
- * that's connected to that machine. If null, that means the local file path.
+ * @param channel To create a path that represents a remote path, pass in a
+ * {@link Channel} that's connected to that machine. If null, that means the
+ * local file path.
*/
public FilePath(VirtualChannel channel, String remote) {
this.channel = channel;
@@ -189,8 +183,7 @@ public final class FilePath implements Serializable {
/**
* To create {@link FilePath} that represents a "local" path.
*
- * <p>
- * A "local" path means a file path on the computer where the
+ * <p> A "local" path means a file path on the computer where the
* constructor invocation happened.
*/
public FilePath(File localPath) {
@@ -200,33 +193,32 @@ public final class FilePath implements Serializable {
/**
* Construct a path starting with a base location.
+ *
* @param base starting point for resolution, and defines channel
* @param rel a path which if relative will be resolved against base
*/
public FilePath(FilePath base, String rel) {
this.channel = base.channel;
- if(isAbsolute(rel)) {
+ if (isAbsolute(rel)) {
// absolute
this.remote = normalize(rel);
- } else
- if(base.isUnix()) {
- this.remote = normalize(base.remote+'/'+rel);
+ } else if (base.isUnix()) {
+ this.remote = normalize(base.remote + '/' + rel);
} else {
//Normalize rel path for windows environment. See http://issues.hudson-ci.org/browse/HUDSON-5084
- this.remote = normalize(base.remote+'\\'+ StringUtils.replace(rel, "/", "\\"));
+ this.remote = normalize(base.remote + '\\' + StringUtils.replace(rel, "/", "\\"));
}
}
private static boolean isAbsolute(String rel) {
return rel.startsWith("/") || DRIVE_PATTERN.matcher(rel).matches();
}
-
private static final Pattern DRIVE_PATTERN = Pattern.compile("[A-Za-z]:[\\\\/].*"),
ABSOLUTE_PREFIX_PATTERN = Pattern.compile("^(\\\\\\\\|(?:[A-Za-z]:)?[\\\\/])[\\\\/]*");
/**
- * {@link File#getParent()} etc cannot handle ".." and "." in the path component very well,
- * so remove them.
+ * {@link File#getParent()} etc cannot handle ".." and "." in the path
+ * component very well, so remove them.
*/
private static String normalize(String path) {
StringBuilder buf = new StringBuilder();
@@ -246,40 +238,60 @@ public final class FilePath implements Serializable {
tokens.add(path.substring(s, i));
s = i;
// Skip any extra separator chars
- while (++i < end && ((c = path.charAt(i)) == '/' || c == '\\')) { }
+ while (++i < end && ((c = path.charAt(i)) == '/' || c == '\\')) {
+ }
// Add token for separator unless we reached the end
- if (i < end) tokens.add(path.substring(s, s+1));
+ if (i < end) {
+ tokens.add(path.substring(s, s + 1));
+ }
s = i;
}
}
- if (s < end) tokens.add(path.substring(s));
+ if (s < end) {
+ tokens.add(path.substring(s));
+ }
// Look through tokens for "." or ".."
for (int i = 0; i < tokens.size();) {
String token = tokens.get(i);
if (token.equals(".")) {
tokens.remove(i);
- if (tokens.size() > 0)
+ if (tokens.size() > 0) {
tokens.remove(i > 0 ? i - 1 : i);
+ }
} else if (token.equals("..")) {
if (i == 0) {
// If absolute path, just remove: /../something
// If relative path, not collapsible so leave as-is
tokens.remove(0);
- if (tokens.size() > 0) token += tokens.remove(0);
- if (!isAbsolute) buf.append(token);
+ if (tokens.size() > 0) {
+ token += tokens.remove(0);
+ }
+ if (!isAbsolute) {
+ buf.append(token);
+ }
} else {
// Normalize: remove something/.. plus separator before/after
i -= 2;
- for (int j = 0; j < 3; j++) tokens.remove(i);
- if (i > 0) tokens.remove(i-1);
- else if (tokens.size() > 0) tokens.remove(0);
+ for (int j = 0; j < 3; j++) {
+ tokens.remove(i);
+ }
+ if (i > 0) {
+ tokens.remove(i - 1);
+ } else if (tokens.size() > 0) {
+ tokens.remove(0);
+ }
}
- } else
+ } else {
i += 2;
+ }
}
// Recombine tokens
- for (String token : tokens) buf.append(token);
- if (buf.length() == 0) buf.append('.');
+ for (String token : tokens) {
+ buf.append(token);
+ }
+ if (buf.length() == 0) {
+ buf.append('.');
+ }
return buf.toString();
}
@@ -288,18 +300,20 @@ public final class FilePath implements Serializable {
*/
private boolean isUnix() {
// if the path represents a local path, there' no need to guess.
- if(!isRemote())
- return File.pathSeparatorChar!=';';
-
+ if (!isRemote()) {
+ return File.pathSeparatorChar != ';';
+ }
+
// note that we can't use the usual File.pathSeparator and etc., as the OS of
// the machine where this code runs and the OS that this FilePath refers to may be different.
// Windows absolute path is 'X:\...', so this is usually a good indication of Windows path
- if(remote.length()>3 && remote.charAt(1)==':' && remote.charAt(2)=='\\')
+ if (remote.length() > 3 && remote.charAt(1) == ':' && remote.charAt(2) == '\\') {
return false;
+ }
// Windows can handle '/' as a path separator but Unix can't,
// so err on Unix side
- return remote.indexOf("\\")==-1;
+ return remote.indexOf("\\") == -1;
}
public String getRemote() {
@@ -307,114 +321,117 @@ public final class FilePath implements Serializable {
}
/**
- * Creates a zip file from this directory or a file and sends that to the given output stream.
+ * Creates a zip file from this directory or a file and sends that to the
+ * given output stream.
*
- * @deprecated as of 1.315. Use {@link #zip(OutputStream)} that has more consistent name.
+ * @deprecated as of 1.315. Use {@link #zip(OutputStream)} that has more
+ * consistent name.
*/
public void createZipArchive(OutputStream os) throws IOException, InterruptedException {
zip(os);
}
/**
- * Creates a zip file from this directory or a file and sends that to the given output stream.
+ * Creates a zip file from this directory or a file and sends that to the
+ * given output stream.
*/
public void zip(OutputStream os) throws IOException, InterruptedException {
- zip(os,(FileFilter)null);
+ zip(os, (FileFilter) null);
}
/**
- * Creates a zip file from this directory by using the specified filter,
- * and sends the result to the given output stream.
+ * Creates a zip file from this directory by using the specified filter, and
+ * sends the result to the given output stream.
*
- * @param filter
- * Must be serializable since it may be executed remotely. Can be null to add all files.
+ * @param filter Must be serializable since it may be executed remotely. Can
+ * be null to add all files.
*
* @since 1.315
*/
public void zip(OutputStream os, FileFilter filter) throws IOException, InterruptedException {
- archive(ArchiverFactory.ZIP,os,filter);
+ archive(ArchiverFactory.ZIP, os, filter);
}
/**
- * Creates a zip file from this directory by only including the files that match the given glob.
+ * Creates a zip file from this directory by only including the files that
+ * match the given glob.
*
- * @param glob
- * Ant style glob, like "**&#x2F;*.xml". If empty or null, this method
- * works like {@link #createZipArchive(OutputStream)}
+ * @param glob Ant style glob, like "**&#x2F;*.xml". If empty or null, this
+ * method works like {@link #createZipArchive(OutputStream)}
*
* @since 1.129
- * @deprecated as of 1.315
- * Use {@link #zip(OutputStream,String)} that has more consistent name.
+ * @deprecated as of 1.315 Use {@link #zip(OutputStream,String)} that has
+ * more consistent name.
*/
public void createZipArchive(OutputStream os, final String glob) throws IOException, InterruptedException {
- archive(ArchiverFactory.ZIP,os,glob);
+ archive(ArchiverFactory.ZIP, os, glob);
}
/**
- * Creates a zip file from this directory by only including the files that match the given glob.
+ * Creates a zip file from this directory by only including the files that
+ * match the given glob.
*
- * @param glob
- * Ant style glob, like "**&#x2F;*.xml". If empty or null, this method
- * works like {@link #createZipArchive(OutputStream)}
+ * @param glob Ant style glob, like "**&#x2F;*.xml". If empty or null, this
+ * method works like {@link #createZipArchive(OutputStream)}
*
* @since 1.315
*/
public void zip(OutputStream os, final String glob) throws IOException, InterruptedException {
- archive(ArchiverFactory.ZIP,os,glob);
+ archive(ArchiverFactory.ZIP, os, glob);
}
/**
- * Uses the given scanner on 'this' directory to list up files and then archive it to a zip stream.
+ * Uses the given scanner on 'this' directory to list up files and then
+ * archive it to a zip stream.
*/
public int zip(OutputStream out, DirScanner scanner) throws IOException, InterruptedException {
return archive(ArchiverFactory.ZIP, out, scanner);
}
/**
- * Archives this directory into the specified archive format, to the given {@link OutputStream}, by using
- * {@link DirScanner} to choose what files to include.
+ * Archives this directory into the specified archive format, to the given
+ * {@link OutputStream}, by using {@link DirScanner} to choose what files to
+ * include.
*
- * @return
- * number of files/directories archived. This is only really useful to check for a situation where nothing
- * is archived.
+ * @return number of files/directories archived. This is only really useful
+ * to check for a situation where nothing is archived.
*/
public int archive(final ArchiverFactory factory, OutputStream os, final DirScanner scanner) throws IOException, InterruptedException {
- final OutputStream out = (channel!=null)?new RemoteOutputStream(os):os;
+ final OutputStream out = (channel != null) ? new RemoteOutputStream(os) : os;
return act(new FileCallable<Integer>() {
public Integer invoke(File f, VirtualChannel channel) throws IOException {
Archiver a = factory.create(out);
try {
- scanner.scan(f,a);
+ scanner.scan(f, a);
} finally {
a.close();
}
return a.countEntries();
}
-
private static final long serialVersionUID = 1L;
});
}
private int archive(final ArchiverFactory factory, OutputStream os, final FileFilter filter) throws IOException, InterruptedException {
- return archive(factory,os,new DirScanner.Filter(filter));
+ return archive(factory, os, new DirScanner.Filter(filter));
}
private int archive(final ArchiverFactory factory, OutputStream os, final String glob) throws IOException, InterruptedException {
- return archive(factory,os,new DirScanner.Glob(glob,null));
+ return archive(factory, os, new DirScanner.Glob(glob, null));
}
/**
* When this {@link FilePath} represents a zip file, extracts that zip file.
*
- * @param target
- * Target directory to expand files to. All the necessary directories will be created.
+ * @param target Target directory to expand files to. All the necessary
+ * directories will be created.
* @since 1.248
* @see #unzipFrom(InputStream)
*/
public void unzip(final FilePath target) throws IOException, InterruptedException {
target.act(new FileCallable<Void>() {
public Void invoke(File dir, VirtualChannel channel) throws IOException {
- unzip(dir,FilePath.this.read());
+ unzip(dir, FilePath.this.read());
return null;
}
private static final long serialVersionUID = 1L;
@@ -424,17 +441,16 @@ public final class FilePath implements Serializable {
/**
* When this {@link FilePath} represents a tar file, extracts that tar file.
*
- * @param target
- * Target directory to expand files to. All the necessary directories will be created.
- * @param compression
- * Compression mode of this tar file.
+ * @param target Target directory to expand files to. All the necessary
+ * directories will be created.
+ * @param compression Compression mode of this tar file.
* @since 1.292
* @see #untarFrom(InputStream, TarCompression)
*/
public void untar(final FilePath target, final TarCompression compression) throws IOException, InterruptedException {
target.act(new FileCallable<Void>() {
public Void invoke(File dir, VirtualChannel channel) throws IOException {
- readFromTar(FilePath.this.getName(),dir,compression.extract(FilePath.this.read()));
+ readFromTar(FilePath.this.getName(), dir, compression.extract(FilePath.this.read()));
return null;
}
private static final long serialVersionUID = 1L;
@@ -442,10 +458,11 @@ public final class FilePath implements Serializable {
}
/**
- * Reads the given InputStream as a zip file and extracts it into this directory.
+ * Reads the given InputStream as a zip file and extracts it into this
+ * directory.
*
- * @param _in
- * The stream will be closed by this method after it's fully read.
+ * @param _in The stream will be closed by this method after it's fully
+ * read.
* @since 1.283
* @see #unzip(FilePath)
*/
@@ -466,13 +483,15 @@ public final class FilePath implements Serializable {
java.util.zip.ZipEntry e;
try {
- while((e=zip.getNextEntry())!=null) {
- File f = new File(dir,e.getName());
- if(e.isDirectory()) {
+ while ((e = zip.getNextEntry()) != null) {
+ File f = new File(dir, e.getName());
+ if (e.isDirectory()) {
f.mkdirs();
} else {
File p = f.getParentFile();
- if(p!=null) p.mkdirs();
+ if (p != null) {
+ p.mkdirs();
+ }
IOUtils.copy(zip, f);
f.setLastModified(e.getTime());
zip.closeEntry();
@@ -487,7 +506,7 @@ public final class FilePath implements Serializable {
* Absolutizes this {@link FilePath} and returns the new one.
*/
public FilePath absolutize() throws IOException, InterruptedException {
- return new FilePath(channel,act(new FileCallable<String>() {
+ return new FilePath(channel, act(new FileCallable<String>() {
public String invoke(File f, VirtualChannel channel) throws IOException {
return f.getAbsolutePath();
}
@@ -496,12 +515,18 @@ public final class FilePath implements Serializable {
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
FilePath that = (FilePath) o;
- if (channel != null ? !channel.equals(that.channel) : that.channel != null) return false;
+ if (channel != null ? !channel.equals(that.channel) : that.channel != null) {
+ return false;
+ }
return remote.equals(that.remote);
}
@@ -510,30 +535,33 @@ public final class FilePath implements Serializable {
public int hashCode() {
return 31 * (channel != null ? channel.hashCode() : 0) + remote.hashCode();
}
-
+
/**
* Supported tar file compression methods.
*/
public enum TarCompression {
+
NONE {
public InputStream extract(InputStream in) {
return in;
}
+
public OutputStream compress(OutputStream out) {
return out;
}
},
GZIP {
public InputStream extract(InputStream _in) throws IOException {
- HeadBufferingStream in = new HeadBufferingStream(_in,SIDE_BUFFER_SIZE);
+ HeadBufferingStream in = new HeadBufferingStream(_in, SIDE_BUFFER_SIZE);
try {
return new GZIPInputStream(in, BUFFER_SIZE);
} catch (IOException e) {
// various people reported "java.io.IOException: Not in GZIP format" here, so diagnose this problem better
in.fillSide();
- throw new IOException2(e.getMessage()+"\nstream="+Util.toHexString(in.getSideBuffer()),e);
+ throw new IOException2(e.getMessage() + "\nstream=" + Util.toHexString(in.getSideBuffer()), e);
}
}
+
public OutputStream compress(OutputStream out) throws IOException {
return new GZIPOutputStream(new BufferedOutputStream(out));
}
@@ -541,16 +569,17 @@ public final class FilePath implements Serializable {
private static final int BUFFER_SIZE = 8192;
public abstract InputStream extract(InputStream in) throws IOException;
+
public abstract OutputStream compress(OutputStream in) throws IOException;
}
/**
- * Reads the given InputStream as a tar file and extracts it into this directory.
+ * Reads the given InputStream as a tar file and extracts it into this
+ * directory.
*
- * @param _in
- * The stream will be closed by this method after it's fully read.
- * @param compression
- * The compression method in use.
+ * @param _in The stream will be closed by this method after it's fully
+ * read.
+ * @param compression The compression method in use.
* @since 1.292
*/
public void untarFrom(InputStream _in, final TarCompression compression) throws IOException, InterruptedException {
@@ -558,7 +587,7 @@ public final class FilePath implements Serializable {
final InputStream in = new RemoteInputStream(_in);
act(new FileCallable<Void>() {
public Void invoke(File dir, VirtualChannel channel) throws IOException {
- readFromTar("input stream",dir, compression.extract(in));
+ readFromTar("input stream", dir, compression.extract(in));
return null;
}
private static final long serialVersionUID = 1L;
@@ -569,29 +598,27 @@ public final class FilePath implements Serializable {
}
/**
- * Given a tgz/zip file, extracts it to the given target directory, if necessary.
+ * Given a tgz/zip file, extracts it to the given target directory, if
+ * necessary.
*
- * <p>
- * This method is a convenience method designed for installing a binary package to a location
- * that supports upgrade and downgrade. Specifically,
+ * <p> This method is a convenience method designed for installing a binary
+ * package to a location that supports upgrade and downgrade. Specifically,
*
- * <ul>
- * <li>If the target directory doesn't exist {@linkplain #mkdirs() it'll be created}.
- * <li>The timestamp of the .tgz file is left in the installation directory upon extraction.
- * <li>If the timestamp left in the directory doesn't match with the timestamp of the current archive file,
- * the directory contents will be discarded and the archive file will be re-extracted.
- * <li>If the connection is refused but the target directory already exists, it is left alone.
- * </ul>
+ * <ul> <li>If the target directory doesn't exist
+ * {@linkplain #mkdirs() it'll be created}. <li>The timestamp of the .tgz
+ * file is left in the installation directory upon extraction. <li>If the
+ * timestamp left in the directory doesn't match with the timestamp of the
+ * current archive file, the directory contents will be discarded and the
+ * archive file will be re-extracted. <li>If the connection is refused but
+ * the target directory already exists, it is left alone. </ul>
*
- * @param archive
- * The resource that represents the tgz/zip file. This URL must support the "Last-Modified" header.
- * (Most common usage is to get this from {@link ClassLoader#getResource(String)})
- * @param listener
- * If non-null, a message will be printed to this listener once this method decides to
- * extract an archive.
- * @return
- * true if the archive was extracted. false if the extraction was skipped because the target directory
- * was considered up to date.
+ * @param archive The resource that represents the tgz/zip file. This URL
+ * must support the "Last-Modified" header. (Most common usage is to get
+ * this from {@link ClassLoader#getResource(String)})
+ * @param listener If non-null, a message will be printed to this listener
+ * once this method decides to extract an archive.
+ * @return true if the archive was extracted. false if the extraction was
+ * skipped because the target directory was considered up to date.
* @since 1.299
*/
public boolean installIfNecessaryFrom(URL archive, TaskListener listener, String message) throws IOException, InterruptedException {
@@ -614,39 +641,42 @@ public final class FilePath implements Serializable {
long sourceTimestamp = con.getLastModified();
FilePath timestamp = this.child(".timestamp");
- if(this.exists()) {
- if(timestamp.exists() && sourceTimestamp ==timestamp.lastModified())
+ if (this.exists()) {
+ if (timestamp.exists() && sourceTimestamp == timestamp.lastModified()) {
return false; // already up to date
+ }
this.deleteContents();
} else {
this.mkdirs();
}
- if(listener!=null)
+ if (listener != null) {
listener.getLogger().println(message);
+ }
InputStream in = con.getInputStream();
CountingInputStream cis = new CountingInputStream(in);
-
+
try {
- if(archive.toExternalForm().endsWith(".zip"))
+ if (archive.toExternalForm().endsWith(".zip")) {
unzipFrom(cis);
- else
- untarFrom(cis,GZIP);
+ } else {
+ untarFrom(cis, GZIP);
+ }
} catch (IOException e) {
throw new IOException2(String.format("Failed to unpack %s (%d bytes read of total %d)",
- archive,cis.getByteCount(),con.getContentLength()),e);
+ archive, cis.getByteCount(), con.getContentLength()), e);
}
timestamp.touch(sourceTimestamp);
return true;
} catch (IOException e) {
- throw new IOException2("Failed to install "+archive+" to "+remote,e);
+ throw new IOException2("Failed to install " + archive + " to " + remote, e);
}
}
/**
- * Reads the URL on the current VM, and writes all the data to this {@link FilePath}
- * (this is different from resolving URL remotely.)
+ * Reads the URL on the current VM, and writes all the data to this
+ * {@link FilePath} (this is different from resolving URL remotely.)
*
* @since 1.293
*/
@@ -660,7 +690,8 @@ public final class FilePath implements Serializable {
}
/**
- * Replaces the content of this file by the data from the given {@link InputStream}.
+ * Replaces the content of this file by the data from the given
+ * {@link InputStream}.
*
* @since 1.293
*/
@@ -675,7 +706,7 @@ public final class FilePath implements Serializable {
/**
* Conveniene method to call {@link FilePath#copyTo(FilePath)}.
- *
+ *
* @since 1.311
*/
public void copyFrom(FilePath src) throws IOException, InterruptedException {
@@ -683,10 +714,11 @@ public final class FilePath implements Serializable {
}
/**
- * Place the data from {@link FileItem} into the file location specified by this {@link FilePath} object.
+ * Place the data from {@link FileItem} into the file location specified by
+ * this {@link FilePath} object.
*/
public void copyFrom(FileItem file) throws IOException, InterruptedException {
- if(channel==null) {
+ if (channel == null) {
try {
file.write(new File(remote));
} catch (IOException e) {
@@ -698,7 +730,7 @@ public final class FilePath implements Serializable {
InputStream i = file.getInputStream();
OutputStream o = write();
try {
- IOUtils.copy(i,o);
+ IOUtils.copy(i, o);
} finally {
o.close();
i.close();
@@ -707,23 +739,24 @@ public final class FilePath implements Serializable {
}
/**
- * Code that gets executed on the machine where the {@link FilePath} is local.
- * Used to act on {@link FilePath}.
+ * Code that gets executed on the machine where the {@link FilePath} is
+ * local. Used to act on {@link FilePath}.
*
* @see FilePath#act(FileCallable)
*/
public static interface FileCallable<T> extends Serializable {
+
/**
- * Performs the computational task on the node where the data is located.
+ * Performs the computational task on the node where the data is
+ * located.
*
- * <p>
- * All the exceptions are forwarded to the caller.
+ * <p> All the exceptions are forwarded to the caller.
*
- * @param f
- * {@link File} that represents the local file that {@link FilePath} has represented.
- * @param channel
- * The "back pointer" of the {@link Channel} that represents the communication
- * with the node from where the code was sent.
+ * @param f {@link File} that represents the local file that
+ * {@link FilePath} has represented.
+ * @param channel The "back pointer" of the {@link Channel} that
+ * represents the communication with the node from where the code was
+ * sent.
*/
T invoke(File f, VirtualChannel channel) throws IOException, InterruptedException;
}
@@ -733,21 +766,21 @@ public final class FilePath implements Serializable {
* so that one can perform local file operations.
*/
public <T> T act(final FileCallable<T> callable) throws IOException, InterruptedException {
- return act(callable,callable.getClass().getClassLoader());
+ return act(callable, callable.getClass().getClassLoader());
}
private <T> T act(final FileCallable<T> callable, ClassLoader cl) throws IOException, InterruptedException {
- if(channel!=null) {
+ if (channel != null) {
// run this on a remote system
try {
- return channel.call(new FileCallableWrapper<T>(callable,cl));
+ return channel.call(new FileCallableWrapper<T>(callable, cl));
} catch (TunneledInterruptedException e) {
- throw (InterruptedException)new InterruptedException().initCause(e);
+ throw (InterruptedException) new InterruptedException().initCause(e);
} catch (AbortException e) {
throw e; // pass through so that the caller can catch it as AbortException
} catch (IOException e) {
// wrap it into a new IOException so that we get the caller's stack trace as well.
- throw new IOException2("remote file operation failed: "+remote+" at "+channel,e);
+ throw new IOException2("remote file operation failed: " + remote + " at " + channel, e);
}
} else {
// the file is on the local machine.
@@ -761,11 +794,11 @@ public final class FilePath implements Serializable {
*/
public <T> Future<T> actAsync(final FileCallable<T> callable) throws IOException, InterruptedException {
try {
- return (channel!=null ? channel : Hudson.MasterComputer.localChannel)
- .callAsync(new FileCallableWrapper<T>(callable));
+ return (channel != null ? channel : Hudson.MasterComputer.localChannel)
+ .callAsync(new FileCallableWrapper<T>(callable));
} catch (IOException e) {
// wrap it into a new IOException so that we get the caller's stack trace as well.
- throw new IOException2("remote file operation failed",e);
+ throw new IOException2("remote file operation failed", e);
}
}
@@ -773,8 +806,8 @@ public final class FilePath implements Serializable {
* Executes some program on the machine that this {@link FilePath} exists,
* so that one can perform local file operations.
*/
- public <V,E extends Throwable> V act(Callable<V,E> callable) throws IOException, InterruptedException, E {
- if(channel!=null) {
+ public <V, E extends Throwable> V act(Callable<V, E> callable) throws IOException, InterruptedException, E {
+ if (channel != null) {
// run this on a remote system
return channel.call(callable);
} else {
@@ -784,8 +817,8 @@ public final class FilePath implements Serializable {
}
/**
- * Converts this file to the URI, relative to the machine
- * on which this file is available.
+ * Converts this file to the URI, relative to the machine on which this file
+ * is available.
*/
public URI toURI() throws IOException, InterruptedException {
return act(new FileCallable<URI>() {
@@ -799,18 +832,19 @@ public final class FilePath implements Serializable {
* Creates this directory.
*/
public void mkdirs() throws IOException, InterruptedException {
- if(!act(new FileCallable<Boolean>() {
+ if (!act(new FileCallable<Boolean>() {
public Boolean invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
- if(f.mkdirs() || f.exists())
+ if (f.mkdirs() || f.exists()) {
return true; // OK
-
+ }
// following Ant <mkdir> task to avoid possible race condition.
Thread.sleep(10);
return f.mkdirs() || f.exists();
}
- }))
- throw new IOException("Failed to mkdirs: "+remote);
+ })) {
+ throw new IOException("Failed to mkdirs: " + remote);
+ }
}
/**
@@ -845,32 +879,39 @@ public final class FilePath implements Serializable {
public String getBaseName() {
String n = getName();
int idx = n.lastIndexOf('.');
- if (idx<0) return n;
- return n.substring(0,idx);
+ if (idx < 0) {
+ return n;
+ }
+ return n.substring(0, idx);
}
+
/**
* Gets just the file name portion.
*
- * This method assumes that the file name is the same between local and remote.
+ * This method assumes that the file name is the same between local and
+ * remote.
*/
public String getName() {
String r = remote;
- if(r.endsWith("\\") || r.endsWith("/"))
- r = r.substring(0,r.length()-1);
+ if (r.endsWith("\\") || r.endsWith("/")) {
+ r = r.substring(0, r.length() - 1);
+ }
- int len = r.length()-1;
- while(len>=0) {
+ int len = r.length() - 1;
+ while (len >= 0) {
char ch = r.charAt(len);
- if(ch=='\\' || ch=='/')
+ if (ch == '\\' || ch == '/') {
break;
+ }
len--;
}
- return r.substring(len+1);
+ return r.substring(len + 1);
}
/**
- * Short for {@code getParent().child(rel)}. Useful for getting other files in the same directory.
+ * Short for {@code getParent().child(rel)}. Useful for getting other files
+ * in the same directory.
*/
public FilePath sibling(String rel) {
return getParent().child(rel);
@@ -880,46 +921,50 @@ public final class FilePath implements Serializable {
* Returns a {@link FilePath} by adding the given suffix to this path name.
*/
public FilePath withSuffix(String suffix) {
- return new FilePath(channel,remote+suffix);
+ return new FilePath(channel, remote + suffix);
}
/**
* The same as {@link FilePath#FilePath(FilePath,String)} but more OO.
+ *
* @param rel a relative or absolute path
* @return a file on the same channel
*/
public FilePath child(String rel) {
- return new FilePath(this,rel);
+ return new FilePath(this, rel);
}
/**
* Gets the parent file.
+ *
* @return parent FilePath or null if there is no parent
*/
public FilePath getParent() {
int i = remote.length() - 2;
for (; i >= 0; i--) {
char ch = remote.charAt(i);
- if(ch=='\\' || ch=='/')
+ if (ch == '\\' || ch == '/') {
break;
+ }
}
- return i >= 0 ? new FilePath( channel, remote.substring(0,i+1) ) : null;
+ return i >= 0 ? new FilePath(channel, remote.substring(0, i + 1)) : null;
}
/**
- * Creates a temporary file in the directory that this {@link FilePath} object designates.
+ * Creates a temporary file in the directory that this {@link FilePath}
+ * object designates.
*/
public FilePath createTempFile(final String prefix, final String suffix) throws IOException, InterruptedException {
try {
- return new FilePath(this,act(new FileCallable<String>() {
+ return new FilePath(this, act(new FileCallable<String>() {
public String invoke(File dir, VirtualChannel channel) throws IOException {
File f = File.createTempFile(prefix, suffix, dir);
return f.getName();
}
}));
} catch (IOException e) {
- throw new IOException2("Failed to create a temp file on "+remote,e);
+ throw new IOException2("Failed to create a temp file on " + remote, e);
}
}
@@ -928,7 +973,7 @@ public final class FilePath implements Serializable {
* given text (encoded in the platform default encoding)
*/
public FilePath createTextTempFile(final String prefix, final String suffix, final String contents) throws IOException, InterruptedException {
- return createTextTempFile(prefix,suffix,contents,true);
+ return createTextTempFile(prefix, suffix, contents, true);
}
/**
@@ -937,18 +982,19 @@ public final class FilePath implements Serializable {
*/
public FilePath createTextTempFile(final String prefix, final String suffix, final String contents, final boolean inThisDirectory) throws IOException, InterruptedException {
try {
- return new FilePath(channel,act(new FileCallable<String>() {
+ return new FilePath(channel, act(new FileCallable<String>() {
public String invoke(File dir, VirtualChannel channel) throws IOException {
- if(!inThisDirectory)
+ if (!inThisDirectory) {
dir = new File(System.getProperty("java.io.tmpdir"));
- else
+ } else {
dir.mkdirs();
+ }
File f;
try {
f = File.createTempFile(prefix, suffix, dir);
} catch (IOException e) {
- throw new IOException2("Failed to create a temporary directory in "+dir,e);
+ throw new IOException2("Failed to create a temporary directory in " + dir, e);
}
Writer w = null;
try {
@@ -962,17 +1008,18 @@ public final class FilePath implements Serializable {
}
}));
} catch (IOException e) {
- throw new IOException2("Failed to create a temp file on "+remote,e);
+ throw new IOException2("Failed to create a temp file on " + remote, e);
}
}
/**
* Creates a temporary directory inside the directory represented by 'this'
+ *
* @since 1.311
*/
public FilePath createTempDir(final String prefix, final String suffix) throws IOException, InterruptedException {
try {
- return new FilePath(this,act(new FileCallable<String>() {
+ return new FilePath(this, act(new FileCallable<String>() {
public String invoke(File dir, VirtualChannel channel) throws IOException {
File f = File.createTempFile(prefix, suffix, dir);
f.delete();
@@ -981,12 +1028,13 @@ public final class FilePath implements Serializable {
}
}));
} catch (IOException e) {
- throw new IOException2("Failed to create a temp directory on "+remote,e);
+ throw new IOException2("Failed to create a temp directory on " + remote, e);
}
}
/**
* Deletes this file.
+ *
* @throws IOException if it exists but could not be successfully deleted
* @return true, for a modicum of compatibility
*/
@@ -1012,8 +1060,8 @@ public final class FilePath implements Serializable {
}
/**
- * Gets the last modified time stamp of this file, by using the clock
- * of the machine where this file actually resides.
+ * Gets the last modified time stamp of this file, by using the clock of the
+ * machine where this file actually resides.
*
* @see File#lastModified()
* @see #touch(long)
@@ -1034,10 +1082,12 @@ public final class FilePath implements Serializable {
public void touch(final long timestamp) throws IOException, InterruptedException {
act(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException {
- if(!f.exists())
+ if (!f.exists()) {
new FileOutputStream(f).close();
- if(!f.setLastModified(timestamp))
- throw new IOException("Failed to set the timestamp of "+f+" to "+timestamp);
+ }
+ if (!f.setLastModified(timestamp)) {
+ throw new IOException("Failed to set the timestamp of " + f + " to " + timestamp);
+ }
return null;
}
});
@@ -1053,7 +1103,7 @@ public final class FilePath implements Serializable {
}
});
}
-
+
/**
* Returns the file size in bytes.
*
@@ -1072,14 +1122,15 @@ public final class FilePath implements Serializable {
*
* On Windows, no-op.
*
- * @param mask
- * File permission mask. To simplify the permission copying,
- * if the parameter is -1, this method becomes no-op.
+ * @param mask File permission mask. To simplify the permission copying, if
+ * the parameter is -1, this method becomes no-op.
* @since 1.303
* @see #mode()
*/
public void chmod(final int mask) throws IOException, InterruptedException {
- if(!isUnix() || mask==-1) return;
+ if (!isUnix() || mask == -1) {
+ return;
+ }
act(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException {
Util.chmod(f, mask);
@@ -1091,13 +1142,14 @@ public final class FilePath implements Serializable {
/**
* Gets the file permission bit mask.
*
- * @return
- * -1 on Windows, since such a concept doesn't make sense.
+ * @return -1 on Windows, since such a concept doesn't make sense.
* @since 1.311
* @see #chmod(int)
*/
public int mode() throws IOException, InterruptedException {
- if(!isUnix()) return -1;
+ if (!isUnix()) {
+ return -1;
+ }
return act(new FileCallable<Integer>() {
public Integer invoke(File f, VirtualChannel channel) throws IOException {
int mode = -1;
@@ -1106,7 +1158,7 @@ public final class FilePath implements Serializable {
} catch (NativeAccessException ex) {
LOGGER.log(Level.WARNING, "Native function mod failed ({0})", NativeUtils.getInstance().getLastUnixError());
}
- return mode;
+ return mode;
}
});
}
@@ -1114,11 +1166,11 @@ public final class FilePath implements Serializable {
/**
* List up files and directories in this directory.
*
- * <p>
- * This method returns direct children of the directory denoted by the 'this' object.
+ * <p> This method returns direct children of the directory denoted by the
+ * 'this' object.
*/
public List<FilePath> list() throws IOException, InterruptedException {
- return list((FileFilter)null);
+ return list((FileFilter) null);
}
/**
@@ -1131,6 +1183,7 @@ public final class FilePath implements Serializable {
}
private static final class DirectoryFilter implements FileFilter, Serializable {
+
public boolean accept(File f) {
return f.isDirectory();
}
@@ -1138,13 +1191,13 @@ public final class FilePath implements Serializable {
}
/**
- * List up files in this directory, just like {@link File#listFiles(FileFilter)}.
+ * List up files in this directory, just like
+ * {@link File#listFiles(FileFilter)}.
*
- * @param filter
- * The optional filter used to narrow down the result.
- * If non-null, must be {@link Serializable}.
- * If this {@link FilePath} represents a remote path,
- * the filter object will be executed on the remote machine.
+ * @param filter The optional filter used to narrow down the result. If
+ * non-null, must be {@link Serializable}. If this {@link FilePath}
+ * represents a remote path, the filter object will be executed on the
+ * remote machine.
*/
public List<FilePath> list(final FileFilter filter) throws IOException, InterruptedException {
if (filter != null && !(filter instanceof Serializable)) {
@@ -1153,33 +1206,36 @@ public final class FilePath implements Serializable {
return act(new FileCallable<List<FilePath>>() {
public List<FilePath> invoke(File f, VirtualChannel channel) throws IOException {
File[] children = f.listFiles(filter);
- if(children ==null) return null;
+ if (children == null) {
+ return null;
+ }
ArrayList<FilePath> r = new ArrayList<FilePath>(children.length);
- for (File child : children)
+ for (File child : children) {
r.add(new FilePath(child));
+ }
return r;
}
- }, (filter!=null?filter:this).getClass().getClassLoader());
+ }, (filter != null ? filter : this).getClass().getClassLoader());
}
/**
* List up files in this directory that matches the given Ant-style filter.
*
- * @param includes
- * See {@link FileSet} for the syntax. String like "foo/*.zip" or "foo/*&#42;/*.xml"
- * @return
- * can be empty but always non-null.
+ * @param includes See {@link FileSet} for the syntax. String like
+ * "foo/*.zip" or "foo/*&#42;/*.xml"
+ * @return can be empty but always non-null.
*/
public FilePath[] list(final String includes) throws IOException, InterruptedException {
return act(new FileCallable<FilePath[]>() {
public FilePath[] invoke(File f, VirtualChannel channel) throws IOException {
- String[] files = glob(f,includes);
+ String[] files = glob(f, includes);
FilePath[] r = new FilePath[files.length];
- for( int i=0; i<r.length; i++ )
- r[i] = new FilePath(new File(f,files[i]));
+ for (int i = 0; i < r.length; i++) {
+ r[i] = new FilePath(new File(f, files[i]));
+ }
return r;
}
@@ -1189,13 +1245,13 @@ public final class FilePath implements Serializable {
/**
* Runs Ant glob expansion.
*
- * @return
- * A set of relative file names from the base directory.
+ * @return A set of relative file names from the base directory.
*/
private static String[] glob(File dir, String includes) throws IOException {
- if(isAbsolute(includes))
- throw new IOException("Expecting Ant GLOB pattern, but saw '"+includes+"'. See http://ant.apache.org/manual/Types/fileset.html for syntax");
- FileSet fs = Util.createFileSet(dir,includes);
+ if (isAbsolute(includes)) {
+ throw new IOException("Expecting Ant GLOB pattern, but saw '" + includes + "'. See http://ant.apache.org/manual/Types/fileset.html for syntax");
+ }
+ FileSet fs = Util.createFileSet(dir, includes);
DirectoryScanner ds = fs.getDirectoryScanner(new Project());
String[] files = ds.getIncludedFiles();
return files;
@@ -1205,16 +1261,17 @@ public final class FilePath implements Serializable {
* Reads this file.
*/
public InputStream read() throws IOException {
- if(channel==null)
+ if (channel == null) {
return new FileInputStream(new File(remote));
+ }
final Pipe p = Pipe.createRemoteToLocal();
- channel.callAsync(new Callable<Void,IOException>() {
+ channel.callAsync(new Callable<Void, IOException>() {
public Void call() throws IOException {
- FileInputStream fis=null;
+ FileInputStream fis = null;
try {
fis = new FileInputStream(new File(remote));
- Util.copyStream(fis,p.getOut());
+ Util.copyStream(fis, p.getOut());
return null;
} finally {
IOUtils.closeQuietly(fis);
@@ -1239,18 +1296,17 @@ public final class FilePath implements Serializable {
}
/**
- * Writes to this file.
- * If this file already exists, it will be overwritten.
+ * Writes to this file. If this file already exists, it will be overwritten.
* If the directory doesn't exist, it will be created.
*/
public OutputStream write() throws IOException, InterruptedException {
- if(channel==null) {
+ if (channel == null) {
File f = new File(remote).getAbsoluteFile();
f.getParentFile().mkdirs();
return new FileOutputStream(f);
}
- return channel.call(new Callable<OutputStream,IOException>() {
+ return channel.call(new Callable<OutputStream, IOException>() {
public OutputStream call() throws IOException {
File f = new File(remote).getAbsoluteFile();
f.getParentFile().mkdirs();
@@ -1263,8 +1319,7 @@ public final class FilePath implements Serializable {
/**
* Overwrites this file by placing the given String as the content.
*
- * @param encoding
- * Null to use the platform default encoding.
+ * @param encoding Null to use the platform default encoding.
* @since 1.105
*/
public void write(final String content, final String encoding) throws IOException, InterruptedException {
@@ -1295,38 +1350,40 @@ public final class FilePath implements Serializable {
}
/**
- * Rename this file/directory to the target filepath. This FilePath and the target must
- * be on the some host
+ * Rename this file/directory to the target filepath. This FilePath and the
+ * target must be on the some host
*/
public void renameTo(final FilePath target) throws IOException, InterruptedException {
- if(this.channel != target.channel) {
- throw new IOException("renameTo target must be on the same host");
- }
+ if (this.channel != target.channel) {
+ throw new IOException("renameTo target must be on the same host");
+ }
act(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException {
- f.renameTo(new File(target.remote));
+ f.renameTo(new File(target.remote));
return null;
}
});
}
/**
- * Moves all the contents of this directory into the specified directory, then delete this directory itself.
+ * Moves all the contents of this directory into the specified directory,
+ * then delete this directory itself.
*
* @since 1.308.
*/
public void moveAllChildrenTo(final FilePath target) throws IOException, InterruptedException {
- if(this.channel != target.channel) {
+ if (this.channel != target.channel) {
throw new IOException("pullUpTo target must be on the same host");
}
act(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException {
File t = new File(target.getRemote());
-
- for(File child : f.listFiles()) {
+
+ for (File child : f.listFiles()) {
File target = new File(t, child.getName());
- if(!child.renameTo(target))
- throw new IOException("Failed to rename "+child+" to "+target);
+ if (!child.renameTo(target)) {
+ throw new IOException("Failed to rename " + child + " to " + target);
+ }
}
f.delete();
return null;
@@ -1346,12 +1403,13 @@ public final class FilePath implements Serializable {
out.close();
}
} catch (IOException e) {
- throw new IOException2("Failed to copy "+this+" to "+target,e);
+ throw new IOException2("Failed to copy " + this + " to " + target, e);
}
}
/**
* Copies this file to the specified target, with file permissions intact.
+ *
* @since 1.311
*/
public void copyToWithPermission(FilePath target) throws IOException, InterruptedException {
@@ -1371,9 +1429,9 @@ public final class FilePath implements Serializable {
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
- Util.copyStream(fis,out);
+ Util.copyStream(fis, out);
try {
- if (Channel.current() != null){
+ if (Channel.current() != null) {
Channel.current().flushPipe();
}
} catch (InterruptedException ex) {
@@ -1389,57 +1447,64 @@ public final class FilePath implements Serializable {
}
/**
- * Remoting interface used for {@link FilePath#copyRecursiveTo(String, FilePath)}.
+ * Remoting interface used for
+ * {@link FilePath#copyRecursiveTo(String, FilePath)}.
*
* TODO: this might not be the most efficient way to do the copy.
*/
interface RemoteCopier {
+
/**
- * @param fileName
- * relative path name to the output file. Path separator must be '/'.
+ * @param fileName relative path name to the output file. Path separator
+ * must be '/'.
*/
void open(String fileName) throws IOException;
+
void write(byte[] buf, int len) throws IOException;
+
void close() throws IOException;
}
/**
- * Copies the contents of this directory recursively into the specified target directory.
- * @since 1.312
+ * Copies the contents of this directory recursively into the specified
+ * target directory.
+ *
+ * @since 1.312
*/
public int copyRecursiveTo(FilePath target) throws IOException, InterruptedException {
- return copyRecursiveTo("**/*",target);
+ return copyRecursiveTo("**/*", target);
}
public int copyRecursiveTo(String fileMask, FilePath target) throws IOException, InterruptedException {
- return copyRecursiveTo(fileMask,null,target);
+ return copyRecursiveTo(fileMask, null, target);
}
/**
- * {@see copyRecursiveTo(String fileMask, String excludes, FilePath target, FilePath.TarCompression remoteCompressionType)}
+ * {
+ *
+ * @see copyRecursiveTo(String fileMask, String excludes, FilePath target,
+ * FilePath.TarCompression remoteCompressionType)}
*/
public int copyRecursiveTo(final String fileMask, final String excludes, final FilePath target)
- throws IOException, InterruptedException {
+ throws IOException, InterruptedException {
return copyRecursiveTo(fileMask, excludes, target, FilePath.TarCompression.GZIP);
}
/**
- * Copies the files that match the given file mask to the specified target node.
+ * Copies the files that match the given file mask to the specified target
+ * node.
*
- * @param fileMask
- * Ant GLOB pattern.
- * String like "foo/bar/*.xml" Multiple patterns can be separated
- * by ',', and whitespace can surround ',' (so that you can write
- * "abc, def" and "abc,def" to mean the same thing.
- * @param excludes
- * Files to be excluded. Can be null.
- * @param remoteCompressionType compression type which will be used before master<->slave files transfer.
- * @return
- * the number of files copied.
+ * @param fileMask Ant GLOB pattern. String like "foo/bar/*.xml" Multiple
+ * patterns can be separated by ',', and whitespace can surround ',' (so
+ * that you can write "abc, def" and "abc,def" to mean the same thing.
+ * @param excludes Files to be excluded. Can be null.
+ * @param remoteCompressionType compression type which will be used before
+ * master<->slave files transfer.
+ * @return the number of files copied.
*/
public int copyRecursiveTo(final String fileMask, final String excludes, final FilePath target,
- final FilePath.TarCompression remoteCompressionType)
- throws IOException, InterruptedException {
+ final FilePath.TarCompression remoteCompressionType)
+ throws IOException, InterruptedException {
if (this.channel == target.channel) {
// local to local copy.
return act(new FileCallable<Integer>() {
@@ -1451,6 +1516,7 @@ public final class FilePath implements Serializable {
try {
class CopyImpl extends Copy {
+
private int copySize;
public CopyImpl() {
@@ -1488,17 +1554,17 @@ public final class FilePath implements Serializable {
Future<Void> future = target.actAsync(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException {
try {
- readFromTar(remote + '/' + fileMask, f, (remoteCompressionType != null?
- remoteCompressionType.extract(pipe.getIn()) :
- FilePath.TarCompression.GZIP.extract(pipe.getIn())));
+ readFromTar(remote + '/' + fileMask, f, (remoteCompressionType != null
+ ? remoteCompressionType.extract(pipe.getIn())
+ : FilePath.TarCompression.GZIP.extract(pipe.getIn())));
return null;
} finally {
pipe.getIn().close();
}
}
});
- int r = writeToTar(new File(remote), fileMask, excludes, (remoteCompressionType != null?
- remoteCompressionType.compress(pipe.getOut()) : FilePath.TarCompression.GZIP.compress(pipe.getOut())));
+ int r = writeToTar(new File(remote), fileMask, excludes, (remoteCompressionType != null
+ ? remoteCompressionType.compress(pipe.getOut()) : FilePath.TarCompression.GZIP.compress(pipe.getOut())));
try {
future.get();
} catch (ExecutionException e) {
@@ -1512,9 +1578,9 @@ public final class FilePath implements Serializable {
Future<Integer> future = actAsync(new FileCallable<Integer>() {
public Integer invoke(File f, VirtualChannel channel) throws IOException {
try {
- return writeToTar(f, fileMask, excludes, (remoteCompressionType != null?
- remoteCompressionType.compress(pipe.getOut()) :
- FilePath.TarCompression.GZIP.compress(pipe.getOut())));
+ return writeToTar(f, fileMask, excludes, (remoteCompressionType != null
+ ? remoteCompressionType.compress(pipe.getOut())
+ : FilePath.TarCompression.GZIP.compress(pipe.getOut())));
} finally {
pipe.getOut().close();
}
@@ -1523,8 +1589,8 @@ public final class FilePath implements Serializable {
try {
//it's possible to get NPE if on slave works old process
readFromTar(remote + '/' + fileMask, new File(target.remote),
- (remoteCompressionType != null? remoteCompressionType.extract(pipe.getIn()) :
- FilePath.TarCompression.GZIP.extract(pipe.getIn())));
+ (remoteCompressionType != null ? remoteCompressionType.extract(pipe.getIn())
+ : FilePath.TarCompression.GZIP.extract(pipe.getIn())));
} catch (IOException e) {// BuildException or IOException
try {
future.get(3, TimeUnit.SECONDS);
@@ -1545,12 +1611,10 @@ public final class FilePath implements Serializable {
}
}
-
/**
* Writes files in 'this' directory to a tar stream.
*
- * @param glob
- * Ant file pattern mask, like "**&#x2F;*.java".
+ * @param glob Ant file pattern mask, like "**&#x2F;*.java".
*/
public int tar(OutputStream out, final String glob) throws IOException, InterruptedException {
return archive(ArchiverFactory.TAR, out, glob);
@@ -1561,7 +1625,8 @@ public final class FilePath implements Serializable {
}
/**
- * Uses the given scanner on 'this' directory to list up files and then archive it to a tar stream.
+ * Uses the given scanner on 'this' directory to list up files and then
+ * archive it to a tar stream.
*/
public int tar(OutputStream out, DirScanner scanner) throws IOException, InterruptedException {
return archive(ArchiverFactory.TAR, out, scanner);
@@ -1570,13 +1635,12 @@ public final class FilePath implements Serializable {
/**
* Writes to a tar stream and stores obtained files to the base dir.
*
- * @return
- * number of files/directories that are written.
+ * @return number of files/directories that are written.
*/
private static Integer writeToTar(File baseDir, String fileMask, String excludes, OutputStream out) throws IOException {
Archiver tw = ArchiverFactory.TAR.create(out);
try {
- new DirScanner.Glob(fileMask,excludes).scan(baseDir,tw);
+ new DirScanner.Glob(fileMask, excludes).scan(baseDir, tw);
} finally {
tw.close();
}
@@ -1591,79 +1655,88 @@ public final class FilePath implements Serializable {
try {
TarEntry te;
while ((te = t.getNextEntry()) != null) {
- File f = new File(baseDir,te.getName());
- if(te.isDirectory()) {
+ File f = new File(baseDir, te.getName());
+ if (te.isDirectory()) {
f.mkdirs();
} else {
File parent = f.getParentFile();
- if (parent != null) parent.mkdirs();
+ if (parent != null) {
+ parent.mkdirs();
+ }
- IOUtils.copy(t,f);
+ IOUtils.copy(t, f);
f.setLastModified(te.getModTime().getTime());
- int mode = te.getMode()&0777;
- if(mode!=0 && !Functions.isWindows()) // be defensive
+ int mode = te.getMode() & 0777;
+ if (mode != 0 && !Functions.isWindows()) // be defensive
+ {
Util.chmod(f, mode);
+ }
}
}
- } catch(IOException e) {
- throw new IOException2("Failed to extract "+name,e);
+ } catch (IOException e) {
+ throw new IOException2("Failed to extract " + name, e);
} finally {
t.close();
}
}
/**
- * Creates a {@link Launcher} for starting processes on the node
- * that has this file.
+ * Creates a {@link Launcher} for starting processes on the node that has
+ * this file.
+ *
* @since 1.89
*/
public Launcher createLauncher(TaskListener listener) throws IOException, InterruptedException {
- if(channel==null)
+ if (channel == null) {
return new LocalLauncher(listener);
- else
- return new RemoteLauncher(listener,channel,channel.call(new IsUnix()));
+ } else {
+ return new RemoteLauncher(listener, channel, channel.call(new IsUnix()));
+ }
}
- private static final class IsUnix implements Callable<Boolean,IOException> {
+ private static final class IsUnix implements Callable<Boolean, IOException> {
+
public Boolean call() throws IOException {
- return File.pathSeparatorChar==':';
+ return File.pathSeparatorChar == ':';
}
private static final long serialVersionUID = 1L;
}
/**
- * Validates the ant file mask (like "foo/bar/*.txt, zot/*.jar")
- * against this directory, and try to point out the problem.
+ * Validates the ant file mask (like "foo/bar/*.txt, zot/*.jar") against
+ * this directory, and try to point out the problem.
*
- * <p>
- * This is useful in conjunction with {@link FormValidation}.
+ * <p> This is useful in conjunction with {@link FormValidation}.
*
- * @return
- * null if no error was found. Otherwise returns a human readable error message.
+ * @return null if no error was found. Otherwise returns a human readable
+ * error message.
* @since 1.90
* @see #validateFileMask(FilePath, String)
*/
public String validateAntFileMask(final String fileMasks) throws IOException, InterruptedException {
return act(new FileCallable<String>() {
public String invoke(File dir, VirtualChannel channel) throws IOException {
- if(fileMasks.startsWith("~"))
+ if (fileMasks.startsWith("~")) {
return Messages.FilePath_TildaDoesntWork();
+ }
- StringTokenizer tokens = new StringTokenizer(fileMasks,",");
+ StringTokenizer tokens = new StringTokenizer(fileMasks, ",");
- while(tokens.hasMoreTokens()) {
+ while (tokens.hasMoreTokens()) {
final String fileMask = tokens.nextToken().trim();
- if(hasMatch(dir,fileMask))
+ if (hasMatch(dir, fileMask)) {
continue; // no error on this portion
-
+ }
// in 1.172 we introduced an incompatible change to stop using ' ' as the separator
// so see if we can match by using ' ' as the separator
- if(fileMask.contains(" ")) {
+ if (fileMask.contains(" ")) {
boolean matched = true;
- for (String token : Util.tokenize(fileMask))
- matched &= hasMatch(dir,token);
- if(matched)
+ for (String token : Util.tokenize(fileMask)) {
+ matched &= hasMatch(dir, token);
+ }
+ if (matched) {
return Messages.FilePath_validateAntFileMask_whitespaceSeprator();
+ }
}
// a common mistake is to assume the wrong base dir, and there are two variations
@@ -1671,41 +1744,47 @@ public final class FilePath implements Serializable {
// and (2) the user gave us cc/dd where aa/bb/cc/dd was correct.
{// check the (1) above first
- String f=fileMask;
- while(true) {
+ String f = fileMask;
+ while (true) {
int idx = findSeparator(f);
- if(idx==-1) break;
- f=f.substring(idx+1);
+ if (idx == -1) {
+ break;
+ }
+ f = f.substring(idx + 1);
- if(hasMatch(dir,f))
- return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask,f);
+ if (hasMatch(dir, f)) {
+ return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask, f);
+ }
}
}
{// check the (2) above next as this is more expensive.
// Try prepending "**/" to see if that results in a match
- FileSet fs = Util.createFileSet(dir,"**/"+fileMask);
+ FileSet fs = Util.createFileSet(dir, "**/" + fileMask);
DirectoryScanner ds = fs.getDirectoryScanner(new Project());
- if(ds.getIncludedFilesCount()!=0) {
+ if (ds.getIncludedFilesCount() != 0) {
// try shorter name first so that the suggestion results in least amount of changes
String[] names = ds.getIncludedFiles();
- Arrays.sort(names,SHORTER_STRING_FIRST);
- for( String f : names) {
+ Arrays.sort(names, SHORTER_STRING_FIRST);
+ for (String f : names) {
// now we want to decompose f to the leading portion that matched "**"
// and the trailing portion that matched the file mask, so that
// we can suggest the user error.
//
// this is not a very efficient/clever way to do it, but it's relatively simple
- String prefix="";
- while(true) {
+ String prefix = "";
+ while (true) {
int idx = findSeparator(f);
- if(idx==-1) break;
-
- prefix+=f.substring(0,idx)+'/';
- f=f.substring(idx+1);
- if(hasMatch(dir,prefix+fileMask))
- return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask, prefix+fileMask);
+ if (idx == -1) {
+ break;
+ }
+
+ prefix += f.substring(0, idx) + '/';
+ f = f.substring(idx + 1);
+ if (hasMatch(dir, prefix + fileMask)) {
+ return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask, prefix + fileMask);
+ }
}
}
}
@@ -1715,26 +1794,28 @@ public final class FilePath implements Serializable {
String previous = null;
String pattern = fileMask;
- while(true) {
- if(hasMatch(dir,pattern)) {
+ while (true) {
+ if (hasMatch(dir, pattern)) {
// found a match
- if(previous==null)
- return Messages.FilePath_validateAntFileMask_portionMatchAndSuggest(fileMask,pattern);
- else
- return Messages.FilePath_validateAntFileMask_portionMatchButPreviousNotMatchAndSuggest(fileMask,pattern,previous);
+ if (previous == null) {
+ return Messages.FilePath_validateAntFileMask_portionMatchAndSuggest(fileMask, pattern);
+ } else {
+ return Messages.FilePath_validateAntFileMask_portionMatchButPreviousNotMatchAndSuggest(fileMask, pattern, previous);
+ }
}
int idx = findSeparator(pattern);
- if(idx<0) {// no more path component left to go back
- if(pattern.equals(fileMask))
+ if (idx < 0) {// no more path component left to go back
+ if (pattern.equals(fileMask)) {
return Messages.FilePath_validateAntFileMask_doesntMatchAnything(fileMask);
- else
- return Messages.FilePath_validateAntFileMask_doesntMatchAnythingAndSuggest(fileMask,pattern);
+ } else {
+ return Messages.FilePath_validateAntFileMask_doesntMatchAnythingAndSuggest(fileMask, pattern);
+ }
}
// cut off the trailing component and try again
previous = pattern;
- pattern = pattern.substring(0,idx);
+ pattern = pattern.substring(0, idx);
}
}
}
@@ -1743,10 +1824,10 @@ public final class FilePath implements Serializable {
}
private boolean hasMatch(File dir, String pattern) {
- FileSet fs = Util.createFileSet(dir,pattern);
+ FileSet fs = Util.createFileSet(dir, pattern);
DirectoryScanner ds = fs.getDirectoryScanner(new Project());
- return ds.getIncludedFilesCount()!=0 || ds.getIncludedDirsCount()!=0;
+ return ds.getIncludedFilesCount() != 0 || ds.getIncludedDirsCount() != 0;
}
/**
@@ -1755,31 +1836,40 @@ public final class FilePath implements Serializable {
private int findSeparator(String pattern) {
int idx1 = pattern.indexOf('\\');
int idx2 = pattern.indexOf('/');
- if(idx1==-1) return idx2;
- if(idx2==-1) return idx1;
- return Math.min(idx1,idx2);
+ if (idx1 == -1) {
+ return idx2;
+ }
+ if (idx2 == -1) {
+ return idx1;
+ }
+ return Math.min(idx1, idx2);
}
});
}
/**
- * Shortcut for {@link #validateFileMask(String)} in case the left-hand side can be null.
+ * Shortcut for {@link #validateFileMask(String)} in case the left-hand side
+ * can be null.
*/
public static FormValidation validateFileMask(FilePath pathOrNull, String value) throws IOException {
- if(pathOrNull==null) return FormValidation.ok();
+ if (pathOrNull == null) {
+ return FormValidation.ok();
+ }
return pathOrNull.validateFileMask(value);
}
/**
- * Short for {@code validateFileMask(value,true)}
+ * Short for {@code validateFileMask(value,true)}
*/
public FormValidation validateFileMask(String value) throws IOException {
- return validateFileMask(value,true);
+ return validateFileMask(value, true);
}
/**
- * Checks the GLOB-style file mask. See {@link #validateAntFileMask(String)}.
- * Requires configure permission on ancestor AbstractProject object in request.
+ * Checks the GLOB-style file mask. See
+ * {@link #validateAntFileMask(String)}. Requires configure permission on
+ * ancestor AbstractProject object in request.
+ *
* @since 1.294
*/
public FormValidation validateFileMask(String value, boolean errorIfNotExist) throws IOException {
@@ -1787,139 +1877,153 @@ public final class FilePath implements Serializable {
subject.checkPermission(Item.CONFIGURE);
value = fixEmpty(value);
- if(value==null)
+ if (value == null) {
return FormValidation.ok();
+ }
try {
- if(!exists()) // no workspace. can't check
+ if (!exists()) // no workspace. can't check
+ {
return FormValidation.ok();
+ }
String msg = validateAntFileMask(value);
- if(errorIfNotExist) return FormValidation.error(msg);
- else return FormValidation.warning(msg);
+ if (errorIfNotExist) {
+ return FormValidation.error(msg);
+ } else {
+ return FormValidation.warning(msg);
+ }
} catch (InterruptedException e) {
return FormValidation.ok();
}
}
/**
- * Validates a relative file path from this {@link FilePath}.
- * Requires configure permission on ancestor AbstractProject object in request.
+ * Validates a relative file path from this {@link FilePath}. Requires
+ * configure permission on ancestor AbstractProject object in request.
*
- * @param value
- * The relative path being validated.
- * @param errorIfNotExist
- * If true, report an error if the given relative path doesn't exist. Otherwise it's a warning.
- * @param expectingFile
- * If true, we expect the relative path to point to a file.
- * Otherwise, the relative path is expected to be pointing to a directory.
+ * @param value The relative path being validated.
+ * @param errorIfNotExist If true, report an error if the given relative
+ * path doesn't exist. Otherwise it's a warning.
+ * @param expectingFile If true, we expect the relative path to point to a
+ * file. Otherwise, the relative path is expected to be pointing to a
+ * directory.
*/
public FormValidation validateRelativePath(String value, boolean errorIfNotExist, boolean expectingFile) throws IOException {
- AbstractProject subject = Stapler.getCurrentRequest().findAncestorObject(AbstractProject.class);
+ AbstractProject subject = Stapler.getCurrentRequest().findAncestorObject(AbstractProject.class);
value = fixEmpty(value);
// none entered yet, or something is seriously wrong
- if (value == null || (AbstractProject<?,?>) subject == null) {
+ if (value == null || (AbstractProject<?, ?>) subject == null) {
return FormValidation.ok();
}
subject.checkPermission(Item.CONFIGURE);
// a common mistake is to use wildcard
- if (value.contains("*")) {
+ if (value.contains("*")) {
return FormValidation.error(Messages.FilePath_validateRelativePath_wildcardNotAllowed());
}
try {
// no base directory. can't check
- if (!exists()) {
+ if (!exists()) {
return FormValidation.ok();
}
-
+
FilePath path = child(value);
if (path.exists()) {
if (expectingFile) {
- if (!path.isDirectory())
+ if (!path.isDirectory()) {
return FormValidation.ok();
- else
+ } else {
return FormValidation.error(Messages.FilePath_validateRelativePath_notFile(value));
+ }
} else {
- if (path.isDirectory())
+ if (path.isDirectory()) {
return FormValidation.ok();
- else
+ } else {
return FormValidation.error(Messages.FilePath_validateRelativePath_notDirectory(value));
+ }
}
}
- String msg = expectingFile ? Messages.FilePath_validateRelativePath_noSuchFile(value) :
- Messages.FilePath_validateRelativePath_noSuchDirectory(value);
- if (errorIfNotExist) return FormValidation.error(msg);
- else return FormValidation.warning(msg);
+ String msg = expectingFile ? Messages.FilePath_validateRelativePath_noSuchFile(value)
+ : Messages.FilePath_validateRelativePath_noSuchDirectory(value);
+ if (errorIfNotExist) {
+ return FormValidation.error(msg);
+ } else {
+ return FormValidation.warning(msg);
+ }
} catch (InterruptedException e) {
return FormValidation.ok();
}
}
/**
- * A convenience method over {@link #validateRelativePath(String, boolean, boolean)}.
+ * A convenience method over
+ * {@link #validateRelativePath(String, boolean, boolean)}.
*/
public FormValidation validateRelativeDirectory(String value, boolean errorIfNotExist) throws IOException {
- return validateRelativePath(value,errorIfNotExist,false);
+ return validateRelativePath(value, errorIfNotExist, false);
}
public FormValidation validateRelativeDirectory(String value) throws IOException {
- return validateRelativeDirectory(value,true);
+ return validateRelativeDirectory(value, true);
}
- @Deprecated @Override
+ @Deprecated
+ @Override
public String toString() {
// to make writing JSPs easily, return local
return remote;
}
public VirtualChannel getChannel() {
- if(channel!=null) return channel;
- else return Hudson.MasterComputer.localChannel;
+ if (channel != null) {
+ return channel;
+ } else {
+ return Hudson.MasterComputer.localChannel;
+ }
}
/**
- * Returns true if this {@link FilePath} represents a remote file.
+ * Returns true if this {@link FilePath} represents a remote file.
*/
public boolean isRemote() {
- return channel!=null;
+ return channel != null;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
Channel target = Channel.current();
- if(channel!=null && channel!=target)
+ if (channel != null && channel != target) {
throw new IllegalStateException("Can't send a remote FilePath to a different remote channel");
+ }
oos.defaultWriteObject();
- oos.writeBoolean(channel==null);
+ oos.writeBoolean(channel == null);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
Channel channel = Channel.current();
- assert channel!=null;
+ assert channel != null;
ois.defaultReadObject();
- if(ois.readBoolean()) {
+ if (ois.readBoolean()) {
this.channel = channel;
} else {
this.channel = null;
}
}
-
private static final long serialVersionUID = 1L;
-
public static int SIDE_BUFFER_SIZE = 1024;
-
private static final Logger LOGGER = Logger.getLogger(FilePath.class.getName());
/**
* Adapts {@link FileCallable} to {@link Callable}.
*/
- private class FileCallableWrapper<T> implements DelegatingCallable<T,IOException> {
+ private class FileCallableWrapper<T> implements DelegatingCallable<T, IOException> {
+
private final FileCallable<T> callable;
private transient ClassLoader classLoader;
@@ -1944,23 +2048,23 @@ public final class FilePath implements Serializable {
public ClassLoader getClassLoader() {
return classLoader;
}
-
private static final long serialVersionUID = 1L;
}
/**
- * Used to tunnel {@link InterruptedException} over a Java signature that only allows {@link IOException}
+ * Used to tunnel {@link InterruptedException} over a Java signature that
+ * only allows {@link IOException}
*/
private static class TunneledInterruptedException extends IOException2 {
+
private TunneledInterruptedException(InterruptedException cause) {
super(cause);
}
private static final long serialVersionUID = 1L;
}
-
private static final Comparator<String> SHORTER_STRING_FIRST = new Comparator<String>() {
public int compare(String o1, String o2) {
- return o1.length()-o2.length();
+ return o1.length() - o2.length();
}
};
}
diff --git a/hudson-core/src/main/java/hudson/Functions.java b/hudson-core/src/main/java/hudson/Functions.java
index 6918b7c..eda47ed 100644
--- a/hudson-core/src/main/java/hudson/Functions.java
+++ b/hudson-core/src/main/java/hudson/Functions.java
@@ -7,10 +7,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
* Kohsuke Kawaguchi, Winston Prakash, Stephen Connolly, Tom Huybrechts, Alan Harder, Romain Seguy
- *
+ *
*
*******************************************************************************/
@@ -125,13 +125,13 @@ import org.eclipse.hudson.security.HudsonSecurityManager;
/**
* Utility functions used in views.
*
- * <p>
- * An instance of this class is created for each request and made accessible
+ * <p> An instance of this class is created for each request and made accessible
* from view pages via the variable 'h' (h stands for Hudson.)
*
* @author Kohsuke Kawaguchi
*/
public class Functions {
+
private static volatile int globalIota = 0;
private int iota;
@@ -139,14 +139,14 @@ public class Functions {
iota = globalIota;
// concurrent requests can use the same ID --- we are just trying to
// prevent the same user from seeing the same ID repeatedly.
- globalIota+=1000;
+ globalIota += 1000;
}
/**
* Generates an unique ID.
*/
public String generateId() {
- return "id"+iota++;
+ return "id" + iota++;
}
public static boolean isModel(Object o) {
@@ -162,23 +162,22 @@ public class Functions {
}
/**
- * Given {@code c=MyList (extends ArrayList<Foo>), base=List}, compute the parameterization of 'base'
- * that's assignable from 'c' (in this case {@code List<Foo>}), and return its n-th type parameter
- * (n=0 would return {@code Foo}).
+ * Given {@code c=MyList (extends ArrayList<Foo>), base=List}, compute the
+ * parameterization of 'base' that's assignable from 'c' (in this case
+ * {@code List<Foo>}), and return its n-th type parameter (n=0 would return
+ * {@code Foo}).
*
- * <p>
- * This method is useful for doing type arithmetic.
+ * <p> This method is useful for doing type arithmetic.
*
- * @throws AssertionError
- * if c' is not parameterized.
+ * @throws AssertionError if c' is not parameterized.
*/
public static <B> Class getTypeParameter(Class<? extends B> c, Class<B> base, int n) {
- Type parameterization = Types.getBaseClass(c,base);
+ Type parameterization = Types.getBaseClass(c, base);
if (parameterization instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) parameterization;
- return Types.erasure(Types.getTypeArgument(pt,n));
+ return Types.erasure(Types.getTypeArgument(pt, n));
} else {
- throw new AssertionError(c+" doesn't properly parameterize "+base);
+ throw new AssertionError(c + " doesn't properly parameterize " + base);
}
}
@@ -187,24 +186,34 @@ public class Functions {
}
/**
- * Prints the integer as a string that represents difference,
- * like "-5", "+/-0", "+3".
+ * Prints the integer as a string that represents difference, like "-5",
+ * "+/-0", "+3".
*/
public static String getDiffString(int i) {
- if(i==0) return "\u00B10"; // +/-0
+ if (i == 0) {
+ return "\u00B10"; // +/-0
+ }
String s = Integer.toString(i);
- if(i>0) return "+"+s;
- else return s;
+ if (i > 0) {
+ return "+" + s;
+ } else {
+ return s;
+ }
}
/**
* {@link #getDiffString(int)} that doesn't show anything for +/-0
*/
public static String getDiffString2(int i) {
- if(i==0) return "";
+ if (i == 0) {
+ return "";
+ }
String s = Integer.toString(i);
- if(i>0) return "+"+s;
- else return s;
+ if (i > 0) {
+ return "+" + s;
+ } else {
+ return s;
+ }
}
/**
@@ -212,10 +221,15 @@ public class Functions {
* if there's something to print
*/
public static String getDiffString2(String prefix, int i, String suffix) {
- if(i==0) return "";
+ if (i == 0) {
+ return "";
+ }
String s = Integer.toString(i);
- if(i>0) return prefix+"+"+s+suffix;
- else return prefix+s+suffix;
+ if (i > 0) {
+ return prefix + "+" + s + suffix;
+ } else {
+ return prefix + s + suffix;
+ }
}
/**
@@ -224,10 +238,11 @@ public class Functions {
public static String addSuffix(int n, String singular, String plural) {
StringBuilder buf = new StringBuilder();
buf.append(n).append(' ');
- if(n==1)
+ if (n == 1) {
buf.append(singular);
- else
+ } else {
buf.append(plural);
+ }
return buf.toString();
}
@@ -235,16 +250,19 @@ public class Functions {
List<Ancestor> ancestors = req.getAncestors();
// find the first and last Run instances
- Ancestor f=null,l=null;
+ Ancestor f = null, l = null;
for (Ancestor anc : ancestors) {
- if(anc.getObject() instanceof Run) {
- if(f==null) f=anc;
- l=anc;
+ if (anc.getObject() instanceof Run) {
+ if (f == null) {
+ f = anc;
+ }
+ l = anc;
}
}
- if(l==null) return null; // there was no Run object
-
- String head = f.getPrev().getUrl()+'/';
+ if (l == null) {
+ return null; // there was no Run object
+ }
+ String head = f.getPrev().getUrl() + '/';
String base = l.getUrl();
String reqUri = req.getOriginalRequestURI();
@@ -257,53 +275,52 @@ public class Functions {
String furl = f.getUrl();
int slashCount = 0;
// Count components in ancestor URL
- for (int i = furl.indexOf('/'); i >= 0; i = furl.indexOf('/', i + 1)) slashCount++;
+ for (int i = furl.indexOf('/'); i >= 0; i = furl.indexOf('/', i + 1)) {
+ slashCount++;
+ }
// Remove that many from request URL, ignoring extra slashes
String rest = reqUri.replaceFirst("(?:/+[^/]*){" + slashCount + "}", "");
- return new RunUrl( (Run) f.getObject(), head, base, rest);
+ return new RunUrl((Run) f.getObject(), head, base, rest);
}
/**
* If we know the user's screen resolution, return it. Otherwise null.
+ *
* @since 1.213
*/
public static Area getScreenResolution() {
- Cookie res = Functions.getCookie(Stapler.getCurrentRequest(),"screenResolution");
- if(res!=null)
+ Cookie res = Functions.getCookie(Stapler.getCurrentRequest(), "screenResolution");
+ if (res != null) {
return Area.parse(res.getValue());
+ }
return null;
}
/**
* URL decomposed for easier computation of relevant URLs.
*
- * <p>
- * The decomposed URL will be of the form:
+ * <p> The decomposed URL will be of the form:
* <pre>
* aaaaaa/524/bbbbb/cccc
* -head-| N |---rest---
* ----- base -----|
* </pre>
*
- * <p>
- * The head portion is the part of the URL from the {@link Hudson}
- * object to the first {@link Run} subtype. When "next/prev build"
- * is chosen, this part remains intact.
+ * <p> The head portion is the part of the URL from the {@link Hudson}
+ * object to the first {@link Run} subtype. When "next/prev build" is
+ * chosen, this part remains intact.
*
- * <p>
- * The <tt>524</tt> is the path from {@link Job} to {@link Run}.
+ * <p> The <tt>524</tt> is the path from {@link Job} to {@link Run}.
*
- * <p>
- * The <tt>bbb</tt> portion is the path after that till the last
- * {@link Run} subtype. The <tt>ccc</tt> portion is the part
- * after that.
+ * <p> The <tt>bbb</tt> portion is the path after that till the last
+ * {@link Run} subtype. The <tt>ccc</tt> portion is the part after that.
*/
public static final class RunUrl {
+
private final String head, base, rest;
private final Run run;
-
public RunUrl(Run run, String head, String base, String rest) {
this.run = run;
this.head = head;
@@ -330,10 +347,10 @@ public class Functions {
}
private String getUrl(Run n) {
- if(n ==null)
+ if (n == null) {
return null;
- else {
- return head+n.getNumber()+rest;
+ } else {
+ return head + n.getNumber() + rest;
}
}
}
@@ -347,9 +364,8 @@ public class Functions {
}
/**
- * @deprecated as of 1.294
- * JEXL now supports the real ternary operator "x?y:z", so this work around
- * is no longer necessary.
+ * @deprecated as of 1.294 JEXL now supports the real ternary operator
+ * "x?y:z", so this work around is no longer necessary.
*/
public static Object ifThenElse(boolean cond, Object thenValue, Object elseValue) {
return cond ? thenValue : elseValue;
@@ -360,15 +376,15 @@ public class Functions {
}
public static Map getSystemProperties() {
- return new TreeMap<Object,Object>(System.getProperties());
+ return new TreeMap<Object, Object>(System.getProperties());
}
public static Map getEnvVars() {
- return new TreeMap<String,String>(EnvVars.masterEnvVars);
+ return new TreeMap<String, String>(EnvVars.masterEnvVars);
}
public static boolean isWindows() {
- return File.pathSeparatorChar==';';
+ return File.pathSeparatorChar == ';';
}
public static List<LogRecord> getLogRecords() {
@@ -379,11 +395,11 @@ public class Functions {
return formatter.format(r);
}
- public static Cookie getCookie(HttpServletRequest req,String name) {
+ public static Cookie getCookie(HttpServletRequest req, String name) {
Cookie[] cookies = req.getCookies();
- if(cookies!=null) {
+ if (cookies != null) {
for (Cookie cookie : cookies) {
- if(cookie.getName().equals(name)) {
+ if (cookie.getName().equals(name)) {
return cookie;
}
}
@@ -391,9 +407,11 @@ public class Functions {
return null;
}
- public static String getCookie(HttpServletRequest req,String name, String defaultValue) {
+ public static String getCookie(HttpServletRequest req, String name, String defaultValue) {
Cookie c = getCookie(req, name);
- if(c==null || c.getValue()==null) return defaultValue;
+ if (c == null || c.getValue() == null) {
+ return defaultValue;
+ }
return c.getValue();
}
@@ -403,7 +421,6 @@ public class Functions {
public static String getYuiSuffix() {
return DEBUG_YUI ? "debug" : "min";
}
-
/**
* Set to true if you need to use the debug version of YUI.
*/
@@ -412,28 +429,32 @@ public class Functions {
/**
* Creates a sub map by using the given range (both ends inclusive).
*/
- public static <V> SortedMap<Integer,V> filter(SortedMap<Integer,V> map, String from, String to) {
- if(from==null && to==null) return map;
- if(to==null)
- return map.headMap(Integer.parseInt(from)-1);
- if(from==null)
+ public static <V> SortedMap<Integer, V> filter(SortedMap<Integer, V> map, String from, String to) {
+ if (from == null && to == null) {
+ return map;
+ }
+ if (to == null) {
+ return map.headMap(Integer.parseInt(from) - 1);
+ }
+ if (from == null) {
return map.tailMap(Integer.parseInt(to));
+ }
- return map.subMap(Integer.parseInt(to),Integer.parseInt(from)-1);
+ return map.subMap(Integer.parseInt(to), Integer.parseInt(from) - 1);
}
-
private static final SimpleFormatter formatter = new SimpleFormatter();
/**
* Used by <tt>layout.jelly</tt> to control the auto refresh behavior.
*
- * @param noAutoRefresh
- * On certain pages, like a page with forms, will have annoying interference
- * with auto refresh. On those pages, disable auto-refresh.
+ * @param noAutoRefresh On certain pages, like a page with forms, will have
+ * annoying interference with auto refresh. On those pages, disable
+ * auto-refresh.
*/
public static void configureAutoRefresh(HttpServletRequest request, HttpServletResponse response, boolean noAutoRefresh) {
- if(noAutoRefresh)
+ if (noAutoRefresh) {
return;
+ }
String param = request.getParameter("auto_refresh");
boolean refresh = isAutoRefresh(request);
@@ -444,7 +465,7 @@ public class Functions {
// Using request.getContextPath() might work but it seems simpler to just use the hudson_ prefix
// to avoid conflicts with any other web apps that might be on the same machine.
c.setPath("/");
- c.setMaxAge(60*60*24*30); // persist it roughly for a month
+ c.setMaxAge(60 * 60 * 24 * 30); // persist it roughly for a month
response.addCookie(c);
}
if (refresh) {
@@ -458,9 +479,9 @@ public class Functions {
return Boolean.parseBoolean(param);
}
Cookie[] cookies = request.getCookies();
- if(cookies==null)
+ if (cookies == null) {
return false; // when API design messes it up, we all suffer
-
+ }
for (Cookie c : cookies) {
if (c.getName().equals("hudson_auto_refresh")) {
return Boolean.parseBoolean(c.getValue());
@@ -470,16 +491,17 @@ public class Functions {
}
/**
- * Finds the given object in the ancestor list and returns its URL.
- * This is used to determine the "current" URL assigned to the given object,
- * so that one can compute relative URLs from it.
+ * Finds the given object in the ancestor list and returns its URL. This is
+ * used to determine the "current" URL assigned to the given object, so that
+ * one can compute relative URLs from it.
*/
- public static String getNearestAncestorUrl(StaplerRequest req,Object it) {
+ public static String getNearestAncestorUrl(StaplerRequest req, Object it) {
List list = req.getAncestors();
- for( int i=list.size()-1; i>=0; i-- ) {
+ for (int i = list.size() - 1; i >= 0; i--) {
Ancestor anc = (Ancestor) list.get(i);
- if(anc.getObject()==it)
+ if (anc.getObject() == it) {
return anc.getUrl();
+ }
}
return null;
}
@@ -489,29 +511,34 @@ public class Functions {
*/
public static String getSearchURL() {
List list = Stapler.getCurrentRequest().getAncestors();
- for( int i=list.size()-1; i>=0; i-- ) {
+ for (int i = list.size() - 1; i >= 0; i--) {
Ancestor anc = (Ancestor) list.get(i);
- if(anc.getObject() instanceof SearchableModelObject)
- return anc.getUrl()+"/search/";
+ if (anc.getObject() instanceof SearchableModelObject) {
+ return anc.getUrl() + "/search/";
+ }
}
return null;
}
public static String appendSpaceIfNotNull(String n) {
- if(n==null) return null;
- else return n+' ';
+ if (n == null) {
+ return null;
+ } else {
+ return n + ' ';
+ }
}
/**
- * One nbsp per 10 pixels in given size, which may be a plain number or "NxN"
- * (like an iconSize). Useful in a sortable table heading.
+ * One nbsp per 10 pixels in given size, which may be a plain number or
+ * "NxN" (like an iconSize). Useful in a sortable table heading.
*/
public static String nbspIndent(String size) {
int i = size.indexOf('x');
i = Integer.parseInt(i > 0 ? size.substring(0, i) : size) / 10;
StringBuilder buf = new StringBuilder(30);
- for (int j = 0; j < i; j++)
+ for (int j = 0; j < i; j++) {
buf.append("&nbsp;");
+ }
return buf.toString();
}
@@ -520,8 +547,10 @@ public class Functions {
}
public static boolean isMultiline(String s) {
- if(s==null) return false;
- return s.indexOf('\r')>=0 || s.indexOf('\n')>=0;
+ if (s == null) {
+ return false;
+ }
+ return s.indexOf('\r') >= 0 || s.indexOf('\n') >= 0;
}
public static String encode(String s) {
@@ -537,11 +566,11 @@ public class Functions {
}
public static String xmlUnescape(String s) {
- return s.replace("&lt;","<").replace("&gt;",">").replace("&amp;","&");
+ return s.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&");
}
public static void checkPermission(Permission permission) throws IOException, ServletException {
- checkPermission(Hudson.getInstance(),permission);
+ checkPermission(Hudson.getInstance(), permission);
}
public static void checkPermission(AccessControlled object, Permission permission) throws IOException, ServletException {
@@ -556,49 +585,51 @@ public class Functions {
* Otherwise it will perform no check and that problem is hard to notice.
*/
public static void checkPermission(Object object, Permission permission) throws IOException, ServletException {
- if (permission == null)
+ if (permission == null) {
return;
-
- if (object instanceof AccessControlled)
- checkPermission((AccessControlled) object,permission);
- else {
+ }
+
+ if (object instanceof AccessControlled) {
+ checkPermission((AccessControlled) object, permission);
+ } else {
List<Ancestor> ancs = Stapler.getCurrentRequest().getAncestors();
- for(Ancestor anc : Iterators.reverse(ancs)) {
+ for (Ancestor anc : Iterators.reverse(ancs)) {
Object o = anc.getObject();
if (o instanceof AccessControlled) {
- checkPermission((AccessControlled) o,permission);
+ checkPermission((AccessControlled) o, permission);
return;
}
}
- checkPermission(Hudson.getInstance(),permission);
+ checkPermission(Hudson.getInstance(), permission);
}
}
/**
* Returns true if the current user has the given permission.
*
- * @param permission
- * If null, returns true. This defaulting is convenient in making the use of this method terse.
+ * @param permission If null, returns true. This defaulting is convenient in
+ * making the use of this method terse.
*/
public static boolean hasPermission(Permission permission) throws IOException, ServletException {
- return hasPermission(Hudson.getInstance(),permission);
+ return hasPermission(Hudson.getInstance(), permission);
}
/**
- * This version is so that the 'hasPermission' can degrade gracefully
- * if "it" is not an {@link AccessControlled} object.
+ * This version is so that the 'hasPermission' can degrade gracefully if
+ * "it" is not an {@link AccessControlled} object.
*/
public static boolean hasPermission(Object object, Permission permission) throws IOException, ServletException {
- if (permission == null)
+ if (permission == null) {
return true;
- if (object instanceof AccessControlled)
- return ((AccessControlled)object).hasPermission(permission);
- else {
+ }
+ if (object instanceof AccessControlled) {
+ return ((AccessControlled) object).hasPermission(permission);
+ } else {
List<Ancestor> ancs = Stapler.getCurrentRequest().getAncestors();
- for(Ancestor anc : Iterators.reverse(ancs)) {
+ for (Ancestor anc : Iterators.reverse(ancs)) {
Object o = anc.getObject();
if (o instanceof AccessControlled) {
- return ((AccessControlled)o).hasPermission(permission);
+ return ((AccessControlled) o).hasPermission(permission);
}
}
return Hudson.getInstance().hasPermission(permission);
@@ -608,7 +639,7 @@ public class Functions {
public static void adminCheck(StaplerRequest req, StaplerResponse rsp, Object required, Permission permission) throws IOException, ServletException {
// this is legacy --- all views should be eventually converted to
// the permission based model.
- if(required!=null && !Hudson.adminCheck(req,rsp)) {
+ if (required != null && !Hudson.adminCheck(req, rsp)) {
// check failed. commit the FORBIDDEN response, then abort.
rsp.setStatus(HttpServletResponse.SC_FORBIDDEN);
rsp.getOutputStream().close();
@@ -616,8 +647,9 @@ public class Functions {
}
// make sure the user owns the necessary permission to access this page.
- if(permission!=null)
+ if (permission != null) {
checkPermission(permission);
+ }
}
/**
@@ -625,14 +657,16 @@ public class Functions {
*/
public static String inferHudsonURL(StaplerRequest req) {
String rootUrl = Hudson.getInstance().getRootUrl();
- if(rootUrl !=null)
- // prefer the one explicitly configured, to work with load-balancer, frontend, etc.
+ if (rootUrl != null) // prefer the one explicitly configured, to work with load-balancer, frontend, etc.
+ {
return rootUrl;
+ }
StringBuilder buf = new StringBuilder();
buf.append(req.getScheme()).append("://");
buf.append(req.getServerName());
- if(req.getLocalPort()!=80)
+ if (req.getLocalPort() != 80) {
buf.append(':').append(req.getLocalPort());
+ }
buf.append(req.getContextPath()).append('/');
return buf.toString();
}
@@ -641,7 +675,7 @@ public class Functions {
return JobPropertyDescriptor.getPropertyDescriptors(clazz);
}
- public static List<Descriptor<BuildWrapper>> getBuildWrapperDescriptors(AbstractProject<?,?> project) {
+ public static List<Descriptor<BuildWrapper>> getBuildWrapperDescriptors(AbstractProject<?, ?> project) {
return BuildWrappers.getFor(project);
}
@@ -653,20 +687,20 @@ public class Functions {
return AuthorizationStrategy.all();
}
- public static List<Descriptor<Builder>> getBuilderDescriptors(AbstractProject<?,?> project) {
+ public static List<Descriptor<Builder>> getBuilderDescriptors(AbstractProject<?, ?> project) {
return BuildStepDescriptor.filter(Builder.all(), project.getClass());
}
- public static List<Descriptor<Publisher>> getPublisherDescriptors(AbstractProject<?,?> project) {
+ public static List<Descriptor<Publisher>> getPublisherDescriptors(AbstractProject<?, ?> project) {
return BuildStepDescriptor.filter(Publisher.all(), project.getClass());
}
- public static List<SCMDescriptor<?>> getSCMDescriptors(AbstractProject<?,?> project) {
+ public static List<SCMDescriptor<?>> getSCMDescriptors(AbstractProject<?, ?> project) {
return SCM._for(project);
}
public static List<Descriptor<ComputerLauncher>> getComputerLauncherDescriptors() {
- return Hudson.getInstance().<ComputerLauncher,Descriptor<ComputerLauncher>>getDescriptorList(ComputerLauncher.class);
+ return Hudson.getInstance().<ComputerLauncher, Descriptor<ComputerLauncher>>getDescriptorList(ComputerLauncher.class);
}
public static List<Descriptor<RetentionStrategy<?>>> getRetentionStrategyDescriptors() {
@@ -680,7 +714,7 @@ public class Functions {
public static List<Descriptor<ViewsTabBar>> getViewsTabBarDescriptors() {
return ViewsTabBar.all();
}
-
+
public static List<Descriptor<CaptchaSupport>> getCaptchaSupportDescriptors() {
return CaptchaSupport.all();
}
@@ -688,7 +722,7 @@ public class Functions {
public static List<Descriptor<MyViewsTabBar>> getMyViewsTabBarDescriptors() {
return MyViewsTabBar.all();
}
-
+
public static List<Descriptor<ScriptSupport>> getScriptSupportDescriptors() {
return ScriptSupport.all();
}
@@ -703,7 +737,6 @@ public class Functions {
}
return result;
}
-
private static final Set<String> globalConfigIgnoredDescriptors = new HashSet<String>();
/**
@@ -716,99 +749,109 @@ public class Functions {
}
/**
- * Gets all the descriptors sorted by their inheritance tree of {@link Describable}
- * so that descriptors of similar types come nearby.
+ * Gets all the descriptors sorted by their inheritance tree of
+ * {@link Describable} so that descriptors of similar types come nearby.
*/
public static Collection<Descriptor> getSortedDescriptorsForGlobalConfig() {
- Map<String,Descriptor> r = new TreeMap<String, Descriptor>();
+ Map<String, Descriptor> r = new TreeMap<String, Descriptor>();
for (Descriptor<?> d : Hudson.getInstance().getExtensionList(Descriptor.class)) {
if (globalConfigIgnoredDescriptors.contains(d.getClass().getName())) {
continue;
}
- if (d.getGlobalConfigPage()==null) continue;
- r.put(buildSuperclassHierarchy(d.clazz, new StringBuilder()).toString(),d);
+ if (d.getGlobalConfigPage() == null) {
+ continue;
+ }
+ r.put(buildSuperclassHierarchy(d.clazz, new StringBuilder()).toString(), d);
}
return r.values();
}
private static StringBuilder buildSuperclassHierarchy(Class c, StringBuilder buf) {
Class sc = c.getSuperclass();
- if (sc!=null) buildSuperclassHierarchy(sc,buf).append(':');
+ if (sc != null) {
+ buildSuperclassHierarchy(sc, buf).append(':');
+ }
return buf.append(c.getName());
}
/**
- * Computes the path to the icon of the given action
- * from the context path.
+ * Computes the path to the icon of the given action from the context path.
*/
public static String getIconFilePath(Action a) {
String name = a.getIconFileName();
- if(name.startsWith("/"))
+ if (name.startsWith("/")) {
return name.substring(1);
- else
- return "images/24x24/"+name;
+ } else {
+ return "images/24x24/" + name;
+ }
}
/**
- * Works like JSTL build-in size(x) function,
- * but handle null gracefully.
+ * Works like JSTL build-in size(x) function, but handle null gracefully.
*/
public static int size2(Object o) throws Exception {
- if(o==null) return 0;
- return ASTSizeFunction.sizeOf(o,Introspector.getUberspect());
+ if (o == null) {
+ return 0;
+ }
+ return ASTSizeFunction.sizeOf(o, Introspector.getUberspect());
}
/**
* Computes the relative path from the current page to the given item.
*/
public static String getRelativeLinkTo(Item p) {
- Map<Object,String> ancestors = new HashMap<Object,String>();
- View view=null;
+ Map<Object, String> ancestors = new HashMap<Object, String>();
+ View view = null;
StaplerRequest request = Stapler.getCurrentRequest();
- for( Ancestor a : request.getAncestors() ) {
- ancestors.put(a.getObject(),a.getRelativePath());
- if(a.getObject() instanceof View)
+ for (Ancestor a : request.getAncestors()) {
+ ancestors.put(a.getObject(), a.getRelativePath());
+ if (a.getObject() instanceof View) {
view = (View) a.getObject();
+ }
}
String path = ancestors.get(p);
- if(path!=null) return path;
+ if (path != null) {
+ return path;
+ }
- Item i=p;
+ Item i = p;
String url = "";
- while(true) {
+ while (true) {
ItemGroup ig = i.getParent();
- url = i.getShortUrl()+url;
+ url = i.getShortUrl() + url;
- if(ig==Hudson.getInstance()) {
+ if (ig == Hudson.getInstance()) {
assert i instanceof TopLevelItem;
- if(view!=null && view.contains((TopLevelItem)i)) {
+ if (view != null && view.contains((TopLevelItem) i)) {
// if p and the current page belongs to the same view, then return a relative path
- return ancestors.get(view)+'/'+url;
+ return ancestors.get(view) + '/' + url;
} else {
// otherwise return a path from the root Hudson
- return request.getContextPath()+'/'+p.getUrl();
+ return request.getContextPath() + '/' + p.getUrl();
}
}
path = ancestors.get(ig);
- if(path!=null) return path+'/'+url;
+ if (path != null) {
+ return path + '/' + url;
+ }
assert ig instanceof Item; // if not, ig must have been the Hudson instance
i = (Item) ig;
}
}
- public static Map<Thread,StackTraceElement[]> dumpAllThreads() {
- Map<Thread,StackTraceElement[]> sorted = new TreeMap<Thread,StackTraceElement[]>(new ThreadSorter());
+ public static Map<Thread, StackTraceElement[]> dumpAllThreads() {
+ Map<Thread, StackTraceElement[]> sorted = new TreeMap<Thread, StackTraceElement[]>(new ThreadSorter());
sorted.putAll(Thread.getAllStackTraces());
return sorted;
}
public static ThreadInfo[] getThreadInfos() {
ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
- return mbean.dumpAllThreads(mbean.isObjectMonitorUsageSupported(),mbean.isSynchronizerUsageSupported());
+ return mbean.dumpAllThreads(mbean.isObjectMonitorUsageSupported(), mbean.isSynchronizerUsageSupported());
}
public static ThreadGroupMap sortThreadsAndGetGroupMap(ThreadInfo[] list) {
@@ -819,22 +862,27 @@ public class Functions {
// Common code for sorting Threads/ThreadInfos by ThreadGroup
private static class ThreadSorterBase {
- protected Map<Long,String> map = new HashMap<Long,String>();
+
+ protected Map<Long, String> map = new HashMap<Long, String>();
private ThreadSorterBase() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
- while (tg.getParent() != null) tg = tg.getParent();
- Thread[] threads = new Thread[tg.activeCount()*2];
+ while (tg.getParent() != null) {
+ tg = tg.getParent();
+ }
+ Thread[] threads = new Thread[tg.activeCount() * 2];
int threadsLen = tg.enumerate(threads, true);
- for (int i = 0; i < threadsLen; i++)
+ for (int i = 0; i < threadsLen; i++) {
map.put(threads[i].getId(), threads[i].getThreadGroup().getName());
+ }
}
protected int compare(long idA, long idB) {
String tga = map.get(idA), tgb = map.get(idB);
- int result = (tga!=null?-1:0) + (tgb!=null?1:0); // Will be non-zero if only one is null
- if (result==0 && tga!=null)
+ int result = (tga != null ? -1 : 0) + (tgb != null ? 1 : 0); // Will be non-zero if only one is null
+ if (result == 0 && tga != null) {
result = tga.compareToIgnoreCase(tgb);
+ }
return result;
}
}
@@ -848,20 +896,24 @@ public class Functions {
return map.get(ti.getThreadId());
}
+ @Override
public int compare(ThreadInfo a, ThreadInfo b) {
int result = compare(a.getThreadId(), b.getThreadId());
- if (result == 0)
+ if (result == 0) {
result = a.getThreadName().compareToIgnoreCase(b.getThreadName());
+ }
return result;
}
}
private static class ThreadSorter extends ThreadSorterBase implements Comparator<Thread> {
+ @Override
public int compare(Thread a, Thread b) {
int result = compare(a.getId(), b.getId());
- if (result == 0)
+ if (result == 0) {
result = a.getName().compareToIgnoreCase(b.getName());
+ }
return result;
}
}
@@ -873,7 +925,7 @@ public class Functions {
try {
System.console();
return true;
- } catch(LinkageError e) {
+ } catch (LinkageError e) {
return false;
}
}
@@ -881,16 +933,16 @@ public class Functions {
// ThreadInfo.toString() truncates the stack trace by first 8, so needed my own version
public static String dumpThreadInfo(ThreadInfo ti, ThreadGroupMap map) {
String grp = map.getThreadGroup(ti);
- StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" +
- " Id=" + ti.getThreadId() + " Group=" +
- (grp != null ? grp : "?") + " " +
- ti.getThreadState());
+ StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\""
+ + " Id=" + ti.getThreadId() + " Group="
+ + (grp != null ? grp : "?") + " "
+ + ti.getThreadState());
if (ti.getLockName() != null) {
sb.append(" on " + ti.getLockName());
}
if (ti.getLockOwnerName() != null) {
- sb.append(" owned by \"" + ti.getLockOwnerName() +
- "\" Id=" + ti.getLockOwnerId());
+ sb.append(" owned by \"" + ti.getLockOwnerName()
+ + "\" Id=" + ti.getLockOwnerId());
}
if (ti.isSuspended()) {
sb.append(" (suspended)");
@@ -900,7 +952,7 @@ public class Functions {
}
sb.append('\n');
StackTraceElement[] stackTrace = ti.getStackTrace();
- for (int i=0; i < stackTrace.length; i++) {
+ for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement ste = stackTrace[i];
sb.append("\tat " + ste.toString());
sb.append('\n');
@@ -929,19 +981,19 @@ public class Functions {
sb.append('\n');
}
}
- }
+ }
- LockInfo[] locks = ti.getLockedSynchronizers();
- if (locks.length > 0) {
- sb.append("\n\tNumber of locked synchronizers = " + locks.length);
- sb.append('\n');
- for (LockInfo li : locks) {
- sb.append("\t- " + li);
- sb.append('\n');
- }
- }
- sb.append('\n');
- return sb.toString();
+ LockInfo[] locks = ti.getLockedSynchronizers();
+ if (locks.length > 0) {
+ sb.append("\n\tNumber of locked synchronizers = " + locks.length);
+ sb.append('\n');
+ for (LockInfo li : locks) {
+ sb.append("\t- " + li);
+ sb.append('\n');
+ }
+ }
+ sb.append('\n');
+ return sb.toString();
}
public static <T> Collection<T> emptyList() {
@@ -950,20 +1002,20 @@ public class Functions {
public static String jsStringEscape(String s) {
StringBuilder buf = new StringBuilder();
- for( int i=0; i<s.length(); i++ ) {
+ for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
- switch(ch) {
- case '\'':
- buf.append("\\'");
- break;
- case '\\':
- buf.append("\\\\");
- break;
- case '"':
- buf.append("\\\"");
- break;
- default:
- buf.append(ch);
+ switch (ch) {
+ case '\'':
+ buf.append("\\'");
+ break;
+ case '\\':
+ buf.append("\\\\");
+ break;
+ case '"':
+ buf.append("\\\"");
+ break;
+ default:
+ buf.append(ch);
}
}
return buf.toString();
@@ -973,8 +1025,10 @@ public class Functions {
* Converts "abc" to "Abc".
*/
public static String capitalize(String s) {
- if(s==null || s.length()==0) return s;
- return Character.toUpperCase(s.charAt(0))+s.substring(1);
+ if (s == null || s.length() == 0) {
+ return s;
+ }
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
public static String getVersion() {
@@ -991,43 +1045,49 @@ public class Functions {
public static String getViewResource(Object it, String path) {
Class clazz = it.getClass();
- if(it instanceof Class)
- clazz = (Class)it;
- if(it instanceof Descriptor)
- clazz = ((Descriptor)it).clazz;
+ if (it instanceof Class) {
+ clazz = (Class) it;
+ }
+ if (it instanceof Descriptor) {
+ clazz = ((Descriptor) it).clazz;
+ }
StringBuilder buf = new StringBuilder(Stapler.getCurrentRequest().getContextPath());
buf.append(Hudson.VIEW_RESOURCE_PATH).append('/');
- buf.append(clazz.getName().replace('.','/').replace('$','/'));
+ buf.append(clazz.getName().replace('.', '/').replace('$', '/'));
buf.append('/').append(path);
return buf.toString();
}
public static boolean hasView(Object it, String path) throws IOException {
- if(it==null) return false;
- return Stapler.getCurrentRequest().getView(it,path)!=null;
+ if (it == null) {
+ return false;
+ }
+ return Stapler.getCurrentRequest().getView(it, path) != null;
}
/**
- * Can be used to check a checkbox by default.
- * Used from views like {@code h.defaultToTrue(scm.useUpdate)}.
- * The expression will evaluate to true if scm is null.
+ * Can be used to check a checkbox by default. Used from views like
+ * {@code h.defaultToTrue(scm.useUpdate)}. The expression will evaluate to
+ * true if scm is null.
*/
public static boolean defaultToTrue(Boolean b) {
- if(b==null) return true;
+ if (b == null) {
+ return true;
+ }
return b;
}
/**
- * If the value exists, return that value. Otherwise return the default value.
- * <p>
- * Starting 1.294, JEXL supports the elvis operator "x?:y" that supercedes this.
+ * If the value exists, return that value. Otherwise return the default
+ * value. <p> Starting 1.294, JEXL supports the elvis operator "x?:y" that
+ * supercedes this.
*
* @since 1.150
*/
public static <T> T defaulted(T value, T defaultValue) {
- return value!=null ? value : defaultValue;
+ return value != null ? value : defaultValue;
}
public static String printThrowable(Throwable t) {
@@ -1037,36 +1097,37 @@ public class Functions {
}
/**
- * Counts the number of rows needed for textarea to fit the content.
- * Minimum 5 rows.
+ * Counts the number of rows needed for textarea to fit the content. Minimum
+ * 5 rows.
*/
public static int determineRows(String s) {
- if(s==null) return 5;
- return Math.max(5,LINE_END.split(s).length);
+ if (s == null) {
+ return 5;
+ }
+ return Math.max(5, LINE_END.split(s).length);
}
/**
- * Converts the Hudson build status to CruiseControl build status,
- * which is either Success, Failure, Exception, or Unknown.
+ * Converts the Hudson build status to CruiseControl build status, which is
+ * either Success, Failure, Exception, or Unknown.
*/
public static String toCCStatus(Item i) {
if (i instanceof Job) {
Job j = (Job) i;
switch (j.getIconColor().noAnime()) {
- case ABORTED:
- case RED:
- case YELLOW:
- return "Failure";
- case BLUE:
- return "Success";
- case DISABLED:
- case GREY:
- return "Unknown";
+ case ABORTED:
+ case RED:
+ case YELLOW:
+ return "Failure";
+ case BLUE:
+ return "Success";
+ case DISABLED:
+ case GREY:
+ return "Unknown";
}
}
return "Unknown";
}
-
private static final Pattern LINE_END = Pattern.compile("\r?\n");
/**
@@ -1077,15 +1138,14 @@ public class Functions {
}
/**
- * When called from within JEXL expression evaluation,
- * this method returns the current {@link JellyContext} used
- * to evaluate the script.
+ * When called from within JEXL expression evaluation, this method returns
+ * the current {@link JellyContext} used to evaluate the script.
*
* @since 1.164
*/
public static JellyContext getCurrentJellyContext() {
JellyContext context = org.eclipse.hudson.ExpressionFactory2.CURRENT_CONTEXT.get();
- assert context!=null;
+ assert context != null;
return context;
}
@@ -1101,49 +1161,55 @@ public class Functions {
}
/**
- * Returns a sub-list if the given list is bigger than the specified 'maxSize'
+ * Returns a sub-list if the given list is bigger than the specified
+ * 'maxSize'
*/
public static <T> List<T> subList(List<T> base, int maxSize) {
- if(maxSize<base.size())
- return base.subList(0,maxSize);
- else
+ if (maxSize < base.size()) {
+ return base.subList(0, maxSize);
+ } else {
return base;
+ }
}
/**
- * Computes the hyperlink to actions, to handle the situation when the {@link Action#getUrlName()}
- * returns absolute URL.
+ * Computes the hyperlink to actions, to handle the situation when the
+ * {@link Action#getUrlName()} returns absolute URL.
*/
- public static String getActionUrl(String itUrl,Action action) {
+ public static String getActionUrl(String itUrl, Action action) {
String urlName = action.getUrlName();
- if(urlName==null) return null; // to avoid NPE and fail to render the whole page
-
- if(SCHEME.matcher(urlName).matches())
+ if (urlName == null) {
+ return null; // to avoid NPE and fail to render the whole page
+ }
+ if (SCHEME.matcher(urlName).matches()) {
return urlName; // absolute URL
- if(urlName.startsWith("/"))
- return Stapler.getCurrentRequest().getContextPath()+urlName;
- else
- // relative URL name
- return Stapler.getCurrentRequest().getContextPath()+'/'+itUrl+urlName;
+ }
+ if (urlName.startsWith("/")) {
+ return Stapler.getCurrentRequest().getContextPath() + urlName;
+ } else // relative URL name
+ {
+ return Stapler.getCurrentRequest().getContextPath() + '/' + itUrl + urlName;
+ }
}
/**
- * Escapes the character unsafe for e-mail address.
- * See http://en.wikipedia.org/wiki/E-mail_address for the details,
- * but here the vocabulary is even more restricted.
+ * Escapes the character unsafe for e-mail address. See
+ * http://en.wikipedia.org/wiki/E-mail_address for the details, but here the
+ * vocabulary is even more restricted.
*/
public static String toEmailSafeString(String projectName) {
// TODO: escape non-ASCII characters
StringBuilder buf = new StringBuilder(projectName.length());
- for( int i=0; i<projectName.length(); i++ ) {
+ for (int i = 0; i < projectName.length(); i++) {
char ch = projectName.charAt(i);
- if(('a'<=ch && ch<='z')
- || ('z'<=ch && ch<='Z')
- || ('0'<=ch && ch<='9')
- || "-_.".indexOf(ch)>=0)
+ if (('a' <= ch && ch <= 'z')
+ || ('z' <= ch && ch <= 'Z')
+ || ('0' <= ch && ch <= '9')
+ || "-_.".indexOf(ch) >= 0) {
buf.append(ch);
- else
+ } else {
buf.append('_'); // escape
+ }
}
return projectName;
}
@@ -1153,20 +1219,20 @@ public class Functions {
}
/**
- * Obtains the host name of the Hudson server that clients can use to talk back to.
- * <p>
- * This is primarily used in <tt>slave-agent.jnlp.jelly</tt> to specify the destination
- * that the slaves talk to.
+ * Obtains the host name of the Hudson server that clients can use to talk
+ * back to. <p> This is primarily used in <tt>slave-agent.jnlp.jelly</tt> to
+ * specify the destination that the slaves talk to.
*/
public String getServerName() {
// Try to infer this from the configured root URL.
// This makes it work correctly when Hudson runs behind a reverse proxy.
String url = Hudson.getInstance().getRootUrl();
try {
- if(url!=null) {
+ if (url != null) {
String host = new URL(url).getHost();
- if(host!=null)
+ if (host != null) {
return host;
+ }
}
} catch (MalformedURLException e) {
// fall back to HTTP request
@@ -1178,7 +1244,9 @@ public class Functions {
* Determines the form validation check URL. See textbox.jelly
*/
public String getCheckUrl(String userDefined, Object descriptor, String field) {
- if(userDefined!=null || field==null) return userDefined;
+ if (userDefined != null || field == null) {
+ return userDefined;
+ }
if (descriptor instanceof Descriptor) {
Descriptor d = (Descriptor) descriptor;
return d.getCheckUrl(field);
@@ -1193,11 +1261,17 @@ public class Functions {
*/
public boolean hyperlinkMatchesCurrentPage(String href) throws UnsupportedEncodingException {
String url = Stapler.getCurrentRequest().getRequestURL().toString();
- if (href == null || href.length() <= 1) return ".".equals(href) && url.endsWith("/");
- url = URLDecoder.decode(url,"UTF-8");
- href = URLDecoder.decode(href,"UTF-8");
- if (url.endsWith("/")) url = url.substring(0, url.length() - 1);
- if (href.endsWith("/")) href = href.substring(0, href.length() - 1);
+ if (href == null || href.length() <= 1) {
+ return ".".equals(href) && url.endsWith("/");
+ }
+ url = URLDecoder.decode(url, "UTF-8");
+ href = URLDecoder.decode(href, "UTF-8");
+ if (url.endsWith("/")) {
+ url = url.substring(0, url.length() - 1);
+ }
+ if (href.endsWith("/")) {
+ href = href.substring(0, href.length() - 1);
+ }
return url.endsWith(href);
}
@@ -1211,10 +1285,12 @@ public class Functions {
*/
public static List<PageDecorator> getPageDecorators() {
// this method may be called to render start up errors, at which point Hudson doesn't exist yet. see HUDSON-3608
- if(Hudson.getInstance()==null) return Collections.emptyList();
+ if (Hudson.getInstance() == null) {
+ return Collections.emptyList();
+ }
return PageDecorator.all();
}
-
+
public static List<Descriptor<Cloud>> getCloudDescriptors() {
return Cloud.all();
}
@@ -1223,8 +1299,9 @@ public class Functions {
* Prepend a prefix only when there's the specified body.
*/
public String prepend(String prefix, String body) {
- if(body!=null && body.length()>0)
- return prefix+body;
+ if (body != null && body.length() > 0) {
+ return prefix + body;
+ }
return body;
}
@@ -1247,35 +1324,40 @@ public class Functions {
public static Date getCurrentTime() {
return new Date();
}
-
- public static Locale getClientLocale(){
+
+ public static Locale getClientLocale() {
return Stapler.getCurrentRequest().getLocale();
}
-
- public static Locale getServerLocale(){
+
+ public static Locale getServerLocale() {
return Locale.getDefault();
}
/**
- * Generate a series of &lt;script> tags to include <tt>script.js</tt>
- * from {@link ConsoleAnnotatorFactory}s and {@link ConsoleAnnotationDescriptor}s.
+ * Generate a series of &lt;script> tags to include <tt>script.js</tt> from
+ * {@link ConsoleAnnotatorFactory}s and
+ * {@link ConsoleAnnotationDescriptor}s.
*/
public static String generateConsoleAnnotationScriptAndStylesheet() {
String cp = Stapler.getCurrentRequest().getContextPath();
StringBuilder buf = new StringBuilder();
for (ConsoleAnnotatorFactory f : ConsoleAnnotatorFactory.all()) {
String path = cp + "/extensionList/" + ConsoleAnnotatorFactory.class.getName() + "/" + f.getClass().getName();
- if (f.hasScript())
- buf.append("<script src='"+path+"/script.js'></script>");
- if (f.hasStylesheet())
- buf.append("<link rel='stylesheet' type='text/css' href='"+path+"/style.css' />");
+ if (f.hasScript()) {
+ buf.append("<script src='" + path + "/script.js'></script>");
+ }
+ if (f.hasStylesheet()) {
+ buf.append("<link rel='stylesheet' type='text/css' href='" + path + "/style.css' />");
+ }
}
for (ConsoleAnnotationDescriptor d : ConsoleAnnotationDescriptor.all()) {
- String path = cp+"/descriptor/"+d.clazz.getName();
- if (d.hasScript())
- buf.append("<script src='"+path+"/script.js'></script>");
- if (d.hasStylesheet())
- buf.append("<link rel='stylesheet' type='text/css' href='"+path+"/style.css' />");
+ String path = cp + "/descriptor/" + d.clazz.getName();
+ if (d.hasScript()) {
+ buf.append("<script src='" + path + "/script.js'></script>");
+ }
+ if (d.hasStylesheet()) {
+ buf.append("<link rel='stylesheet' type='text/css' href='" + path + "/style.css' />");
+ }
}
return buf.toString();
}
@@ -1288,8 +1370,9 @@ public class Functions {
try {
List<String> r = new ArrayList<String>();
Enumeration<String> e = LogManager.getLogManager().getLoggerNames();
- while (e.hasMoreElements())
+ while (e.hasMoreElements()) {
r.add(e.nextElement());
+ }
return r;
} catch (ConcurrentModificationException e) {
// retry
@@ -1298,18 +1381,22 @@ public class Functions {
}
/**
- * Used by &lt;f:password/> so that we send an encrypted value to the client.
+ * Used by &lt;f:password/> so that we send an encrypted value to the
+ * client.
*/
public String getPasswordValue(Object o) {
- if (o==null) return null;
- if (o instanceof Secret) return ((Secret)o).getEncryptedValue();
+ if (o == null) {
+ return null;
+ }
+ if (o instanceof Secret) {
+ return ((Secret) o).getEncryptedValue();
+ }
return o.toString();
}
public List filterDescriptors(Object context, Iterable descriptors) {
- return DescriptorVisibilityFilter.apply(context,descriptors);
+ return DescriptorVisibilityFilter.apply(context, descriptors);
}
-
private static final Pattern SCHEME = Pattern.compile("[a-z]+://.+");
/**
@@ -1336,6 +1423,7 @@ public class Functions {
/**
* Returns true if current user is the author of the job.
+ *
* @param job job.
* @return returns true if current user is the author of the job.
*/
@@ -1345,13 +1433,14 @@ public class Functions {
}
/**
- * Resolves the target object for the given object. If the object is a StaplerProxy, then return the proxy target.
+ * Resolves the target object for the given object. If the object is a
+ * StaplerProxy, then return the proxy target.
*
* @since 2.1.0
*/
public static Object resolveStaplerObject(final Object obj) {
if (obj instanceof StaplerProxy) {
- return ((StaplerProxy)obj).getTarget();
+ return ((StaplerProxy) obj).getTarget();
}
return obj;
}
@@ -1368,6 +1457,7 @@ public class Functions {
return null;
}
Iterable<T> templates = Iterables.filter(items, new Predicate<T>() {
+ @Override
public boolean apply(T item) {
return name.equalsIgnoreCase(item.getName());
}
@@ -1378,17 +1468,19 @@ public class Functions {
/**
* Returns true if the {@link Item#WIPEOUT} permission is enabled.
*
- * By default the "Wipe Out Workspace" action is available on job when user has {@link Item#BUILD} permission
- * (if user can trigger builds). If this behavior is not acceptable for project you can enable the
- * {@code hudson.security.WipeOutPermission} system property. It will add "WipeOut" permission checkbox into
- * permission control panel to manage "Wipe Out Workspace" action.
+ * By default the "Wipe Out Workspace" action is available on job when user
+ * has {@link Item#BUILD} permission (if user can trigger builds). If this
+ * behavior is not acceptable for project you can enable the
+ * {@code hudson.security.WipeOutPermission} system property. It will add
+ * "WipeOut" permission checkbox into permission control panel to manage
+ * "Wipe Out Workspace" action.
*
* @return true if the {@link Item#WIPEOUT} permission is enabled.
*/
public static boolean isWipeOutPermissionEnabled() {
return Boolean.getBoolean("hudson.security.WipeOutPermission");
}
-
+
public static boolean disableUpdateCenterSwitch() {
return Boolean.getBoolean("hudson.pluginManager.disableUpdateCenterSwitch");
}
diff --git a/hudson-core/src/main/java/hudson/PluginManager.java b/hudson-core/src/main/java/hudson/PluginManager.java
index 621c59f..1af0e60 100644
--- a/hudson-core/src/main/java/hudson/PluginManager.java
+++ b/hudson-core/src/main/java/hudson/PluginManager.java
@@ -7,10 +7,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
* Kohsuke Kawaguchi, Stephen Connolly, Tom Huybrechts, Winston Prakash
- *
+ *
*******************************************************************************/
package hudson;
@@ -75,57 +75,50 @@ import static hudson.init.InitMilestone.PLUGINS_STARTED;
* @author Kohsuke Kawaguchi
*/
public abstract class PluginManager extends AbstractModelObject {
+
/**
* All discovered plugins.
*/
protected final List<PluginWrapper> plugins = new ArrayList<PluginWrapper>();
-
/**
* All active plugins.
*/
- protected final List<PluginWrapper> activePlugins = new CopyOnWriteArrayList<PluginWrapper> ();
-
+ protected final List<PluginWrapper> activePlugins = new CopyOnWriteArrayList<PluginWrapper>();
protected final List<FailedPlugin> failedPlugins = new ArrayList<FailedPlugin>();
-
/**
* Plug-in root directory.
*/
//TODO: review and check whether we can do it private
public final File rootDir;
-
/**
- * @deprecated as of 1.355
- * {@link PluginManager} can now live longer than {@link Hudson} instance, so
- * use {@code Hudson.getInstance().servletContext} instead.
+ * @deprecated as of 1.355 {@link PluginManager} can now live longer than
+ * {@link Hudson} instance, so use
+ * {@code Hudson.getInstance().servletContext} instead.
*/
public final ServletContext context;
-
/**
- * {@link ClassLoader} that can load all the publicly visible classes from plugins
- * (and including the classloader that loads Hudson itself.)
+ * {@link ClassLoader} that can load all the publicly visible classes from
+ * plugins (and including the classloader that loads Hudson itself.)
*
*/
// implementation is minimal --- just enough to run XStream
// and load plugin-contributed classes.
//TODO: review and check whether we can do it private
public final ClassLoader uberClassLoader = new UberClassLoader();
-
/**
- * Once plugin is uploaded, this flag becomes true.
- * This is used to report a message that Hudson needs to be restarted
- * for new plugins to take effect.
+ * Once plugin is uploaded, this flag becomes true. This is used to report a
+ * message that Hudson needs to be restarted for new plugins to take effect.
*/
//TODO: review and check whether we can do it private
public volatile boolean pluginUploaded = false;
-
/**
- * The initialization of {@link PluginManager} splits into two parts;
- * one is the part about listing them, extracting them, and preparing classloader for them.
- * The 2nd part is about creating instances. Once the former completes this flags become true,
- * as the 2nd part can be repeated for each Hudson instance.
+ * The initialization of {@link PluginManager} splits into two parts; one is
+ * the part about listing them, extracting them, and preparing classloader
+ * for them. The 2nd part is about creating instances. Once the former
+ * completes this flags become true, as the 2nd part can be repeated for
+ * each Hudson instance.
*/
private boolean pluginListed = false;
-
/**
* Strategy for creating and initializing plugins
*/
@@ -135,9 +128,10 @@ public abstract class PluginManager extends AbstractModelObject {
this.context = context;
this.rootDir = rootDir;
- if(!rootDir.exists())
+ if (!rootDir.exists()) {
rootDir.mkdirs();
-
+ }
+
strategy = createPluginStrategy();
}
@@ -158,9 +152,9 @@ public abstract class PluginManager extends AbstractModelObject {
}
/**
- * Called immediately after the construction.
- * This is a separate method so that code executed from here will see a valid value in
- * {@link Hudson#pluginManager}.
+ * Called immediately after the construction. This is a separate method so
+ * that code executed from here will see a valid value in
+ * {@link Hudson#pluginManager}.
*/
public TaskBuilder initTasks(final InitStrategy initStrategy) {
TaskBuilder builder;
@@ -171,78 +165,90 @@ public abstract class PluginManager extends AbstractModelObject {
{
Handle loadBundledPlugins = add("Loading bundled plugins", new Executable() {
+ @Override
public void run(Reactor session) throws Exception {
bundledPlugins = loadBundledPlugins();
}
});
Handle listUpPlugins = requires(loadBundledPlugins).add("Listing up plugins", new Executable() {
+ @Override
public void run(Reactor session) throws Exception {
archives = initStrategy.listPluginArchives(PluginManager.this);
}
});
- requires(listUpPlugins).attains(PLUGINS_LISTED).add("Preparing plugins",new Executable() {
+ requires(listUpPlugins).attains(PLUGINS_LISTED).add("Preparing plugins", new Executable() {
+ @Override
public void run(Reactor session) throws Exception {
// once we've listed plugins, we can fill in the reactor with plugin-specific initialization tasks
TaskGraphBuilder g = new TaskGraphBuilder();
- final Map<String,File> inspectedShortNames = new HashMap<String,File>();
+ final Map<String, File> inspectedShortNames = new HashMap<String, File>();
- for( final File arc : archives ) {
+ for (final File arc : archives) {
g.followedBy().notFatal().attains(PLUGINS_LISTED).add("Inspecting plugin " + arc, new Executable() {
+ @Override
public void run(Reactor session1) throws Exception {
try {
PluginWrapper p = strategy.createPluginWrapper(arc);
- if (isDuplicate(p)) return;
+ if (isDuplicate(p)) {
+ return;
+ }
p.isBundled = bundledPlugins.contains(arc.getName());
plugins.add(p);
- if(p.isActive())
+ if (p.isActive()) {
activePlugins.add(p);
+ }
} catch (IOException e) {
- failedPlugins.add(new FailedPlugin(arc.getName(),e));
+ failedPlugins.add(new FailedPlugin(arc.getName(), e));
throw e;
}
}
/**
- * Inspects duplication. this happens when you run hpi:run on a bundled plugin,
- * as well as putting numbered hpi files, like "cobertura-1.0.hpi" and "cobertura-1.1.hpi"
+ * Inspects duplication. this happens when
+ * you run hpi:run on a bundled plugin, as
+ * well as putting numbered hpi files, like
+ * "cobertura-1.0.hpi" and
+ * "cobertura-1.1.hpi"
*/
private boolean isDuplicate(PluginWrapper p) {
String shortName = p.getShortName();
if (inspectedShortNames.containsKey(shortName)) {
- LOGGER.info("Ignoring "+arc+" because "+inspectedShortNames.get(shortName)+" is already loaded");
+ LOGGER.info("Ignoring " + arc + " because " + inspectedShortNames.get(shortName) + " is already loaded");
return true;
}
- inspectedShortNames.put(shortName,arc);
+ inspectedShortNames.put(shortName, arc);
return false;
}
});
}
- g.requires(PLUGINS_PREPARED).add("Checking cyclic dependencies",new Executable() {
+ g.requires(PLUGINS_PREPARED).add("Checking cyclic dependencies", new Executable() {
/**
* Makes sure there's no cycle in dependencies.
*/
+ @Override
public void run(Reactor reactor) throws Exception {
try {
new CyclicGraphDetector<PluginWrapper>() {
@Override
protected List<PluginWrapper> getEdges(PluginWrapper p) {
List<PluginWrapper> next = new ArrayList<PluginWrapper>();
- addTo(p.getDependencies(),next);
- addTo(p.getOptionalDependencies(),next);
+ addTo(p.getDependencies(), next);
+ addTo(p.getOptionalDependencies(), next);
return next;
}
private void addTo(List<Dependency> dependencies, List<PluginWrapper> r) {
for (Dependency d : dependencies) {
PluginWrapper p = getPlugin(d.shortName);
- if (p!=null)
+ if (p != null) {
r.add(p);
+ }
}
}
}.run(getPlugins());
@@ -269,82 +275,89 @@ public abstract class PluginManager extends AbstractModelObject {
// lists up initialization tasks about loading plugins.
return TaskBuilder.union(initializerFinder, // this scans @Initializer in the core once
- builder,new TaskGraphBuilder() {{
- requires(PLUGINS_LISTED).attains(PLUGINS_PREPARED).add("Loading plugins",new Executable() {
- /**
- * Once the plugins are listed, schedule their initialization.
- */
- public void run(Reactor session) throws Exception {
- Hudson.getInstance().lookup.set(PluginInstanceStore.class,new PluginInstanceStore());
- TaskGraphBuilder g = new TaskGraphBuilder();
-
- // schedule execution of loading plugins
- for (final PluginWrapper p : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
- g.followedBy().notFatal().attains(PLUGINS_PREPARED).add("Loading plugin " + p.getShortName(), new Executable() {
- public void run(Reactor session) throws Exception {
- try {
- LOGGER.info("Loading plugin - " + p.getShortName());
- p.resolvePluginDependencies();
- strategy.load(p);
- } catch (Exception e) {
- LOGGER.info("Failed to load plugin - " + p.getShortName() + " because of error " + e.getLocalizedMessage());
- failedPlugins.add(new FailedPlugin(p.getShortName(), e));
- activePlugins.remove(p);
- plugins.remove(p);
- throw e;
- }
- }
- });
- }
+ builder, new TaskGraphBuilder() {
+ {
+ requires(PLUGINS_LISTED).attains(PLUGINS_PREPARED).add("Loading plugins", new Executable() {
+ /**
+ * Once the plugins are listed, schedule their
+ * initialization.
+ */
+ public void run(Reactor session) throws Exception {
+ Hudson.getInstance().lookup.set(PluginInstanceStore.class, new PluginInstanceStore());
+ TaskGraphBuilder g = new TaskGraphBuilder();
+
+ // schedule execution of loading plugins
+ for (final PluginWrapper p : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
+ g.followedBy().notFatal().attains(PLUGINS_PREPARED).add("Loading plugin " + p.getShortName(), new Executable() {
+ @Override
+ public void run(Reactor session) throws Exception {
+ try {
+ LOGGER.info("Loading plugin - " + p.getShortName());
+ p.resolvePluginDependencies();
+ strategy.load(p);
+ } catch (Exception e) {
+ LOGGER.info("Failed to load plugin - " + p.getShortName() + " because of error " + e.getLocalizedMessage());
+ failedPlugins.add(new FailedPlugin(p.getShortName(), e));
+ activePlugins.remove(p);
+ plugins.remove(p);
+ throw e;
+ }
+ }
+ });
+ }
- // schedule execution of initializing plugins
- for (final PluginWrapper p : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
- g.followedBy().notFatal().attains(PLUGINS_STARTED).add("Initializing plugin " + p.getShortName(), new Executable() {
- public void run(Reactor session) throws Exception {
- try {
- p.getPlugin().postInitialize();
- } catch (Exception e) {
- failedPlugins.add(new FailedPlugin(p.getShortName(), e));
- activePlugins.remove(p);
- plugins.remove(p);
- throw e;
+ // schedule execution of initializing plugins
+ for (final PluginWrapper p : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
+ g.followedBy().notFatal().attains(PLUGINS_STARTED).add("Initializing plugin " + p.getShortName(), new Executable() {
+ @Override
+ public void run(Reactor session) throws Exception {
+ try {
+ p.getPlugin().postInitialize();
+ } catch (Exception e) {
+ failedPlugins.add(new FailedPlugin(p.getShortName(), e));
+ activePlugins.remove(p);
+ plugins.remove(p);
+ throw e;
+ }
}
+ });
+ }
+
+ g.followedBy().attains(PLUGINS_STARTED).add("Discovering plugin initialization tasks", new Executable() {
+ @Override
+ public void run(Reactor reactor) throws Exception {
+ // rescan to find plugin-contributed @Initializer
+ reactor.addAll(initializerFinder.discoverTasks(reactor));
}
});
- }
-
- g.followedBy().attains(PLUGINS_STARTED).add("Discovering plugin initialization tasks", new Executable() {
- public void run(Reactor reactor) throws Exception {
- // rescan to find plugin-contributed @Initializer
- reactor.addAll(initializerFinder.discoverTasks(reactor));
- }
- });
- // register them all
- session.addAll(g.discoverTasks(session));
- }
- });
- }});
+ // register them all
+ session.addAll(g.discoverTasks(session));
+ }
+ });
+ }
+ });
}
/**
- * If the war file has any "/WEB-INF/plugins/*.hpi", extract them into the plugin directory.
+ * If the war file has any "/WEB-INF/plugins/*.hpi", extract them into the
+ * plugin directory.
*
- * @return
- * File names of the bundled plugins. Like {"ssh-slaves.hpi","subvesrion.hpi"}
- * @throws Exception
- * Any exception will be reported and halt the startup.
+ * @return File names of the bundled plugins. Like
+ * {"ssh-slaves.hpi","subvesrion.hpi"}
+ * @throws Exception Any exception will be reported and halt the startup.
*/
protected abstract Collection<String> loadBundledPlugins() throws Exception;
/**
- * Copies the bundled plugin from the given URL to the destination of the given file name (like 'abc.hpi'),
- * with a reasonable up-to-date check. A convenience method to be used by the {@link #loadBundledPlugins()}.
+ * Copies the bundled plugin from the given URL to the destination of the
+ * given file name (like 'abc.hpi'), with a reasonable up-to-date check. A
+ * convenience method to be used by the {@link #loadBundledPlugins()}.
*/
protected void copyBundledPlugin(URL src, String fileName) throws IOException {
long lastModified = src.openConnection().getLastModified();
File file = new File(rootDir, fileName);
- File pinFile = new File(rootDir, fileName+".pinned");
+ File pinFile = new File(rootDir, fileName + ".pinned");
// update file if:
// - no file exists today
@@ -360,7 +373,8 @@ public abstract class PluginManager extends AbstractModelObject {
}
/**
- * Creates a hudson.PluginStrategy, looking at the corresponding system property.
+ * Creates a hudson.PluginStrategy, looking at the corresponding system
+ * property.
*/
private PluginStrategy createPluginStrategy() {
// Allow the user to specify a the plugin strategy to use with a system property
@@ -407,13 +421,13 @@ public abstract class PluginManager extends AbstractModelObject {
}
/**
- * Returns true if any new plugin was added, which means a restart is required
- * for the change to take effect.
+ * Returns true if any new plugin was added, which means a restart is
+ * required for the change to take effect.
*/
public boolean isPluginUploaded() {
return pluginUploaded;
}
-
+
public List<PluginWrapper> getPlugins() {
return plugins;
}
@@ -424,37 +438,43 @@ public abstract class PluginManager extends AbstractModelObject {
public PluginWrapper getPlugin(String shortName) {
for (PluginWrapper p : plugins) {
- if(p.getShortName().equals(shortName))
+ if (p.getShortName().equals(shortName)) {
return p;
+ }
}
return null;
}
/**
- * Get the plugin instance that implements a specific class, use to find your plugin singleton.
- * Note: beware the classloader fun.
+ * Get the plugin instance that implements a specific class, use to find
+ * your plugin singleton. Note: beware the classloader fun.
+ *
* @param pluginClazz The class that your plugin implements.
- * @return The plugin singleton or <code>null</code> if for some reason the plugin is not loaded.
+ * @return The plugin singleton or <code>null</code> if for some reason the
+ * plugin is not loaded.
*/
public PluginWrapper getPlugin(Class<? extends Plugin> pluginClazz) {
for (PluginWrapper p : plugins) {
- if(pluginClazz.isInstance(p.getPlugin()))
+ if (pluginClazz.isInstance(p.getPlugin())) {
return p;
+ }
}
return null;
}
/**
- * Get the plugin instances that extend a specific class, use to find similar plugins.
- * Note: beware the classloader fun.
+ * Get the plugin instances that extend a specific class, use to find
+ * similar plugins. Note: beware the classloader fun.
+ *
* @param pluginSuperclass The class that your plugin is derived from.
* @return The list of plugins implementing the specified class.
*/
public List<PluginWrapper> getPlugins(Class<? extends Plugin> pluginSuperclass) {
List<PluginWrapper> result = new ArrayList<PluginWrapper>();
for (PluginWrapper p : plugins) {
- if(pluginSuperclass.isInstance(p.getPlugin()))
+ if (pluginSuperclass.isInstance(p.getPlugin())) {
result.add(p);
+ }
}
return Collections.unmodifiableList(result);
}
@@ -468,10 +488,10 @@ public abstract class PluginManager extends AbstractModelObject {
}
/**
- * Discover all the service provider implementations of the given class,
- * via <tt>META-INF/services</tt>.
+ * Discover all the service provider implementations of the given class, via
+ * <tt>META-INF/services</tt>.
*/
- public <T> Collection<Class<? extends T>> discover( Class<T> spi ) {
+ public <T> Collection<Class<? extends T>> discover(Class<T> spi) {
Set<Class<? extends T>> result = new HashSet<Class<? extends T>>();
for (PluginWrapper p : activePlugins) {
@@ -502,14 +522,15 @@ public abstract class PluginManager extends AbstractModelObject {
UpdateCenter uc = Hudson.getInstance().getUpdateCenter();
BulkChange bc = new BulkChange(uc);
try {
- for (String id : req.getParameterValues("sources"))
+ for (String id : req.getParameterValues("sources")) {
uc.getSites().remove(uc.getById(id));
+ }
} finally {
bc.commit();
}
- } else
- if (req.hasParameter("add"))
+ } else if (req.hasParameter("add")) {
return new HttpRedirect("addSite");
+ }
return new HttpRedirect("./sites");
}
@@ -520,21 +541,21 @@ public abstract class PluginManager extends AbstractModelObject {
public void doInstall(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
Enumeration<String> en = req.getParameterNames();
while (en.hasMoreElements()) {
- String n = en.nextElement();
- if(n.startsWith("plugin.")) {
+ String n = en.nextElement();
+ if (n.startsWith("plugin.")) {
n = n.substring(7);
if (n.indexOf(".") > 0) {
String[] pluginInfo = n.split("\\.");
UpdateSite.Plugin p = Hudson.getInstance().getUpdateCenter().getById(pluginInfo[1]).getPlugin(pluginInfo[0]);
- if(p==null)
- throw new Failure("No such plugin: "+n);
+ if (p == null) {
+ throw new Failure("No such plugin: " + n);
+ }
p.deploy();
}
}
}
rsp.sendRedirect("../updateCenter/");
}
-
/**
* Bare-minimum configuration mechanism to change the update center.
@@ -545,15 +566,15 @@ public abstract class PluginManager extends AbstractModelObject {
UpdateCenter uc = hudson.getUpdateCenter();
PersistedList<UpdateSite> sites = uc.getSites();
for (UpdateSite s : sites) {
- if (s.getId().equals("default"))
+ if (s.getId().equals("default")) {
sites.remove(s);
+ }
}
- sites.add(new UpdateSite("default",site));
-
+ sites.add(new UpdateSite("default", site));
+
return HttpResponses.redirectToContextRoot();
}
-
public HttpResponse doProxyConfigure(
@QueryParameter("proxy.server") String server,
@QueryParameter("proxy.port") String port,
@@ -563,23 +584,23 @@ public abstract class PluginManager extends AbstractModelObject {
@QueryParameter("proxy.authNeeded") String authNeeded) throws IOException {
Hudson hudson = Hudson.getInstance();
hudson.checkPermission(Hudson.ADMINISTER);
-
+
server = Util.fixEmptyAndTrim(server);
if ((server != null) && !"".equals(server)) {
// If port is not specified assume it is port 80 (usual default for HTTP port)
int portNumber = 80;
- if (!"".equals(Util.fixNull(port))){
+ if (!"".equals(Util.fixNull(port))) {
portNumber = Integer.parseInt(Util.fixNull(port));
}
-
+
boolean proxyAuthNeeded = "on".equals(Util.fixNull(authNeeded));
- if (!proxyAuthNeeded){
+ if (!proxyAuthNeeded) {
userName = "";
password = "";
}
-
- hudson.proxy.configure(server , portNumber, Util.fixEmptyAndTrim(noProxyFor),
+
+ hudson.proxy.configure(server, portNumber, Util.fixEmptyAndTrim(noProxyFor),
Util.fixEmptyAndTrim(userName), Util.fixEmptyAndTrim(password), "on".equals(Util.fixNull(authNeeded)));
hudson.proxy.save();
} else {
@@ -602,10 +623,12 @@ public abstract class PluginManager extends AbstractModelObject {
// Parse the request
FileItem fileItem = (FileItem) upload.parseRequest(req).get(0);
String fileName = Util.getFileName(fileItem.getName());
- if("".equals(fileName))
+ if ("".equals(fileName)) {
return new HttpRedirect("advanced");
- if(!fileName.endsWith(".hpi"))
+ }
+ if (!fileName.endsWith(".hpi")) {
throw new Failure(hudson.model.Messages.Hudson_NotAPlugin(fileName));
+ }
fileItem.write(new File(rootDir, fileName));
fileItem.delete();
@@ -623,9 +646,9 @@ public abstract class PluginManager extends AbstractModelObject {
* {@link ClassLoader} that can see all plugins.
*/
public final class UberClassLoader extends ClassLoader {
+
/**
- * Make generated types visible.
- * Keyed by the generated class name.
+ * Make generated types visible. Keyed by the generated class name.
*/
private ConcurrentMap<String, WeakReference<Class>> generatedClasses = new ConcurrentHashMap<String, WeakReference<Class>>();
@@ -634,27 +657,31 @@ public abstract class PluginManager extends AbstractModelObject {
}
public void addNamedClass(String className, Class c) {
- generatedClasses.put(className,new WeakReference<Class>(c));
+ generatedClasses.put(className, new WeakReference<Class>(c));
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
WeakReference<Class> wc = generatedClasses.get(name);
- if (wc!=null) {
+ if (wc != null) {
Class c = wc.get();
- if (c!=null) return c;
- else generatedClasses.remove(name,wc);
+ if (c != null) {
+ return c;
+ } else {
+ generatedClasses.remove(name, wc);
+ }
}
// first, use the context classloader so that plugins that are loading
// can use its own classloader first.
ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if(cl!=null && cl!=this)
+ if (cl != null && cl != this) {
try {
return cl.loadClass(name);
- } catch(ClassNotFoundException e) {
+ } catch (ClassNotFoundException e) {
// not found. try next
}
+ }
for (PluginWrapper p : activePlugins) {
try {
@@ -671,8 +698,9 @@ public abstract class PluginManager extends AbstractModelObject {
protected URL findResource(String name) {
for (PluginWrapper p : activePlugins) {
URL url = p.classLoader.getResource(name);
- if(url!=null)
+ if (url != null) {
return url;
+ }
}
return null;
}
@@ -687,19 +715,18 @@ public abstract class PluginManager extends AbstractModelObject {
}
@Override
- public String toString()
- {
+ public String toString() {
// only for debugging purpose
- return "classLoader " + getClass().getName();
+ return "classLoader " + getClass().getName();
}
}
-
private static final Logger LOGGER = Logger.getLogger(PluginManager.class.getName());
/**
* Remembers why a plugin failed to deploy.
*/
public static final class FailedPlugin {
+
public final String name;
public final Exception cause;
@@ -717,6 +744,7 @@ public abstract class PluginManager extends AbstractModelObject {
* Stores {@link Plugin} instances.
*/
/*package*/ static final class PluginInstanceStore {
- final Map<PluginWrapper,Plugin> store = new Hashtable<PluginWrapper,Plugin>();
+
+ final Map<PluginWrapper, Plugin> store = new Hashtable<PluginWrapper, Plugin>();
}
}
diff --git a/hudson-core/src/main/java/hudson/model/Queue.java b/hudson-core/src/main/java/hudson/model/Queue.java
index 31a0197..94a1218 100644
--- a/hudson-core/src/main/java/hudson/model/Queue.java
+++ b/hudson-core/src/main/java/hudson/model/Queue.java
@@ -7,10 +7,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
* Kohsuke Kawaguchi, Stephen Connolly, Tom Huybrechts, InfraDNA, Inc.
- *
+ *
*
*******************************************************************************/
@@ -94,13 +94,12 @@ import java.util.HashSet;
/**
* Build queue.
*
- * <p>
- * This class implements the core scheduling logic. {@link Task} represents the executable
- * task that are placed in the queue. While in the queue, it's wrapped into {@link Item}
- * so that we can keep track of additional data used for deciding what to exeucte when.
+ * <p> This class implements the core scheduling logic. {@link Task} represents
+ * the executable task that are placed in the queue. While in the queue, it's
+ * wrapped into {@link Item} so that we can keep track of additional data used
+ * for deciding what to exeucte when.
*
- * <p>
- * Items in queue goes through several stages, as depicted below:
+ * <p> Items in queue goes through several stages, as depicted below:
* <pre>
* (enter) --> waitingList --+--> blockedProjects
* | ^
@@ -109,38 +108,34 @@ import java.util.HashSet;
* +--> buildables ---> pending ---> (executed)
* </pre>
*
- * <p>
- * In addition, at any stage, an item can be removed from the queue (for example, when the user
- * cancels a job in the queue.) See the corresponding field for their exact meanings.
+ * <p> In addition, at any stage, an item can be removed from the queue (for
+ * example, when the user cancels a job in the queue.) See the corresponding
+ * field for their exact meanings.
*
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public class Queue extends ResourceController implements Saveable {
+
/**
* Items that are waiting for its quiet period to pass.
*
- * <p>
- * This consists of {@link Item}s that cannot be run yet
- * because its time has not yet come.
+ * <p> This consists of {@link Item}s that cannot be run yet because its
+ * time has not yet come.
*/
private final Set<WaitingItem> waitingList = new TreeSet<WaitingItem>();
-
/**
- * {@link Task}s that can be built immediately
- * but blocked because another build is in progress,
- * required {@link Resource}s are not available, or otherwise blocked
- * by {@link Task#isBuildBlocked()}.
+ * {@link Task}s that can be built immediately but blocked because another
+ * build is in progress, required {@link Resource}s are not available, or
+ * otherwise blocked by {@link Task#isBuildBlocked()}.
*/
private final ItemList<BlockedItem> blockedProjects = new ItemList<BlockedItem>();
-
/**
- * {@link Task}s that can be built immediately
- * that are waiting for available {@link Executor}.
- * This list is sorted in such a way that earlier items are built earlier.
+ * {@link Task}s that can be built immediately that are waiting for
+ * available {@link Executor}. This list is sorted in such a way that
+ * earlier items are built earlier.
*/
private final ItemList<BuildableItem> buildables = new ItemList<BuildableItem>();
-
/**
* {@link Task}s that are being handed over to the executor, but execution
* has not started yet.
@@ -148,26 +143,24 @@ public class Queue extends ResourceController implements Saveable {
private final ItemList<BuildableItem> pendings = new ItemList<BuildableItem>();
/**
- * Data structure created for each idle {@link Executor}.
- * This is a job offer from the queue to an executor.
+ * Data structure created for each idle {@link Executor}. This is a job
+ * offer from the queue to an executor.
*
- * <p>
- * An idle executor (that calls {@link Queue#pop()} creates
- * a new {@link JobOffer} and gets itself {@linkplain Queue#parked parked},
- * and we'll eventually hand out an {@link #workUnit} to build.
+ * <p> An idle executor (that calls {@link Queue#pop()} creates a new
+ * {@link JobOffer} and gets itself {@linkplain Queue#parked parked}, and
+ * we'll eventually hand out an {@link #workUnit} to build.
*/
public class JobOffer extends MappingWorksheet.ExecutorSlot {
- public final Executor executor;
+ public final Executor executor;
/**
- * Used to wake up an executor, when it has an offered
- * {@link Project} to build.
+ * Used to wake up an executor, when it has an offered {@link Project}
+ * to build.
*/
private final OneShotEvent event = new OneShotEvent(Queue.this);
-
/**
- * The work unit that this {@link Executor} is going to handle.
- * (Or null, in which case event is used to trigger a queue maintenance.)
+ * The work unit that this {@link Executor} is going to handle. (Or
+ * null, in which case event is used to trigger a queue maintenance.)
*/
private WorkUnit workUnit;
@@ -188,18 +181,22 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * Verifies that the {@link Executor} represented by this object is capable of executing the given task.
+ * Verifies that the {@link Executor} represented by this object is
+ * capable of executing the given task.
*/
public boolean canTake(Task task) {
Node node = getNode();
- if (node==null) return false; // this executor is about to die
-
- if(node.canTake(task)!=null)
+ if (node == null) {
+ return false; // this executor is about to die
+ }
+ if (node.canTake(task) != null) {
return false; // this node is not able to take the task
-
- for (QueueTaskDispatcher d : QueueTaskDispatcher.all())
- if (d.canTake(node,task)!=null)
+ }
+ for (QueueTaskDispatcher d : QueueTaskDispatcher.all()) {
+ if (d.canTake(node, task) != null) {
return false;
+ }
+ }
return isAvailable();
}
@@ -219,18 +216,15 @@ public class Queue extends ResourceController implements Saveable {
return getNode().getMode() == Mode.NORMAL;
}
}
-
/**
* The executors that are currently waiting for a job to run.
*/
- private final Map<Executor,JobOffer> parked = new HashMap<Executor,JobOffer>();
-
+ private final Map<Executor, JobOffer> parked = new HashMap<Executor, JobOffer>();
private volatile transient LoadBalancer loadBalancer;
-
private volatile transient QueueSorter sorter;
public Queue(LoadBalancer loadBalancer) {
- this.loadBalancer = loadBalancer.sanitize();
+ this.loadBalancer = loadBalancer.sanitize();
// if all the executors are busy doing something, then the queue won't be maintained in
// timely fashion, so use another thread to make sure it happens.
new MaintainTask(this);
@@ -241,7 +235,9 @@ public class Queue extends ResourceController implements Saveable {
}
public void setLoadBalancer(LoadBalancer loadBalancer) {
- if(loadBalancer==null) throw new IllegalArgumentException();
+ if (loadBalancer == null) {
+ throw new IllegalArgumentException();
+ }
this.loadBalancer = loadBalancer;
}
@@ -267,9 +263,10 @@ public class Queue extends ResourceController implements Saveable {
String line;
while ((line = in.readLine()) != null) {
AbstractProject j = Hudson.getInstance().getItemByFullName(line, AbstractProject.class);
- if (j != null)
+ if (j != null) {
j.scheduleBuild();
- }
+ }
+ }
} finally {
IOUtils.closeQuietly(in);
}
@@ -283,12 +280,12 @@ public class Queue extends ResourceController implements Saveable {
for (Object o : list) {
if (o instanceof Task) {
// backward compatibility
- schedule((Task)o, 0);
+ schedule((Task) o, 0);
} else if (o instanceof Item) {
- Item item = (Item)o;
- if(item.task==null)
+ Item item = (Item) o;
+ if (item.task == null) {
continue; // botched persistence. throw this one away
-
+ }
maxId = Math.max(maxId, item.id);
if (item instanceof WaitingItem) {
waitingList.add((WaitingItem) item);
@@ -322,15 +319,20 @@ public class Queue extends ResourceController implements Saveable {
/**
* Persists the queue contents to the disk.
*/
+ @Override
public synchronized void save() {
- if(BulkChange.contains(this)) return;
-
+ if (BulkChange.contains(this)) {
+ return;
+ }
+
// write out the tasks on the queue
- ArrayList<Queue.Item> items = new ArrayList<Queue.Item>();
- for (Item item: getItems()) {
- if(item.task instanceof TransientTask) continue;
- items.add(item);
- }
+ ArrayList<Queue.Item> items = new ArrayList<Queue.Item>();
+ for (Item item : getItems()) {
+ if (item.task instanceof TransientTask) {
+ continue;
+ }
+ items.add(item);
+ }
try {
XmlFile queueFile = new XmlFile(XSTREAM, getXMLQueueFile());
@@ -342,14 +344,15 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * Wipes out all the items currently in the queue, as if all of them are cancelled at once.
+ * Wipes out all the items currently in the queue, as if all of them are
+ * cancelled at once.
*/
-
- @CLIMethod(name="clear-queue")
+ @CLIMethod(name = "clear-queue")
public synchronized void clear() {
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
- for (WaitingItem i : waitingList)
+ for (WaitingItem i : waitingList) {
i.onCancelled();
+ }
waitingList.clear();
blockedProjects.cancelAll();
buildables.cancelAll();
@@ -373,19 +376,17 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * @deprecated as of 1.311
- * Use {@link #schedule(AbstractProject)}
+ * @deprecated as of 1.311 Use {@link #schedule(AbstractProject)}
*/
public boolean add(AbstractProject p) {
- return schedule(p)!=null;
+ return schedule(p) != null;
}
/**
* Schedule a new build for this project.
*
- * @return true if the project is actually added to the queue.
- * false if the queue contained it and therefore the add()
- * was noop
+ * @return true if the project is actually added to the queue. false if the
+ * queue contained it and therefore the add() was noop
*/
public WaitingItem schedule(AbstractProject p) {
return schedule(p, p.getQuietPeriod());
@@ -394,46 +395,49 @@ public class Queue extends ResourceController implements Saveable {
/**
* Schedules a new build with a custom quiet period.
*
- * <p>
- * Left for backward compatibility with &lt;1.114.
+ * <p> Left for backward compatibility with &lt;1.114.
*
* @since 1.105
- * @deprecated as of 1.311
- * Use {@link #schedule(Task, int)}
+ * @deprecated as of 1.311 Use {@link #schedule(Task, int)}
*/
public boolean add(AbstractProject p, int quietPeriod) {
- return schedule(p, quietPeriod)!=null;
+ return schedule(p, quietPeriod) != null;
}
/**
* Schedules an execution of a task.
*
- * @param actions
- * These actions can be used for associating information scoped to a particular build, to
- * the task being queued. Upon the start of the build, these {@link Action}s will be automatically
- * added to the {@link Run} object, and hence avaialable to everyone.
- * For the convenience of the caller, this list can contain null, and those will be silently ignored.
+ * @param actions These actions can be used for associating information
+ * scoped to a particular build, to the task being queued. Upon the start of
+ * the build, these {@link Action}s will be automatically added to the
+ * {@link Run} object, and hence avaialable to everyone. For the convenience
+ * of the caller, this list can contain null, and those will be silently
+ * ignored.
* @since 1.311
- * @return
- * null if this task is already in the queue and therefore the add operation was no-op.
- * Otherwise indicates the {@link WaitingItem} object added, although the nature of the queue
- * is that such {@link Item} only captures the state of the item at a particular moment,
- * and by the time you inspect the object, some of its information can be already stale.
+ * @return null if this task is already in the queue and therefore the add
+ * operation was no-op. Otherwise indicates the {@link WaitingItem} object
+ * added, although the nature of the queue is that such {@link Item} only
+ * captures the state of the item at a particular moment, and by the time
+ * you inspect the object, some of its information can be already stale.
*
- * That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#id}, etc.
+ * That said, one can still look at
+ * {@link WaitingItem#future}, {@link WaitingItem#id}, etc.
*/
public synchronized WaitingItem schedule(Task p, int quietPeriod, List<Action> actions) {
// remove nulls
actions = new ArrayList<Action>(actions);
for (Iterator<Action> itr = actions.iterator(); itr.hasNext();) {
- Action a = itr.next();
- if (a==null) itr.remove();
+ Action a = itr.next();
+ if (a == null) {
+ itr.remove();
+ }
}
- for(QueueDecisionHandler h : QueueDecisionHandler.all())
- if (!h.shouldSchedule(p, actions))
+ for (QueueDecisionHandler h : QueueDecisionHandler.all()) {
+ if (!h.shouldSchedule(p, actions)) {
return null; // veto
-
+ }
+ }
return scheduleInternal(p, quietPeriod, actions);
}
@@ -441,62 +445,65 @@ public class Queue extends ResourceController implements Saveable {
* Schedules an execution of a task.
*
* @since 1.311
- * @return
- * null if this task is already in the queue and therefore the add operation was no-op.
- * Otherwise indicates the {@link WaitingItem} object added, although the nature of the queue
- * is that such {@link Item} only captures the state of the item at a particular moment,
- * and by the time you inspect the object, some of its information can be already stale.
+ * @return null if this task is already in the queue and therefore the add
+ * operation was no-op. Otherwise indicates the {@link WaitingItem} object
+ * added, although the nature of the queue is that such {@link Item} only
+ * captures the state of the item at a particular moment, and by the time
+ * you inspect the object, some of its information can be already stale.
*
- * That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#id}, etc.
+ * That said, one can still look at
+ * {@link WaitingItem#future}, {@link WaitingItem#id}, etc.
*/
private synchronized WaitingItem scheduleInternal(Task p, int quietPeriod, List<Action> actions) {
Calendar due = new GregorianCalendar();
- due.add(Calendar.SECOND, quietPeriod);
+ due.add(Calendar.SECOND, quietPeriod);
// Do we already have this task in the queue? Because if so, we won't schedule a new one.
- List<Item> duplicatesInQueue = new ArrayList<Item>();
- for(Item item : getItems(p)) {
- boolean shouldScheduleItem = false;
- for (QueueAction action: item.getActions(QueueAction.class)) {
+ List<Item> duplicatesInQueue = new ArrayList<Item>();
+ for (Item item : getItems(p)) {
+ boolean shouldScheduleItem = false;
+ for (QueueAction action : item.getActions(QueueAction.class)) {
shouldScheduleItem |= action.shouldSchedule(actions);
- }
- for (QueueAction action: Util.filter(actions,QueueAction.class)) {
+ }
+ for (QueueAction action : Util.filter(actions, QueueAction.class)) {
shouldScheduleItem |= action.shouldSchedule(item.getActions());
- }
- if(!shouldScheduleItem) {
- duplicatesInQueue.add(item);
- }
- }
- if (duplicatesInQueue.isEmpty()) {
- LOGGER.fine(p.getFullDisplayName() + " added to queue");
-
- // put the item in the queue
- WaitingItem added = new WaitingItem(due,p,actions);
- waitingList.add(added);
+ }
+ if (!shouldScheduleItem) {
+ duplicatesInQueue.add(item);
+ }
+ }
+ if (duplicatesInQueue.isEmpty()) {
+ LOGGER.fine(p.getFullDisplayName() + " added to queue");
+
+ // put the item in the queue
+ WaitingItem added = new WaitingItem(due, p, actions);
+ waitingList.add(added);
scheduleMaintenance(); // let an executor know that a new item is in the queue.
return added;
- }
+ }
LOGGER.fine(p.getFullDisplayName() + " is already in the queue");
// but let the actions affect the existing stuff.
- for(Item item : duplicatesInQueue) {
- for(FoldableAction a : Util.filter(actions,FoldableAction.class)) {
+ for (Item item : duplicatesInQueue) {
+ for (FoldableAction a : Util.filter(actions, FoldableAction.class)) {
a.foldIntoExisting(item, p, actions);
}
}
boolean queueUpdated = false;
- for(WaitingItem wi : Util.filter(duplicatesInQueue,WaitingItem.class)) {
- if(quietPeriod<=0) {
+ for (WaitingItem wi : Util.filter(duplicatesInQueue, WaitingItem.class)) {
+ if (quietPeriod <= 0) {
// the user really wants to build now, and they mean NOW.
// so let's pull in the timestamp if we can.
- if (wi.timestamp.before(due))
+ if (wi.timestamp.before(due)) {
continue;
+ }
} else {
// otherwise we do the normal quiet period implementation
- if (wi.timestamp.after(due))
+ if (wi.timestamp.after(due)) {
continue;
+ }
// quiet period timer reset. start the period over again
}
@@ -504,45 +511,46 @@ public class Queue extends ResourceController implements Saveable {
waitingList.remove(wi);
wi.timestamp = due;
waitingList.add(wi);
- queueUpdated=true;
+ queueUpdated = true;
}
- if (queueUpdated) scheduleMaintenance();
+ if (queueUpdated) {
+ scheduleMaintenance();
+ }
return null;
}
-
+
/**
- * @deprecated as of 1.311
- * Use {@link #schedule(Task, int)}
+ * @deprecated as of 1.311 Use {@link #schedule(Task, int)}
*/
public synchronized boolean add(Task p, int quietPeriod) {
- return schedule(p, quietPeriod)!=null;
+ return schedule(p, quietPeriod) != null;
}
public synchronized WaitingItem schedule(Task p, int quietPeriod) {
- return schedule(p, quietPeriod, new Action[0]);
+ return schedule(p, quietPeriod, new Action[0]);
}
/**
- * @deprecated as of 1.311
- * Use {@link #schedule(Task, int, Action...)}
+ * @deprecated as of 1.311 Use {@link #schedule(Task, int, Action...)}
*/
public synchronized boolean add(Task p, int quietPeriod, Action... actions) {
- return schedule(p, quietPeriod, actions)!=null;
+ return schedule(p, quietPeriod, actions) != null;
}
/**
* Convenience wrapper method around {@link #schedule(Task, int, List)}
*/
public synchronized WaitingItem schedule(Task p, int quietPeriod, Action... actions) {
- return schedule(p, quietPeriod, Arrays.asList(actions));
+ return schedule(p, quietPeriod, Arrays.asList(actions));
}
/**
- * Cancels the item in the queue. If the item is scheduled more than once, cancels the first occurrence.
+ * Cancels the item in the queue. If the item is scheduled more than once,
+ * cancels the first occurrence.
*
* @return true if the project was indeed in the queue and was removed.
- * false if this was no-op.
+ * false if this was no-op.
*/
public synchronized boolean cancel(Task p) {
LOGGER.fine("Cancelling " + p.getFullDisplayName());
@@ -555,15 +563,16 @@ public class Queue extends ResourceController implements Saveable {
}
}
// use bitwise-OR to make sure that both branches get evaluated all the time
- return blockedProjects.cancel(p)!=null | buildables.cancel(p)!=null;
+ return blockedProjects.cancel(p) != null | buildables.cancel(p) != null;
}
-
+
public synchronized boolean cancel(Item item) {
LOGGER.fine("Cancelling " + item.task.getFullDisplayName() + " item#" + item.id);
// use bitwise-OR to make sure that all the branches get evaluated all the time
boolean r = (item instanceof WaitingItem && waitingList.remove(item)) | blockedProjects.remove(item) | buildables.remove(item);
- if(r)
+ if (r) {
item.onCancelled();
+ }
return r;
}
@@ -578,33 +587,53 @@ public class Queue extends ResourceController implements Saveable {
/**
* Gets a snapshot of items in the queue.
*
- * Generally speaking the array is sorted such that the items that are most likely built sooner are
- * at the end.
+ * Generally speaking the array is sorted such that the items that are most
+ * likely built sooner are at the end.
*/
- @Exported(inline=true)
+ @Exported(inline = true)
public synchronized Item[] getItems() {
Item[] r = new Item[waitingList.size() + blockedProjects.size() + buildables.size() + pendings.size()];
waitingList.toArray(r);
int idx = waitingList.size();
- for (BlockedItem p : blockedProjects.values())
+ for (BlockedItem p : blockedProjects.values()) {
r[idx++] = p;
- for (BuildableItem p : reverse(buildables.values()))
+ }
+ for (BuildableItem p : reverse(buildables.values())) {
r[idx++] = p;
- for (BuildableItem p : reverse(pendings.values()))
+ }
+ for (BuildableItem p : reverse(pendings.values())) {
r[idx++] = p;
+ }
return r;
}
-
+
public synchronized Item getItem(int id) {
- for (Item item: waitingList) if (item.id == id) return item;
- for (Item item: blockedProjects) if (item.id == id) return item;
- for (Item item: buildables) if (item.id == id) return item;
- for (Item item: pendings) if (item.id == id) return item;
- return null;
+ for (Item item : waitingList) {
+ if (item.id == id) {
+ return item;
+ }
+ }
+ for (Item item : blockedProjects) {
+ if (item.id == id) {
+ return item;
+ }
+ }
+ for (Item item : buildables) {
+ if (item.id == id) {
+ return item;
+ }
+ }
+ for (Item item : pendings) {
+ if (item.id == id) {
+ return item;
+ }
+ }
+ return null;
}
/**
- * Gets all the {@link BuildableItem}s that are waiting for an executor in the given {@link Computer}.
+ * Gets all the {@link BuildableItem}s that are waiting for an executor in
+ * the given {@link Computer}.
*/
public synchronized List<BuildableItem> getBuildableItems(Computer c) {
List<BuildableItem> result = new ArrayList<BuildableItem>();
@@ -616,8 +645,9 @@ public class Queue extends ResourceController implements Saveable {
private void _getBuildableItems(Computer c, ItemList<BuildableItem> col, List<BuildableItem> result) {
Node node = c.getNode();
for (BuildableItem p : col.values()) {
- if (node.canTake(p.task) == null)
+ if (node.canTake(p.task) == null) {
result.add(p);
+ }
}
}
@@ -641,9 +671,11 @@ public class Queue extends ResourceController implements Saveable {
* Is the given task currently pending execution?
*/
public synchronized boolean isPending(Task t) {
- for (BuildableItem i : pendings)
- if (i.task.equals(t))
+ for (BuildableItem i : pendings) {
+ if (i.task.equals(t)) {
return true;
+ }
+ }
return false;
}
@@ -666,12 +698,16 @@ public class Queue extends ResourceController implements Saveable {
*/
public synchronized int countBuildableItemsFor(Label l) {
int r = 0;
- for (BuildableItem bi : buildables.values())
- if(bi.task.getAssignedLabel()==l)
+ for (BuildableItem bi : buildables.values()) {
+ if (bi.task.getAssignedLabel() == l) {
r++;
- for (BuildableItem bi : pendings.values())
- if(bi.task.getAssignedLabel()==l)
+ }
+ }
+ for (BuildableItem bi : pendings.values()) {
+ if (bi.task.getAssignedLabel() == l) {
r++;
+ }
+ }
return r;
}
@@ -682,18 +718,22 @@ public class Queue extends ResourceController implements Saveable {
*/
public synchronized Item getItem(Task t) {
BlockedItem bp = blockedProjects.get(t);
- if (bp!=null)
+ if (bp != null) {
return bp;
+ }
BuildableItem bi = buildables.get(t);
- if(bi!=null)
+ if (bi != null) {
return bi;
+ }
bi = pendings.get(t);
- if(bi!=null)
+ if (bi != null) {
return bi;
+ }
for (Item item : waitingList) {
- if (item.task == t)
+ if (item.task == t) {
return item;
+ }
}
return null;
}
@@ -704,13 +744,14 @@ public class Queue extends ResourceController implements Saveable {
* @return null if the project is not in the queue.
*/
public synchronized List<Item> getItems(Task t) {
- List<Item> result =new ArrayList<Item>();
- result.addAll(blockedProjects.getAll(t));
- result.addAll(buildables.getAll(t));
+ List<Item> result = new ArrayList<Item>();
+ result.addAll(blockedProjects.getAll(t));
+ result.addAll(buildables.getAll(t));
result.addAll(pendings.getAll(t));
for (Item item : waitingList) {
- if (item.task == t)
+ if (item.task == t) {
result.add(item);
+ }
}
return result;
}
@@ -718,29 +759,27 @@ public class Queue extends ResourceController implements Saveable {
/**
* Left for backward compatibility.
*
- * @see #getItem(Task)
- public synchronized Item getItem(AbstractProject p) {
- return getItem((Task) p);
- }
+ * @see #getItem(Task) public synchronized Item getItem(AbstractProject p) {
+ * return getItem((Task) p); }
*/
-
/**
* Returns true if this queue contains the said project.
*/
public synchronized boolean contains(Task t) {
- if (blockedProjects.containsKey(t) || buildables.containsKey(t) || pendings.containsKey(t))
+ if (blockedProjects.containsKey(t) || buildables.containsKey(t) || pendings.containsKey(t)) {
return true;
+ }
for (Item item : waitingList) {
- if (item.task == t)
+ if (item.task == t) {
return true;
+ }
}
return false;
}
/**
- * Called by the executor to fetch something to build next.
- * <p>
- * This method blocks until a next project becomes buildable.
+ * Called by the executor to fetch something to build next. <p> This method
+ * blocks until a next project becomes buildable.
*/
public synchronized WorkUnit pop() throws InterruptedException {
final Executor exec = Executor.currentExecutor();
@@ -774,30 +813,34 @@ public class Queue extends ResourceController implements Saveable {
// one last check to make sure this build is not blocked.
if (isBuildBlocked(p.task)) {
itr.remove();
- blockedProjects.put(p.task,new BlockedItem(p));
+ blockedProjects.put(p.task, new BlockedItem(p));
continue;
}
List<JobOffer> candidates = new ArrayList<JobOffer>(parked.size());
- for (JobOffer j : parked.values())
- if(j.canTake(p.task))
+ for (JobOffer j : parked.values()) {
+ if (j.canTake(p.task)) {
candidates.add(j);
+ }
+ }
MappingWorksheet ws = new MappingWorksheet(p, candidates);
Mapping m = loadBalancer.map(p.task, ws);
- if (m == null)
- // if we couldn't find the executor that fits,
- // just leave it in the buildables list and
- // check if we can execute other projects
+ if (m == null) // if we couldn't find the executor that fits,
+ // just leave it in the buildables list and
+ // check if we can execute other projects
+ {
continue;
+ }
// found a matching executor. use it.
WorkUnitContext wuc = new WorkUnitContext(p);
m.execute(wuc);
itr.remove();
- if (!wuc.getWorkUnits().isEmpty())
+ if (!wuc.getWorkUnits().isEmpty()) {
pendings.add(p);
+ }
}
// we went over all the buildable projects and awaken
@@ -808,13 +851,16 @@ public class Queue extends ResourceController implements Saveable {
if (!waitingList.isEmpty()) {
// wait until the first item in the queue is due
sleep = peek().timestamp.getTimeInMillis() - new GregorianCalendar().getTimeInMillis();
- if (sleep < 100) sleep = 100; // avoid wait(0)
+ if (sleep < 100) {
+ sleep = 100; // avoid wait(0)
+ }
}
- if (sleep == -1)
+ if (sleep == -1) {
offer.event.block();
- else
+ } else {
offer.event.block(sleep);
+ }
// retract the offer object
assert parked.get(exec) == offer;
@@ -826,8 +872,9 @@ public class Queue extends ResourceController implements Saveable {
LOGGER.fine("Pop returning " + offer.workUnit + " for " + exec.getName());
// TODO: I think this has to be done by the last executor that leaves the pop(), not by main executor
- if (offer.workUnit.isMainWork())
+ if (offer.workUnit.isMainWork()) {
pendings.remove(offer.workUnit.context.item);
+ }
return offer.workUnit;
}
@@ -852,10 +899,8 @@ public class Queue extends ResourceController implements Saveable {
/**
* Checks the queue and runs anything that can be run.
*
- * <p>
- * When conditions are changed, this method should be invoked.
- * <p>
- * This wakes up one {@link Executor} so that it will maintain a queue.
+ * <p> When conditions are changed, this method should be invoked. <p> This
+ * wakes up one {@link Executor} so that it will maintain a queue.
*/
public synchronized void scheduleMaintenance() {
// this code assumes that after this method is called
@@ -877,13 +922,14 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * Make sure we don't queue two tasks of the same project to be built
- * unless that project allows concurrent builds.
+ * Make sure we don't queue two tasks of the same project to be built unless
+ * that project allows concurrent builds.
*/
private boolean allowNewBuildableTask(Task t) {
try {
- if (t.isConcurrentBuild())
+ if (t.isConcurrentBuild()) {
return true;
+ }
} catch (AbstractMethodError e) {
// earlier versions don't have the "isConcurrentBuild" method, so fall back gracefully
}
@@ -891,14 +937,14 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * Queue maintenance.
- * <p>
- * Move projects between {@link #waitingList}, {@link #blockedProjects}, and {@link #buildables}
+ * Queue maintenance. <p> Move projects between
+ * {@link #waitingList}, {@link #blockedProjects}, and {@link #buildables}
* appropriately.
*/
public synchronized void maintain() {
- if (LOGGER.isLoggable(Level.FINE))
+ if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Queue maintenance started " + this);
+ }
// blocked -> buildable
Iterator<BlockedItem> itr = blockedProjects.values().iterator();
@@ -915,9 +961,9 @@ public class Queue extends ResourceController implements Saveable {
while (!waitingList.isEmpty()) {
WaitingItem top = peek();
- if (!top.timestamp.before(new GregorianCalendar()))
+ if (!top.timestamp.before(new GregorianCalendar())) {
return; // finished moving all ready items from queue
-
+ }
waitingList.remove(top);
Task p = top.task;
if (!isBuildBlocked(p) && allowNewBuildableTask(p)) {
@@ -928,32 +974,38 @@ public class Queue extends ResourceController implements Saveable {
// this can't be built now because another build is in progress
// set this project aside.
LOGGER.fine(p.getFullDisplayName() + " is blocked");
- blockedProjects.put(p,new BlockedItem(top));
+ blockedProjects.put(p, new BlockedItem(top));
}
}
final QueueSorter s = sorter;
- if (s != null)
- s.sortBuildableItems(buildables);
+ if (s != null) {
+ s.sortBuildableItems(buildables);
+ }
}
private void makeBuildable(BuildableItem p) {
- if(Hudson.FLYWEIGHT_SUPPORT && p.task instanceof FlyweightTask && !ifBlockedByHudsonShutdown(p.task)) {
+ if (Hudson.FLYWEIGHT_SUPPORT && p.task instanceof FlyweightTask && !ifBlockedByHudsonShutdown(p.task)) {
ConsistentHash<Node> hash = new ConsistentHash<Node>(new Hash<Node>() {
public String hash(Node node) {
return node.getNodeName();
}
});
Hudson h = Hudson.getInstance();
- hash.add(h, h.getNumExecutors()*100);
- for (Node n : h.getNodes())
- hash.add(n,n.getNumExecutors()*100);
+ hash.add(h, h.getNumExecutors() * 100);
+ for (Node n : h.getNodes()) {
+ hash.add(n, n.getNumExecutors() * 100);
+ }
Label lbl = p.task.getAssignedLabel();
for (Node n : hash.list(p.task.getFullDisplayName())) {
Computer c = n.toComputer();
- if (c==null || c.isOffline()) continue;
- if (lbl!=null && !lbl.contains(n)) continue;
+ if (c == null || c.isOffline()) {
+ continue;
+ }
+ if (lbl != null && !lbl.contains(n)) {
+ continue;
+ }
c.startFlyWeightTask(new WorkUnitContext(p).createWorkUnit(p.task));
pendings.add(p);
return;
@@ -961,8 +1013,8 @@ public class Queue extends ResourceController implements Saveable {
// if the execution get here, it means we couldn't schedule it anywhere.
// so do the scheduling like other normal jobs.
}
-
- buildables.put(p.task,p);
+
+ buildables.put(p.task, p);
}
public static boolean ifBlockedByHudsonShutdown(Task task) {
@@ -975,74 +1027,75 @@ public class Queue extends ResourceController implements Saveable {
/**
* Marks {@link Task}s that are not persisted.
+ *
* @since 1.311
*/
- public interface TransientTask extends Task {}
+ public interface TransientTask extends Task {
+ }
/**
* Marks {@link Task}s that do not consume {@link Executor}.
+ *
* @see OneOffExecutor
* @since 1.318
*/
- public interface FlyweightTask extends Task {}
+ public interface FlyweightTask extends Task {
+ }
/**
- * Marks {@link Task}s that are not affected by the {@linkplain Hudson#isQuietingDown()} quieting down},
- * because these tasks keep other tasks executing.
+ * Marks {@link Task}s that are not affected by the
+ * {@linkplain Hudson#isQuietingDown()} quieting down}, because these tasks
+ * keep other tasks executing.
*
- * @since 1.336
+ * @since 1.336
*/
- public interface NonBlockingTask extends Task {}
+ public interface NonBlockingTask extends Task {
+ }
/**
* Task whose execution is controlled by the queue.
*
- * <p>
- * {@link #equals(Object) Value equality} of {@link Task}s is used
- * to collapse two tasks into one. This is used to avoid infinite
- * queue backlog.
+ * <p> {@link #equals(Object) Value equality} of {@link Task}s is used to
+ * collapse two tasks into one. This is used to avoid infinite queue
+ * backlog.
*
- * <p>
- * Pending {@link Task}s are persisted when Hudson shuts down, so
- * it needs to be persistable via XStream. To create a non-persisted
- * transient Task, extend {@link TransientTask} marker interface.
+ * <p> Pending {@link Task}s are persisted when Hudson shuts down, so it
+ * needs to be persistable via XStream. To create a non-persisted transient
+ * Task, extend {@link TransientTask} marker interface.
*
- * <p>
- * Plugins are encouraged to extend from {@link AbstractQueueTask}
+ * <p> Plugins are encouraged to extend from {@link AbstractQueueTask}
* instead of implementing this interface directly, to maintain
* compatibility with future changes to this interface.
*
- * <p>
- * For historical reasons, {@link Task} object by itself
- * also represents the "primary" sub-task (and as implied by this
- * design, a {@link Task} must have at least one sub-task.)
- * Most of the time, the primary subtask is the only sub task.
+ * <p> For historical reasons, {@link Task} object by itself also represents
+ * the "primary" sub-task (and as implied by this design, a {@link Task}
+ * must have at least one sub-task.) Most of the time, the primary subtask
+ * is the only sub task.
*/
public interface Task extends ModelObject, SubTask {
+
/**
- * Returns true if the execution should be blocked
- * for temporary reasons.
+ * Returns true if the execution should be blocked for temporary
+ * reasons.
*
- * <p>
- * Short-hand for {@code getCauseOfBlockage()!=null}.
+ * <p> Short-hand for {@code getCauseOfBlockage()!=null}.
*/
boolean isBuildBlocked();
/**
- * @deprecated as of 1.330
- * Use {@link CauseOfBlockage#getShortDescription()} instead.
+ * @deprecated as of 1.330 Use
+ * {@link CauseOfBlockage#getShortDescription()} instead.
*/
String getWhyBlocked();
/**
- * If the execution of this task should be blocked for temporary reasons,
- * this method returns a non-null object explaining why.
+ * If the execution of this task should be blocked for temporary
+ * reasons, this method returns a non-null object explaining why.
*
- * <p>
- * Otherwise this method returns null, indicating that the build can proceed right away.
+ * <p> Otherwise this method returns null, indicating that the build can
+ * proceed right away.
*
- * <p>
- * This can be used to define mutual exclusion that goes beyond
+ * <p> This can be used to define mutual exclusion that goes beyond
* {@link #getResourceList()}.
*/
CauseOfBlockage getCauseOfBlockage();
@@ -1050,8 +1103,8 @@ public class Queue extends ResourceController implements Saveable {
/**
* Unique name of this task.
*
- * <p>
- * This method is no longer used, left here for compatibility. Just return {@link #getDisplayName()}.
+ * <p> This method is no longer used, left here for compatibility. Just
+ * return {@link #getDisplayName()}.
*/
String getName();
@@ -1061,31 +1114,32 @@ public class Queue extends ResourceController implements Saveable {
String getFullDisplayName();
/**
- * Checks the permission to see if the current user can abort this executable.
- * Returns normally from this method if it's OK.
+ * Checks the permission to see if the current user can abort this
+ * executable. Returns normally from this method if it's OK.
*
- * @throws org.acegisecurity.AccessDeniedException if the permission is not granted.
+ * @throws org.acegisecurity.AccessDeniedException if the permission is
+ * not granted.
*/
void checkAbortPermission();
/**
- * Works just like {@link #checkAbortPermission()} except it indicates the status by a return value,
- * instead of exception.
+ * Works just like {@link #checkAbortPermission()} except it indicates
+ * the status by a return value, instead of exception.
*/
boolean hasAbortPermission();
-
+
/**
- * Returns the URL of this task relative to the context root of the application.
+ * Returns the URL of this task relative to the context root of the
+ * application.
*
- * <p>
- * When the user clicks an item in the queue, this is the page where the user is taken to.
- * Hudson expects the current instance to be bound to the URL returned by this method.
+ * <p> When the user clicks an item in the queue, this is the page where
+ * the user is taken to. Hudson expects the current instance to be bound
+ * to the URL returned by this method.
*
- * @return
- * URL that ends with '/'.
+ * @return URL that ends with '/'.
*/
String getUrl();
-
+
/**
* True if the task allows concurrent builds
*
@@ -1096,17 +1150,15 @@ public class Queue extends ResourceController implements Saveable {
/**
* Obtains the {@link SubTask}s that constitute this task.
*
- * <p>
- * The collection returned by this method must also contain the primary {@link SubTask}
- * represented by this {@link Task} object itself as the first element.
- * The returned value is read-only.
+ * <p> The collection returned by this method must also contain the
+ * primary {@link SubTask} represented by this {@link Task} object
+ * itself as the first element. The returned value is read-only.
*
- * <p>
- * At least size 1.
+ * <p> At least size 1.
*
- * <p>
- * Since this is a newly added method, the invocation may results in {@link AbstractMethodError}.
- * Use {@link Tasks#getSubTasksOf(Task)} that avoids this.
+ * <p> Since this is a newly added method, the invocation may results in
+ * {@link AbstractMethodError}. Use {@link Tasks#getSubTasksOf(Task)}
+ * that avoids this.
*
* @since 1.377
*/
@@ -1116,34 +1168,34 @@ public class Queue extends ResourceController implements Saveable {
/**
* Represents the real meat of the computation run by {@link Executor}.
*
- * <h2>Views</h2>
- * <p>
- * Implementation must have <tt>executorCell.jelly</tt>, which is
- * used to render the HTML that indicates this executable is executing.
+ * <h2>Views</h2> <p> Implementation must have <tt>executorCell.jelly</tt>,
+ * which is used to render the HTML that indicates this executable is
+ * executing.
*/
public interface Executable extends Runnable {
+
/**
- * Task from which this executable was created.
- * Never null.
+ * Task from which this executable was created. Never null.
*
- * <p>
- * Since this method went through a signature change in 1.377, the invocation may results in
- * {@link AbstractMethodError}.
- * Use {@link Executables#getParentOf(Executable)} that avoids this.
+ * <p> Since this method went through a signature change in 1.377, the
+ * invocation may results in {@link AbstractMethodError}. Use
+ * {@link Executables#getParentOf(Executable)} that avoids this.
*/
SubTask getParent();
/**
* Called by {@link Executor} to perform the task
*/
+ @Override
void run();
-
+
/**
* Estimate of how long will it take to execute this executable.
* Measured in milliseconds.
- *
- * Please, consider using {@link Executables#getEstimatedDurationFor(Executable)}
- * to protected against AbstractMethodErrors!
+ *
+ * Please, consider using
+ * {@link Executables#getEstimatedDurationFor(Executable)} to protected
+ * against AbstractMethodErrors!
*
* @return -1 if it's impossible to estimate.
* @since 1.383
@@ -1151,9 +1203,11 @@ public class Queue extends ResourceController implements Saveable {
long getEstimatedDuration();
/**
- * Used to render the HTML. Should be a human readable text of what this executable is.
+ * Used to render the HTML. Should be a human readable text of what this
+ * executable is.
*/
- @Override String toString();
+ @Override
+ String toString();
}
/**
@@ -1161,61 +1215,71 @@ public class Queue extends ResourceController implements Saveable {
*/
@ExportedBean(defaultVisibility = 999)
public static abstract class Item extends Actionable {
+
/**
- * VM-wide unique ID that tracks the {@link Task} as it moves through different stages
- * in the queue (each represented by different subtypes of {@link Item}.
+ * VM-wide unique ID that tracks the {@link Task} as it moves through
+ * different stages in the queue (each represented by different subtypes
+ * of {@link Item}.
*/
//TODO: review and check whether we can do it private
- public final int id;
-
- /**
+ public final int id;
+ /**
* Project to be built.
*/
//TODO: review and check whether we can do it private
@Exported
public final Task task;
-
private /*almost final*/ transient FutureImpl future;
/**
- * Build is blocked because another build is in progress,
- * required {@link Resource}s are not available, or otherwise blocked
- * by {@link Task#isBuildBlocked()}.
+ * Build is blocked because another build is in progress, required
+ * {@link Resource}s are not available, or otherwise blocked by
+ * {@link Task#isBuildBlocked()}.
*/
@Exported
- public boolean isBlocked() { return this instanceof BlockedItem; }
+ public boolean isBlocked() {
+ return this instanceof BlockedItem;
+ }
/**
- * Build is waiting the executor to become available.
- * This flag is only used in {@link Queue#getItems()} for
- * 'pseudo' items that are actually not really in the queue.
+ * Build is waiting the executor to become available. This flag is only
+ * used in {@link Queue#getItems()} for 'pseudo' items that are actually
+ * not really in the queue.
*/
@Exported
- public boolean isBuildable() { return this instanceof BuildableItem; }
+ public boolean isBuildable() {
+ return this instanceof BuildableItem;
+ }
/**
* True if the item is starving for an executor for too long.
*/
@Exported
- public boolean isStuck() { return false; }
+ public boolean isStuck() {
+ return false;
+ }
/**
- * Can be used to wait for the completion (either normal, abnormal, or cancellation) of the {@link Task}.
- * <p>
- * Just like {@link #id}, the same object tracks various stages of the queue.
+ * Can be used to wait for the completion (either normal, abnormal, or
+ * cancellation) of the {@link Task}. <p> Just like {@link #id}, the
+ * same object tracks various stages of the queue.
*/
- public Future<Executable> getFuture() { return future; }
+ public Future<Executable> getFuture() {
+ return future;
+ }
/**
- * Convenience method that returns a read only view of the {@link Cause}s associated with this item in the queue.
+ * Convenience method that returns a read only view of the
+ * {@link Cause}s associated with this item in the queue.
*
* @return can be empty but never null
* @since 1.343
*/
public final List<Cause> getCauses() {
CauseAction ca = getAction(CauseAction.class);
- if (ca!=null)
+ if (ca != null) {
return Collections.unmodifiableList(ca.getCauses());
+ }
return Collections.emptyList();
}
@@ -1223,11 +1287,13 @@ public class Queue extends ResourceController implements Saveable {
this.task = task;
this.id = id;
this.future = future;
- for (Action action: actions) addAction(action);
+ for (Action action : actions) {
+ addAction(action);
+ }
}
-
+
protected Item(Item item) {
- this(item.task, item.getActions(), item.id, item.future);
+ this(item.task, item.getActions(), item.id, item.future);
}
public int getId() {
@@ -1239,12 +1305,13 @@ public class Queue extends ResourceController implements Saveable {
}
/**
- * Gets a human-readable status message describing why it's in the queue.
+ * Gets a human-readable status message describing why it's in the
+ * queue.
*/
@Exported
public final String getWhy() {
CauseOfBlockage cob = getCauseOfBlockage();
- return cob!=null ? cob.getShortDescription() : null;
+ return cob != null ? cob.getShortDescription() : null;
}
/**
@@ -1255,46 +1322,50 @@ public class Queue extends ResourceController implements Saveable {
/**
* Gets a human-readable message about the parameters of this item
+ *
* @return String
*/
@Exported
public String getParams() {
- StringBuilder s = new StringBuilder();
- for(Action action : getActions()) {
- if(action instanceof ParametersAction) {
- ParametersAction pa = (ParametersAction)action;
- for (ParameterValue p : pa.getParameters()) {
- s.append('\n').append(p.getShortDescription());
- }
- }
- }
- return s.toString();
- }
-
+ StringBuilder s = new StringBuilder();
+ for (Action action : getActions()) {
+ if (action instanceof ParametersAction) {
+ ParametersAction pa = (ParametersAction) action;
+ for (ParameterValue p : pa.getParameters()) {
+ s.append('\n').append(p.getShortDescription());
+ }
+ }
+ }
+ return s.toString();
+ }
+
public boolean hasCancelPermission() {
return task.hasAbortPermission();
}
-
+
+ @Override
public String getDisplayName() {
- // TODO Auto-generated method stub
- return null;
- }
+ // TODO Auto-generated method stub
+ return null;
+ }
- public String getSearchUrl() {
- // TODO Auto-generated method stub
- return null;
- }
+ @Override
+ public String getSearchUrl() {
+ // TODO Auto-generated method stub
+ return null;
+ }
/**
* Called from queue.jelly.
*/
public HttpResponse doCancelQueue() throws IOException, ServletException {
- Hudson.getInstance().getQueue().cancel(this);
+ Hudson.getInstance().getQueue().cancel(this);
return HttpResponses.forwardToPreviousPage();
}
/**
- * Participates in the cancellation logic to set the {@link #future} accordingly.
+ * Participates in the cancellation logic to set the {@link #future}
+ * accordingly.
*/
/*package*/ void onCancelled() {
future.setAsCancelled();
@@ -1307,59 +1378,62 @@ public class Queue extends ResourceController implements Saveable {
@Override
public String toString() {
- return getClass().getName()+':'+task.toString();
+ return getClass().getName() + ':' + task.toString();
}
}
-
+
/**
- * An optional interface for actions on Queue.Item.
- * Lets the action cooperate in queue management.
- *
+ * An optional interface for actions on Queue.Item. Lets the action
+ * cooperate in queue management.
+ *
* @since 1.300-ish.
*/
public interface QueueAction extends Action {
- /**
- * Returns whether the new item should be scheduled.
- * An action should return true if the associated task is 'different enough' to warrant a separate execution.
- */
- public boolean shouldSchedule(List<Action> actions);
+
+ /**
+ * Returns whether the new item should be scheduled. An action should
+ * return true if the associated task is 'different enough' to warrant a
+ * separate execution.
+ */
+ public boolean shouldSchedule(List<Action> actions);
}
/**
- * Extension point for deciding if particular job should be scheduled or not.
+ * Extension point for deciding if particular job should be scheduled or
+ * not.
*
- * <p>
- * This handler is consulted every time someone tries to submit a task to the queue.
- * If any of the registered handlers returns false, the task will not be added
- * to the queue, and the task will never get executed.
+ * <p> This handler is consulted every time someone tries to submit a task
+ * to the queue. If any of the registered handlers returns false, the task
+ * will not be added to the queue, and the task will never get executed.
*
- * <p>
- * This extension point is still a subject to change, as we are seeking more
- * comprehensive Queue pluggability. See HUDSON-2072.
+ * <p> This extension point is still a subject to change, as we are seeking
+ * more comprehensive Queue pluggability. See HUDSON-2072.
*
* @since 1.316
*/
public static abstract class QueueDecisionHandler implements ExtensionPoint {
- /**
- * Returns whether the new item should be scheduled.
- */
- public abstract boolean shouldSchedule(Task p, List<Action> actions);
-
- /**
- * All registered {@link QueueDecisionHandler}s
- * @return
- */
- public static ExtensionList<QueueDecisionHandler> all() {
- return Hudson.getInstance().getExtensionList(QueueDecisionHandler.class);
- }
+
+ /**
+ * Returns whether the new item should be scheduled.
+ */
+ public abstract boolean shouldSchedule(Task p, List<Action> actions);
+
+ /**
+ * All registered {@link QueueDecisionHandler}s
+ *
+ * @return
+ */
+ public static ExtensionList<QueueDecisionHandler> all() {
+ return Hudson.getInstance().getExtensionList(QueueDecisionHandler.class);
+ }
}
-
+
/**
* {@link Item} in the {@link Queue#waitingList} stage.
*/
public static final class WaitingItem extends Item implements Comparable<WaitingItem> {
- private static final AtomicInteger COUNTER = new AtomicInteger(0);
-
+
+ private static final AtomicInteger COUNTER = new AtomicInteger(0);
/**
* This item can be run after this time.
*/
@@ -1375,20 +1449,25 @@ public class Queue extends ResourceController implements Saveable {
super(project, actions, COUNTER.incrementAndGet(), new FutureImpl(project));
this.timestamp = timestamp;
}
-
+
+ @Override
public int compareTo(WaitingItem that) {
int r = this.timestamp.getTime().compareTo(that.timestamp.getTime());
- if (r != 0) return r;
+ if (r != 0) {
+ return r;
+ }
return this.id - that.id;
}
+ @Override
public CauseOfBlockage getCauseOfBlockage() {
long diff = timestamp.getTimeInMillis() - System.currentTimeMillis();
- if (diff > 0)
+ if (diff > 0) {
return CauseOfBlockage.fromMessage(Messages._Queue_InQuietPeriod(Util.getTimeSpanString(diff)));
- else
+ } else {
return CauseOfBlockage.fromMessage(Messages._Queue_Unknown());
+ }
}
}
@@ -1396,6 +1475,7 @@ public class Queue extends ResourceController implements Saveable {
* Common part between {@link BlockedItem} and {@link BuildableItem}.
*/
public static abstract class NotWaitingItem extends Item {
+
/**
* When did this job exit the {@link Queue#waitingList} phase?
*/
@@ -1417,6 +1497,7 @@ public class Queue extends ResourceController implements Saveable {
* {@link Item} in the {@link Queue#blockedProjects} stage.
*/
public final class BlockedItem extends NotWaitingItem {
+
public BlockedItem(WaitingItem wi) {
super(wi);
}
@@ -1429,7 +1510,9 @@ public class Queue extends ResourceController implements Saveable {
ResourceActivity r = getBlockingActivity(task);
if (r != null) {
if (r == task) // blocked by itself, meaning another build is in progress
+ {
return CauseOfBlockage.fromMessage(Messages._Queue_InProgress());
+ }
return CauseOfBlockage.fromMessage(Messages._Queue_BlockedBy(r.getDisplayName()));
}
return task.getCauseOfBlockage();
@@ -1440,6 +1523,7 @@ public class Queue extends ResourceController implements Saveable {
* {@link Item} in the {@link Queue#buildables} stage.
*/
public final static class BuildableItem extends NotWaitingItem {
+
public BuildableItem(WaitingItem wi) {
super(wi);
}
@@ -1448,52 +1532,60 @@ public class Queue extends ResourceController implements Saveable {
super(ni);
}
+ @Override
public CauseOfBlockage getCauseOfBlockage() {
Hudson hudson = Hudson.getInstance();
- if(ifBlockedByHudsonShutdown(task))
+ if (ifBlockedByHudsonShutdown(task)) {
return CauseOfBlockage.fromMessage(Messages._Queue_HudsonIsAboutToShutDown());
+ }
Label label = task.getAssignedLabel();
- if (hudson.getNodes().isEmpty())
+ if (hudson.getNodes().isEmpty()) {
label = null; // no master/slave. pointless to talk about nodes
-
+ }
if (label != null) {
if (label.isOffline()) {
Set<Node> nodes = label.getNodes();
- if (nodes.size() != 1) return new BecauseLabelIsOffline(label);
- else return new BecauseNodeIsOffline(nodes.iterator().next());
+ if (nodes.size() != 1) {
+ return new BecauseLabelIsOffline(label);
+ } else {
+ return new BecauseNodeIsOffline(nodes.iterator().next());
+ }
}
}
- if(label==null)
+ if (label == null) {
return CauseOfBlockage.fromMessage(Messages._Queue_WaitingForNextAvailableExecutor());
+ }
Set<Node> nodes = label.getNodes();
- if (nodes.size() != 1) return new BecauseLabelIsBusy(label);
- else return new BecauseNodeIsBusy(nodes.iterator().next());
+ if (nodes.size() != 1) {
+ return new BecauseLabelIsBusy(label);
+ } else {
+ return new BecauseNodeIsBusy(nodes.iterator().next());
+ }
}
@Override
public boolean isStuck() {
Label label = task.getAssignedLabel();
- if(label!=null && label.isOffline())
- // no executor online to process this job. definitely stuck.
+ if (label != null && label.isOffline()) // no executor online to process this job. definitely stuck.
+ {
return true;
+ }
long d = task.getEstimatedDuration();
- long elapsed = System.currentTimeMillis()-buildableStartMilliseconds;
- if(d>=0) {
+ long elapsed = System.currentTimeMillis() - buildableStartMilliseconds;
+ if (d >= 0) {
// if we were running elsewhere, we would have done this build ten times.
- return elapsed > Math.max(d,60000L)*10;
+ return elapsed > Math.max(d, 60000L) * 10;
} else {
// more than a day in the queue
- return TimeUnit2.MILLISECONDS.toHours(elapsed)>24;
+ return TimeUnit2.MILLISECONDS.toHours(elapsed) > 24;
}
}
}
-
private static final Logger LOGGER = Logger.getLogger(Queue.class.getName());
-
/**
* This {@link XStream} instance is used to persist {@link Task}s.
*/
@@ -1501,50 +1593,54 @@ public class Queue extends ResourceController implements Saveable {
static {
XSTREAM.registerConverter(new AbstractSingleValueConverter() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean canConvert(Class klazz) {
+ return hudson.model.Item.class.isAssignableFrom(klazz);
+ }
- @Override
- @SuppressWarnings("unchecked")
- public boolean canConvert(Class klazz) {
- return hudson.model.Item.class.isAssignableFrom(klazz);
- }
-
- @Override
- public Object fromString(String string) {
+ @Override
+ public Object fromString(String string) {
Object item = Hudson.getInstance().getItemByFullName(string);
- if(item==null) throw new NoSuchElementException("No such job exists: "+string);
+ if (item == null) {
+ throw new NoSuchElementException("No such job exists: " + string);
+ }
return item;
- }
+ }
- @Override
- public String toString(Object item) {
- return ((hudson.model.Item) item).getFullName();
- }
+ @Override
+ public String toString(Object item) {
+ return ((hudson.model.Item) item).getFullName();
+ }
});
XSTREAM.registerConverter(new AbstractSingleValueConverter() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean canConvert(Class klazz) {
+ return Run.class.isAssignableFrom(klazz);
+ }
- @SuppressWarnings("unchecked")
- @Override
- public boolean canConvert(Class klazz) {
- return Run.class.isAssignableFrom(klazz);
- }
-
- @Override
- public Object fromString(String string) {
- String[] split = string.split("#");
- String projectName = split[0];
- int buildNumber = Integer.parseInt(split[1]);
- Job<?,?> job = (Job<?,?>) Hudson.getInstance().getItemByFullName(projectName);
- if(job==null) throw new NoSuchElementException("No such job exists: "+projectName);
- Run<?,?> run = job.getBuildByNumber(buildNumber);
- if(run==null) throw new NoSuchElementException("No such build: "+string);
- return run;
- }
-
- @Override
- public String toString(Object object) {
- Run<?,?> run = (Run<?,?>) object;
- return run.getParent().getFullName() + "#" + run.getNumber();
- }
+ @Override
+ public Object fromString(String string) {
+ String[] split = string.split("#");
+ String projectName = split[0];
+ int buildNumber = Integer.parseInt(split[1]);
+ Job<?, ?> job = (Job<?, ?>) Hudson.getInstance().getItemByFullName(projectName);
+ if (job == null) {
+ throw new NoSuchElementException("No such job exists: " + projectName);
+ }
+ Run<?, ?> run = job.getBuildByNumber(buildNumber);
+ if (run == null) {
+ throw new NoSuchElementException("No such build: " + string);
+ }
+ return run;
+ }
+
+ @Override
+ public String toString(Object object) {
+ Run<?, ?> run = (Run<?, ?>) object;
+ return run.getParent().getFullName() + "#" + run.getNumber();
+ }
});
}
@@ -1553,6 +1649,7 @@ public class Queue extends ResourceController implements Saveable {
* {@link Queue} gets GC-ed.
*/
private static class MaintainTask extends SafeTimerTask {
+
private final WeakReference<Queue> queue;
MaintainTask(Queue queue) {
@@ -1562,84 +1659,94 @@ public class Queue extends ResourceController implements Saveable {
Trigger.timer.schedule(this, interval, interval);
}
+ @Override
protected void doRun() {
Queue q = queue.get();
- if (q != null)
+ if (q != null) {
q.maintain();
- else
+ } else {
cancel();
+ }
}
}
-
+
/**
* {@link ArrayList} of {@link Item} with more convenience methods.
*/
private static class ItemList<T extends Item> extends ArrayList<T> {
- public T get(Task task) {
- for (T item: this) {
- if (item.task == task) {
- return item;
- }
- }
- return null;
- }
-
- public List<T> getAll(Task task) {
- List<T> result = new ArrayList<T>();
- for (T item: this) {
- if (item.task == task) {
- result.add(item);
- }
- }
- return result;
- }
-
- public boolean containsKey(Task task) {
- return get(task) != null;
- }
-
- public T remove(Task task) {
- Iterator<T> it = iterator();
- while (it.hasNext()) {
- T t = it.next();
- if (t.task == task) {
- it.remove();
- return t;
- }
- }
- return null;
- }
-
- public void put(Task task, T item) {
- assert item.task == task;
- add(item);
- }
-
- public ItemList<T> values() {
- return this;
- }
+
+ public T get(Task task) {
+ for (T item : this) {
+ if (item.task == task) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ public List<T> getAll(Task task) {
+ List<T> result = new ArrayList<T>();
+ for (T item : this) {
+ if (item.task == task) {
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+ public boolean containsKey(Task task) {
+ return get(task) != null;
+ }
+
+ public T remove(Task task) {
+ Iterator<T> it = iterator();
+ while (it.hasNext()) {
+ T t = it.next();
+ if (t.task == task) {
+ it.remove();
+ return t;
+ }
+ }
+ return null;
+ }
+
+ public void put(Task task, T item) {
+ assert item.task == task;
+ add(item);
+ }
+
+ public ItemList<T> values() {
+ return this;
+ }
/**
- * Works like {@link #remove(Task)} but also marks the {@link Item} as cancelled.
+ * Works like {@link #remove(Task)} but also marks the {@link Item} as
+ * cancelled.
*/
public T cancel(Task p) {
T x = remove(p);
- if(x!=null) x.onCancelled();
+ if (x != null) {
+ x.onCancelled();
+ }
return x;
}
/**
- * Works like {@link #remove(Object)} but also marks the {@link Item} as cancelled.
+ * Works like {@link #remove(Object)} but also marks the {@link Item} as
+ * cancelled.
*/
public boolean cancel(Item t) {
boolean r = remove(t);
- if(r) t.onCancelled();
+ if (r) {
+ t.onCancelled();
+ }
return r;
}
public void cancelAll() {
- for (T t : this)
+ for (T t : this) {
t.onCancelled();
+ }
clear();
}
}
@@ -1652,7 +1759,7 @@ public class Queue extends ResourceController implements Saveable {
/**
* Restores the queue content during the start up.
*/
- @Initializer(after=JOB_LOADED)
+ @Initializer(after = JOB_LOADED)
public static void init(Hudson h) {
h.getQueue().load();
}
diff --git a/hudson-core/src/main/java/hudson/model/Run.java b/hudson-core/src/main/java/hudson/model/Run.java
index 5c87d50..4233ab2 100644
--- a/hudson-core/src/main/java/hudson/model/Run.java
+++ b/hudson-core/src/main/java/hudson/model/Run.java
@@ -7,10 +7,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
- * Contributors:
+ * Contributors:
*
* Kohsuke Kawaguchi, Daniel Dyer, Red Hat, Inc., Tom Huybrechts, Romain Seguy, Yahoo! Inc., Darek Ostolski
- *
+ *
*
*******************************************************************************/
@@ -106,76 +106,69 @@ import static java.util.logging.Level.FINE;
/**
* A particular execution of {@link Job}.
*
- * <p>
- * Custom {@link Run} type is always used in conjunction with
- * a custom {@link Job} type, so there's no separate registration
- * mechanism for custom {@link Run} types.
+ * <p> Custom {@link Run} type is always used in conjunction with a custom
+ * {@link Job} type, so there's no separate registration mechanism for custom
+ * {@link Run} types.
*
* @author Kohsuke Kawaguchi
* @see RunListener
*/
@ExportedBean
-public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,RunT>>
+public abstract class Run<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, RunT>>
extends Actionable implements ExtensionPoint, Comparable<RunT>, AccessControlled, PersistenceRoot, DescriptorByNameOwner {
protected transient final JobT project;
-
/**
* Build number.
*
- * <p>
- * In earlier versions &lt; 1.24, this number is not unique nor continuous,
- * but going forward, it will, and this really replaces the build id.
+ * <p> In earlier versions &lt; 1.24, this number is not unique nor
+ * continuous, but going forward, it will, and this really replaces the
+ * build id.
*/
public /*final*/ int number;
-
/**
- * Previous build. Can be null.
- * These two fields are maintained and updated by {@link RunMap}.
+ * Previous build. Can be null. These two fields are maintained and updated
+ * by {@link RunMap}.
*/
protected volatile transient RunT previousBuild;
-
/**
* Next build. Can be null.
*/
protected volatile transient RunT nextBuild;
-
/**
- * Pointer to the next younger build in progress. This data structure is lazily updated,
- * so it may point to the build that's already completed. This pointer is set to 'this'
- * if the computation determines that everything earlier than this build is already completed.
+ * Pointer to the next younger build in progress. This data structure is
+ * lazily updated, so it may point to the build that's already completed.
+ * This pointer is set to 'this' if the computation determines that
+ * everything earlier than this build is already completed.
*/
/* does not compile on JDK 7: private*/ volatile transient RunT previousBuildInProgress;
-
/**
* When the build is scheduled.
*/
protected transient final long timestamp;
-
/**
- * The build result.
- * This value may change while the state is in {@link State#BUILDING}.
+ * The build result. This value may change while the state is in
+ * {@link State#BUILDING}.
*/
protected volatile Result result;
-
/**
* Human-readable description. Can be null.
*/
protected volatile String description;
-
/**
- * Human-readable name of this build. Can be null.
- * If non-null, this text is displayed instead of "#NNN", which is the default.
+ * Human-readable name of this build. Can be null. If non-null, this text is
+ * displayed instead of "#NNN", which is the default.
+ *
* @since 1.390
*/
private volatile String displayName;
-
/**
* The current build state.
*/
protected volatile transient State state;
private static enum State {
+
/**
* Build is created/queued but we haven't started building it.
*/
@@ -185,8 +178,8 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
BUILDING,
/**
- * Build is completed now, and the status is determined,
- * but log files are still being updated.
+ * Build is completed now, and the status is determined, but log files
+ * are still being updated.
*/
POST_PRODUCTION,
/**
@@ -194,33 +187,28 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
COMPLETED
}
-
/**
* Number of milli-seconds it took to run this build.
*/
protected long duration;
-
/**
- * Charset in which the log file is written.
- * For compatibility reason, this field may be null.
- * For persistence, this field is string and not {@link Charset}.
+ * Charset in which the log file is written. For compatibility reason, this
+ * field may be null. For persistence, this field is string and not
+ * {@link Charset}.
*
* @see #getCharset()
* @since 1.257
*/
protected String charset;
-
/**
* Keeps this log entries.
*/
private boolean keepLog;
-
/**
* If the build is in progress, remember {@link Runner} that's running it.
* This field is not persisted.
*/
private volatile transient Runner runner;
-
protected static final ThreadLocal<SimpleDateFormat> ID_FORMATTER =
new ThreadLocal<SimpleDateFormat>() {
@Override
@@ -238,11 +226,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Constructor for creating a {@link Run} object in
- * an arbitrary state.
+ * Constructor for creating a {@link Run} object in an arbitrary state.
*/
protected Run(JobT job, Calendar timestamp) {
- this(job,timestamp.getTimeInMillis());
+ this(job, timestamp.getTimeInMillis());
}
protected Run(JobT job, long timestamp) {
@@ -263,28 +250,32 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Called after the build is loaded and the object is added to the build list.
+ * Called after the build is loaded and the object is added to the build
+ * list.
*/
protected void onLoad() {
- for (Action a : getActions())
- if (a instanceof RunAction)
+ for (Action a : getActions()) {
+ if (a instanceof RunAction) {
((RunAction) a).onLoad();
+ }
+ }
}
@Override
public void addAction(Action a) {
super.addAction(a);
- if (a instanceof RunAction)
+ if (a instanceof RunAction) {
((RunAction) a).onAttached(this);
+ }
}
/*package*/ static long parseTimestampFromBuildDir(File buildDir) throws IOException {
try {
return ID_FORMATTER.get().parse(buildDir.getName()).getTime();
} catch (ParseException e) {
- throw new IOException2("Invalid directory name "+buildDir,e);
+ throw new IOException2("Invalid directory name " + buildDir, e);
} catch (NumberFormatException e) {
- throw new IOException2("Invalid directory name "+buildDir,e);
+ throw new IOException2("Invalid directory name " + buildDir, e);
}
}
@@ -293,7 +284,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
@SuppressWarnings({"unchecked"})
private RunT _this() {
- return (RunT)this;
+ return (RunT) this;
}
/**
@@ -306,8 +297,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Returns the build result.
*
- * <p>
- * When a build is {@link #isBuilding() in progress}, this method
+ * <p> When a build is {@link #isBuilding() in progress}, this method
* returns an intermediate result.
*/
@Exported
@@ -317,44 +307,50 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
public void setResult(Result r) {
// state can change only when we are building
- assert state==State.BUILDING;
+ assert state == State.BUILDING;
// result can only get worse
- if(result==null) {
+ if (result == null) {
result = r;
- LOGGER.log(FINE, toString()+" : result is set to "+r,new Exception());
+ LOGGER.log(FINE, toString() + " : result is set to " + r, new Exception());
} else {
- if(r.isWorseThan(result)) {
- LOGGER.log(FINE, toString()+" : result is set to "+r,new Exception());
+ if (r.isWorseThan(result)) {
+ LOGGER.log(FINE, toString() + " : result is set to " + r, new Exception());
result = r;
}
}
}
/**
- * Gets the subset of {@link #getActions()} that consists of {@link BuildBadgeAction}s.
+ * Gets the subset of {@link #getActions()} that consists of
+ * {@link BuildBadgeAction}s.
*/
public List<BuildBadgeAction> getBadgeActions() {
List<BuildBadgeAction> r = null;
for (Action a : getActions()) {
- if(a instanceof BuildBadgeAction) {
- if(r==null)
+ if (a instanceof BuildBadgeAction) {
+ if (r == null) {
r = new ArrayList<BuildBadgeAction>();
- r.add((BuildBadgeAction)a);
+ }
+ r.add((BuildBadgeAction) a);
}
}
- if(isKeepLog()) {
- if(r==null)
+ if (isKeepLog()) {
+ if (r == null) {
r = new ArrayList<BuildBadgeAction>();
+ }
r.add(new KeepLogBuildBadge());
}
- if(r==null) return Collections.emptyList();
- else return r;
+ if (r == null) {
+ return Collections.emptyList();
+ } else {
+ return r;
+ }
}
/**
- * Returns true if the build is not completed yet.
- * This includes "not started yet" state.
+ * Returns true if the build is not completed yet. This includes "not
+ * started yet" state.
*/
@Exported
public boolean isBuilding() {
@@ -373,10 +369,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Otherwise null.
*/
public Executor getExecutor() {
- for( Computer c : Hudson.getInstance().getComputers() ) {
+ for (Computer c : Hudson.getInstance().getComputers()) {
for (Executor e : c.getExecutors()) {
- if(e.getCurrentExecutable()==this)
+ if (e.getCurrentExecutable() == this) {
return e;
+ }
}
}
return null;
@@ -384,28 +381,32 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Gets the charset in which the log file is written.
+ *
* @return never null.
* @since 1.257
*/
public final Charset getCharset() {
- if(charset==null) return Charset.defaultCharset();
+ if (charset == null) {
+ return Charset.defaultCharset();
+ }
return Charset.forName(charset);
}
/**
* Returns the {@link Cause}s that tirggered a build.
*
- * <p>
- * If a build sits in the queue for a long time, multiple build requests made during this period
- * are all rolled up into one build, hence this method may return a list.
+ * <p> If a build sits in the queue for a long time, multiple build requests
+ * made during this period are all rolled up into one build, hence this
+ * method may return a list.
*
- * @return
- * can be empty but never null. read-only.
+ * @return can be empty but never null. read-only.
* @since 1.321
*/
public List<Cause> getCauses() {
CauseAction a = getAction(CauseAction.class);
- if (a==null) return Collections.emptyList();
+ if (a == null) {
+ return Collections.emptyList();
+ }
return Collections.unmodifiableList(a.getCauses());
}
@@ -415,9 +416,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* @since 1.362
*/
public <T extends Cause> T getCause(Class<T> type) {
- for (Cause c : getCauses())
- if (type.isInstance(c))
+ for (Cause c : getCauses()) {
+ if (type.isInstance(c)) {
return type.cast(c);
+ }
+ }
return null;
}
@@ -428,16 +431,17 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
@Exported
public final boolean isKeepLog() {
- return getWhyKeepLog()!=null;
+ return getWhyKeepLog() != null;
}
/**
- * If {@link #isKeepLog()} returns true, returns a human readable
- * one-line string that explains why it's being kept.
+ * If {@link #isKeepLog()} returns true, returns a human readable one-line
+ * string that explains why it's being kept.
*/
public String getWhyKeepLog() {
- if(keepLog)
+ if (keepLog) {
return Messages.Run_MarkedExplicitly();
+ }
return null; // not marked at all
}
@@ -466,7 +470,8 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Same as {@link #getTimestamp()} but in a different type, that is since the time of the epoc.
+ * Same as {@link #getTimestamp()} but in a different type, that is since
+ * the time of the epoc.
*/
public final long getTimeInMillis() {
return timestamp;
@@ -477,9 +482,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
return description;
}
-
/**
* Returns the length-limited description.
+ *
* @return The length-limited description.
*/
public String getTruncatedDescription() {
@@ -495,9 +500,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
int displayChars = 0;
int lastTruncatablePoint = -1;
- for (int i=0; i<sz; i++) {
+ for (int i = 0; i < sz; i++) {
char ch = description.charAt(i);
- if(ch == '<') {
+ if (ch == '<') {
inTag = true;
} else if (ch == '>') {
inTag = false;
@@ -516,25 +521,25 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
String truncDesc = description;
// Could not find a preferred truncable index, force a trunc at maxTruncLength
- if (lastTruncatablePoint == -1)
+ if (lastTruncatablePoint == -1) {
lastTruncatablePoint = maxTruncLength;
+ }
if (displayChars >= maxDescrLength) {
truncDesc = truncDesc.substring(0, lastTruncatablePoint) + ending;
}
-
+
return truncDesc;
-
+
}
/**
* Gets the string that says how long since this build has started.
*
- * @return
- * string like "3 minutes" "1 day" etc.
+ * @return string like "3 minutes" "1 day" etc.
*/
public String getTimestampString() {
- long duration = new GregorianCalendar().getTimeInMillis()-timestamp;
+ long duration = new GregorianCalendar().getTimeInMillis() - timestamp;
return Util.getPastTimeString(duration);
}
@@ -549,9 +554,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Gets the string that says how long the build took to run.
*/
public String getDurationString() {
- if(isBuilding())
+ if (isBuilding()) {
return Messages.Run_InProgressDuration(
- Util.getTimeSpanString(System.currentTimeMillis()-timestamp));
+ Util.getTimeSpanString(System.currentTimeMillis() - timestamp));
+ }
return Util.getTimeSpanString(duration);
}
@@ -567,17 +573,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Gets the icon color for display.
*/
public BallColor getIconColor() {
- if(!isBuilding()) {
+ if (!isBuilding()) {
// already built
return getResult().color;
}
// a new build is in progress
BallColor baseColor;
- if(previousBuild==null)
+ if (previousBuild == null) {
baseColor = BallColor.GREY;
- else
+ } else {
baseColor = previousBuild.getIconColor();
+ }
return baseColor.anime();
}
@@ -586,7 +593,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Returns true if the build is still queued and hasn't started yet.
*/
public boolean hasntStartedYet() {
- return state ==State.NOT_STARTED;
+ return state == State.NOT_STARTED;
}
@Override
@@ -595,25 +602,24 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
public String getFullName() {
- return project.getFullName()+" #"+number;
+ return project.getFullName() + " #" + number;
}
@Exported
public String getFullDisplayName() {
- return project.getFullDisplayName()+' '+getDisplayName();
+ return project.getFullDisplayName() + ' ' + getDisplayName();
}
public String getDisplayName() {
- return displayName!=null ? displayName : "#"+number;
+ return displayName != null ? displayName : "#" + number;
}
public boolean hasCustomDisplayName() {
- return displayName!=null;
+ return displayName != null;
}
/**
- * @param value
- * Set to null to revert back to the default "#NNN".
+ * @param value Set to null to revert back to the default "#NNN".
*/
public void setDisplayName(String value) throws IOException {
checkPermission(UPDATE);
@@ -621,7 +627,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
save();
}
- @Exported(visibility=2)
+ @Exported(visibility = 2)
public int getNumber() {
return number;
}
@@ -631,36 +637,39 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Gets the most recent {@linkplain #isBuilding() completed} build excluding 'this' Run itself.
+ * Gets the most recent {@linkplain #isBuilding() completed} build excluding
+ * 'this' Run itself.
*/
public final RunT getPreviousCompletedBuild() {
- RunT r=getPreviousBuild();
- while (r!=null && r.isBuilding())
- r=r.getPreviousBuild();
+ RunT r = getPreviousBuild();
+ while (r != null && r.isBuilding()) {
+ r = r.getPreviousBuild();
+ }
return r;
}
/**
- * Obtains the next younger build in progress. It uses a skip-pointer so that we can compute this without
- * O(n) computation time. This method also fixes up the skip list as we go, in a way that's concurrency safe.
+ * Obtains the next younger build in progress. It uses a skip-pointer so
+ * that we can compute this without O(n) computation time. This method also
+ * fixes up the skip list as we go, in a way that's concurrency safe.
*
- * <p>
- * We basically follow the existing skip list, and wherever we find a non-optimal pointer, we remember them
- * in 'fixUp' and update them later.
+ * <p> We basically follow the existing skip list, and wherever we find a
+ * non-optimal pointer, we remember them in 'fixUp' and update them later.
*/
public final RunT getPreviousBuildInProgress() {
- if(previousBuildInProgress==this) return null; // the most common case
-
+ if (previousBuildInProgress == this) {
+ return null; // the most common case
+ }
List<RunT> fixUp = new ArrayList<RunT>();
RunT r = _this(); // 'r' is the source of the pointer (so that we can add it to fix up if we find that the target of the pointer is inefficient.)
RunT answer;
while (true) {
RunT n = r.previousBuildInProgress;
- if (n==null) {// no field computed yet.
- n=r.getPreviousBuild();
+ if (n == null) {// no field computed yet.
+ n = r.getPreviousBuild();
fixUp.add(r);
}
- if (r==n || n==null) {
+ if (r == n || n == null) {
// this indicates that we know there's no build in progress beyond this point
answer = null;
break;
@@ -676,19 +685,22 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
// fix up so that the next look up will run faster
- for (RunT f : fixUp)
- f.previousBuildInProgress = answer==null ? f : answer;
+ for (RunT f : fixUp) {
+ f.previousBuildInProgress = answer == null ? f : answer;
+ }
return answer;
}
/**
- * Returns the last build that was actually built - i.e., skipping any with Result.NOT_BUILT
+ * Returns the last build that was actually built - i.e., skipping any with
+ * Result.NOT_BUILT
*/
public RunT getPreviousBuiltBuild() {
- RunT r=previousBuild;
+ RunT r = previousBuild;
// in certain situations (aborted m2 builds) r.getResult() can still be null, although it should theoretically never happen
- while( r!=null && (r.getResult() == null || r.getResult()==Result.NOT_BUILT) )
- r=r.previousBuild;
+ while (r != null && (r.getResult() == null || r.getResult() == Result.NOT_BUILT)) {
+ r = r.previousBuild;
+ }
return r;
}
@@ -696,9 +708,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Returns the last build that didn't fail before this build.
*/
public RunT getPreviousNotFailedBuild() {
- RunT r=previousBuild;
- while( r!=null && r.getResult()==Result.FAILURE )
- r=r.previousBuild;
+ RunT r = previousBuild;
+ while (r != null && r.getResult() == Result.FAILURE) {
+ r = r.previousBuild;
+ }
return r;
}
@@ -706,45 +719,49 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Returns the last failed build before this build.
*/
public RunT getPreviousFailedBuild() {
- RunT r=previousBuild;
- while( r!=null && r.getResult()!=Result.FAILURE )
- r=r.previousBuild;
+ RunT r = previousBuild;
+ while (r != null && r.getResult() != Result.FAILURE) {
+ r = r.previousBuild;
+ }
return r;
}
/**
* Returns the last successful build before this build.
+ *
* @since 1.383
*/
public RunT getPreviousSuccessfulBuild() {
- RunT r=previousBuild;
- while( r!=null && r.getResult()!=Result.SUCCESS )
- r=r.previousBuild;
+ RunT r = previousBuild;
+ while (r != null && r.getResult() != Result.SUCCESS) {
+ r = r.previousBuild;
+ }
return r;
}
/**
- * Returns the last 'numberOfBuilds' builds with a build result >= 'threshold'.
- *
+ * Returns the last 'numberOfBuilds' builds with a build result >=
+ * 'threshold'.
+ *
* @param numberOfBuilds the desired number of builds
* @param threshold the build result threshold
- * @return a list with the builds (youngest build first).
- * May be smaller than 'numberOfBuilds' or even empty
- * if not enough builds satisfying the threshold have been found. Never null.
+ * @return a list with the builds (youngest build first). May be smaller
+ * than 'numberOfBuilds' or even empty if not enough builds satisfying the
+ * threshold have been found. Never null.
* @since 1.383
*/
public List<RunT> getPreviousBuildsOverThreshold(int numberOfBuilds, Result threshold) {
List<RunT> builds = new ArrayList<RunT>(numberOfBuilds);
-
+
RunT r = getPreviousBuild();
while (r != null && builds.size() < numberOfBuilds) {
- if (!r.isBuilding() &&
- (r.getResult() != null && r.getResult().isBetterOrEqualTo(threshold))) {
+ if (!r.isBuilding()
+ && (r.getResult() != null && r.getResult().isBetterOrEqualTo(threshold))) {
builds.add(r);
}
r = r.getPreviousBuild();
}
-
+
return builds;
}
@@ -753,33 +770,34 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Returns the URL of this {@link Run}, relative to the context root of Hudson.
+ * Returns the URL of this {@link Run}, relative to the context root of
+ * Hudson.
*
- * @return
- * String like "job/foo/32/" with trailing slash but no leading slash.
+ * @return String like "job/foo/32/" with trailing slash but no leading
+ * slash.
*/
// I really messed this up. I'm hoping to fix this some time
// it shouldn't have trailing '/', and instead it should have leading '/'
public String getUrl() {
- return project.getUrl()+getNumber()+'/';
+ return project.getUrl() + getNumber() + '/';
}
/**
* Obtains the absolute URL to this build.
*
- * @deprecated
- * This method shall <b>NEVER</b> be used during HTML page rendering, as it won't work with
- * network set up like Apache reverse proxy.
- * This method is only intended for the remote API clients who cannot resolve relative references
- * (even this won't work for the same reason, which should be fixed.)
+ * @deprecated This method shall <b>NEVER</b> be used during HTML page
+ * rendering, as it won't work with network set up like Apache reverse
+ * proxy. This method is only intended for the remote API clients who cannot
+ * resolve relative references (even this won't work for the same reason,
+ * which should be fixed.)
*/
- @Exported(visibility=2,name="url")
+ @Exported(visibility = 2, name = "url")
public final String getAbsoluteUrl() {
- return project.getAbsoluteUrl()+getNumber()+'/';
+ return project.getAbsoluteUrl() + getNumber() + '/';
}
public final String getSearchUrl() {
- return getNumber()+"/";
+ return getNumber() + "/";
}
/**
@@ -789,14 +807,14 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
public String getId() {
return ID_FORMATTER.get().format(new Date(timestamp));
}
-
+
/**
- * Get the date formatter used to convert the directory name in to a timestamp
- * This is nasty exposure of private data, but needed all the time the directory
- * containing the build is used as it's timestamp.
+ * Get the date formatter used to convert the directory name in to a
+ * timestamp This is nasty exposure of private data, but needed all the time
+ * the directory containing the build is used as it's timestamp.
*/
public static DateFormat getIDFormatter() {
- return ID_FORMATTER.get();
+ return ID_FORMATTER.get();
}
public Descriptor getDescriptorByName(String className) {
@@ -809,7 +827,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Files related to this {@link Run} should be stored below this directory.
*/
public File getRootDir() {
- File f = new File(project.getBuildDir(),getId());
+ File f = new File(project.getBuildDir(), getId());
f.mkdirs();
return f;
}
@@ -818,7 +836,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Gets the directory where the artifacts are archived.
*/
public File getArtifactsDir() {
- return new File(getRootDir(),"archive");
+ return new File(getRootDir(), "archive");
}
/**
@@ -834,7 +852,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
public List<Artifact> getArtifactsUpTo(int n) {
ArtifactList r = new ArtifactList();
- addArtifacts(getArtifactsDir(),"","",r,null,n);
+ addArtifacts(getArtifactsDir(), "", "", r, null, n);
r.computeDisplayName();
return r;
}
@@ -842,16 +860,17 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Returns true if this run has any artifacts.
*
- * <p>
- * The strange method name is so that we can access it from EL.
+ * <p> The strange method name is so that we can access it from EL.
*/
public boolean getHasArtifacts() {
return !getArtifactsUpTo(1).isEmpty();
}
- private int addArtifacts( File dir, String path, String pathHref, ArtifactList r, Artifact parent, int upTo ) {
+ private int addArtifacts(File dir, String path, String pathHref, ArtifactList r, Artifact parent, int upTo) {
String[] children = dir.list();
- if(children==null) return 0;
+ if (children == null) {
+ return 0;
+ }
Arrays.sort(children, String.CASE_INSENSITIVE_ORDER);
int n = 0;
@@ -859,88 +878,96 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
String childPath = path + child;
String childHref = pathHref + Util.rawEncode(child);
File sub = new File(dir, child);
- boolean collapsed = (children.length==1 && parent!=null);
+ boolean collapsed = (children.length == 1 && parent != null);
Artifact a;
if (collapsed) {
// Collapse single items into parent node where possible:
a = new Artifact(parent.getFileName() + '/' + child, childPath,
- sub.isDirectory() ? null : childHref, parent.getTreeNodeId());
+ sub.isDirectory() ? null : childHref, parent.getTreeNodeId());
r.tree.put(a, r.tree.remove(parent));
} else {
// Use null href for a directory:
a = new Artifact(child, childPath,
- sub.isDirectory() ? null : childHref, "n" + ++r.idSeq);
- r.tree.put(a, parent!=null ? parent.getTreeNodeId() : null);
+ sub.isDirectory() ? null : childHref, "n" + ++r.idSeq);
+ r.tree.put(a, parent != null ? parent.getTreeNodeId() : null);
}
if (sub.isDirectory()) {
- n += addArtifacts(sub, childPath + '/', childHref + '/', r, a, upTo-n);
- if (n>=upTo) break;
+ n += addArtifacts(sub, childPath + '/', childHref + '/', r, a, upTo - n);
+ if (n >= upTo) {
+ break;
+ }
} else {
// Don't store collapsed path in ArrayList (for correct data in external API)
r.add(collapsed ? new Artifact(child, a.relativePath, a.href, a.treeNodeId) : a);
- if (++n>=upTo) break;
+ if (++n >= upTo) {
+ break;
+ }
}
}
return n;
}
-
/**
- * Maximum number of artifacts to list before using switching to the tree view.
+ * Maximum number of artifacts to list before using switching to the tree
+ * view.
*/
public static final int LIST_CUTOFF = Integer.parseInt(System.getProperty("hudson.model.Run.ArtifactList.listCutoff", "16"));
-
/**
- * Maximum number of artifacts to show in tree view before just showing a link.
+ * Maximum number of artifacts to show in tree view before just showing a
+ * link.
*/
public static final int TREE_CUTOFF = Integer.parseInt(System.getProperty("hudson.model.Run.ArtifactList.treeCutoff", "40"));
// ..and then "too many"
-
public final class ArtifactList extends ArrayList<Artifact> {
+
/**
- * Map of Artifact to treeNodeId of parent node in tree view.
- * Contains Artifact objects for directories and files (the ArrayList contains only files).
+ * Map of Artifact to treeNodeId of parent node in tree view. Contains
+ * Artifact objects for directories and files (the ArrayList contains
+ * only files).
*/
- private LinkedHashMap<Artifact,String> tree = new LinkedHashMap<Artifact,String>();
+ private LinkedHashMap<Artifact, String> tree = new LinkedHashMap<Artifact, String>();
private int idSeq = 0;
- public Map<Artifact,String> getTree() {
+ public Map<Artifact, String> getTree() {
return tree;
}
public void computeDisplayName() {
- if(size()>LIST_CUTOFF) return; // we are not going to display file names, so no point in computing this
-
+ if (size() > LIST_CUTOFF) {
+ return; // we are not going to display file names, so no point in computing this
+ }
int maxDepth = 0;
int[] len = new int[size()];
String[][] tokens = new String[size()][];
- for( int i=0; i<tokens.length; i++ ) {
+ for (int i = 0; i < tokens.length; i++) {
tokens[i] = get(i).relativePath.split("[\\\\/]+");
- maxDepth = Math.max(maxDepth,tokens[i].length);
+ maxDepth = Math.max(maxDepth, tokens[i].length);
len[i] = 1;
}
boolean collision;
- int depth=0;
+ int depth = 0;
do {
collision = false;
- Map<String,Integer/*index*/> names = new HashMap<String,Integer>();
+ Map<String, Integer/*index*/> names = new HashMap<String, Integer>();
for (int i = 0; i < tokens.length; i++) {
String[] token = tokens[i];
- String displayName = combineLast(token,len[i]);
+ String displayName = combineLast(token, len[i]);
Integer j = names.put(displayName, i);
- if(j!=null) {
+ if (j != null) {
collision = true;
- if(j>=0)
+ if (j >= 0) {
len[j]++;
+ }
len[i]++;
- names.put(displayName,-1); // occupy this name but don't let len[i] incremented with additional collisions
+ names.put(displayName, -1); // occupy this name but don't let len[i] incremented with additional collisions
}
}
- } while(collision && depth++<maxDepth);
+ } while (collision && depth++ < maxDepth);
- for (int i = 0; i < tokens.length; i++)
- get(i).displayPath = combineLast(tokens[i],len[i]);
+ for (int i = 0; i < tokens.length; i++) {
+ get(i).displayPath = combineLast(tokens[i], len[i]);
+ }
// OUTER:
// for( int n=1; n<maxLen; n++ ) {
@@ -970,8 +997,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
private String combineLast(String[] token, int n) {
StringBuilder buf = new StringBuilder();
- for( int i=Math.max(0,token.length-n); i<token.length; i++ ) {
- if(buf.length()>0) buf.append('/');
+ for (int i = Math.max(0, token.length - n); i < token.length; i++) {
+ if (buf.length() > 0) {
+ buf.append('/');
+ }
buf.append(token[i]);
}
return buf.toString();
@@ -983,30 +1012,28 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
@ExportedBean
public class Artifact {
+
/**
* Relative path name from {@link Run#getArtifactsDir()}
*/
- @Exported(visibility=3)
+ @Exported(visibility = 3)
public final String relativePath;
-
/**
- * Truncated form of {@link #relativePath} just enough
- * to disambiguate {@link Artifact}s.
+ * Truncated form of {@link #relativePath} just enough to disambiguate
+ * {@link Artifact}s.
*/
/*package*/ String displayPath;
-
/**
- * The filename of the artifact.
- * (though when directories with single items are collapsed for tree view, name may
- * include multiple path components, like "dist/pkg/mypkg")
+ * The filename of the artifact. (though when directories with single
+ * items are collapsed for tree view, name may include multiple path
+ * components, like "dist/pkg/mypkg")
*/
private String name;
-
/**
- * Properly encoded relativePath for use in URLs. This field is null for directories.
+ * Properly encoded relativePath for use in URLs. This field is null for
+ * directories.
*/
private String href;
-
/**
* Id of this node for use in tree view.
*/
@@ -1023,18 +1050,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Gets the artifact file.
*/
public File getFile() {
- return new File(getArtifactsDir(),relativePath);
+ return new File(getArtifactsDir(), relativePath);
}
/**
* Returns just the file name portion, without the path.
*/
- @Exported(visibility=3)
+ @Exported(visibility = 3)
public String getFileName() {
return name;
}
- @Exported(visibility=3)
+ @Exported(visibility = 3)
public String getDisplayPath() {
return displayPath;
}
@@ -1057,62 +1084,66 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Returns the log file.
*/
public File getLogFile() {
- return new File(getRootDir(),"log");
+ return new File(getRootDir(), "log");
}
/**
- * Returns an input stream that reads from the log file.
- * It will use a gzip-compressed log file (log.gz) if that exists.
+ * Returns an input stream that reads from the log file. It will use a
+ * gzip-compressed log file (log.gz) if that exists.
*
- * @throws IOException
+ * @throws IOException
* @return an input stream from the log file, or null if none exists
* @since 1.349
*/
public InputStream getLogInputStream() throws IOException {
- File logFile = getLogFile();
- if (logFile.exists() ) {
+ File logFile = getLogFile();
+ if (logFile.exists()) {
return new FileInputStream(logFile);
- }
+ }
- File compressedLogFile = new File(logFile.getParentFile(), logFile.getName()+ ".gz");
- if (compressedLogFile.exists()) {
+ File compressedLogFile = new File(logFile.getParentFile(), logFile.getName() + ".gz");
+ if (compressedLogFile.exists()) {
return new GZIPInputStream(new FileInputStream(compressedLogFile));
- }
-
- return new NullInputStream(0);
+ }
+
+ return new NullInputStream(0);
}
public Reader getLogReader() throws IOException {
- if (charset==null) return new InputStreamReader(getLogInputStream());
- else return new InputStreamReader(getLogInputStream(),charset);
+ if (charset == null) {
+ return new InputStreamReader(getLogInputStream());
+ } else {
+ return new InputStreamReader(getLogInputStream(), charset);
+ }
}
/**
- * Used from <tt>console.jelly</tt> to write annotated log to the given output.
+ * Used from <tt>console.jelly</tt> to write annotated log to the given
+ * output.
*
* @since 1.349
*/
public void writeLogTo(long offset, XMLOutput out) throws IOException {
try {
- getLogText().writeHtmlTo(offset,out.asWriter());
- } catch (IOException e) {
- // try to fall back to the old getLogInputStream()
- // mainly to support .gz compressed files
- // In this case, console annotation handling will be turned off.
- InputStream input = getLogInputStream();
- try {
- IOUtils.copy(input, out.asWriter());
- } finally {
- IOUtils.closeQuietly(input);
- }
- }
+ getLogText().writeHtmlTo(offset, out.asWriter());
+ } catch (IOException e) {
+ // try to fall back to the old getLogInputStream()
+ // mainly to support .gz compressed files
+ // In this case, console annotation handling will be turned off.
+ InputStream input = getLogInputStream();
+ try {
+ IOUtils.copy(input, out.asWriter());
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+ }
}
/**
* Used to URL-bind {@link AnnotatedLargeText}.
*/
public AnnotatedLargeText getLogText() {
- return new AnnotatedLargeText(getLogFile(),getCharset(),!isLogUpdated(),this);
+ return new AnnotatedLargeText(getLogFile(), getCharset(), !isLogUpdated(), this);
}
@Override
@@ -1121,8 +1152,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
.add("console")
.add("changes");
for (Action a : getActions()) {
- if(a.getIconFileName()!=null)
+ if (a.getIconFileName() != null) {
builder.add(a.getUrlName());
+ }
}
return builder;
}
@@ -1145,10 +1177,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Deletes this build's artifacts.
+ * Deletes this build's artifacts.
*
- * @throws IOException
- * if we fail to delete.
+ * @throws IOException if we fail to delete.
*
* @since 1.350
*/
@@ -1161,8 +1192,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Deletes this build and its entire log
*
- * @throws IOException
- * if we fail to delete.
+ * @throws IOException if we fail to delete.
*/
public synchronized void delete() throws IOException {
RunListener.fireDeleted(this);
@@ -1172,27 +1202,28 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
link.delete();
File rootDir = getRootDir();
- File tmp = new File(rootDir.getParentFile(),'.'+rootDir.getName());
-
+ File tmp = new File(rootDir.getParentFile(), '.' + rootDir.getName());
+
boolean renamingSucceeded = rootDir.renameTo(tmp);
Util.deleteRecursive(tmp);
// some user reported that they see some left-over .xyz files in the workspace,
// so just to make sure we've really deleted it, schedule the deletion on VM exit, too.
- if(tmp.exists())
+ if (tmp.exists()) {
tmp.deleteOnExit();
+ }
- if(!renamingSucceeded)
- throw new IOException(rootDir+" is in use");
+ if (!renamingSucceeded) {
+ throw new IOException(rootDir + " is in use");
+ }
removeRunFromParent();
}
@SuppressWarnings("unchecked") // seems this is too clever for Java's type system?
private void removeRunFromParent() {
- getParent().removeRun((RunT)this);
+ getParent().removeRun((RunT) this);
}
-
/**
* @see CheckPoint#report()
*/
@@ -1204,34 +1235,38 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* @see CheckPoint#block()
*/
/*package*/ static void waitForCheckpoint(CheckPoint id) throws InterruptedException {
- while(true) {
+ while (true) {
Run b = RunnerStack.INSTANCE.peek().getBuild().getPreviousBuildInProgress();
- if(b==null) return; // no pending earlier build
+ if (b == null) {
+ return; // no pending earlier build
+ }
Run.Runner runner = b.runner;
- if(runner==null) {
+ if (runner == null) {
// polled at the wrong moment. try again.
Thread.sleep(0);
continue;
}
- if(runner.checkpoints.waitForCheckPoint(id))
+ if (runner.checkpoints.waitForCheckPoint(id)) {
return; // confirmed that the previous build reached the check point
-
+ }
// the previous build finished without ever reaching the check point. try again.
}
}
protected abstract class Runner {
+
/**
- * Keeps track of the check points attained by a build, and abstracts away the synchronization needed to
- * maintain this data structure.
+ * Keeps track of the check points attained by a build, and abstracts
+ * away the synchronization needed to maintain this data structure.
*/
private final class CheckpointSet {
+
/**
- * Stages of the builds that this runner has completed. This is used for concurrent {@link Runner}s to
- * coordinate and serialize their executions where necessary.
+ * Stages of the builds that this runner has completed. This is used
+ * for concurrent {@link Runner}s to coordinate and serialize their
+ * executions where necessary.
*/
private final Set<CheckPoint> checkpoints = new HashSet<CheckPoint>();
-
private boolean allDone;
protected synchronized void report(CheckPoint identifier) {
@@ -1242,10 +1277,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
protected synchronized boolean waitForCheckPoint(CheckPoint identifier) throws InterruptedException {
final Thread t = Thread.currentThread();
final String oldName = t.getName();
- t.setName(oldName+" : waiting for "+identifier+" on "+getFullDisplayName());
+ t.setName(oldName + " : waiting for " + identifier + " on " + getFullDisplayName());
try {
- while(!allDone && !checkpoints.contains(identifier))
+ while (!allDone && !checkpoints.contains(identifier)) {
wait();
+ }
return checkpoints.contains(identifier);
} finally {
t.setName(oldName);
@@ -1253,45 +1289,41 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Notifies that the build is fully completed and all the checkpoint locks be released.
+ * Notifies that the build is fully completed and all the checkpoint
+ * locks be released.
*/
private synchronized void allDone() {
allDone = true;
notifyAll();
}
}
-
private final CheckpointSet checkpoints = new CheckpointSet();
/**
* Performs the main build and returns the status code.
*
- * @throws Exception
- * exception will be recorded and the build will be considered a failure.
+ * @throws Exception exception will be recorded and the build will be
+ * considered a failure.
*/
- public abstract Result run( BuildListener listener ) throws Exception, RunnerAbortedException;
+ public abstract Result run(BuildListener listener) throws Exception, RunnerAbortedException;
/**
- * Performs the post-build action.
- * <p>
- * This method is called after {@linkplain #run(BuildListener) the main portion of the build is completed.}
- * This is a good opportunity to do notifications based on the result
- * of the build. When this method is called, the build is not really
- * finalized yet, and the build is still considered in progress --- for example,
- * even if the build is successful, this build still won't be picked up
- * by {@link Job#getLastSuccessfulBuild()}.
+ * Performs the post-build action. <p> This method is called after
+ * {@linkplain #run(BuildListener) the main portion of the build is completed.}
+ * This is a good opportunity to do notifications based on the result of
+ * the build. When this method is called, the build is not really
+ * finalized yet, and the build is still considered in progress --- for
+ * example, even if the build is successful, this build still won't be
+ * picked up by {@link Job#getLastSuccessfulBuild()}.
*/
- public abstract void post( BuildListener listener ) throws Exception;
+ public abstract void post(BuildListener listener) throws Exception;
/**
- * Performs final clean up action.
- * <p>
- * This method is called after {@link #post(BuildListener)},
- * after the build result is fully finalized. This is the point
- * where the build is already considered completed.
- * <p>
- * Among other things, this is often a necessary pre-condition
- * before invoking other builds that depend on this build.
+ * Performs final clean up action. <p> This method is called after
+ * {@link #post(BuildListener)}, after the build result is fully
+ * finalized. This is the point where the build is already considered
+ * completed. <p> Among other things, this is often a necessary
+ * pre-condition before invoking other builds that depend on this build.
*/
public abstract void cleanUp(BuildListener listener) throws Exception;
@@ -1301,17 +1333,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Used in {@link Runner#run} to indicates that a fatal error in a build
- * is reported to {@link BuildListener} and the build should be simply aborted
+ * Used in {@link Runner#run} to indicates that a fatal error in a build is
+ * reported to {@link BuildListener} and the build should be simply aborted
* without further recording a stack trace.
*/
- public static final class RunnerAbortedException extends RuntimeException {}
+ public static final class RunnerAbortedException extends RuntimeException {
+ }
protected final void run(Runner job) {
- if(result!=null)
+ if (result != null) {
return; // already built.
-
- StreamBuildListener listener=null;
+ }
+ StreamBuildListener listener = null;
runner = job;
onStartBuilding();
@@ -1345,35 +1378,35 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
}
- listener = new StreamBuildListener(logger,charset);
+ listener = new StreamBuildListener(logger, charset);
listener.started(getCauses());
- RunListener.fireStarted(this,listener);
+ RunListener.fireStarted(this, listener);
// create a symlink from build number to ID.
- Util.createSymlink(getParent().getBuildDir(),getId(),String.valueOf(getNumber()),listener);
+ Util.createSymlink(getParent().getBuildDir(), getId(), String.valueOf(getNumber()), listener);
setResult(job.run(listener));
- LOGGER.info(toString()+" main build action completed: "+result);
+ LOGGER.info(toString() + " main build action completed: " + result);
CheckPoint.MAIN_COMPLETED.report();
} catch (ThreadDeath t) {
throw t;
- } catch( AbortException e ) {// orderly abortion.
+ } catch (AbortException e) {// orderly abortion.
result = Result.FAILURE;
listener.error(e.getMessage());
- LOGGER.log(FINE, "Build "+this+" aborted",e);
- } catch( RunnerAbortedException e ) {// orderly abortion.
+ LOGGER.log(FINE, "Build " + this + " aborted", e);
+ } catch (RunnerAbortedException e) {// orderly abortion.
result = Result.FAILURE;
- LOGGER.log(FINE, "Build "+this+" aborted",e);
- } catch( InterruptedException e) {
+ LOGGER.log(FINE, "Build " + this + " aborted", e);
+ } catch (InterruptedException e) {
// aborted
result = Result.ABORTED;
listener.getLogger().println(Messages.Run_BuildAborted());
- LOGGER.log(Level.INFO,toString()+" aborted",e);
- } catch( Throwable e ) {
- handleFatalBuildProblem(listener,e);
+ LOGGER.log(Level.INFO, toString() + " aborted", e);
+ } catch (Throwable e) {
+ handleFatalBuildProblem(listener, e);
result = Result.FAILURE;
}
@@ -1382,8 +1415,8 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
} catch (ThreadDeath t) {
throw t;
- } catch( Throwable e ) {
- handleFatalBuildProblem(listener,e);
+ } catch (Throwable e) {
+ handleFatalBuildProblem(listener, e);
result = Result.FAILURE;
} finally {
long end = System.currentTimeMillis();
@@ -1399,17 +1432,19 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
try {
job.cleanUp(listener);
} catch (Exception e) {
- handleFatalBuildProblem(listener,e);
+ handleFatalBuildProblem(listener, e);
// too late to update the result now
}
- RunListener.fireCompleted(this,listener);
+ RunListener.fireCompleted(this, listener);
- if(listener!=null)
+ if (listener != null) {
listener.finished(result);
- if(listener!=null)
+ }
+ if (listener != null) {
listener.closeQuietly();
-
+ }
+
if (logger != null) {
IOUtils.closeQuietly(logger);
}
@@ -1417,16 +1452,16 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
try {
save();
} catch (IOException e) {
- LOGGER.log(Level.SEVERE, "Failed to save build record",e);
+ LOGGER.log(Level.SEVERE, "Failed to save build record", e);
}
}
try {
getParent().logRotate();
} catch (IOException e) {
- LOGGER.log(Level.SEVERE, "Failed to rotate log",e);
+ LOGGER.log(Level.SEVERE, "Failed to rotate log", e);
} catch (InterruptedException e) {
- LOGGER.log(Level.SEVERE, "Failed to rotate log",e);
+ LOGGER.log(Level.SEVERE, "Failed to rotate log", e);
}
} finally {
onEndBuilding();
@@ -1437,12 +1472,13 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Handles a fatal build problem (exception) that occurred during the build.
*/
private void handleFatalBuildProblem(BuildListener listener, Throwable e) {
- if(listener!=null) {
- if(e instanceof IOException)
- Util.displayIOException((IOException)e,listener);
+ if (listener != null) {
+ if (e instanceof IOException) {
+ Util.displayIOException((IOException) e, listener);
+ }
Writer w = listener.fatalError(e.getMessage());
- if(w!=null) {
+ if (w != null) {
try {
e.printStackTrace(new PrintWriter(w));
w.close();
@@ -1458,8 +1494,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
protected void onStartBuilding() {
state = State.BUILDING;
- if (runner!=null)
+ if (runner != null) {
RunnerStack.INSTANCE.push(runner);
+ }
}
/**
@@ -1467,7 +1504,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
*/
protected void onEndBuilding() {
// signal that we've finished building.
- if (runner!=null) {
+ if (runner != null) {
// MavenBuilds may be created without their corresponding runners.
state = State.COMPLETED;
runner.checkpoints.allDone();
@@ -1488,40 +1525,41 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Save the settings to a file.
*/
public synchronized void save() throws IOException {
- if(BulkChange.contains(this)) return;
+ if (BulkChange.contains(this)) {
+ return;
+ }
getDataFile().write(this);
SaveableListener.fireOnChange(this, getDataFile());
}
private XmlFile getDataFile() {
- return new XmlFile(XSTREAM,new File(getRootDir(),"build.xml"));
+ return new XmlFile(XSTREAM, new File(getRootDir(), "build.xml"));
}
/**
* Gets the log of the build as a string.
*
- * @deprecated since 2007-11-11.
- * Use {@link #getLog(int)} instead as it avoids loading
- * the whole log into memory unnecessarily.
+ * @deprecated since 2007-11-11. Use {@link #getLog(int)} instead as it
+ * avoids loading the whole log into memory unnecessarily.
*/
@Deprecated
public String getLog() throws IOException {
- return Util.loadFile(getLogFile(),getCharset());
+ return Util.loadFile(getLogFile(), getCharset());
}
/**
- * Gets the log of the build as a list of strings (one per log line).
- * The number of lines returned is constrained by the maxLines parameter.
+ * Gets the log of the build as a list of strings (one per log line). The
+ * number of lines returned is constrained by the maxLines parameter.
*
- * @param maxLines The maximum number of log lines to return. If the log
- * is bigger than this, only the most recent lines are returned.
- * @return A list of log lines. Will have no more than maxLines elements.
+ * @param maxLines The maximum number of log lines to return. If the log is
+ * bigger than this, only the most recent lines are returned.
+ * @return A list of log lines. Will have no more than maxLines elements.
* @throws IOException If there is a problem reading the log file.
*/
public List<String> getLog(int maxLines) throws IOException {
int lineCount = 0;
List<String> logLines = new LinkedList<String>();
- BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getLogFile()),getCharset()));
+ BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getLogFile()), getCharset()));
try {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
logLines.add(line);
@@ -1530,8 +1568,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
// never have to hold the full contents of a huge log file in memory.
// Adding to and removing from the ends of a linked list are cheap
// operations.
- if (lineCount > maxLines)
+ if (lineCount > maxLines) {
logLines.remove(0);
+ }
}
} finally {
reader.close();
@@ -1540,14 +1579,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
// If the log has been truncated, include that information.
// Use set (replaces the first element) rather than add so that
// the list doesn't grow beyond the specified maximum number of lines.
- if (lineCount > maxLines)
+ if (lineCount > maxLines) {
logLines.set(0, "[...truncated " + (lineCount - (maxLines - 1)) + " lines...]");
+ }
return ConsoleNote.removeNotes(logLines);
}
- public void doBuildStatus( StaplerRequest req, StaplerResponse rsp ) throws IOException {
- rsp.sendRedirect2(req.getContextPath()+"/images/48x48/"+getBuildStatusUrl());
+ public void doBuildStatus(StaplerRequest req, StaplerResponse rsp) throws IOException {
+ rsp.sendRedirect2(req.getContextPath() + "/images/48x48/" + getBuildStatusUrl());
}
public String getBuildStatusUrl() {
@@ -1555,6 +1595,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
public static class Summary {
+
/**
* Is this build worse or better, compared to the previous build?
*/
@@ -1582,42 +1623,51 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
public Summary getBuildStatusSummary() {
Run prev = getPreviousBuild();
- if(getResult()==Result.SUCCESS) {
- if(prev==null || prev.getResult()== Result.SUCCESS)
+ if (getResult() == Result.SUCCESS) {
+ if (prev == null || prev.getResult() == Result.SUCCESS) {
return new Summary(false, Messages.Run_Summary_Stable());
- else
+ } else {
return new Summary(false, Messages.Run_Summary_BackToNormal());
+ }
}
- if(getResult()==Result.FAILURE) {
+ if (getResult() == Result.FAILURE) {
RunT since = getPreviousNotFailedBuild();
- if(since==null)
+ if (since == null) {
return new Summary(false, Messages.Run_Summary_BrokenForALongTime());
- if(since==prev)
+ }
+ if (since == prev) {
return new Summary(true, Messages.Run_Summary_BrokenSinceThisBuild());
+ }
RunT failedBuild = since.getNextBuild();
return new Summary(false, Messages.Run_Summary_BrokenSince(failedBuild.getDisplayName()));
}
- if(getResult()==Result.ABORTED)
+ if (getResult() == Result.ABORTED) {
return new Summary(false, Messages.Run_Summary_Aborted());
+ }
- if(getResult()==Result.UNSTABLE) {
- if(((Run)this) instanceof AbstractBuild) {
- AbstractTestResultAction trN = ((AbstractBuild)(Run)this).getTestResultAction();
- AbstractTestResultAction trP = prev==null ? null : ((AbstractBuild) prev).getTestResultAction();
- if(trP==null) {
- if(trN!=null && trN.getFailCount()>0)
+ if (getResult() == Result.UNSTABLE) {
+ if (((Run) this) instanceof AbstractBuild) {
+ AbstractTestResultAction trN = ((AbstractBuild) (Run) this).getTestResultAction();
+ AbstractTestResultAction trP = prev == null ? null : ((AbstractBuild) prev).getTestResultAction();
+ if (trP == null) {
+ if (trN != null && trN.getFailCount() > 0) {
return new Summary(false, Messages.Run_Summary_TestFailures(trN.getFailCount()));
- else // ???
+ } else // ???
+ {
return new Summary(false, Messages.Run_Summary_Unstable());
+ }
}
- if(trP.getFailCount()==0)
+ if (trP.getFailCount() == 0) {
return new Summary(true, Messages.Run_Summary_TestsStartedToFail(trN.getFailCount()));
- if(trP.getFailCount() < trN.getFailCount())
- return new Summary(true, Messages.Run_Summary_MoreTestsFailing(trN.getFailCount()-trP.getFailCount(), trN.getFailCount()));
- if(trP.getFailCount() > trN.getFailCount())
- return new Summary(false, Messages.Run_Summary_LessTestsFailing(trP.getFailCount()-trN.getFailCount(), trN.getFailCount()));
+ }
+ if (trP.getFailCount() < trN.getFailCount()) {
+ return new Summary(true, Messages.Run_Summary_MoreTestsFailing(trN.getFailCount() - trP.getFailCount(), trN.getFailCount()));
+ }
+ if (trP.getFailCount() > trN.getFailCount()) {
+ return new Summary(false, Messages.Run_Summary_LessTestsFailing(trP.getFailCount() - trN.getFailCount(), trN.getFailCount()));
+ }
return new Summary(false, Messages.Run_Summary_TestsStillFailing(trN.getFailCount()));
}
@@ -1630,10 +1680,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Serves the artifacts.
*/
public DirectoryBrowserSupport doArtifact() {
- if(Functions.isArtifactsPermissionEnabled()) {
- checkPermission(ARTIFACTS);
+ if (Functions.isArtifactsPermissionEnabled()) {
+ checkPermission(ARTIFACTS);
}
- return new DirectoryBrowserSupport(this,new FilePath(getArtifactsDir()), project.getDisplayName()+' '+getDisplayName(), "package.png", true);
+ return new DirectoryBrowserSupport(this, new FilePath(getArtifactsDir()), project.getDisplayName() + ' ' + getDisplayName(), "package.png", true);
}
/**
@@ -1649,13 +1699,13 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Returns the build time stamp in the body.
*/
- public void doBuildTimestamp( StaplerRequest req, StaplerResponse rsp, @QueryParameter String format) throws IOException {
+ public void doBuildTimestamp(StaplerRequest req, StaplerResponse rsp, @QueryParameter String format) throws IOException {
rsp.setContentType("text/plain");
rsp.setCharacterEncoding("US-ASCII");
rsp.setStatus(HttpServletResponse.SC_OK);
- DateFormat df = format==null ?
- DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT, Locale.ENGLISH) :
- new SimpleDateFormat(format,req.getLocale());
+ DateFormat df = format == null
+ ? DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH)
+ : new SimpleDateFormat(format, req.getLocale());
rsp.getWriter().print(df.format(getTime()));
}
@@ -1668,7 +1718,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
FlushProofOutputStream out = null;
try {
out = new FlushProofOutputStream(rsp.getCompressedOutputStream(req));
- getLogText().writeLogTo(0,out);
+ getLogText().writeLogTo(0, out);
} finally {
IOUtils.closeQuietly(out);
}
@@ -1676,14 +1726,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Handles incremental log output.
- * @deprecated as of 1.352
- * Use {@code getLogText().doProgressiveText(req,rsp)}
+ *
+ * @deprecated as of 1.352 Use
+ * {@code getLogText().doProgressiveText(req,rsp)}
*/
- public void doProgressiveLog( StaplerRequest req, StaplerResponse rsp) throws IOException {
- getLogText().doProgressText(req,rsp);
+ public void doProgressiveLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
+ getLogText().doProgressText(req, rsp);
}
- public void doToggleLogKeep( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
+ public void doToggleLogKeep(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
keepLog(!keepLog);
rsp.forwardToPreviousPage(req);
}
@@ -1691,7 +1742,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Marks this build to keep the log.
*/
- @CLIMethod(name="keep-build")
+ @CLIMethod(name = "keep-build")
public final void keepLog() throws IOException {
keepLog(true);
}
@@ -1705,7 +1756,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Deletes the build when the button is pressed.
*/
- public void doDoDelete( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
+ public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
requirePOST();
checkPermission(DELETE);
@@ -1713,13 +1764,13 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
// marked to be preserved, or if the build should not be deleted
// due to dependencies!
String why = getWhyKeepLog();
- if (why!=null) {
- sendError(Messages.Run_UnableToDelete(toString(),why),req,rsp);
+ if (why != null) {
+ sendError(Messages.Run_UnableToDelete(toString(), why), req, rsp);
return;
}
delete();
- rsp.sendRedirect2(req.getContextPath()+'/' + getParent().getUrl());
+ rsp.sendRedirect2(req.getContextPath() + '/' + getParent().getUrl());
}
public void setDescription(String description) throws IOException {
@@ -1727,20 +1778,19 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
this.description = description;
save();
}
-
+
/**
* Accepts the new description.
*/
- public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
+ public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
setDescription(req.getParameter("description"));
rsp.sendRedirect("."); // go to the top page
}
/**
- * @deprecated as of 1.292
- * Use {@link #getEnvironment()} instead.
+ * @deprecated as of 1.292 Use {@link #getEnvironment()} instead.
*/
- public Map<String,String> getEnvVars() {
+ public Map<String, String> getEnvVars() {
try {
return getEnvironment();
} catch (IOException e) {
@@ -1758,17 +1808,17 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Returns the map that contains environmental variables to be used for launching
- * processes for this build.
+ * Returns the map that contains environmental variables to be used for
+ * launching processes for this build.
+ *
+ * <p> {@link BuildStep}s that invoke external processes should use this.
+ * This allows {@link BuildWrapper}s and other project configurations (such
+ * as JDK selection) to take effect.
*
- * <p>
- * {@link BuildStep}s that invoke external processes should use this.
- * This allows {@link BuildWrapper}s and other project configurations (such as JDK selection)
- * to take effect.
+ * <p> Unlike earlier {@link #getEnvVars()}, this map contains the whole
+ * environment, not just the overrides, so one can introspect values to
+ * change its behavior.
*
- * <p>
- * Unlike earlier {@link #getEnvVars()}, this map contains the whole environment,
- * not just the overrides, so one can introspect values to change its behavior.
* @since 1.305
*/
public EnvVars getEnvironment(TaskListener log) throws IOException, InterruptedException {
@@ -1813,16 +1863,17 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
}
/**
- * Builds up the environment variable map that's sufficient to identify a process
- * as ours. This is used to kill run-away processes via {@link ProcessTree#killAll(Map)}.
+ * Builds up the environment variable map that's sufficient to identify a
+ * process as ours. This is used to kill run-away processes via
+ * {@link ProcessTree#killAll(Map)}.
*/
public final EnvVars getCharacteristicEnvVars() {
EnvVars env = new EnvVars();
- env.put("HUDSON_SERVER_COOKIE",Util.getDigestOf("ServerID:"+Hudson.getInstance().getSecretKey()));
- env.put("BUILD_NUMBER",String.valueOf(number));
- env.put("BUILD_ID",getId());
- env.put("BUILD_TAG","hudson-"+getParent().getName()+"-"+number);
- env.put("JOB_NAME",getParent().getFullName());
+ env.put("HUDSON_SERVER_COOKIE", Util.getDigestOf("ServerID:" + Hudson.getInstance().getSecretKey()));
+ env.put("BUILD_NUMBER", String.valueOf(number));
+ env.put("BUILD_ID", getId());
+ env.put("BUILD_TAG", "hudson-" + getParent().getName() + "-" + number);
+ env.put("JOB_NAME", getParent().getFullName());
return env;
}
@@ -1830,7 +1881,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
return project.getName() + "#" + getNumber();
}
- public static Run<?,?> fromExternalizableId(String id) {
+ public static Run<?, ?> fromExternalizableId(String id) {
int hash = id.lastIndexOf('#');
if (hash <= 0) {
throw new IllegalArgumentException("Invalid id");
@@ -1838,15 +1889,16 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
String jobName = id.substring(0, hash);
int number = Integer.parseInt(id.substring(hash + 1));
- Job<?,?> job = (Job<?,?>) Hudson.getInstance().getItem(jobName);
+ Job<?, ?> job = (Job<?, ?>) Hudson.getInstance().getItem(jobName);
return job.getBuildByNumber(number);
}
/**
* Returns the estimated duration for this run if it is currently running.
- * Default to {@link Job#getEstimatedDuration()}, may be overridden in subclasses
- * if duration may depend on run specific parameters (like incremental Maven builds).
- *
+ * Default to {@link Job#getEstimatedDuration()}, may be overridden in
+ * subclasses if duration may depend on run specific parameters (like
+ * incremental Maven builds).
+ *
* @return the estimated duration in milliseconds
* @since 1.383
*/
@@ -1854,7 +1906,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
return project.getEstimatedDuration();
}
- public HttpResponse doConfigSubmit( StaplerRequest req ) throws IOException, ServletException, FormException {
+ public HttpResponse doConfigSubmit(StaplerRequest req) throws IOException, ServletException, FormException {
checkPermission(UPDATE);
BulkChange bc = new BulkChange(this);
try {
@@ -1871,47 +1923,47 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
setDisplayName(Util.fixEmptyAndTrim(json.getString("displayName")));
setDescription(json.getString("description"));
}
-
public static final XStream XSTREAM = new XStream2();
+
static {
- XSTREAM.alias("build",FreeStyleBuild.class);
- XSTREAM.alias("matrix-build",MatrixBuild.class);
- XSTREAM.alias("matrix-run",MatrixRun.class);
+ XSTREAM.alias("build", FreeStyleBuild.class);
+ XSTREAM.alias("matrix-build", MatrixBuild.class);
+ XSTREAM.alias("matrix-run", MatrixRun.class);
XSTREAM.registerConverter(Result.conv);
}
-
private static final Logger LOGGER = Logger.getLogger(Run.class.getName());
-
/**
- * Sort by date. Newer ones first.
+ * Sort by date. Newer ones first.
*/
public static final Comparator<Run> ORDER_BY_DATE = new Comparator<Run>() {
public int compare(Run lhs, Run rhs) {
long lt = lhs.getTimeInMillis();
long rt = rhs.getTimeInMillis();
- if(lt>rt) return -1;
- if(lt<rt) return 1;
+ if (lt > rt) {
+ return -1;
+ }
+ if (lt < rt) {
+ return 1;
+ }
return 0;
}
};
-
/**
* {@link FeedAdapter} to produce feed from the summary of this build.
*/
public static final FeedAdapter<Run> FEED_ADAPTER = new DefaultFeedAdapter();
-
/**
* {@link FeedAdapter} to produce feeds to show one build per project.
*/
public static final FeedAdapter<Run> FEED_ADAPTER_LATEST = new DefaultFeedAdapter() {
/**
- * The entry unique ID needs to be tied to a project, so that
- * new builds will replace the old result.
+ * The entry unique ID needs to be tied to a project, so that new builds
+ * will replace the old result.
*/
@Override
public String getEntryID(Run e) {
// can't use a meaningful year field unless we remember when the job was created.
- return "tag:hudson.java.net,2008:"+e.getParent().getAbsoluteUrl();
+ return "tag:hudson.java.net,2008:" + e.getParent().getAbsoluteUrl();
}
};
@@ -1919,25 +1971,38 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* {@link BuildBadgeAction} that shows the logs are being kept.
*/
public final class KeepLogBuildBadge implements BuildBadgeAction {
- public String getIconFileName() { return null; }
- public String getDisplayName() { return null; }
- public String getUrlName() { return null; }
- public String getWhyKeepLog() { return Run.this.getWhyKeepLog(); }
- }
- public static final PermissionGroup PERMISSIONS = new PermissionGroup(Run.class,Messages._Run_Permissions_Title());
- public static final Permission DELETE = new Permission(PERMISSIONS,"Delete",Messages._Run_DeletePermission_Description(),Permission.DELETE);
- public static final Permission UPDATE = new Permission(PERMISSIONS,"Update",Messages._Run_UpdatePermission_Description(),Permission.UPDATE);
- /** See {@link hudson.Functions#isArtifactsPermissionEnabled} */
- public static final Permission ARTIFACTS = new Permission(PERMISSIONS,"Artifacts",Messages._Run_ArtifactsPermission_Description(), null,
- Functions.isArtifactsPermissionEnabled());
+ public String getIconFileName() {
+ return null;
+ }
+
+ public String getDisplayName() {
+ return null;
+ }
+
+ public String getUrlName() {
+ return null;
+ }
+
+ public String getWhyKeepLog() {
+ return Run.this.getWhyKeepLog();
+ }
+ }
+ public static final PermissionGroup PERMISSIONS = new PermissionGroup(Run.class, Messages._Run_Permissions_Title());
+ public static final Permission DELETE = new Permission(PERMISSIONS, "Delete", Messages._Run_DeletePermission_Description(), Permission.DELETE);
+ public static final Permission UPDATE = new Permission(PERMISSIONS, "Update", Messages._Run_UpdatePermission_Description(), Permission.UPDATE);
+ /**
+ * See {@link hudson.Functions#isArtifactsPermissionEnabled}
+ */
+ public static final Permission ARTIFACTS = new Permission(PERMISSIONS, "Artifacts", Messages._Run_ArtifactsPermission_Description(), null,
+ Functions.isArtifactsPermissionEnabled());
private static class DefaultFeedAdapter implements FeedAdapter<Run> {
private static final String DESCRIPTION_SUFIX = "description:";
public String getEntryTitle(Run entry) {
- return entry+" ("+entry.getBuildStatusSummary().message+")";
+ return entry + " (" + entry.getBuildStatusSummary().message + ")";
}
public String getEntryUrl(Run entry) {
@@ -1946,12 +2011,12 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
public String getEntryID(Run entry) {
return "tag:" + "hudson.java.net,"
- + entry.getTimestamp().get(Calendar.YEAR) + ":"
- + entry.getParent().getName()+':'+entry.getId();
+ + entry.getTimestamp().get(Calendar.YEAR) + ":"
+ + entry.getParent().getName() + ':' + entry.getId();
}
public String getEntryDescription(Run entry) {
- return (entry.getDescription()!= null ? DESCRIPTION_SUFIX + entry.getDescription(): null);
+ return (entry.getDescription() != null ? DESCRIPTION_SUFIX + entry.getDescription() : null);
}
public Calendar getEntryTimestamp(Run entry) {
@@ -1966,27 +2031,29 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
@Override
public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
Object result = super.getDynamic(token, req, rsp);
- if (result == null)
- // Next/Previous Build links on an action page (like /job/Abc/123/testReport)
- // will also point to same action (/job/Abc/124/testReport), but other builds
- // may not have the action.. tell browsers to redirect up to the build page.
+ if (result == null) // Next/Previous Build links on an action page (like /job/Abc/123/testReport)
+ // will also point to same action (/job/Abc/124/testReport), but other builds
+ // may not have the action.. tell browsers to redirect up to the build page.
+ {
result = new RedirectUp();
+ }
return result;
}
public static class RedirectUp {
+
public void doDynamic(StaplerResponse rsp) throws IOException {
// Compromise to handle both browsers (auto-redirect) and programmatic access
// (want accurate 404 response).. send 404 with javscript to redirect browsers.
rsp.setStatus(HttpServletResponse.SC_NOT_FOUND);
rsp.setContentType("text/html;charset=UTF-8");
PrintWriter out = rsp.getWriter();
- out.println("<html><head>" +
- "<meta http-equiv='refresh' content='1;url=..'/>" +
- "<script>window.location.replace('..');</script>" +
- "</head>" +
- "<body style='background-color:white; color:white;'>" +
- "Not found</body></html>");
+ out.println("<html><head>"
+ + "<meta http-equiv='refresh' content='1;url=..'/>"
+ + "<script>window.location.replace('..');</script>"
+ + "</head>"
+ + "<body style='background-color:white; color:white;'>"
+ + "Not found</body></html>");
out.flush();
}
}