| author | Henrik Lynggaard Hansen | 2012-07-17 15:55:51 (EDT) |
|---|---|---|
| committer | Henrik Lynggaard Hansen | 2012-07-17 15:55:51 (EDT) |
| commit | bbaac1367e66ef1a4a698664cabecd29abbb6fe4 (patch) (side-by-side diff) | |
| tree | d6da12fb4f3256f434b71202f5878fa0f548f6b7 | |
| parent | 825e47b2ae6a94d7be58a9f180e10928c8d62613 (diff) | |
| download | org.eclipse.hudson.core-bbaac1367e66ef1a4a698664cabecd29abbb6fe4.zip org.eclipse.hudson.core-bbaac1367e66ef1a4a698664cabecd29abbb6fe4.tar.gz org.eclipse.hudson.core-bbaac1367e66ef1a4a698664cabecd29abbb6fe4.tar.bz2 | |
Reformat hudson.os and hudson.schedulerrefs/changes/27/6827/1
Change-Id: If5f3ff060effd6a250969abf44d42ad34a3d6ec9
Signed-off-by: Henrik Lynggaard Hansen <henrik@hlyh.dk>
10 files changed, 429 insertions, 382 deletions
diff --git a/hudson-core/src/main/java/hudson/os/EmbeddedSu.java b/hudson-core/src/main/java/hudson/os/EmbeddedSu.java index c0a3924..7f2b73a 100644 --- a/hudson-core/src/main/java/hudson/os/EmbeddedSu.java +++ b/hudson-core/src/main/java/hudson/os/EmbeddedSu.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 - * + * *******************************************************************************/ package hudson.os; @@ -27,11 +27,13 @@ import java.util.Collection; import java.util.logging.Logger; /** - * Encapsulates the process launch through <tt>su</tt> (embedded_su(1M) to be exact) + * Encapsulates the process launch through <tt>su</tt> (embedded_su(1M) to be + * exact) * * @author Kohsuke Kawaguchi */ public class EmbeddedSu { + /** * Not meant to be instantiated. */ @@ -39,105 +41,105 @@ public class EmbeddedSu { } /** - * Launches a process as configured by {@link ProcessBuilder}, but under - * a separate user priviledge by using <tt>su</tt> functionality. + * Launches a process as configured by {@link ProcessBuilder}, but under a + * separate user priviledge by using <tt>su</tt> functionality. * - * @param user - * The user name in which the new process runs. - * @param pwd - * The password of the user. + * @param user The user name in which the new process runs. + * @param pwd The password of the user. */ public static Process startWithSu(String user, String pwd, ProcessBuilder pb) throws IOException { - if (user==null || pwd==null) + if (user == null || pwd == null) { throw new IllegalArgumentException(); - + } + // su only invokes a shell, so the argument has to be packed into the -c option StringBuilder buf = new StringBuilder("exec "); - for( String cmd : pb.command() ) { + for (String cmd : pb.command()) { buf.append(' '); // to prevent shell from interfering with characters like '$' and '`', // put everything in single-quotes. When we do this, single-quotes in // arguments have to be escaped. - buf.append('\'').append(cmd.replaceAll("\'","'\''")).append('\''); + buf.append('\'').append(cmd.replaceAll("\'", "'\''")).append('\''); } List<String> cmds = pb.command(); cmds.clear(); - cmds.addAll(Arrays.asList("/usr/lib/embedded_su",user,"-c",buf.toString())); + cmds.addAll(Arrays.asList("/usr/lib/embedded_su", user, "-c", buf.toString())); // now the command line massage is ready. start a process Process proc = pb.start(); - PrintWriter out = new PrintWriter(proc.getOutputStream(),true); + PrintWriter out = new PrintWriter(proc.getOutputStream(), true); InputStream in = proc.getInputStream(); // send initialization block LOGGER.fine("Initiating embedded_su conversation"); out.println("."); /* - embedded_su often sends us PAM_ERROR_MSG that's useful, so capture them. - alice@opensolaris:~$ /usr/lib/embedded_su root - . - CONV 1 - PAM_PROMPT_ECHO_OFF - Password: - . - root - CONV 1 - PAM_ERROR_MSG - Roles can only be assumed by authorized users - . - ERROR - embedded_su: Sorry - . + embedded_su often sends us PAM_ERROR_MSG that's useful, so capture them. + alice@opensolaris:~$ /usr/lib/embedded_su root + . + CONV 1 + PAM_PROMPT_ECHO_OFF + Password: + . + root + CONV 1 + PAM_ERROR_MSG + Roles can only be assumed by authorized users + . + ERROR + embedded_su: Sorry + . */ List<String> errorMessages = new ArrayList<String>(); - while(true) { + while (true) { String line = readLine(in); - if(line.startsWith("CONV")) { + if (line.startsWith("CONV")) { // how many blocks do we expect? int n = Integer.parseInt(line.substring(5)); - for( int i=0; i<n; i++) { + for (int i = 0; i < n; i++) { String header = readLine(in); String textBlock = readTextBlock(in); - LOGGER.fine("Got "+header+" : "+textBlock); - if(header.startsWith("PAM_PROMPT_ECHO_OFF")) { + LOGGER.fine("Got " + header + " : " + textBlock); + if (header.startsWith("PAM_PROMPT_ECHO_OFF")) { // this is where we want to send the password // if we are asked the password for the 2nd time, it's rather unlikely that // the same value is expected --- instead, its' probably a retry. out.println(pwd); pwd = null; } - if(header.startsWith("PAM_PROMPT_ECHO_ON")) { + if (header.startsWith("PAM_PROMPT_ECHO_ON")) { // embedded_su expects some value but this is probably not where we want to send the password out.println(); } - if(header.startsWith("PAM_ERROR_MSG")) { + if (header.startsWith("PAM_ERROR_MSG")) { errorMessages.add(textBlock); } // ignore the rest } continue; } - if(line.startsWith("SUCCESS")) { - LOGGER.fine("Authentication successful: "+line); + if (line.startsWith("SUCCESS")) { + LOGGER.fine("Authentication successful: " + line); return proc; } - if(line.startsWith("ERROR")) { - LOGGER.fine("Authentication faied: "+line); - throw new SuAuthenticationFailureException(readTextBlock(in)+join(errorMessages)); + if (line.startsWith("ERROR")) { + LOGGER.fine("Authentication faied: " + line); + throw new SuAuthenticationFailureException(readTextBlock(in) + join(errorMessages)); } - LOGGER.fine("Unrecognized response: "+line); - throw new IOException("Unrecognized response from embedded_su "+line); + LOGGER.fine("Unrecognized response: " + line); + throw new IOException("Unrecognized response from embedded_su " + line); } } private static String join(Collection<String> col) { StringBuilder buf = new StringBuilder(); - for (String a : col) + for (String a : col) { buf.append(a); + } return buf.toString(); } @@ -150,8 +152,10 @@ public class EmbeddedSu { ByteArrayOutputStream buf = new ByteArrayOutputStream(); int ch; - while((ch=in.read())!=-1) { - if(ch=='\n') return buf.toString(); + while ((ch = in.read()) != -1) { + if (ch == '\n') { + return buf.toString(); + } buf.write(ch); } throw new EOFException(); @@ -163,18 +167,18 @@ public class EmbeddedSu { private static String readTextBlock(InputStream in) throws IOException { StringBuilder buf = new StringBuilder(); - while(true) { + while (true) { String line = readLine(in); - if(line.equals(".")) + if (line.equals(".")) { return buf.toString(); // end of it - - if(line.startsWith("..")) + } + if (line.startsWith("..")) { buf.append(line.substring(1)); - else + } else { buf.append(line); + } buf.append('\n'); } } - private static final Logger LOGGER = Logger.getLogger(EmbeddedSu.class.getName()); } diff --git a/hudson-core/src/main/java/hudson/os/SU.java b/hudson-core/src/main/java/hudson/os/SU.java index cb6b2c6..cce4d9d 100644 --- a/hudson-core/src/main/java/hudson/os/SU.java +++ b/hudson-core/src/main/java/hudson/os/SU.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 - * + * * *******************************************************************************/ @@ -36,43 +36,45 @@ import java.io.PrintStream; import java.util.Collections; /** - * Executes {@link Callable} as the super user, by forking a new process and executing the closure in there - * if necessary. + * Executes {@link Callable} as the super user, by forking a new process and + * executing the closure in there if necessary. * - * <p> - * A best effort is made to execute the closure as root, but we may still end up exeucting the closure - * in the non-root privilege, so the closure should expect that and handle it gracefully. + * <p> A best effort is made to execute the closure as root, but we may still + * end up exeucting the closure in the non-root privilege, so the closure should + * expect that and handle it gracefully. * - * <p> - * Still very much experimental. Subject to change. <b>Don't use it.</b> + * <p> Still very much experimental. Subject to change. <b>Don't use it.</b> * * @author Kohsuke Kawaguchi */ public abstract class SU { + private SU() { // not meant to be instantiated } /** - * Returns a {@link VirtualChannel} that's connected to the priviledge-escalated environment. + * Returns a {@link VirtualChannel} that's connected to the + * priviledge-escalated environment. * - * @return - * Never null. This may represent a channel to a separate JVM, or just {@link LocalChannel}. - * Close this channel and the SU environment will be shut down. + * @return Never null. This may represent a channel to a separate JVM, or + * just {@link LocalChannel}. Close this channel and the SU environment will + * be shut down. */ public static VirtualChannel start(final TaskListener listener, final String rootUsername, final String rootPassword) throws IOException, InterruptedException { - if(File.pathSeparatorChar==';') // on Windows + if (File.pathSeparatorChar == ';') // on Windows + { return newLocalChannel(); // TODO: perhaps use RunAs to run as an Administrator? - + } String os = Util.fixNull(System.getProperty("os.name")); - if(os.equals("Linux")) + if (os.equals("Linux")) { return new UnixSu() { protected String sudoExe() { return "sudo"; } protected Process sudoWithPass(ArgumentListBuilder args) throws IOException { - args.prepend(sudoExe(),"-S"); - listener.getLogger().println("$ "+Util.join(args.toList()," ")); + args.prepend(sudoExe(), "-S"); + listener.getLogger().println("$ " + Util.join(args.toList(), " ")); ProcessBuilder pb = new ProcessBuilder(args.toCommandArray()); Process p = pb.start(); // TODO: use -p to detect prompt @@ -83,9 +85,10 @@ public abstract class SU { ps.println(rootPassword); return p; } - }.start(listener,rootPassword); + }.start(listener, rootPassword); + } - if(os.equals("SunOS")) + if (os.equals("SunOS")) { return new UnixSu() { protected String sudoExe() { return "/usr/bin/pfexec"; @@ -96,9 +99,10 @@ public abstract class SU { ProcessBuilder pb = new ProcessBuilder(args.prepend(sudoExe()).toCommandArray()); return EmbeddedSu.startWithSu(rootUsername, rootPassword, pb); } - // in solaris, pfexec never asks for a password, so username==null means - // we won't be using password. this helps disambiguate empty password - }.start(listener,rootUsername==null?null:rootPassword); + // in solaris, pfexec never asks for a password, so username==null means + // we won't be using password. this helps disambiguate empty password + }.start(listener, rootUsername == null ? null : rootPassword); + } // TODO: Mac? @@ -111,9 +115,10 @@ public abstract class SU { } /** - * Starts a new priviledge-escalated environment, execute a closure, and shut it down. + * Starts a new priviledge-escalated environment, execute a closure, and + * shut it down. */ - public static <V,T extends Throwable> V execute(TaskListener listener, String rootUsername, String rootPassword, final Callable<V, T> closure) throws T, IOException, InterruptedException { + public static <V, T extends Throwable> V execute(TaskListener listener, String rootUsername, String rootPassword, final Callable<V, T> closure) throws T, IOException, InterruptedException { VirtualChannel ch = start(listener, rootUsername, rootPassword); try { return ch.call(closure); @@ -138,19 +143,23 @@ public abstract class SU { throw new IOException(exc); } - if(uid==0) // already running as root + if (uid == 0) // already running as root + { return newLocalChannel(); + } String javaExe = System.getProperty("java.home") + "/bin/java"; File slaveJar = Which.jarFile(Launcher.class); ArgumentListBuilder args = new ArgumentListBuilder().add(javaExe); - if(slaveJar.isFile()) + if (slaveJar.isFile()) { args.add("-jar").add(slaveJar); - else // in production code this never happens, but during debugging this is convenientud + } else // in production code this never happens, but during debugging this is convenientud + { args.add("-cp").add(slaveJar).add(hudson.remoting.Launcher.class.getName()); + } - if(rootPassword==null) { + if (rootPassword == null) { // try sudo, in the hope that the user has the permission to do so without password return new LocalLauncher(listener).launchChannel( args.prepend(sudoExe()).toCommandArray(), @@ -159,7 +168,7 @@ public abstract class SU { // try sudo with the given password. Also run in pfexec so that we can elevate the privileges Process proc = sudoWithPass(args); return Channels.forProcess(args.toStringWithQuote(), Computer.threadPoolForRemoting, proc, - listener.getLogger() ); + listener.getLogger()); } } } diff --git a/hudson-core/src/main/java/hudson/os/SuAuthenticationFailureException.java b/hudson-core/src/main/java/hudson/os/SuAuthenticationFailureException.java index ec85b93..e736086 100644 --- a/hudson-core/src/main/java/hudson/os/SuAuthenticationFailureException.java +++ b/hudson-core/src/main/java/hudson/os/SuAuthenticationFailureException.java @@ -1,18 +1,19 @@ -/******************************************************************************* +/** + * ***************************************************************************** * * Copyright (c) 2004-2009 Oracle Corporation. * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: * - * Kohsuke Kawaguchi - * - *******************************************************************************/ - + * Kohsuke Kawaguchi + * + ****************************************************************************** + */ package hudson.os; import java.io.IOException; @@ -20,12 +21,12 @@ import java.io.IOException; /** * 'su' failed to authenticate the given credential. * - * <p> - * Wrong password, invalid user name, that sort of things. + * <p> Wrong password, invalid user name, that sort of things. * * @author Kohsuke Kawaguchi */ public class SuAuthenticationFailureException extends IOException { + public SuAuthenticationFailureException(String message) { super(message); } diff --git a/hudson-core/src/main/java/hudson/os/solaris/ZFSInstaller.java b/hudson-core/src/main/java/hudson/os/solaris/ZFSInstaller.java index fca6905..e8ad794 100644 --- a/hudson-core/src/main/java/hudson/os/solaris/ZFSInstaller.java +++ b/hudson-core/src/main/java/hudson/os/solaris/ZFSInstaller.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: + * + * * - * - * * *******************************************************************************/ @@ -51,22 +51,21 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * Encourages the user to migrate HUDSON_HOME on a ZFS file system. + * Encourages the user to migrate HUDSON_HOME on a ZFS file system. * * @author Kohsuke Kawaguchi * @since 1.283 */ public class ZFSInstaller extends AdministrativeMonitor implements Serializable { + /** * True if $HUDSON_HOME is a ZFS file system by itself. */ private final boolean active = shouldBeActive(); - /** * This will be the file system name that we'll create. */ private String prospectiveZfsFileSystemName; - private NativeUtils nativeUtils = NativeUtils.getInstance(); public boolean isActivated() { @@ -87,33 +86,34 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable } private boolean shouldBeActive() { - if(!System.getProperty("os.name").equals("SunOS") || disabled) - // on systems that don't have ZFS, we don't need this monitor + if (!System.getProperty("os.name").equals("SunOS") || disabled) // on systems that don't have ZFS, we don't need this monitor + { return false; + } try { List<NativeZfsFileSystem> roots = nativeUtils.getZfsRoots(); - - if(roots.isEmpty()) - return false; // no active ZFS pool + if (roots.isEmpty()) { + return false; // no active ZFS pool + } // if we don't run on a ZFS file system, activate NativeZfsFileSystem hudsonZfs = nativeUtils.getZfsByMountPoint(Hudson.getInstance().getRootDir()); - if(hudsonZfs!=null) + if (hudsonZfs != null) { return false; // already on ZFS - + } // decide what file system we'll create NativeZfsFileSystem pool = roots.get(0); - + prospectiveZfsFileSystemName = computeHudsonFileSystemName(pool); return true; } catch (Exception e) { - LOGGER.log(Level.WARNING, "Failed to detect whether Hudson is on ZFS",e); + LOGGER.log(Level.WARNING, "Failed to detect whether Hudson is on ZFS", e); return false; } catch (LinkageError e) { LOGGER.info("No ZFS available. If you believe this is an error, increase the logging level to get the stack trace"); - LOGGER.log(Level.FINE,"Stack trace of failed ZFS load",e); + LOGGER.log(Level.FINE, "Stack trace of failed ZFS load", e); return false; } } @@ -125,7 +125,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable requirePOST(); Hudson.getInstance().checkPermission(Hudson.ADMINISTER); - if(req.hasParameter("n")) { + if (req.hasParameter("n")) { // we'll shut up disable(true); return HttpResponses.redirectViaContextPath("/manage"); @@ -137,25 +137,23 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable /** * Creates a ZFS file system to migrate the data to. * - * <p> - * This has to be done while we still have an interactive access with the user, since it involves the password. + * <p> This has to be done while we still have an interactive access with + * the user, since it involves the password. * - * <p> - * An exception will be thrown if the operation fails. A normal completion means a success. + * <p> An exception will be thrown if the operation fails. A normal + * completion means a success. * - * @return - * The ZFS dataset name to migrate the data to. + * @return The ZFS dataset name to migrate the data to. */ private String createZfsFileSystem(final TaskListener listener, String rootUsername, String rootPassword) throws IOException, InterruptedException { // capture the UID that Hudson runs under // so that we can allow this user to do everything on this new partition - + final File home = Hudson.getInstance().getRootDir(); // this is the actual creation of the file system. // return true indicating a success return SU.execute(listener, rootUsername, rootPassword, new Callable<String, IOException>() { - public String call() throws IOException { NativeZfsFileSystem hudson = null; try { @@ -194,7 +192,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable return hudson.getName(); } catch (NativeAccessException ex) { Logger.getLogger(ZFSInstaller.class.getName()).log(Level.SEVERE, null, ex); - if (hudson != null){ + if (hudson != null) { hudson.destory(); } throw new IOException(); @@ -207,7 +205,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable * Called from the confirmation screen to actually initiate the migration. */ public void doStart(StaplerRequest req, StaplerResponse rsp, @QueryParameter String username, @QueryParameter String password) throws ServletException, IOException { - requirePOST(); + requirePOST(); Hudson hudson = Hudson.getInstance(); hudson.checkPermission(Hudson.ADMINISTER); @@ -215,23 +213,23 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable ByteArrayOutputStream log = new ByteArrayOutputStream(); StreamTaskListener listener = new StreamTaskListener(log); try { - datasetName = createZfsFileSystem(listener,username,password); + datasetName = createZfsFileSystem(listener, username, password); } catch (Exception e) { e.printStackTrace(listener.error(e.getMessage())); if (e.getCause() instanceof NativeAccessException) { NativeAccessException ze = (NativeAccessException) e; - if(ze.getCode() == NativeAccessException.PERMISSION) { + if (ze.getCode() == NativeAccessException.PERMISSION) { // permission problem. ask the user to give us the root password - req.setAttribute("message",log.toString()); - rsp.forward(this,"askRootPassword",req); + req.setAttribute("message", log.toString()); + rsp.forward(this, "askRootPassword", req); return; } } // for other kinds of problems, report and bail out - req.setAttribute("pre",true); - sendError(log.toString(),req,rsp); + req.setAttribute("pre", true); + sendError(log.toString(), req, rsp); return; } @@ -239,7 +237,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable WebAppController.get().install(new HudsonIsRestarting()); // redirect the user to the manage page - rsp.sendRedirect2(req.getContextPath()+"/manage"); + rsp.sendRedirect2(req.getContextPath() + "/manage"); // asynchronously restart, so that we can give a bit of time to the browser to load "restarting..." screen. new Thread("restart thread") { @@ -247,15 +245,15 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable public void run() { try { Thread.sleep(5000); - + Map<String, String> properties = new HashMap<String, String>(); properties.put("ZFSInstaller.migrate", datasetName); nativeUtils.restartJavaProcess(properties, true); } catch (NativeAccessException ex) { - LOGGER.log(Level.SEVERE, "Restart failed", ex); + LOGGER.log(Level.SEVERE, "Restart failed", ex); } catch (InterruptedException e) { - LOGGER.log(Level.SEVERE, "Restart failed",e); + LOGGER.log(Level.SEVERE, "Restart failed", e); } } }.start(); @@ -264,11 +262,11 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable @Extension public static AdministrativeMonitor init() { String migrationTarget = System.getProperty(ZFSInstaller.class.getName() + ".migrate"); - if(migrationTarget!=null) { + if (migrationTarget != null) { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamTaskListener listener = new StreamTaskListener(new ForkOutputStream(System.out, out)); try { - if(migrate(listener,migrationTarget)) { + if (migrate(listener, migrationTarget)) { // completed successfully return new MigrationCompleteNotice(); } @@ -282,8 +280,9 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable // install the monitor if applicable ZFSInstaller zi = new ZFSInstaller(); - if(zi.isActivated()) + if (zi.isActivated()) { return zi; + } return null; } @@ -293,62 +292,61 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable * * TODO: do this in a separate JVM to elevate the privilege. * - * @param listener - * Log of migration goes here. - * @param target - * Dataset to move the data to. - * @return - * false if a migration failed. + * @param listener Log of migration goes here. + * @param target Dataset to move the data to. + * @return false if a migration failed. */ private static boolean migrate(TaskListener listener, String target) throws IOException, InterruptedException { try { NativeUtils nativeUtils = NativeUtils.getInstance(); - + PrintStream out = listener.getLogger(); File home = Hudson.getInstance().getRootDir(); // do the migration NativeZfsFileSystem existing = nativeUtils.getZfsByMountPoint(home); - if(existing!=null) { - out.println(home+" is already on ZFS. Doing nothing"); + if (existing != null) { + out.println(home + " is already on ZFS. Doing nothing"); return true; } File tmpDir = Util.createTempDir(); // mount a new file system to a temporary location - out.println("Opening "+target); + out.println("Opening " + target); NativeZfsFileSystem hudson = nativeUtils.openZfs(target); hudson.setMountPoint(tmpDir); - hudson.setProperty("hudson:managed-by","hudson"); // mark this file system as "managed by Hudson" + hudson.setProperty("hudson:managed-by", "hudson"); // mark this file system as "managed by Hudson" hudson.mount(); // copy all the files out.println("Copying all existing data files"); - if(system(home,listener, "/usr/bin/cp","-pR",".", tmpDir.getAbsolutePath())!=0) { - out.println("Failed to copy "+home+" to "+tmpDir); + if (system(home, listener, "/usr/bin/cp", "-pR", ".", tmpDir.getAbsolutePath()) != 0) { + out.println("Failed to copy " + home + " to " + tmpDir); return false; } // unmount - out.println("Unmounting "+target); + out.println("Unmounting " + target); hudson.unmount(NativeZfsFileSystem.MS_FORCE); // move the original directory to the side - File backup = new File(home.getPath()+".backup"); - out.println("Moving "+home+" to "+backup); - if(backup.exists()) + File backup = new File(home.getPath() + ".backup"); + out.println("Moving " + home + " to " + backup); + if (backup.exists()) { Util.deleteRecursive(backup); - if(!home.renameTo(backup)) { - out.println("Failed to move your current data "+home+" out of the way"); + } + if (!home.renameTo(backup)) { + out.println("Failed to move your current data " + home + " out of the way"); } // update the mount point - out.println("Creating a new mount point at "+home); - if(!home.mkdir()) - throw new IOException("Failed to create mount point "+home); + out.println("Creating a new mount point at " + home); + if (!home.mkdir()) { + throw new IOException("Failed to create mount point " + home); + } - out.println("Mounting "+target); + out.println("Mounting " + target); hudson.setMountPoint(home); hudson.mount(); @@ -359,9 +357,9 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable hudson.share(); // delete back up - out.println("Deleting "+backup); - if(system(new File("/"),listener,"/usr/bin/rm","-rf",backup.getAbsolutePath())!=0) { - out.println("Failed to delete "+backup.getAbsolutePath()); + out.println("Deleting " + backup); + if (system(new File("/"), listener, "/usr/bin/rm", "-rf", backup.getAbsolutePath()) != 0) { + out.println("Failed to delete " + backup.getAbsolutePath()); return false; } @@ -380,13 +378,15 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable private static String computeHudsonFileSystemName(NativeZfsFileSystem top) { try { NativeUtils nativeUtils = NativeUtils.getInstance(); - - if(!nativeUtils.zfsExists(top.getName()+"/hudson")) - return top.getName()+"/hudson"; - for( int i = 2; ; i++ ) { + + if (!nativeUtils.zfsExists(top.getName() + "/hudson")) { + return top.getName() + "/hudson"; + } + for (int i = 2;; i++) { String name = top.getName() + "/hudson" + i; - if(!nativeUtils.zfsExists(name)) + if (!nativeUtils.zfsExists(name)) { return name; + } } } catch (NativeAccessException ex) { Logger.getLogger(ZFSInstaller.class.getName()).log(Level.SEVERE, null, ex); @@ -398,6 +398,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable * Used to indicate that the migration was completed successfully. */ public static final class MigrationCompleteNotice extends AdministrativeMonitor { + public boolean isActivated() { return true; } @@ -407,6 +408,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable * Used to indicate a failure in the migration. */ public static final class MigrationFailedNotice extends AdministrativeMonitor { + ByteArrayOutputStream record; MigrationFailedNotice(ByteArrayOutputStream record) { @@ -416,16 +418,14 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable public boolean isActivated() { return true; } - + public String getLog() { return record.toString(); } } - private static final Logger LOGGER = Logger.getLogger(ZFSInstaller.class.getName()); - /** * Escape hatch in case JNI calls fatally crash, like in HUDSON-3733. */ - public static boolean disabled = Boolean.getBoolean(ZFSInstaller.class.getName()+".disabled"); + public static boolean disabled = Boolean.getBoolean(ZFSInstaller.class.getName() + ".disabled"); } diff --git a/hudson-core/src/main/java/hudson/os/solaris/ZFSProvisioner.java b/hudson-core/src/main/java/hudson/os/solaris/ZFSProvisioner.java index ce20ba8..8db67aa 100644 --- a/hudson-core/src/main/java/hudson/os/solaris/ZFSProvisioner.java +++ b/hudson-core/src/main/java/hudson/os/solaris/ZFSProvisioner.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: + * Contributors: + * + * * - * - * * *******************************************************************************/ @@ -43,7 +43,7 @@ import java.util.logging.Logger; * @author Kohsuke Kawaguchi */ public class ZFSProvisioner extends FileSystemProvisioner implements Serializable { - + private NativeUtils nativeUtils = NativeUtils.getInstance(); private final Node node; private final String rootDataset; @@ -54,22 +54,23 @@ public class ZFSProvisioner extends FileSystemProvisioner implements Serializabl public String invoke(File f, VirtualChannel channel) throws IOException { try { NativeZfsFileSystem fs = nativeUtils.getZfsByMountPoint(f); - if(fs != null) return fs.getName(); + if (fs != null) { + return fs.getName(); + } } catch (NativeAccessException ex) { Logger.getLogger(ZFSProvisioner.class.getName()).log(Level.SEVERE, null, ex); } - + // TODO: for now, only support slaves that are already on ZFS. throw new IOException("Not on ZFS"); } }); } - public void prepareWorkspace(AbstractBuild<?,?> build, FilePath ws, final TaskListener listener) throws IOException, InterruptedException { + public void prepareWorkspace(AbstractBuild<?, ?> build, FilePath ws, final TaskListener listener) throws IOException, InterruptedException { final String name = build.getProject().getFullName(); - - ws.act(new FileCallable<Void>() { + ws.act(new FileCallable<Void>() { public Void invoke(File f, VirtualChannel channel) throws IOException { try { NativeZfsFileSystem fs = nativeUtils.getZfsByMountPoint(f); @@ -96,13 +97,13 @@ public class ZFSProvisioner extends FileSystemProvisioner implements Serializabl public Void invoke(File f, VirtualChannel channel) throws IOException { try { NativeZfsFileSystem fs = nativeUtils.getZfsByMountPoint(f); - if(fs != null){ - fs.destory(true); + if (fs != null) { + fs.destory(true); } } catch (NativeAccessException ex) { Logger.getLogger(ZFSProvisioner.class.getName()).log(Level.SEVERE, null, ex); } - + return null; } }); @@ -121,6 +122,7 @@ public class ZFSProvisioner extends FileSystemProvisioner implements Serializabl @Extension public static final class DescriptorImpl extends FileSystemProvisionerDescriptor { + public boolean discard(FilePath ws, TaskListener listener) throws IOException, InterruptedException { // TODO return false; @@ -130,6 +132,5 @@ public class ZFSProvisioner extends FileSystemProvisioner implements Serializabl return "ZFS"; } } - private static final long serialVersionUID = 1L; } diff --git a/hudson-core/src/main/java/hudson/os/solaris/package-info.java b/hudson-core/src/main/java/hudson/os/solaris/package-info.java index 065099e..aa20300 100644 --- a/hudson-core/src/main/java/hudson/os/solaris/package-info.java +++ b/hudson-core/src/main/java/hudson/os/solaris/package-info.java @@ -1,16 +1,18 @@ -/******************************************************************************* +/** + * ***************************************************************************** * * Copyright (c) 2004-2011 Oracle Corporation * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * * - *******************************************************************************/ + * + ****************************************************************************** + */ /** * Solaris specific features of Hudson. */ diff --git a/hudson-core/src/main/java/hudson/scheduler/BaseParser.java b/hudson-core/src/main/java/hudson/scheduler/BaseParser.java index 364c263..823c435 100644 --- a/hudson-core/src/main/java/hudson/scheduler/BaseParser.java +++ b/hudson-core/src/main/java/hudson/scheduler/BaseParser.java @@ -7,11 +7,11 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* + * Contributors: + * * Kohsuke Kawaguchi -* - * + * + * * *******************************************************************************/ @@ -23,30 +23,31 @@ import org.antlr.runtime.RecognizerSharedState; import org.antlr.runtime.Token; import org.antlr.runtime.TokenStream; - - /** * @author Kohsuke Kawaguchi */ abstract class BaseParser extends Parser { - private static final int[] LOWER_BOUNDS = new int[] {0,0,1,0,0}; - private static final int[] UPPER_BOUNDS = new int[] {59,23,31,12,7}; + + private static final int[] LOWER_BOUNDS = new int[]{0, 0, 1, 0, 0}; + private static final int[] UPPER_BOUNDS = new int[]{59, 23, 31, 12, 7}; protected BaseParser(TokenStream tokenStream) { super(tokenStream); } - + protected BaseParser(TokenStream stream, RecognizerSharedState sharedState) { - super(stream, sharedState); + super(stream, sharedState); } protected long doRange(int start, int end, int step, int field) throws RecognitionException { rangeCheck(start, field); rangeCheck(end, field); - if (step <= 0) + if (step <= 0) { error(Messages.BaseParser_MustBePositive(step)); - if (start>end) - error(Messages.BaseParser_StartEndReversed(end,start)); + } + if (start > end) { + error(Messages.BaseParser_StartEndReversed(end, start)); + } long bits = 0; for (int i = start; i <= end; i += step) { @@ -55,56 +56,58 @@ abstract class BaseParser extends Parser { return bits; } - protected long doRange( int step, int field ) throws RecognitionException { - return doRange( LOWER_BOUNDS[field], UPPER_BOUNDS[field], step, field ); + protected long doRange(int step, int field) throws RecognitionException { + return doRange(LOWER_BOUNDS[field], UPPER_BOUNDS[field], step, field); } protected void rangeCheck(int value, int field) throws RecognitionException { - if( value<LOWER_BOUNDS[field] || UPPER_BOUNDS[field]<value ) { - error(Messages.BaseParser_OutOfRange(value,LOWER_BOUNDS[field],UPPER_BOUNDS[field])); + if (value < LOWER_BOUNDS[field] || UPPER_BOUNDS[field] < value) { + error(Messages.BaseParser_OutOfRange(value, LOWER_BOUNDS[field], UPPER_BOUNDS[field])); } } private void error(String msg) throws RecognitionException { Token token = getTokenStream().LT(0); throw new SemanticException( - msg, - token.getLine(), - token.getCharPositionInLine() - ); + msg, + token.getLine(), + token.getCharPositionInLine()); } - + public static class SemanticException extends RecognitionException { - String msg; - Throwable throwable; - - public SemanticException(String msg, int line, int charPositionInLine) { - super(); - this.msg = msg; - this.line = line; - this.charPositionInLine = charPositionInLine; - } - - public SemanticException(String msg, Throwable e) { - super(); - this.msg = msg; - this.throwable = e; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("SemanticException: "); - sb.append(msg); - if (line > 0 || charPositionInLine > 0) - sb.append(" at [").append(line).append(',').append(charPositionInLine); - if (throwable != null) - sb.append(" from ").append(throwable.toString()); - return sb.toString(); - } - - @Override - public String getMessage() { - return msg; - } + + String msg; + Throwable throwable; + + public SemanticException(String msg, int line, int charPositionInLine) { + super(); + this.msg = msg; + this.line = line; + this.charPositionInLine = charPositionInLine; + } + + public SemanticException(String msg, Throwable e) { + super(); + this.msg = msg; + this.throwable = e; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("SemanticException: "); + sb.append(msg); + if (line > 0 || charPositionInLine > 0) { + sb.append(" at [").append(line).append(',').append(charPositionInLine); + } + if (throwable != null) { + sb.append(" from ").append(throwable.toString()); + } + return sb.toString(); + } + + @Override + public String getMessage() { + return msg; + } } } diff --git a/hudson-core/src/main/java/hudson/scheduler/CronTab.java b/hudson-core/src/main/java/hudson/scheduler/CronTab.java index 503e341..35cfea5 100644 --- a/hudson-core/src/main/java/hudson/scheduler/CronTab.java +++ b/hudson-core/src/main/java/hudson/scheduler/CronTab.java @@ -7,10 +7,10 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * Contributors: -* -* Kohsuke Kawaguchi, InfraDNA, Inc. - * + * Contributors: + * + * Kohsuke Kawaguchi, InfraDNA, Inc. + * * *******************************************************************************/ @@ -32,25 +32,21 @@ import org.antlr.runtime.RecognitionException; * @author Kohsuke Kawaguchi */ public final class CronTab { + /** - * bits[0]: minutes - * bits[1]: hours - * bits[2]: days - * bits[3]: months + * bits[0]: minutes bits[1]: hours bits[2]: days bits[3]: months * * false:not scheduled <-> true scheduled */ final long[] bits = new long[4]; - int dayOfWeek; - /** * Textual representation. */ private String spec; public CronTab(String format) throws RecognitionException { - this(format,1); + this(format, 1); } public CronTab(String format, int line) throws RecognitionException { @@ -65,56 +61,64 @@ public final class CronTab { spec = format; parser.startRule(this); - if((dayOfWeek&(1<<7))!=0) + if ((dayOfWeek & (1 << 7)) != 0) { dayOfWeek |= 1; // copy bit 7 over to bit 0 + } } - /** * Returns true if the given calendar matches */ boolean check(Calendar cal) { - if(!checkBits(bits[0],cal.get(MINUTE))) + if (!checkBits(bits[0], cal.get(MINUTE))) { return false; - if(!checkBits(bits[1],cal.get(HOUR_OF_DAY))) + } + if (!checkBits(bits[1], cal.get(HOUR_OF_DAY))) { return false; - if(!checkBits(bits[2],cal.get(DAY_OF_MONTH))) + } + if (!checkBits(bits[2], cal.get(DAY_OF_MONTH))) { return false; - if(!checkBits(bits[3],cal.get(MONTH)+1)) + } + if (!checkBits(bits[3], cal.get(MONTH) + 1)) { return false; - if(!checkBits(dayOfWeek,cal.get(Calendar.DAY_OF_WEEK)-1)) + } + if (!checkBits(dayOfWeek, cal.get(Calendar.DAY_OF_WEEK) - 1)) { return false; + } return true; } private static abstract class CalendarField { + /** * {@link Calendar} field ID. */ final int field; /** - * Lower field is a calendar field whose value needs to be reset when we change the value in this field. - * For example, if we modify the value in HOUR, MINUTES must be reset. + * Lower field is a calendar field whose value needs to be reset when we + * change the value in this field. For example, if we modify the value + * in HOUR, MINUTES must be reset. */ final CalendarField lowerField; /** - * Whether this field is 0-origin or 1-origin differs between Crontab and {@link Calendar}, - * so this field adjusts that. If crontab is 1 origin and calendar is 0 origin, this field is 1 - * that is the value is {@code (cronOrigin-calendarOrigin)} + * Whether this field is 0-origin or 1-origin differs between Crontab + * and {@link Calendar}, so this field adjusts that. If crontab is 1 + * origin and calendar is 0 origin, this field is 1 that is the value is + * {@code (cronOrigin-calendarOrigin)} */ final int offset; /** - * When we reset this field, we set the field to this value. - * For example, resetting {@link Calendar#DAY_OF_MONTH} means setting it to 1. + * When we reset this field, we set the field to this value. For + * example, resetting {@link Calendar#DAY_OF_MONTH} means setting it to + * 1. */ final int min; /** - * If this calendar field has other aliases such that a change in this field - * modifies other field values, then true. + * If this calendar field has other aliases such that a change in this + * field modifies other field values, then true. */ final boolean redoAdjustmentIfModified; - /** * What is this field? Useful for debugging */ @@ -124,7 +128,7 @@ public final class CronTab { this.displayName = displayName; this.field = field; this.min = min; - this.redoAdjustmentIfModified= redoAdjustmentIfModified; + this.redoAdjustmentIfModified = redoAdjustmentIfModified; this.lowerField = lowerField; this.offset = offset; } @@ -133,15 +137,15 @@ public final class CronTab { * Gets the current value of this field in the given calendar. */ int valueOf(Calendar c) { - return c.get(field)+offset; + return c.get(field) + offset; } void addTo(Calendar c, int i) { - c.add(field,i); + c.add(field, i); } void setTo(Calendar c, int i) { - c.set(field,i-offset); + c.set(field, i - offset); } void clear(Calendar c) { @@ -149,43 +153,50 @@ public final class CronTab { } /** - * Given the value 'n' (which represents the current value), finds the smallest x such that: - * 1) x matches the specified {@link CronTab} (as far as this field is concerned.) - * 2) x>=n (inclusive) + * Given the value 'n' (which represents the current value), finds the + * smallest x such that: 1) x matches the specified {@link CronTab} (as + * far as this field is concerned.) 2) x>=n (inclusive) * - * If there's no such bit, return -1. Note that if 'n' already matches the crontab, the same n will be returned. + * If there's no such bit, return -1. Note that if 'n' already matches + * the crontab, the same n will be returned. */ private int ceil(CronTab c, int n) { long bits = bits(c); - while ((bits|(1L<<n))!=bits) { - if (n>60) return -1; + while ((bits | (1L << n)) != bits) { + if (n > 60) { + return -1; + } n++; } return n; } /** - * Given a bit mask, finds the first bit that's on, and return its index. + * Given a bit mask, finds the first bit that's on, and return its + * index. */ private int first(CronTab c) { - return ceil(c,0); + return ceil(c, 0); } private int floor(CronTab c, int n) { long bits = bits(c); - while ((bits|(1L<<n))!=bits) { - if (n==0) return -1; + while ((bits | (1L << n)) != bits) { + if (n == 0) { + return -1; + } n--; } return n; } private int last(CronTab c) { - return floor(c,63); + return floor(c, 63); } /** - * Extracts the bit masks from the given {@link CronTab} that matches this field. + * Extracts the bit masks from the given {@link CronTab} that matches + * this field. */ abstract long bits(CronTab c); @@ -193,60 +204,76 @@ public final class CronTab { * Increment the next field. */ abstract void rollUp(Calendar cal, int i); + private static final CalendarField MINUTE = new CalendarField("minute", Calendar.MINUTE, 0, 0, false, null) { + long bits(CronTab c) { + return c.bits[0]; + } - private static final CalendarField MINUTE = new CalendarField("minute", Calendar.MINUTE, 0, 0, false, null) { - long bits(CronTab c) { return c.bits[0]; } - void rollUp(Calendar cal, int i) { cal.add(Calendar.HOUR_OF_DAY,i); } + void rollUp(Calendar cal, int i) { + cal.add(Calendar.HOUR_OF_DAY, i); + } }; - private static final CalendarField HOUR = new CalendarField("hour", Calendar.HOUR_OF_DAY, 0, 0, false, MINUTE) { - long bits(CronTab c) { return c.bits[1]; } - void rollUp(Calendar cal, int i) { cal.add(Calendar.DAY_OF_MONTH,i); } + private static final CalendarField HOUR = new CalendarField("hour", Calendar.HOUR_OF_DAY, 0, 0, false, MINUTE) { + long bits(CronTab c) { + return c.bits[1]; + } + + void rollUp(Calendar cal, int i) { + cal.add(Calendar.DAY_OF_MONTH, i); + } }; - private static final CalendarField DAY_OF_MONTH = new CalendarField("day", Calendar.DAY_OF_MONTH, 1, 0, true, HOUR) { - long bits(CronTab c) { return c.bits[2]; } - void rollUp(Calendar cal, int i) { cal.add(Calendar.MONTH,i); } + private static final CalendarField DAY_OF_MONTH = new CalendarField("day", Calendar.DAY_OF_MONTH, 1, 0, true, HOUR) { + long bits(CronTab c) { + return c.bits[2]; + } + + void rollUp(Calendar cal, int i) { + cal.add(Calendar.MONTH, i); + } }; - private static final CalendarField MONTH = new CalendarField("month", Calendar.MONTH, 1, 1, false, DAY_OF_MONTH) { - long bits(CronTab c) { return c.bits[3]; } - void rollUp(Calendar cal, int i) { cal.add(Calendar.YEAR,i); } + private static final CalendarField MONTH = new CalendarField("month", Calendar.MONTH, 1, 1, false, DAY_OF_MONTH) { + long bits(CronTab c) { + return c.bits[3]; + } + + void rollUp(Calendar cal, int i) { + cal.add(Calendar.YEAR, i); + } }; - private static final CalendarField DAY_OF_WEEK = new CalendarField("dow", Calendar.DAY_OF_WEEK, 1,-1, true, HOUR) { - long bits(CronTab c) { return c.dayOfWeek; } + private static final CalendarField DAY_OF_WEEK = new CalendarField("dow", Calendar.DAY_OF_WEEK, 1, -1, true, HOUR) { + long bits(CronTab c) { + return c.dayOfWeek; + } + void rollUp(Calendar cal, int i) { - cal.add(Calendar.DAY_OF_WEEK,7); + cal.add(Calendar.DAY_OF_WEEK, 7); } @Override void setTo(Calendar c, int i) { - int v = i-offset; - c.set(field,v); - if (v<c.getFirstDayOfWeek()) { + int v = i - offset; + c.set(field, v); + if (v < c.getFirstDayOfWeek()) { // in crontab, the first DoW is always Sunday, but in Java, it can be Monday or in theory arbitrary other days. // When first DoW is 1/2 Monday, calendar points to 1/2 Monday, setting the DoW to Sunday makes // the calendar moves forward to 1/8 Sunday, instead of 1/1 Sunday. So we need to compensate that effect here. - addTo(c,-7); + addTo(c, -7); } } }; - private static final CalendarField[] ADJUST_ORDER = { MONTH, DAY_OF_MONTH, DAY_OF_WEEK, HOUR, MINUTE }; } - /** - * Computes the nearest future timestamp that matches this cron tab. - * <p> - * More precisely, given the time 't', computes another smallest time x such that: + * Computes the nearest future timestamp that matches this cron tab. <p> + * More precisely, given the time 't', computes another smallest time x such + * that: * - * <ul> - * <li>x >= t (inclusive) - * <li>x matches this crontab - * </ul> + * <ul> <li>x >= t (inclusive) <li>x matches this crontab </ul> * - * <p> - * Note that if t already matches this cron, it's returned as is. + * <p> Note that if t already matches this cron, it's returned as is. */ public Calendar ceil(long t) { Calendar cal = new GregorianCalendar(Locale.US); @@ -264,23 +291,26 @@ public final class CronTab { while (true) { for (CalendarField f : CalendarField.ADJUST_ORDER) { int cur = f.valueOf(cal); - int next = f.ceil(this,cur); - if (cur==next) continue; // this field is already in a good shape. move on to next - + int next = f.ceil(this, cur); + if (cur == next) { + continue; // this field is already in a good shape. move on to next + } // we are modifying this field, so clear all the lower level fields - for (CalendarField l=f.lowerField; l!=null; l=l.lowerField) + for (CalendarField l = f.lowerField; l != null; l = l.lowerField) { l.clear(cal); + } - if (next<0) { + if (next < 0) { // we need to roll over to the next field. f.rollUp(cal, 1); - f.setTo(cal,f.first(this)); + f.setTo(cal, f.first(this)); // since higher order field is affected by this, we need to restart from all over continue OUTER; } else { - f.setTo(cal,next); - if (f.redoAdjustmentIfModified) + f.setTo(cal, next); + if (f.redoAdjustmentIfModified) { continue OUTER; // when we modify DAY_OF_MONTH and DAY_OF_WEEK, do it all over from the top + } } } return cal; // all fields adjusted @@ -288,17 +318,13 @@ public final class CronTab { } /** - * Computes the nearest past timestamp that matched this cron tab. - * <p> - * More precisely, given the time 't', computes another smallest time x such that: + * Computes the nearest past timestamp that matched this cron tab. <p> More + * precisely, given the time 't', computes another smallest time x such + * that: * - * <ul> - * <li>x <= t (inclusive) - * <li>x matches this crontab - * </ul> + * <ul> <li>x <= t (inclusive) <li>x matches this crontab </ul> * - * <p> - * Note that if t already matches this cron, it's returned as is. + * <p> Note that if t already matches this cron, it's returned as is. */ public Calendar floor(long t) { Calendar cal = new GregorianCalendar(Locale.US); @@ -316,32 +342,35 @@ public final class CronTab { while (true) { for (CalendarField f : CalendarField.ADJUST_ORDER) { int cur = f.valueOf(cal); - int next = f.floor(this,cur); - if (cur==next) continue; // this field is already in a good shape. move on to next - + int next = f.floor(this, cur); + if (cur == next) { + continue; // this field is already in a good shape. move on to next + } // we are modifying this field, so clear all the lower level fields - for (CalendarField l=f.lowerField; l!=null; l=l.lowerField) + for (CalendarField l = f.lowerField; l != null; l = l.lowerField) { l.clear(cal); + } - if (next<0) { + if (next < 0) { // we need to borrow from the next field. - f.rollUp(cal,-1); + f.rollUp(cal, -1); // the problem here, in contrast with the ceil method, is that // the maximum value of the field is not always a fixed value (that is, day of month) // so we zero-clear all the lower fields, set the desired value +1, - f.setTo(cal,f.last(this)); - f.addTo(cal,1); + f.setTo(cal, f.last(this)); + f.addTo(cal, 1); // then subtract a minute to achieve maximum values on all the lower fields, // with the desired value in 'f' - CalendarField.MINUTE.addTo(cal,-1); + CalendarField.MINUTE.addTo(cal, -1); // since higher order field is affected by this, we need to restart from all over continue OUTER; } else { - f.setTo(cal,next); - f.addTo(cal,1); - CalendarField.MINUTE.addTo(cal,-1); - if (f.redoAdjustmentIfModified) + f.setTo(cal, next); + f.addTo(cal, 1); + CalendarField.MINUTE.addTo(cal, -1); + if (f.redoAdjustmentIfModified) { continue OUTER; // when we modify DAY_OF_MONTH and DAY_OF_WEEK, do it all over from the top + } } } return cal; // all fields adjusted @@ -349,48 +378,47 @@ public final class CronTab { } void set(String format) throws RecognitionException { - set(format,1); + set(format, 1); } /** * Returns true if n-th bit is on. */ private boolean checkBits(long bitMask, int n) { - return (bitMask|(1L<<n))==bitMask; + return (bitMask | (1L << n)) == bitMask; } public String toString() { - return super.toString()+"["+ - toString("minute",bits[0])+','+ - toString("hour",bits[1])+','+ - toString("dayOfMonth",bits[2])+','+ - toString("month",bits[3])+','+ - toString("dayOfWeek",dayOfWeek)+']'; + return super.toString() + "[" + + toString("minute", bits[0]) + ',' + + toString("hour", bits[1]) + ',' + + toString("dayOfMonth", bits[2]) + ',' + + toString("month", bits[3]) + ',' + + toString("dayOfWeek", dayOfWeek) + ']'; } private String toString(String key, long bit) { - return key+'='+Long.toHexString(bit); + return key + '=' + Long.toHexString(bit); } /** - * Checks if this crontab entry looks reasonable, - * and if not, return an warning message. + * Checks if this crontab entry looks reasonable, and if not, return an + * warning message. * - * <p> - * The point of this method is to catch syntactically correct - * but semantically suspicious combinations, like - * "* 0 * * *" + * <p> The point of this method is to catch syntactically correct but + * semantically suspicious combinations, like "* 0 * * *" */ public String checkSanity() { - for( int i=0; i<5; i++ ) { - long bitMask = (i<4)?bits[i]:(long)dayOfWeek; - for( int j=LOWER_BOUNDS[i]; j<=UPPER_BOUNDS[i]; j++ ) { - if(!checkBits(bitMask,j)) { + for (int i = 0; i < 5; i++) { + long bitMask = (i < 4) ? bits[i] : (long) dayOfWeek; + for (int j = LOWER_BOUNDS[i]; j <= UPPER_BOUNDS[i]; j++) { + if (!checkBits(bitMask, j)) { // this rank has a sparse entry. // if we have a sparse rank, one of them better be the left-most. - if(i>0) - return "Do you really mean \"every minute\" when you say \""+spec+"\"? "+ - "Perhaps you meant \"0 "+spec.substring(spec.indexOf(' ')+1)+"\""; + if (i > 0) { + return "Do you really mean \"every minute\" when you say \"" + spec + "\"? " + + "Perhaps you meant \"0 " + spec.substring(spec.indexOf(' ') + 1) + "\""; + } // once we find a sparse rank, upper ranks don't matter return null; } @@ -399,8 +427,7 @@ public final class CronTab { return null; } - // lower/uppser bounds of fields - private static final int[] LOWER_BOUNDS = new int[] {0,0,1,0,0}; - private static final int[] UPPER_BOUNDS = new int[] {59,23,31,12,7}; + private static final int[] LOWER_BOUNDS = new int[]{0, 0, 1, 0, 0}; + private static final int[] UPPER_BOUNDS = new int[]{59, 23, 31, 12, 7}; } diff --git a/hudson-core/src/main/java/hudson/scheduler/CronTabList.java b/hudson-core/src/main/java/hudson/scheduler/CronTabList.java index 2e3ea5d..d879364 100644 --- a/hudson-core/src/main/java/hudson/scheduler/CronTabList.java +++ b/hudson-core/src/main/java/hudson/scheduler/CronTabList.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 - * + * * *******************************************************************************/ @@ -28,6 +28,7 @@ import org.antlr.runtime.RecognitionException; * @author Kohsuke Kawaguchi */ public final class CronTabList { + private final List<CronTab> tabs; public CronTabList(Collection<CronTab> tabs) { @@ -47,13 +48,11 @@ public final class CronTabList { } /** - * Checks if this crontab entry looks reasonable, - * and if not, return an warning message. + * Checks if this crontab entry looks reasonable, and if not, return an + * warning message. * - * <p> - * The point of this method is to catch syntactically correct - * but semantically suspicious combinations, like - * "* 0 * * *" + * <p> The point of this method is to catch syntactically correct but + * semantically suspicious combinations, like "* 0 * * *" */ public String checkSanity() { for (CronTab tab : tabs) { @@ -71,8 +70,9 @@ public final class CronTabList { for (String line : format.split("\\r?\\n")) { lineNumber++; line = line.trim(); - if (line.length() == 0 || line.startsWith("#")) + if (line.length() == 0 || line.startsWith("#")) { continue; // ignorable line + } try { r.add(new CronTab(line, lineNumber)); } catch (RecognitionException e) { diff --git a/hudson-core/src/main/java/hudson/scheduler/package.html b/hudson-core/src/main/java/hudson/scheduler/package.html index 22025cc..4106d33 100644 --- a/hudson-core/src/main/java/hudson/scheduler/package.html +++ b/hudson-core/src/main/java/hudson/scheduler/package.html @@ -16,5 +16,5 @@ --> <html><head/><body> -Classes that implement cron-like features -</body></html>
\ No newline at end of file + Classes that implement cron-like features + </body></html>
\ No newline at end of file |

