提交 a489cc4e 编写于 作者: M Matt Sicker

Move Windows util code into test sources

Signed-off-by: NMatt Sicker <boards@gmail.com>
上级 b747845f
......@@ -30,7 +30,6 @@ import hudson.util.VariableResolver;
import jenkins.util.SystemProperties;
import jenkins.util.io.PathRemover;
import jenkins.util.os.windows.WindowsCommandLineFormatter;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
......@@ -1277,28 +1276,6 @@ public class Util {
}
}
/**
* Creates an NTFS junction point if supported. Similar to symbolic links, NTFS provides junction points which
* provide different features than symbolic links. This method is primarily useful for unit testing on Windows.
* @param junction NTFS junction point to create
* @param target target directory to junction
* @return the newly created junction point
* @throws IOException if the call to mklink exits with a non-zero status code
* @throws InterruptedException if the call to mklink is interrupted before completing
* @throws AssertionError if this method is called on a non-Windows platform
*/
static @Nonnull File createJunction(@Nonnull File junction, @Nonnull File target) throws IOException, InterruptedException {
if (!Functions.isWindows()) throw new AssertionError("Cannot create junctions on non-Windows platforms");
String command = "cmd.exe /C mklink /J " +
WindowsCommandLineFormatter.quoteArgumentForCmd(junction.getAbsolutePath()) +
' ' +
WindowsCommandLineFormatter.quoteArgumentForCmd(target.getAbsolutePath());
Process process = Runtime.getRuntime().exec(command);
int result = process.waitFor();
if (result != 0) throw new IOException("Command `" + command + "` failed with status code " + result);
return junction;
}
/**
* Encodes the URL by RFC 2396.
*
......
......@@ -26,6 +26,7 @@ package hudson;
import hudson.FilePath.TarCompression;
import hudson.model.TaskListener;
import hudson.os.PosixAPI;
import hudson.os.WindowsUtil;
import hudson.remoting.VirtualChannel;
import hudson.util.NullStream;
import hudson.util.StreamTaskListener;
......@@ -836,7 +837,7 @@ public class FilePathTest {
Path targetDir = temp.newFolder("targetDir").toPath();
Path targetContents = Files.createFile(targetDir.resolve("contents.txt"));
Path toDelete = temp.newFolder("toDelete").toPath();
File junction = Util.createJunction(toDelete.resolve("junction").toFile(), targetDir.toFile());
File junction = WindowsUtil.createJunction(toDelete.resolve("junction").toFile(), targetDir.toFile());
Files.createFile(toDelete.resolve("foo"));
Files.createFile(toDelete.resolve("bar"));
FilePath f = new FilePath(toDelete.toFile());
......
......@@ -8,6 +8,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import java.io.File;
import hudson.os.WindowsUtil;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
......@@ -32,7 +34,7 @@ public class RemoveWindowsDirectoryJunctionTest {
File subdir1 = tmp.newFolder("notJunction");
File f1 = new File(subdir1, "testfile1.txt");
assertTrue("Unable to create temporary file in notJunction directory", f1.createNewFile());
File j1 = Util.createJunction(tmp.getRoot(), subdir1);
File j1 = WindowsUtil.createJunction(tmp.getRoot(), subdir1);
Util.deleteRecursive(j1);
assertFalse("Windows Junction should have been removed", j1.exists());
assertTrue("Contents of Windows Junction should not be removed", f1.exists());
......
......@@ -43,6 +43,7 @@ import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.*;
import hudson.os.WindowsUtil;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Assume;
......@@ -262,7 +263,7 @@ public class UtilTest {
Assume.assumeTrue("Uses Windows-specific features", Functions.isWindows());
File targetDir = tmp.newFolder("targetDir");
File d = tmp.newFolder("dir");
File junction = Util.createJunction(new File(d, "junction"), targetDir);
File junction = WindowsUtil.createJunction(new File(d, "junction"), targetDir);
assertTrue(Util.isSymlink(junction));
}
......@@ -274,7 +275,7 @@ public class UtilTest {
File file = new File(targetDir, "test-file");
new FilePath(file).touch(System.currentTimeMillis());
File dir = tmp.newFolder();
File junction = Util.createJunction(new File(dir, "junction"), targetDir);
File junction = WindowsUtil.createJunction(new File(dir, "junction"), targetDir);
assertTrue(Util.isSymlink(junction));
assertFalse(Util.isSymlink(file));
......
......@@ -22,24 +22,21 @@
* THE SOFTWARE.
*/
package jenkins.util.os.windows;
package hudson.os;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import hudson.Functions;
import org.apache.commons.io.IOUtils;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Provides formatting utilities for Windows command line processes.
*
* @see <a href="https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way">Everyone quotes command line arguments the wrong way</a>
*/
@Restricted(NoExternalUse.class)
public final class WindowsCommandLineFormatter {
private WindowsCommandLineFormatter() {
}
import static org.junit.Assert.assertTrue;
public class WindowsUtil {
/**
* Quotes an argument while escaping special characters interpreted by CreateProcess.
*/
......@@ -83,4 +80,33 @@ public final class WindowsCommandLineFormatter {
return CMD_METACHARS.matcher(quoteArgument(argument)).replaceAll("^$0");
}
/**
* Executes a command and arguments using {@code cmd.exe /C ...}.
*/
public static @Nonnull Process execCmd(String... argv) throws IOException {
String command = Arrays.stream(argv).map(WindowsUtil::quoteArgumentForCmd).collect(Collectors.joining(" "));
return Runtime.getRuntime().exec(new String[]{"cmd.exe", "/C", command});
}
/**
* Creates an NTFS junction point if supported. Similar to symbolic links, NTFS provides junction points which
* provide different features than symbolic links.
* @param junction NTFS junction point to create
* @param target target directory to junction
* @return the newly created junction point
* @throws IOException if the call to mklink exits with a non-zero status code
* @throws InterruptedException if the call to mklink is interrupted before completing
* @throws AssertionError if this method is called on a non-Windows platform
*/
public static @Nonnull File createJunction(@Nonnull File junction, @Nonnull File target) throws IOException, InterruptedException {
assertTrue(Functions.isWindows());
Process mklink = execCmd("mklink", "/J", junction.getAbsolutePath(), target.getAbsolutePath());
int result = mklink.waitFor();
if (result != 0) {
String stderr = IOUtils.toString(mklink.getErrorStream());
String stdout = IOUtils.toString(mklink.getInputStream());
throw new IOException("Process exited with " + result + "\nStandard Output:\n" + stdout + "\nError Output:\n" + stderr);
}
return junction;
}
}
......@@ -22,19 +22,21 @@
* THE SOFTWARE.
*/
package jenkins.util.os.windows;
package hudson.os;
import org.junit.Test;
import static org.junit.Assert.*;
public class WindowsCommandLineFormatterTest {
/**
* Test the test utility code, too!
*/
public class WindowsUtilTest {
@Test
public void testQuoteArgument() {
String input = "C:\\Programs and \"Settings\"\\System32\\\\";
String expected = "\"C:\\Programs and \\\"Settings\\\"\\System32\\\\\\\\\"";
String actual = WindowsCommandLineFormatter.quoteArgument(input);
String actual = WindowsUtil.quoteArgument(input);
assertEquals(expected, actual);
}
......@@ -42,7 +44,7 @@ public class WindowsCommandLineFormatterTest {
public void testQuoteArgumentForCmd() {
String input = "hello \"\\world&";
String expected = "^\"hello \\^\"\\world^&^\"";
String actual = WindowsCommandLineFormatter.quoteArgumentForCmd(input);
String actual = WindowsUtil.quoteArgumentForCmd(input);
assertEquals(expected, actual);
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册