提交 94b427f8 编写于 作者: J Jesse Glick

Merge branch 'master' into JenkinsRule-additions

...@@ -29,4 +29,4 @@ indent_style = space ...@@ -29,4 +29,4 @@ indent_style = space
indent_size = 2 indent_size = 2
[*.md] [*.md]
trim_trailing_whitespace = false~ trim_trailing_whitespace = false
\ No newline at end of file
...@@ -55,7 +55,15 @@ Upcoming changes</a> ...@@ -55,7 +55,15 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. --> <!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=--> <div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image> <ul class=image>
<li class=> <li class=bug>
Jenkins CLI doesn't handle arguments with equal signs
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21160">issue 21160</a>)
<li class=bug>
master/slave communication ping reacts badly if a clock jumps.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21251">issue 21251</a>)
<li class=rfe>
JNLP slaves can now connect to master through HTTP proxy.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-6167">issue 21251</a>)
</ul> </ul>
</div><!--=TRUNK-END=--> </div><!--=TRUNK-END=-->
<h3><a name=v1.605>What's new in 1.605</a> (2015/03/16)</h3> <h3><a name=v1.605>What's new in 1.605</a> (2015/03/16)</h3>
......
...@@ -190,7 +190,7 @@ THE SOFTWARE. ...@@ -190,7 +190,7 @@ THE SOFTWARE.
<dependency><!-- JENKINS-21160: remoting also depends on args4j, please update accordingly --> <dependency><!-- JENKINS-21160: remoting also depends on args4j, please update accordingly -->
<groupId>args4j</groupId> <groupId>args4j</groupId>
<artifactId>args4j</artifactId> <artifactId>args4j</artifactId>
<version>2.0.23</version> <version>2.0.31</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jenkins-ci</groupId> <groupId>org.jenkins-ci</groupId>
......
...@@ -131,7 +131,7 @@ public class Util { ...@@ -131,7 +131,7 @@ public class Util {
public static String replaceMacro( @CheckForNull String s, @Nonnull Map<String,String> properties) { public static String replaceMacro( @CheckForNull String s, @Nonnull Map<String,String> properties) {
return replaceMacro(s,new VariableResolver.ByMap<String>(properties)); return replaceMacro(s,new VariableResolver.ByMap<String>(properties));
} }
/** /**
* Replaces the occurrence of '$key' by <tt>resolver.get('key')</tt>. * Replaces the occurrence of '$key' by <tt>resolver.get('key')</tt>.
* *
...@@ -143,7 +143,7 @@ public class Util { ...@@ -143,7 +143,7 @@ public class Util {
if (s == null) { if (s == null) {
return null; return null;
} }
int idx=0; int idx=0;
while(true) { while(true) {
Matcher m = VARIABLE.matcher(s); Matcher m = VARIABLE.matcher(s);
...@@ -370,6 +370,30 @@ public class Util { ...@@ -370,6 +370,30 @@ public class Util {
} }
} }
/**
* A mostly accurate check of whether a path is a relative path or not. This is designed to take a path against
* an unknown operating system so may give invalid results.
*
* @param path the path.
* @return {@code true} if the path looks relative.
* @since 1.606
*/
public static boolean isRelativePath(String path) {
if (path.startsWith("/"))
return false;
if (path.startsWith("\\\\") && path.length() > 3 && path.indexOf('\\', 3) != -1)
return false; // a UNC path which is the most absolute you can get on windows
if (path.length() >= 3 && ':' == path.charAt(1)) {
// never mind that the drive mappings can be changed between sessions, we just want to
// know if the 3rd character is a `\` (or a '/' is acceptable too)
char p = path.charAt(0);
if (('A' <= p && p <= 'Z') || ('a' <= p && p <= 'z')) {
return path.charAt(2) != '\\' && path.charAt(2) != '/';
}
}
return true;
}
/** /**
* Creates a new temporary directory. * Creates a new temporary directory.
*/ */
...@@ -624,7 +648,7 @@ public class Util { ...@@ -624,7 +648,7 @@ public class Util {
* Converts a string into 128-bit AES key. * Converts a string into 128-bit AES key.
* @since 1.308 * @since 1.308
*/ */
@Nonnull @Nonnull
public static SecretKey toAes128Key(@Nonnull String s) { public static SecretKey toAes128Key(@Nonnull String s) {
try { try {
// turn secretKey into 256 bit hash // turn secretKey into 256 bit hash
...@@ -743,9 +767,9 @@ public class Util { ...@@ -743,9 +767,9 @@ public class Util {
/** /**
* Combines number and unit, with a plural suffix if needed. * Combines number and unit, with a plural suffix if needed.
* *
* @deprecated * @deprecated
* Use individual localization methods instead. * Use individual localization methods instead.
* See {@link Messages#Util_year(Object)} for an example. * See {@link Messages#Util_year(Object)} for an example.
* Deprecated since 2009-06-24, remove method after 2009-12-24. * Deprecated since 2009-06-24, remove method after 2009-12-24.
*/ */
...@@ -780,7 +804,7 @@ public class Util { ...@@ -780,7 +804,7 @@ public class Util {
* {@link #rawEncode(String)} should generally be used instead, though be careful to pass only * {@link #rawEncode(String)} should generally be used instead, though be careful to pass only
* a single path component to that method (it will encode /, but this method does not). * a single path component to that method (it will encode /, but this method does not).
*/ */
@Nonnull @Nonnull
public static String encode(@Nonnull String s) { public static String encode(@Nonnull String s) {
try { try {
boolean escaped = false; boolean escaped = false;
...@@ -888,7 +912,7 @@ public class Util { ...@@ -888,7 +912,7 @@ public class Util {
/** /**
* Escapes HTML unsafe characters like &lt;, &amp; to the respective character entities. * Escapes HTML unsafe characters like &lt;, &amp; to the respective character entities.
*/ */
@Nonnull @Nonnull
public static String escape(@Nonnull String text) { public static String escape(@Nonnull String text) {
if (text==null) return null; if (text==null) return null;
StringBuilder buf = new StringBuilder(text.length()+64); StringBuilder buf = new StringBuilder(text.length()+64);
...@@ -1112,7 +1136,7 @@ public class Util { ...@@ -1112,7 +1136,7 @@ public class Util {
* @param symlinkPath * @param symlinkPath
* Where to create a symlink in (relative to {@code baseDir}) * Where to create a symlink in (relative to {@code baseDir})
*/ */
public static void createSymlink(@Nonnull File baseDir, @Nonnull String targetPath, public static void createSymlink(@Nonnull File baseDir, @Nonnull String targetPath,
@Nonnull String symlinkPath, @Nonnull TaskListener listener) throws InterruptedException { @Nonnull String symlinkPath, @Nonnull TaskListener listener) throws InterruptedException {
try { try {
if (createSymlinkJava7(baseDir, targetPath, symlinkPath)) { if (createSymlinkJava7(baseDir, targetPath, symlinkPath)) {
...@@ -1346,7 +1370,7 @@ public class Util { ...@@ -1346,7 +1370,7 @@ public class Util {
* @deprecated since 2008-05-13. This method is broken (see ISSUE#1666). It should probably * @deprecated since 2008-05-13. This method is broken (see ISSUE#1666). It should probably
* be removed but I'm not sure if it is considered part of the public API * be removed but I'm not sure if it is considered part of the public API
* that needs to be maintained for backwards compatibility. * that needs to be maintained for backwards compatibility.
* Use {@link #encode(String)} instead. * Use {@link #encode(String)} instead.
*/ */
@Deprecated @Deprecated
public static String encodeRFC2396(String url) { public static String encodeRFC2396(String url) {
...@@ -1367,7 +1391,7 @@ public class Util { ...@@ -1367,7 +1391,7 @@ public class Util {
s = "<span class=error style='display:inline-block'>"+s+"</span>"; s = "<span class=error style='display:inline-block'>"+s+"</span>";
return s; return s;
} }
/** /**
* Returns the parsed string if parsed successful; otherwise returns the default number. * Returns the parsed string if parsed successful; otherwise returns the default number.
* If the string is null, empty or a ParseException is thrown then the defaultNumber * If the string is null, empty or a ParseException is thrown then the defaultNumber
......
...@@ -30,10 +30,12 @@ import org.kohsuke.args4j.Argument; ...@@ -30,10 +30,12 @@ import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.FieldSetter;
import org.kohsuke.args4j.spi.Setter; import org.kohsuke.args4j.spi.Setter;
import org.kohsuke.args4j.spi.OptionHandler; import org.kohsuke.args4j.spi.OptionHandler;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
...@@ -79,6 +81,16 @@ class MethodBinder { ...@@ -79,6 +81,16 @@ class MethodBinder {
public boolean isMultiValued() { public boolean isMultiValued() {
return false; return false;
} }
@Override
public FieldSetter asFieldSetter() {
return null;
}
@Override
public AnnotatedElement asAnnotatedElement() {
return p;
}
}; };
Option option = p.annotation(Option.class); Option option = p.annotation(Option.class);
if (option!=null) { if (option!=null) {
...@@ -148,5 +160,10 @@ class MethodBinder { ...@@ -148,5 +160,10 @@ class MethodBinder {
public Class<? extends Annotation> annotationType() { public Class<? extends Annotation> annotationType() {
return base.annotationType(); return base.annotationType();
} }
@Override
public boolean hidden() {
return base.hidden();
}
} }
} }
/* /*
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Erik Ramfelt, Martin Eigenbrodt, Stephen Connolly, Tom Huybrechts * Erik Ramfelt, Martin Eigenbrodt, Stephen Connolly, Tom Huybrechts
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...@@ -63,6 +63,7 @@ import jenkins.security.MasterToSlaveCallable; ...@@ -63,6 +63,7 @@ import jenkins.security.MasterToSlaveCallable;
import jenkins.slaves.WorkspaceLocator; import jenkins.slaves.WorkspaceLocator;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerRequest;
...@@ -92,8 +93,12 @@ public abstract class Slave extends Node implements Serializable { ...@@ -92,8 +93,12 @@ public abstract class Slave extends Node implements Serializable {
private final String description; private final String description;
/** /**
* Absolute path to the root of the workspace * Path to the root of the workspace from the view point of this node, such as "/hudson", this need not
* from the view point of this node, such as "/hudson" * be absolute provided that the launcher establishes a consistent working directory, such as "./.jenkins-slave"
* when used with an SSH launcher.
*
* NOTE: if the administrator is using a relative path they are responsible for ensuring that the launcher used
* provides a consistent working directory
*/ */
protected final String remoteFS; protected final String remoteFS;
...@@ -121,14 +126,14 @@ public abstract class Slave extends Node implements Serializable { ...@@ -121,14 +126,14 @@ public abstract class Slave extends Node implements Serializable {
* Whitespace-separated labels. * Whitespace-separated labels.
*/ */
private String label=""; private String label="";
private /*almost final*/ DescribableList<NodeProperty<?>,NodePropertyDescriptor> nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(Jenkins.getInstance()); private /*almost final*/ DescribableList<NodeProperty<?>,NodePropertyDescriptor> nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(Jenkins.getInstance());
/** /**
* Lazily computed set of labels from {@link #label}. * Lazily computed set of labels from {@link #label}.
*/ */
private transient volatile Set<Label> labels; private transient volatile Set<Label> labels;
/** /**
* Id of user which creates this slave {@link User}. * Id of user which creates this slave {@link User}.
*/ */
...@@ -147,7 +152,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -147,7 +152,7 @@ public abstract class Slave extends Node implements Serializable {
Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy) throws FormException, IOException { Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy) throws FormException, IOException {
this(name, nodeDescription, remoteFS, numExecutors, mode, labelString, launcher, retentionStrategy, new ArrayList()); this(name, nodeDescription, remoteFS, numExecutors, mode, labelString, launcher, retentionStrategy, new ArrayList());
} }
public Slave(@Nonnull String name, String nodeDescription, String remoteFS, int numExecutors, public Slave(@Nonnull String name, String nodeDescription, String remoteFS, int numExecutors,
Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy, List<? extends NodeProperty<?>> nodeProperties) throws FormException, IOException { Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy, List<? extends NodeProperty<?>> nodeProperties) throws FormException, IOException {
this.name = name; this.name = name;
...@@ -159,7 +164,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -159,7 +164,7 @@ public abstract class Slave extends Node implements Serializable {
this.launcher = launcher; this.launcher = launcher;
this.retentionStrategy = retentionStrategy; this.retentionStrategy = retentionStrategy;
getAssignedLabels(); // compute labels now getAssignedLabels(); // compute labels now
this.nodeProperties.replaceBy(nodeProperties); this.nodeProperties.replaceBy(nodeProperties);
Slave node = (Slave) Jenkins.getInstance().getNode(name); Slave node = (Slave) Jenkins.getInstance().getNode(name);
...@@ -168,7 +173,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -168,7 +173,7 @@ public abstract class Slave extends Node implements Serializable {
} }
else{ else{
User user = User.current(); User user = User.current();
userId = user!=null ? user.getId() : "anonymous"; userId = user!=null ? user.getId() : "anonymous";
} }
if (name.equals("")) if (name.equals(""))
throw new FormException(Messages.Slave_InvalidConfig_NoName(), null); throw new FormException(Messages.Slave_InvalidConfig_NoName(), null);
...@@ -179,10 +184,10 @@ public abstract class Slave extends Node implements Serializable { ...@@ -179,10 +184,10 @@ public abstract class Slave extends Node implements Serializable {
if (this.numExecutors<=0) if (this.numExecutors<=0)
throw new FormException(Messages.Slave_InvalidConfig_Executors(name), null); throw new FormException(Messages.Slave_InvalidConfig_Executors(name), null);
} }
/** /**
* Return id of user which created this slave * Return id of user which created this slave
* *
* @return id of user * @return id of user
*/ */
public String getUserId() { public String getUserId() {
...@@ -192,7 +197,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -192,7 +197,7 @@ public abstract class Slave extends Node implements Serializable {
public void setUserId(String userId){ public void setUserId(String userId){
this.userId = userId; this.userId = userId;
} }
public ComputerLauncher getLauncher() { public ComputerLauncher getLauncher() {
return launcher == null ? new JNLPLauncher() : launcher; return launcher == null ? new JNLPLauncher() : launcher;
} }
...@@ -214,7 +219,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -214,7 +219,7 @@ public abstract class Slave extends Node implements Serializable {
} }
public void setNodeName(String name) { public void setNodeName(String name) {
this.name = name; this.name = name;
} }
public String getNodeDescription() { public String getNodeDescription() {
...@@ -237,7 +242,7 @@ public abstract class Slave extends Node implements Serializable { ...@@ -237,7 +242,7 @@ public abstract class Slave extends Node implements Serializable {
assert nodeProperties != null; assert nodeProperties != null;
return nodeProperties; return nodeProperties;
} }
public RetentionStrategy getRetentionStrategy() { public RetentionStrategy getRetentionStrategy() {
return retentionStrategy == null ? RetentionStrategy.Always.INSTANCE : retentionStrategy; return retentionStrategy == null ? RetentionStrategy.Always.INSTANCE : retentionStrategy;
} }
...@@ -273,14 +278,21 @@ public abstract class Slave extends Node implements Serializable { ...@@ -273,14 +278,21 @@ public abstract class Slave extends Node implements Serializable {
return workspace; return workspace;
} }
} }
FilePath r = getWorkspaceRoot(); FilePath r = getWorkspaceRoot();
if(r==null) return null; // offline if(r==null) return null; // offline
return r.child(item.getFullName()); return r.child(item.getFullName());
} }
@CheckForNull
public FilePath getRootPath() { public FilePath getRootPath() {
return createPath(remoteFS); final SlaveComputer computer = getComputer();
if (computer == null) {
// if computer is null then channel is null and thus we were going to return null anyway
return null;
} else {
return createPath(StringUtils.defaultString(computer.getAbsoluteRemoteFs(), remoteFS));
}
} }
/** /**
...@@ -422,10 +434,8 @@ public abstract class Slave extends Node implements Serializable { ...@@ -422,10 +434,8 @@ public abstract class Slave extends Node implements Serializable {
if(value.startsWith("\\\\") || value.startsWith("/net/")) if(value.startsWith("\\\\") || value.startsWith("/net/"))
return FormValidation.warning(Messages.Slave_Network_Mounted_File_System_Warning()); return FormValidation.warning(Messages.Slave_Network_Mounted_File_System_Warning());
if (!value.contains("\\") && !value.startsWith("/")) { if (Util.isRelativePath(value)) {
// Unix-looking path that doesn't start with '/' return FormValidation.warning(Messages.Slave_Remote_Relative_Path_Warning());
// TODO: detect Windows-looking relative path
return FormValidation.error(Messages.Slave_the_remote_root_must_be_an_absolute_path());
} }
return FormValidation.ok(); return FormValidation.ok();
......
/* /*
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...@@ -41,6 +41,7 @@ import java.util.Date; ...@@ -41,6 +41,7 @@ import java.util.Date;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.QueryParameter;
...@@ -57,7 +58,7 @@ public class CommandLauncher extends ComputerLauncher { ...@@ -57,7 +58,7 @@ public class CommandLauncher extends ComputerLauncher {
* "ssh myslave java -jar /path/to/hudson-remoting.jar" * "ssh myslave java -jar /path/to/hudson-remoting.jar"
*/ */
private final String agentCommand; private final String agentCommand;
/** /**
* Optional environment variables to add to the current environment. Can be null. * Optional environment variables to add to the current environment. Can be null.
*/ */
...@@ -67,7 +68,7 @@ public class CommandLauncher extends ComputerLauncher { ...@@ -67,7 +68,7 @@ public class CommandLauncher extends ComputerLauncher {
public CommandLauncher(String command) { public CommandLauncher(String command) {
this(command, null); this(command, null);
} }
public CommandLauncher(String command, EnvVars env) { public CommandLauncher(String command, EnvVars env) {
this.agentCommand = command; this.agentCommand = command;
this.env = env; this.env = env;
...@@ -90,10 +91,10 @@ public class CommandLauncher extends ComputerLauncher { ...@@ -90,10 +91,10 @@ public class CommandLauncher extends ComputerLauncher {
Process _proc = null; Process _proc = null;
try { try {
Slave node = computer.getNode(); Slave node = computer.getNode();
if (node == null) { if (node == null) {
throw new AbortException("Cannot launch commands on deleted nodes"); throw new AbortException("Cannot launch commands on deleted nodes");
} }
listener.getLogger().println(hudson.model.Messages.Slave_Launching(getTimestamp())); listener.getLogger().println(hudson.model.Messages.Slave_Launching(getTimestamp()));
if(getCommand().trim().length()==0) { if(getCommand().trim().length()==0) {
listener.getLogger().println(Messages.CommandLauncher_NoLaunchCommand()); listener.getLogger().println(Messages.CommandLauncher_NoLaunchCommand());
...@@ -103,8 +104,8 @@ public class CommandLauncher extends ComputerLauncher { ...@@ -103,8 +104,8 @@ public class CommandLauncher extends ComputerLauncher {
ProcessBuilder pb = new ProcessBuilder(Util.tokenize(getCommand())); ProcessBuilder pb = new ProcessBuilder(Util.tokenize(getCommand()));
final EnvVars cookie = _cookie = EnvVars.createCookie(); final EnvVars cookie = _cookie = EnvVars.createCookie();
pb.environment().putAll(cookie); pb.environment().putAll(cookie);
pb.environment().put("WORKSPACE", node.getRemoteFS()); //path for local slave log pb.environment().put("WORKSPACE", StringUtils.defaultString(computer.getAbsoluteRemoteFs(), node.getRemoteFS())); //path for local slave log
{// system defined variables {// system defined variables
String rootUrl = Jenkins.getInstance().getRootUrl(); String rootUrl = Jenkins.getInstance().getRootUrl();
...@@ -118,7 +119,7 @@ public class CommandLauncher extends ComputerLauncher { ...@@ -118,7 +119,7 @@ public class CommandLauncher extends ComputerLauncher {
if (env != null) { if (env != null) {
pb.environment().putAll(env); pb.environment().putAll(env);
} }
final Process proc = _proc = pb.start(); final Process proc = _proc = pb.start();
// capture error information from stderr. this will terminate itself // capture error information from stderr. this will terminate itself
......
/* /*
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...@@ -53,6 +53,7 @@ import jenkins.slaves.EncryptedSlaveAgentJnlpFile; ...@@ -53,6 +53,7 @@ import jenkins.slaves.EncryptedSlaveAgentJnlpFile;
import jenkins.slaves.systemInfo.SlaveSystemInfo; import jenkins.slaves.systemInfo.SlaveSystemInfo;
import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.io.FilenameUtils;
import org.kohsuke.stapler.WebMethod; import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.interceptor.RequirePOST; import org.kohsuke.stapler.interceptor.RequirePOST;
...@@ -102,7 +103,7 @@ public class SlaveComputer extends Computer { ...@@ -102,7 +103,7 @@ public class SlaveComputer extends Computer {
* *
* <p> * <p>
* This is normally the same as {@link Slave#getLauncher()} but * This is normally the same as {@link Slave#getLauncher()} but
* can be different. See {@link #grabLauncher(Node)}. * can be different. See {@link #grabLauncher(Node)}.
*/ */
private ComputerLauncher launcher; private ComputerLauncher launcher;
...@@ -132,6 +133,8 @@ public class SlaveComputer extends Computer { ...@@ -132,6 +133,8 @@ public class SlaveComputer extends Computer {
private Object constructed = new Object(); private Object constructed = new Object();
private transient volatile String absoluteRemoteFs;
public SlaveComputer(Slave slave) { public SlaveComputer(Slave slave) {
super(slave); super(slave);
this.log = new ReopenableRotatingFileOutputStream(getLogFile(),10); this.log = new ReopenableRotatingFileOutputStream(getLogFile(),10);
...@@ -249,6 +252,9 @@ public class SlaveComputer extends Computer { ...@@ -249,6 +252,9 @@ public class SlaveComputer extends Computer {
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(taskListener.error(Messages.ComputerLauncher_abortedLaunch())); e.printStackTrace(taskListener.error(Messages.ComputerLauncher_abortedLaunch()));
throw e; throw e;
} catch (Exception e) {
e.printStackTrace(taskListener.error(Messages.ComputerLauncher_unexpectedError()));
throw e;
} }
} finally { } finally {
if (channel==null) { if (channel==null) {
...@@ -274,7 +280,7 @@ public class SlaveComputer extends Computer { ...@@ -274,7 +280,7 @@ public class SlaveComputer extends Computer {
if (launcher instanceof ExecutorListener) { if (launcher instanceof ExecutorListener) {
((ExecutorListener)launcher).taskAccepted(executor, task); ((ExecutorListener)launcher).taskAccepted(executor, task);
} }
//getNode() can return null at indeterminate times when nodes go offline //getNode() can return null at indeterminate times when nodes go offline
Slave node = getNode(); Slave node = getNode();
if (node != null && node.getRetentionStrategy() instanceof ExecutorListener) { if (node != null && node.getRetentionStrategy() instanceof ExecutorListener) {
...@@ -410,6 +416,19 @@ public class SlaveComputer extends Computer { ...@@ -410,6 +416,19 @@ public class SlaveComputer extends Computer {
return channel.call(new LoadingTime(true)); return channel.call(new LoadingTime(true));
} }
/**
* Returns the remote FS root absolute path or {@code null} if the slave is off-line. The absolute path may change
* between connections if the connection method does not provide a consistent working directory and the node's
* remote FS is specified as a relative path.
*
* @return the remote FS root absolute path or {@code null} if the slave is off-line.
* @since 1.606
*/
@CheckForNull
public String getAbsoluteRemoteFs() {
return channel == null ? null : absoluteRemoteFs;
}
static class LoadingCount extends MasterToSlaveCallable<Integer,RuntimeException> { static class LoadingCount extends MasterToSlaveCallable<Integer,RuntimeException> {
private final boolean resource; private final boolean resource;
LoadingCount(boolean resource) { LoadingCount(boolean resource) {
...@@ -481,11 +500,16 @@ public class SlaveComputer extends Computer { ...@@ -481,11 +500,16 @@ public class SlaveComputer extends Computer {
if (node == null) { // Node has been disabled/removed during the connection if (node == null) { // Node has been disabled/removed during the connection
throw new IOException("Node "+nodeName+" has been deleted during the channel setup"); throw new IOException("Node "+nodeName+" has been deleted during the channel setup");
} }
String remoteFs = node.getRemoteFS(); String remoteFS = node.getRemoteFS();
if(_isUnix && !remoteFs.contains("/") && remoteFs.contains("\\")) if (Util.isRelativePath(remoteFS)) {
log.println("WARNING: "+remoteFs+" looks suspiciously like Windows path. Maybe you meant "+remoteFs.replace('\\','/')+"?"); remoteFS = channel.call(new AbsolutePath(remoteFS));
FilePath root = new FilePath(channel,remoteFs); log.println("NOTE: Relative remote path resolved to: "+remoteFS);
}
if(_isUnix && !remoteFS.contains("/") && remoteFS.contains("\\"))
log.println("WARNING: "+remoteFS
+" looks suspiciously like Windows path. Maybe you meant "+remoteFS.replace('\\','/')+"?");
FilePath root = new FilePath(channel,remoteFS);
// reference counting problem is known to happen, such as JENKINS-9017, and so as a preventive measure // reference counting problem is known to happen, such as JENKINS-9017, and so as a preventive measure
// we pin the base classloader so that it'll never get GCed. When this classloader gets released, // we pin the base classloader so that it'll never get GCed. When this classloader gets released,
...@@ -519,6 +543,7 @@ public class SlaveComputer extends Computer { ...@@ -519,6 +543,7 @@ public class SlaveComputer extends Computer {
isUnix = _isUnix; isUnix = _isUnix;
numRetryAttempt = 0; numRetryAttempt = 0;
this.channel = channel; this.channel = channel;
this.absoluteRemoteFs = remoteFS;
defaultCharset = Charset.forName(defaultCharsetName); defaultCharset = Charset.forName(defaultCharsetName);
synchronized (statusChangeLock) { synchronized (statusChangeLock) {
...@@ -634,9 +659,13 @@ public class SlaveComputer extends Computer { ...@@ -634,9 +659,13 @@ public class SlaveComputer extends Computer {
*/ */
private void closeChannel() { private void closeChannel() {
// TODO: race condition between this and the setChannel method. // TODO: race condition between this and the setChannel method.
Channel c = channel; Channel c;
channel = null; synchronized (channelLock) {
isUnix = null; c = channel;
channel = null;
absoluteRemoteFs = null;
isUnix = null;
}
if (c != null) { if (c != null) {
try { try {
c.close(); c.close();
...@@ -708,6 +737,21 @@ public class SlaveComputer extends Computer { ...@@ -708,6 +737,21 @@ public class SlaveComputer extends Computer {
} }
} }
private static final class AbsolutePath extends MasterToSlaveCallable<String,IOException> {
private static final long serialVersionUID = 1L;
private final String relativePath;
private AbsolutePath(String relativePath) {
this.relativePath = relativePath;
}
public String call() throws IOException {
return new File(relativePath).getAbsolutePath();
}
}
private static final class DetectDefaultCharset extends MasterToSlaveCallable<String,IOException> { private static final class DetectDefaultCharset extends MasterToSlaveCallable<String,IOException> {
public String call() throws IOException { public String call() throws IOException {
return Charset.defaultCharset().name(); return Charset.defaultCharset().name();
...@@ -744,7 +788,7 @@ public class SlaveComputer extends Computer { ...@@ -744,7 +788,7 @@ public class SlaveComputer extends Computer {
} }
Channel.current().setProperty("slave",Boolean.TRUE); // indicate that this side of the channel is the slave side. Channel.current().setProperty("slave",Boolean.TRUE); // indicate that this side of the channel is the slave side.
return null; return null;
} }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
......
...@@ -28,6 +28,7 @@ import org.kohsuke.stapler.ClassDescriptor; ...@@ -28,6 +28,7 @@ import org.kohsuke.stapler.ClassDescriptor;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
...@@ -122,7 +123,7 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils { ...@@ -122,7 +123,7 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils {
} }
} }
public static final class Parameter { public static final class Parameter implements AnnotatedElement {
private final MethodInfo parent; private final MethodInfo parent;
private final int index; private final int index;
...@@ -180,6 +181,26 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils { ...@@ -180,6 +181,26 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils {
return names[index]; return names[index];
return null; return null;
} }
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> type) {
return annotation(type)!=null;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> type) {
return annotation(type);
}
@Override
public Annotation[] getAnnotations() {
return annotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return annotations();
}
} }
/** /**
......
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2012, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -25,7 +25,6 @@ Submit=\u4fdd\u5b58 ...@@ -25,7 +25,6 @@ Submit=\u4fdd\u5b58
Upload\ Plugin=\u30d7\u30e9\u30b0\u30a4\u30f3\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 Upload\ Plugin=\u30d7\u30e9\u30b0\u30a4\u30f3\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9
Upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 Upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9
File=\u30d5\u30a1\u30a4\u30eb File=\u30d5\u30a1\u30a4\u30eb
lastUpdated=\u30c7\u30fc\u30bf\u66f4\u65b0\u6642\u523b: {0}
uploadtext=\ uploadtext=\
.hpi\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u3066\u3001\u30d7\u30e9\u30b0\u30a4\u30f3\u30ea\u30dd\u30b8\u30c8\u30ea\u4ee5\u5916\u304b\u3089\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059\u3002 .hpi\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u3066\u3001\u30d7\u30e9\u30b0\u30a4\u30f3\u30ea\u30dd\u30b8\u30c8\u30ea\u4ee5\u5916\u304b\u3089\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059\u3002
Update\ Site=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30b5\u30a4\u30c8 Update\ Site=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30b5\u30a4\u30c8
......
...@@ -25,9 +25,9 @@ THE SOFTWARE. ...@@ -25,9 +25,9 @@ THE SOFTWARE.
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form"> <j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<j:invokeStatic var="ds" className="jenkins.model.DownloadSettings" method="get"/> <j:invokeStatic var="ds" className="jenkins.model.DownloadSettings" method="get"/>
<form method="post" action="${ds.useBrowser ? 'checkUpdates' : 'checkUpdatesServer'}"> ${%lastUpdated(app.updateCenter.lastUpdatedString)}
${%lastUpdated(app.updateCenter.lastUpdatedString)} <f:link href="${ds.useBrowser ? 'checkUpdates' : 'checkUpdatesServer'}" post="true" clazz="yui-button yui-submit-button submit-button primary">
<f:submit value="${%Check now}" /> <button>${%Check now}</button>
</form> </f:link>
</j:jelly> </j:jelly>
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2012, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -21,3 +21,4 @@ ...@@ -21,3 +21,4 @@
# THE SOFTWARE. # THE SOFTWARE.
Check\ now=\u66f4\u65b0 Check\ now=\u66f4\u65b0
lastUpdated=\u30c7\u30fc\u30bf\u66f4\u65b0\u6642\u523b: {0}
...@@ -25,4 +25,5 @@ MemoryUsageMonitor.TOTAL=\u5408\u8a08 ...@@ -25,4 +25,5 @@ MemoryUsageMonitor.TOTAL=\u5408\u8a08
OldDataMonitor.DisplayName=\u65e7\u30c7\u30fc\u30bf\u306e\u7ba1\u7406 OldDataMonitor.DisplayName=\u65e7\u30c7\u30fc\u30bf\u306e\u7ba1\u7406
OldDataMonitor.Description=\ OldDataMonitor.Description=\
\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u6574\u7406\u3057\u3066\u3001\u53e4\u3044\u30d7\u30e9\u30b0\u30a4\u30f3\u3084\u524d\u30d0\u30fc\u30b8\u30e7\u30f3\u306e\u4e0d\u8981\u306a\u60c5\u5831\u3092\u53d6\u308a\u9664\u304d\u307e\u3059\u3002 \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u6574\u7406\u3057\u3066\u3001\u53e4\u3044\u30d7\u30e9\u30b0\u30a4\u30f3\u3084\u524d\u30d0\u30fc\u30b8\u30e7\u30f3\u306e\u4e0d\u8981\u306a\u60c5\u5831\u3092\u53d6\u308a\u9664\u304d\u307e\u3059\u3002
HudsonHomeDiskUsageMonitor.DisplayName=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf\u30e2\u30cb\u30bf
# The MIT License # The MIT License
# #
# Copyright (c) 2011, Seiji Sogabe # Copyright (c) 2011-2015, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -23,4 +23,4 @@ ...@@ -23,4 +23,4 @@
blurb=\ blurb=\
\u6b21\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u306f\u3001ID\u3092\u6301\u3063\u3066\u3044\u306a\u3044\u306e\u3067\u554f\u984c\u3092\u8d77\u3053\u3059\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u6700\u65b0\u306e\u7269\u306b\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u304f\u3060\u3055\u3044\u3002\ \u6b21\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u306f\u3001ID\u3092\u6301\u3063\u3066\u3044\u306a\u3044\u306e\u3067\u554f\u984c\u3092\u8d77\u3053\u3059\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u6700\u65b0\u306e\u7269\u306b\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u304f\u3060\u3055\u3044\u3002\
\u6700\u65b0\u306e\u7269\u3067\u3042\u308c\u3070\u3001\u4fee\u6b63\u3067\u304d\u308b\u3088\u3046\u306bJIRA\u306b\u30d0\u30b0\u3068\u3057\u3066\u767b\u9332\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \u6700\u65b0\u306e\u7269\u3067\u3042\u308c\u3070\u3001\u4fee\u6b63\u3067\u304d\u308b\u3088\u3046\u306bJIRA\u306b\u30d0\u30b0\u3068\u3057\u3066\u767b\u9332\u3057\u3066\u304f\u3060\u3055\u3044\u3002
problem=Descriptor {0} from plugin {2} with display name {1} problem=\u30d7\u30e9\u30b0\u30a4\u30f3 {2} \u306e\u30c7\u30a3\u30b9\u30af\u30ea\u30d7\u30bf {0} (\u8868\u793a\u540d {1})
\ No newline at end of file \ No newline at end of file
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
Welcome\ to\ Jenkins!=Jenkins\u3078\u3088\u3046\u3053\u305D\uFF01 Welcome\ to\ Jenkins!=Jenkins\u3078\u3088\u3046\u3053\u305d\uff01
newJob=\u958B\u59CB\u3059\u308B\u305F\u3081\u306B<a href="newJob">\u65B0\u3057\u3044\u30B8\u30E7\u30D6</a>\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002 newJob=<a href="newJob">\u65b0\u3057\u3044\u30b8\u30e7\u30d6</a>\u3092\u4f5c\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002
login=\u65B0\u3057\u3044\u30B8\u30E7\u30D6\u3092\u4F5C\u6210\u3059\u308B\u306B\u306F\u3001<a href="{0}/{1}?from={2}">\u30ED\u30B0\u30A4\u30F3</a>\u3057\u3066\u304F\u3060\u3055\u3044\u3002 login=\u65b0\u3057\u3044\u30b8\u30e7\u30d6\u3092\u4f5c\u6210\u3059\u308b\u306b\u306f\u3001<a href="{0}/{1}?from={2}">\u30ed\u30b0\u30a4\u30f3</a>\u3057\u3066\u304f\u3060\u3055\u3044\u3002
signup=\u3082\u3057\u3042\u306A\u305F\u304C\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u6301\u3063\u3066\u3044\u306A\u3051\u308C\u3070\u3001\u4ECA<a href="signup">\u53C2\u52A0</a>\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 signup=\u3082\u3057\u3042\u306a\u305f\u304c\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u6301\u3063\u3066\u3044\u306a\u3051\u308c\u3070\u3001\u4eca<a href="signup">\u53c2\u52a0</a>\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
submit.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u30aa\u30f3\u30e9\u30a4\u30f3\u306b\u623b\u3059 submit.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u30aa\u30f3\u30e9\u30a4\u30f3\u306b\u623b\u3059
submit.not.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u4e00\u6642\u7684\u306b\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u3059\u308b submit.not.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u4e00\u6642\u7684\u306b\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u3059\u308b
None=\u306a\u3057 None=\u306a\u3057
Labels\:=\u30e9\u30d9\u30eb: Labels\=\u30e9\u30d9\u30eb
title.projects_tied_on={0}\u3067\u306e\u307f\u8d77\u52d5\u3059\u308b\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 title.projects_tied_on={0}\u3067\u306e\u307f\u8d77\u52d5\u3059\u308b\u30d7\u30ed\u30b8\u30a7\u30af\u30c8
title.no_manual_launch=\u3053\u306e\u30ce\u30fc\u30c9\u306e\u53ef\u7528\u6027\u306e\u30dd\u30ea\u30b7\u30fc\u306f''{0}''\u3067\u3059\u3002\u73fe\u5728\u3001\u305d\u306e\u30dd\u30ea\u30b7\u30fc\u306b\u57fa\u3065\u3044\u3066\u3001\u3053\u306e\u30ce\u30fc\u30c9\u306f\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002 title.no_manual_launch=\u3053\u306e\u30ce\u30fc\u30c9\u306e\u53ef\u7528\u6027\u306e\u30dd\u30ea\u30b7\u30fc\u306f''{0}''\u3067\u3059\u3002\u73fe\u5728\u3001\u305d\u306e\u30dd\u30ea\u30b7\u30fc\u306b\u57fa\u3065\u3044\u3066\u3001\u3053\u306e\u30ce\u30fc\u30c9\u306f\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002
Created\ by=\u30ce\u30fc\u30c9\u4f5c\u6210\u8005 Created\ by=\u30ce\u30fc\u30c9\u4f5c\u6210\u8005
......
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -20,10 +20,9 @@ ...@@ -20,10 +20,9 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
title={0}\u306E\u30D3\u30EB\u30C9\u6642\u9593\u306E\u50BE\u5411 title={0}\u306e\u30d3\u30eb\u30c9\u6642\u9593\u306e\u50be\u5411
Timeline=\u30BF\u30A4\u30E0\u30E9\u30A4\u30F3 Timeline=\u30bf\u30a4\u30e0\u30e9\u30a4\u30f3
Build=\u30D3\u30EB\u30C9 Build=\u30d3\u30eb\u30c9
Build\ Time\ Trend=\u30D3\u30EB\u30C9\u6642\u9593\u306E\u63A8\u79FB Build\ Time\ Trend=\u30d3\u30eb\u30c9\u6642\u9593\u306e\u63a8\u79fb
Duration=\u6240\u8981\u6642\u9593 Duration=\u6240\u8981\u6642\u9593
Slave=\u30B9\u30EC\u30FC\u30D6 Slave=\u30b9\u30ec\u30fc\u30d6
More\ than\ 1\ builds\ are\ needed\ for\ the\ trend\ report.=\u30B0\u30E9\u30D5\u3092\u63CF\u753B\u3059\u308B\u305F\u3081\u306B\u306F\u6700\u4F4E\uFF12\u3064\u306E\u30D3\u30EB\u30C9\u304C\u5FC5\u8981\u3067\u3059\u3002
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
Back\ to\ Dashboard=\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3078\u623B\u308B Back\ to\ Dashboard=\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u3078\u623b\u308b
Overview=\u6982\u8981 Overview=\u6982\u8981
Load\ Statistics=\u8CA0\u8377\u7D71\u8A08 Load\ Statistics=\u8ca0\u8377\u7d71\u8a08
Configure=\u8a2d\u5b9a
\ No newline at end of file
...@@ -244,7 +244,9 @@ Slave.Launching={0} Launching slave agent ...@@ -244,7 +244,9 @@ Slave.Launching={0} Launching slave agent
Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the master. Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the master.
Slave.Remote.Director.Mandatory=Remote directory is mandatory Slave.Remote.Director.Mandatory=Remote directory is mandatory
Slave.Terminated={0} slave agent was terminated Slave.Terminated={0} slave agent was terminated
Slave.the_remote_root_must_be_an_absolute_path=The remote root must be an absolute path. Slave.Remote.Relative.Path.Warning=Are you sure you want to use a relative path for the FS root? Note that relative \
paths require that you can assure that the selected launcher provides a consistent current working directory. Using \
an absolute path is highly recommended.
Slave.UnableToLaunch=Unable to launch the slave agent for {0}{1} Slave.UnableToLaunch=Unable to launch the slave agent for {0}{1}
Slave.UnixSlave=This is a Unix slave Slave.UnixSlave=This is a Unix slave
Slave.WindowsSlave=This is a Windows slave Slave.WindowsSlave=This is a Windows slave
......
<div> <div>
<p> <p>
A slave needs to have a directory dedicated to Jenkins. Specify A slave needs to have a directory dedicated to Jenkins. Specify
the absolute path of this work directory on the slave, such as the path of this work directory on the slave. It is best to use
'/var/jenkins' or 'c:\jenkins'. This should be a path local to the slave an absolute path, such as '/var/jenkins' or 'c:\jenkins'. This
machine. There's no need for this path to be visible from the master, should be a path local to the slave machine. There's no need for
under normal circumstances. this path to be visible from the master, under normal circumstances.
<p> <p>
Slaves do not maintain important data (other than active workspaces Slaves do not maintain important data (other than active workspaces
of projects last built on it), so you can possibly set the slave of projects last built on it), so you can possibly set the slave
workspace to a temporary directory. The only downside of doing this workspace to a temporary directory. The only downside of doing this
is that you may lose the up-to-date workspace if the slave is turned off. is that you may lose the up-to-date workspace if the slave is turned off.
<p>
If you use a relative path, such as './jenkins-slave', the path will
be relative to the current working directory that the launcher provides.
<ul>
<li>For launchers where Jenkins controls starting the slave process, such
as SSH, the current working directory will typically be consistent,
<i>e.g.</i> the user's home directory. This means that Jenkins will be able to
rely on the caching of tool installations and workspaces from previous
builds.
</li>
<li>For launchers where Jenkins has no control over starting the slave
process, such as JNLP when launched from either the command line or via
a web browser link, the current working directory may change between
launches of the slave and use of a relative path may prove problematic.
The principal issue encountered when using relative paths with launchers
like JNLP is the proliferation of stale workspaces and tool installation
on the slave machine. This can cause disk space issues.
<i>Note: there are some cloud providers that specifically use relative
paths with the JNLP launcher to allow for dynamically provisioned pools
of semi-heterogeneous slaves.</i></li>
</ul>
</div> </div>
# The MIT License # The MIT License
# #
# Copyright (c) 2011, Seiji Sogabe # Copyright (c) 2011-2015, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -23,3 +23,4 @@ ...@@ -23,3 +23,4 @@
Name=\u540d\u524d Name=\u540d\u524d
Save=\u4fdd\u5b58 Save=\u4fdd\u5b58
title={0} \u306e\u8a2d\u5b9a title={0} \u306e\u8a2d\u5b9a
Description=\u8aac\u660e
\ No newline at end of file
<div> <div>
Behaves exactly the same as Jenkins &lt;1.164. Namely, if you have the "admin" role, Behaves exactly the same as Jenkins &lt;1.164. Namely, if you have the "admin" role,
you'll be granted full control over the system, and otherwise (including anonyomus you'll be granted full control over the system, and otherwise (including anonymous
users) you'll only have the read access. users) you'll only have the read access.
</div> </div>
\ No newline at end of file
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi # Copyright (c) 2015, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights # in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is # copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions: # furnished to do so, subject to the following conditions:
# #
# The above copyright notice and this permission notice shall be included in # The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. # all copies or substantial portions of the Software.
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...@@ -20,6 +20,4 @@ ...@@ -20,6 +20,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
Build\ after\ other\ projects\ are\ built=\u4ed6\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30d3\u30eb\u30c9\u5f8c\u306b\u30d3\u30eb\u30c9 Log\ Records=\u30ed\u30b0\u30ec\u30b3\u30fc\u30c9
Project\ names=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d
Multiple\ projects\ can\ be\ specified\ like\ 'abc,\ def'=\u8907\u6570\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u6307\u5b9a\u3059\u308b\u306b\u306fabc, def\u306e\u3088\u3046\u306b\u30ab\u30f3\u30de\u3067\u533a\u5207\u308a\u307e\u3059
\ No newline at end of file
# The MIT License # The MIT License
# #
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
...@@ -24,3 +24,5 @@ Files\ to\ archive=\u4fdd\u5b58\u3059\u308b\u30d5\u30a1\u30a4\u30eb ...@@ -24,3 +24,5 @@ Files\ to\ archive=\u4fdd\u5b58\u3059\u308b\u30d5\u30a1\u30a4\u30eb
Excludes=\u9664\u5916\u3059\u308b\u30d5\u30a1\u30a4\u30eb Excludes=\u9664\u5916\u3059\u308b\u30d5\u30a1\u30a4\u30eb
allowEmptyArchive=\u6210\u679c\u7269\u304c\u4f55\u3082\u306a\u3044\u5834\u5408\u3067\u3082\u30d3\u30eb\u30c9\u3092\u5931\u6557\u306b\u3057\u306a\u3044 allowEmptyArchive=\u6210\u679c\u7269\u304c\u4f55\u3082\u306a\u3044\u5834\u5408\u3067\u3082\u30d3\u30eb\u30c9\u3092\u5931\u6557\u306b\u3057\u306a\u3044
Fingerprint\ all\ archived\ artifacts=\u4fdd\u5b58\u3055\u308c\u305f\u6210\u679c\u7269\u306e\u6307\u7d0b\u3092\u8a18\u9332 Fingerprint\ all\ archived\ artifacts=\u4fdd\u5b58\u3055\u308c\u305f\u6210\u679c\u7269\u306e\u6307\u7d0b\u3092\u8a18\u9332
onlyIfSuccessful=\u30d3\u30eb\u30c9\u304c\u6210\u529f\u3057\u305f\u5834\u5408\u306e\u307f\u4fdd\u5b58
defaultExcludes=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u5bfe\u8c61\u5916\u30d5\u30a1\u30a4\u30eb\u8a2d\u5b9a\u3092\u4f7f\u7528
\ No newline at end of file
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
pending=\u4FDD\u7559 pending=\u4fdd\u7559
cancel\ this\ build=\u3053\u306E\u30D3\u30EB\u30C9\u3092\u4E2D\u6B62 cancel\ this\ build=\u3053\u306e\u30d3\u30eb\u30c9\u3092\u4e2d\u6b62
Expected\ build\ number=\u6b21\u30d3\u30eb\u30c9No
...@@ -21,4 +21,3 @@ ...@@ -21,4 +21,3 @@
# THE SOFTWARE. # THE SOFTWARE.
expand=\u62e1\u5f35 expand=\u62e1\u5f35
collapse=\u9589\u3058\u308b
/* /*
* The MIT License * The MIT License
* *
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Daniel Dyer, Erik Ramfelt, Richard Bair, id:cactusman * Daniel Dyer, Erik Ramfelt, Richard Bair, id:cactusman
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...@@ -32,7 +32,11 @@ import java.io.ByteArrayOutputStream; ...@@ -32,7 +32,11 @@ import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
...@@ -74,7 +78,7 @@ public class UtilTest { ...@@ -74,7 +78,7 @@ public class UtilTest {
assertEquals("asd$${AA}dd", Util.replaceMacro("asd$$$${AA}dd",m)); assertEquals("asd$${AA}dd", Util.replaceMacro("asd$$$${AA}dd",m));
assertEquals("$", Util.replaceMacro("$$",m)); assertEquals("$", Util.replaceMacro("$$",m));
assertEquals("$$", Util.replaceMacro("$$$$",m)); assertEquals("$$", Util.replaceMacro("$$$$",m));
// dots // dots
assertEquals("a.B", Util.replaceMacro("$A.B", m)); assertEquals("a.B", Util.replaceMacro("$A.B", m));
assertEquals("a-b", Util.replaceMacro("${A.B}", m)); assertEquals("a-b", Util.replaceMacro("${A.B}", m));
...@@ -136,7 +140,7 @@ public class UtilTest { ...@@ -136,7 +140,7 @@ public class UtilTest {
String encoded = Util.encode(urlWithSpaces); String encoded = Util.encode(urlWithSpaces);
assertEquals(encoded, "http://hudson/job/Hudson%20Job"); assertEquals(encoded, "http://hudson/job/Hudson%20Job");
} }
/** /**
* Test the rawEncode() method. * Test the rawEncode() method.
*/ */
...@@ -190,16 +194,16 @@ public class UtilTest { ...@@ -190,16 +194,16 @@ public class UtilTest {
System.err.println("log output: " + log); System.err.println("log output: " + log);
assertEquals(buf.toString(),Util.resolveSymlink(new File(d,"x"))); assertEquals(buf.toString(),Util.resolveSymlink(new File(d,"x")));
// test linking from another directory // test linking from another directory
File anotherDir = new File(d,"anotherDir"); File anotherDir = new File(d,"anotherDir");
assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir()); assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir());
Util.createSymlink(d,"a","anotherDir/link",l); Util.createSymlink(d,"a","anotherDir/link",l);
assertEquals("a",Util.resolveSymlink(new File(d,"anotherDir/link"))); assertEquals("a",Util.resolveSymlink(new File(d,"anotherDir/link")));
// JENKINS-12331: either a bug in createSymlink or this isn't supposed to work: // JENKINS-12331: either a bug in createSymlink or this isn't supposed to work:
//assertTrue(Util.isSymlink(new File(d,"anotherDir/link"))); //assertTrue(Util.isSymlink(new File(d,"anotherDir/link")));
File external = File.createTempFile("something", ""); File external = File.createTempFile("something", "");
...@@ -213,11 +217,11 @@ public class UtilTest { ...@@ -213,11 +217,11 @@ public class UtilTest {
Util.deleteRecursive(d); Util.deleteRecursive(d);
} }
} }
@Test @Test
public void testIsSymlink() throws IOException, InterruptedException { public void testIsSymlink() throws IOException, InterruptedException {
Assume.assumeTrue(!Functions.isWindows()); Assume.assumeTrue(!Functions.isWindows());
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamTaskListener l = new StreamTaskListener(baos); StreamTaskListener l = new StreamTaskListener(baos);
File d = tmp.getRoot(); File d = tmp.getRoot();
...@@ -225,17 +229,17 @@ public class UtilTest { ...@@ -225,17 +229,17 @@ public class UtilTest {
new FilePath(new File(d, "original")).touch(0); new FilePath(new File(d, "original")).touch(0);
assertFalse(Util.isSymlink(new File(d, "original"))); assertFalse(Util.isSymlink(new File(d, "original")));
Util.createSymlink(d,"original","link", l); Util.createSymlink(d,"original","link", l);
assertTrue(Util.isSymlink(new File(d, "link"))); assertTrue(Util.isSymlink(new File(d, "link")));
// test linking to another directory // test linking to another directory
File dir = new File(d,"dir"); File dir = new File(d,"dir");
assertTrue("Couldn't create "+dir,dir.mkdir()); assertTrue("Couldn't create "+dir,dir.mkdir());
assertFalse(Util.isSymlink(new File(d,"dir"))); assertFalse(Util.isSymlink(new File(d,"dir")));
File anotherDir = new File(d,"anotherDir"); File anotherDir = new File(d,"anotherDir");
assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir()); assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir());
Util.createSymlink(d,"dir","anotherDir/symlinkDir",l); Util.createSymlink(d,"dir","anotherDir/symlinkDir",l);
// JENKINS-12331: either a bug in createSymlink or this isn't supposed to work: // JENKINS-12331: either a bug in createSymlink or this isn't supposed to work:
// assertTrue(Util.isSymlink(new File(d,"anotherDir/symlinkDir"))); // assertTrue(Util.isSymlink(new File(d,"anotherDir/symlinkDir")));
...@@ -276,7 +280,7 @@ public class UtilTest { ...@@ -276,7 +280,7 @@ public class UtilTest {
assertEquals("&#039;&quot;", Util.escape("'\"")); assertEquals("&#039;&quot;", Util.escape("'\""));
assertEquals("&nbsp; ", Util.escape(" ")); assertEquals("&nbsp; ", Util.escape(" "));
} }
/** /**
* Compute 'known-correct' digests and see if I still get them when computed concurrently * Compute 'known-correct' digests and see if I still get them when computed concurrently
* to another digest. * to another digest.
...@@ -286,19 +290,19 @@ public class UtilTest { ...@@ -286,19 +290,19 @@ public class UtilTest {
public void testDigestThreadSafety() throws InterruptedException { public void testDigestThreadSafety() throws InterruptedException {
String a = "abcdefgh"; String a = "abcdefgh";
String b = "123456789"; String b = "123456789";
String digestA = Util.getDigestOf(a); String digestA = Util.getDigestOf(a);
String digestB = Util.getDigestOf(b); String digestB = Util.getDigestOf(b);
DigesterThread t1 = new DigesterThread(a, digestA); DigesterThread t1 = new DigesterThread(a, digestA);
DigesterThread t2 = new DigesterThread(b, digestB); DigesterThread t2 = new DigesterThread(b, digestB);
t1.start(); t1.start();
t2.start(); t2.start();
t1.join(); t1.join();
t2.join(); t2.join();
if (t1.error != null) { if (t1.error != null) {
fail(t1.error); fail(t1.error);
} }
...@@ -306,18 +310,18 @@ public class UtilTest { ...@@ -306,18 +310,18 @@ public class UtilTest {
fail(t2.error); fail(t2.error);
} }
} }
private static class DigesterThread extends Thread { private static class DigesterThread extends Thread {
private String string; private String string;
private String expectedDigest; private String expectedDigest;
private String error; private String error;
public DigesterThread(String string, String expectedDigest) { public DigesterThread(String string, String expectedDigest) {
this.string = string; this.string = string;
this.expectedDigest = expectedDigest; this.expectedDigest = expectedDigest;
} }
public void run() { public void run() {
for (int i=0; i < 1000; i++) { for (int i=0; i < 1000; i++) {
String digest = Util.getDigestOf(this.string); String digest = Util.getDigestOf(this.string);
...@@ -349,4 +353,56 @@ public class UtilTest { ...@@ -349,4 +353,56 @@ public class UtilTest {
assertEquals(p.toString(), "va.l.ue", p.get("k.e.y")); assertEquals(p.toString(), "va.l.ue", p.get("k.e.y"));
assertEquals(p.toString(), 1, p.size()); assertEquals(p.toString(), 1, p.size());
} }
@Test
public void isRelativePathUnix() {
assertThat("/", not(aRelativePath()));
assertThat("/foo/bar", not(aRelativePath()));
assertThat("/foo/../bar", not(aRelativePath()));
assertThat("", aRelativePath());
assertThat(".", aRelativePath());
assertThat("..", aRelativePath());
assertThat("./foo", aRelativePath());
assertThat("./foo/bar", aRelativePath());
assertThat("./foo/bar/", aRelativePath());
}
@Test
public void isRelativePathWindows() {
assertThat("\\", aRelativePath());
assertThat("\\foo\\bar", aRelativePath());
assertThat("\\foo\\..\\bar", aRelativePath());
assertThat("", aRelativePath());
assertThat(".", aRelativePath());
assertThat(".\\foo", aRelativePath());
assertThat(".\\foo\\bar", aRelativePath());
assertThat(".\\foo\\bar\\", aRelativePath());
assertThat("\\\\foo", aRelativePath());
assertThat("\\\\foo\\", not(aRelativePath()));
assertThat("\\\\foo\\c", not(aRelativePath()));
assertThat("C:", aRelativePath());
assertThat("z:", aRelativePath());
assertThat("0:", aRelativePath());
assertThat("c:.", aRelativePath());
assertThat("c:\\", not(aRelativePath()));
assertThat("c:/", not(aRelativePath()));
}
private static RelativePathMatcher aRelativePath() {
return new RelativePathMatcher();
}
private static class RelativePathMatcher extends BaseMatcher<String> {
@Override
public boolean matches(Object item) {
return Util.isRelativePath((String) item);
}
@Override
public void describeTo(Description description) {
description.appendText("a relative path");
}
}
} }
...@@ -176,7 +176,7 @@ THE SOFTWARE. ...@@ -176,7 +176,7 @@ THE SOFTWARE.
<dependency> <dependency>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>remoting</artifactId> <artifactId>remoting</artifactId>
<version>2.49</version> <version>2.50</version>
</dependency> </dependency>
<dependency> <dependency>
......
...@@ -96,7 +96,7 @@ class SlaveTest { ...@@ -96,7 +96,7 @@ class SlaveTest {
def d = j.jenkins.getDescriptorByType(DumbSlave.DescriptorImpl.class) def d = j.jenkins.getDescriptorByType(DumbSlave.DescriptorImpl.class)
assert d.doCheckRemoteFS("c:\\")==FormValidation.ok(); assert d.doCheckRemoteFS("c:\\")==FormValidation.ok();
assert d.doCheckRemoteFS("/tmp")==FormValidation.ok(); assert d.doCheckRemoteFS("/tmp")==FormValidation.ok();
assert d.doCheckRemoteFS("relative/path").kind==ERROR; assert d.doCheckRemoteFS("relative/path").kind==WARNING;
assert d.doCheckRemoteFS("/net/foo/bar/zot").kind==WARNING; assert d.doCheckRemoteFS("/net/foo/bar/zot").kind==WARNING;
assert d.doCheckRemoteFS("\\\\machine\\folder\\foo").kind==WARNING; assert d.doCheckRemoteFS("\\\\machine\\folder\\foo").kind==WARNING;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册