// Copyright 2017 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.vfs; import com.google.devtools.build.lib.util.OS; /** * An interface class representing the differences in path style between different OSs. * *

Eg. case sensitivity, '/' mounts vs. 'C:/', etc. */ public interface OsPathPolicy { int NORMALIZED = 0; // Path is normalized int NEEDS_NORMALIZE = 1; // Path requires normalization /** Returns required normalization level, passed to {@link #normalize}. */ int needsToNormalize(String path); /** * Returns the required normalization level if an already normalized string is concatenated with * another normalized path fragment. * *

This method may be faster than {@link #needsToNormalize(String)}. */ int needsToNormalizeSuffix(String normalizedSuffix); /** * Normalizes the passed string according to the passed normalization level. * * @param normalizationLevel The normalizationLevel from {@link #needsToNormalize} */ String normalize(String path, int normalizationLevel); /** * Returns the length of the mount, eg. 1 for unix '/', 3 for Windows 'C:/'. * *

If the path is relative, 0 is returned */ int getDriveStrLength(String path); /** Compares two path strings, using the given OS case sensitivity. */ int compare(String s1, String s2); /** Compares two characters, using the given OS case sensitivity. */ int compare(char c1, char c2); /** Tests two path strings for equality, using the given OS case sensitivity. */ boolean equals(String s1, String s2); /** Computes the hash code for a path string. */ int hash(String s); /** * Returns whether the passed string starts with the given prefix, given the OS case sensitivity. * *

This is a pure string operation and doesn't need to worry about matching path segments. */ boolean startsWith(String path, String prefix); /** * Returns whether the passed string ends with the given prefix, given the OS case sensitivity. * *

This is a pure string operation and doesn't need to worry about matching path segments. */ boolean endsWith(String path, String suffix); /** Returns the separator used for normalized paths. */ char getSeparator(); /** Returns whether the unnormalized character c is a separator. */ boolean isSeparator(char c); boolean isCaseSensitive(); static OsPathPolicy getFilePathOs() { switch (OS.getCurrent()) { case LINUX: case FREEBSD: case UNKNOWN: return UnixOsPathPolicy.INSTANCE; case DARWIN: // NOTE: We *should* return a path policy that is case insensitive, // but we currently don't handle this return UnixOsPathPolicy.INSTANCE; case WINDOWS: return WindowsOsPathPolicy.INSTANCE; default: throw new AssertionError("Not covering all OSs"); } } /** Utilities for implementations of {@link OsPathPolicy}. */ class Utils { /** * Normalizes any '.' and '..' in-place in the segment array by shifting other segments to the * front. Returns the remaining number of items. */ static int removeRelativePaths(String[] segments, int starti, boolean isAbsolute) { int segmentCount = 0; int shift = starti; int n = segments.length; for (int i = starti; i < n; ++i) { String segment = segments[i]; switch (segment) { case ".": ++shift; break; case "..": if (segmentCount > 0 && !segments[segmentCount - 1].equals("..")) { // Remove the last segment, if there is one and it is not "..". This // means that the resulting path can still contain ".." // segments at the beginning. segmentCount--; shift += 2; break; } else if (isAbsolute) { // If this is absolute, then just pop it the ".." off and remain at root ++shift; break; } // Fall through default: ++segmentCount; if (shift > 0) { segments[i - shift] = segments[i]; } break; } } return segmentCount; } } }