diff options
Diffstat (limited to 'src/main')
3 files changed, 71 insertions, 60 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/util/DependencySet.java b/src/main/java/com/google/devtools/build/lib/util/DependencySet.java index 358610d14d..e2ce5fb6ce 100644 --- a/src/main/java/com/google/devtools/build/lib/util/DependencySet.java +++ b/src/main/java/com/google/devtools/build/lib/util/DependencySet.java @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.atomic.AtomicReference; /** * Representation of a set of file dependencies for a given output file. There @@ -99,10 +100,18 @@ public final class DependencySet { * Adds a given dependency to this DependencySet instance. */ private void addDependency(String dep) { + dep = translatePath(dep); Path depPath = root.getRelative(dep); dependencies.add(depPath); } + private String translatePath(String path) { + if (OS.getCurrent() != OS.WINDOWS) { + return path; + } + return WindowsPath.translateWindowsPath(path); + } + /** * Reads a dotd file into this DependencySet instance. */ @@ -241,4 +250,64 @@ public final class DependencySet { public int hashCode() { return dependencies.hashCode(); } + + private static final class WindowsPath { + private static final AtomicReference<String> UNIX_ROOT = new AtomicReference<>(null); + + private static String translateWindowsPath(String path) { + int n = path.length(); + if (n == 0 || path.charAt(0) != '/') { + return path; + } + if (n >= 2 && isAsciiLetter(path.charAt(1)) && (n == 2 || path.charAt(2) == '/')) { + StringBuilder sb = new StringBuilder(path.length()); + sb.append(Character.toUpperCase(path.charAt(1))); + sb.append(":/"); + sb.append(path, 2, path.length()); + return sb.toString(); + } else { + String unixRoot = getUnixRoot(); + return unixRoot + path; + } + } + + private static boolean isAsciiLetter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + private static String getUnixRoot() { + String value = UNIX_ROOT.get(); + if (value == null) { + String jvmFlag = "bazel.windows_unix_root"; + value = determineUnixRoot(jvmFlag); + if (value == null) { + throw new IllegalStateException( + String.format( + "\"%1$s\" JVM flag is not set. Use the --host_jvm_args flag. " + + "For example: " + + "\"--host_jvm_args=-D%1$s=c:/tools/msys64\".", + jvmFlag)); + } + value = value.replace('\\', '/'); + if (value.length() > 3 && value.endsWith("/")) { + value = value.substring(0, value.length() - 1); + } + UNIX_ROOT.set(value); + } + return value; + } + + private static String determineUnixRoot(String jvmArgName) { + // Get the path from a JVM flag, if specified. + String path = System.getProperty(jvmArgName); + if (path == null) { + return null; + } + path = path.trim(); + if (path.isEmpty()) { + return null; + } + return path; + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/vfs/Path.java b/src/main/java/com/google/devtools/build/lib/vfs/Path.java index 6fe6118b9a..1d3947dcdc 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/Path.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/Path.java @@ -78,11 +78,6 @@ public class Path implements Comparable<Path>, Serializable, SkylarkPrintable { /** * Makes the proper invocation of {@link FileSystem#getCachedChildPathInternal}, doing * filesystem-specific logic if necessary. - * - * <p>On Unix filesystems this method merely calls through to {@code - * FileSystem.getCachedChildPathInternal(parent, child)}, but on Windows this can be used to - * handle the translatation of absolute Unix paths to absolute Windows paths, e.g. "/c" to "C:/" - * or "/usr" to "C:/tools/msys64/usr". */ Path getCachedChildPathInternal(Path path, String childName); } diff --git a/src/main/java/com/google/devtools/build/lib/windows/WindowsFileSystem.java b/src/main/java/com/google/devtools/build/lib/windows/WindowsFileSystem.java index 21de058e07..af97e27d3d 100644 --- a/src/main/java/com/google/devtools/build/lib/windows/WindowsFileSystem.java +++ b/src/main/java/com/google/devtools/build/lib/windows/WindowsFileSystem.java @@ -32,7 +32,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.attribute.DosFileAttributes; import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -106,42 +105,11 @@ public class WindowsFileSystem extends JavaIoFileSystem { private static Path getCachedChildPathInternalImpl( Path parent, String child, Function<String, String> resolver) { if (parent != null && parent.isRootDirectory()) { - // This is a top-level directory. It's either a drive name ("C:" or "c") or some other - // Unix path (e.g. "/usr"). - // - // We need to translate it to an absolute Windows path. The correct way would be looking - // up /etc/mtab to see if any mount point matches the prefix of the path, and change the - // prefix to the mounted path. Looking up /etc/mtab each time we create a path however - // would be too expensive so we use a heuristic instead. - // - // If the name looks like a volume name ("C:" or "c") then we treat it as such, otherwise - // we make it relative to UNIX_ROOT, thus "/usr" becomes "C:/tools/msys64/usr". - // - // This heuristic ignores other mount points as well as procfs. - - // TODO(laszlocsomor): use GetLogicalDrives to retrieve the list of drives and only apply - // this heuristic for the valid drives. It's possible that the user has a directory "/a" - // but no "A:\" drive, so in that case we should prepend the MSYS root. - + // This is a top-level directory. It must be a drive name ("C:" or "c"). if (WindowsPath.isWindowsVolumeName(child)) { child = WindowsPath.getDriveLetter((WindowsPath) parent, child) + ":"; } else { - if (UNIX_ROOT.get() == null) { - String jvmFlag = "bazel.windows_unix_root"; - PathFragment value = determineUnixRoot(jvmFlag); - if (value == null) { - throw new IllegalStateException( - String.format( - "\"%1$s\" JVM flag is not set. Use the --host_jvm_args flag or export the " - + "BAZEL_SH environment variable. For example " - + "\"--host_jvm_args=-D%1$s=c:/tools/msys64\" or " - + "\"set BAZEL_SH=c:/tools/msys64/usr/bin/bash.exe\". " - + "parent=(%2$s) name=(%3$s)", - jvmFlag, parent, child)); - } - UNIX_ROOT.set(value); - } - parent = parent.getRelative(UNIX_ROOT.get()); + throw new IllegalArgumentException("Cannot create Unix-style paths on Windows."); } } @@ -303,8 +271,6 @@ public class WindowsFileSystem extends JavaIoFileSystem { return WindowsPathFactory.createForTesting(mockResolver); } - private static final AtomicReference<PathFragment> UNIX_ROOT = new AtomicReference<>(null); - public static final LinkOption[] NO_OPTIONS = new LinkOption[0]; public static final LinkOption[] NO_FOLLOW = new LinkOption[] {LinkOption.NOFOLLOW_LINKS}; @@ -478,23 +444,4 @@ public class WindowsFileSystem extends JavaIoFileSystem { return Files.readAttributes( file.toPath(), DosFileAttributes.class, symlinkOpts(followSymlinks)); } - - private static PathFragment determineUnixRoot(String jvmArgName) { - // Get the path from a JVM flag, if specified. - String path = System.getProperty(jvmArgName); - if (path == null) { - return null; - } - - path = path.trim(); - if (path.isEmpty()) { - return null; - } - - PathFragment result = PathFragment.create(path); - if (result.getDriveLetter() == '\0' || !result.isAbsolute()) { - return null; - } - return result; - } } |