hudson.plugins.project_inheritance.util.PathMapping.java Source code

Java tutorial

Introduction

Here is the source code for hudson.plugins.project_inheritance.util.PathMapping.java

Source

/**
 * Copyright (c) 2011-2013, Intel Mobile Communications GmbH
 * 
 * 
 * This file is part of the Inheritance plug-in for Jenkins.
 * 
 * The Inheritance plug-in is free software: you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation in version 3
 * of the License
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

package hudson.plugins.project_inheritance.util;

import java.io.File;
import java.util.AbstractMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FilenameUtils;

public class PathMapping {
    private static final Pattern absPathPattern = Pattern.compile("^(/|[a-zA-Z]:|\\\\\\\\)");
    public final TreeMap<String, String> map = new TreeMap<String, String>();

    public PathMapping(String srcDir, Set<String> srcFiles, String target) {

        //Checking if the source is Windows or Unix
        String srcSep = (isUnixPath(srcDir)) ? "/" : "\\";
        String dstSep = (isUnixPath(target)) ? "/" : "\\";

        for (String src : srcFiles) {
            //Determine full source and destination path
            final String fullSrc = String.format("%s%s%s", srcDir, srcSep, src);
            final String fullDst = String.format("%s%s%s", target, dstSep, src);
            map.put(fullSrc, fullDst);
        }
    }

    public static boolean isUnixPath(String path) {
        if (path.contains("/")) {
            return true;
        } else if (path.contains("\\")) {
            return false;
        }
        return true;
    }

    public static boolean isPathSingleton(String path) {
        return !(path.contains("/") || path.contains("\\"));
    }

    public static boolean isAbsolute(String path) {
        if (path == null) {
            return false;
        }
        Matcher m = absPathPattern.matcher(path);
        return m.find();
    }

    public static Entry<String, String> splitPath(String path) {
        File f = new File(path);
        String base = f.getName();
        String dir = path.substring(0, path.length() - base.length() - 1);
        return new AbstractMap.SimpleEntry<String, String>(dir, base);
    }

    public static String join(String front, String end) {
        if (front == null || end == null) {
            throw new NullPointerException("May not pass null values for path parts");
        }
        if (isAbsolute(end)) {
            return end;
        }

        boolean isUnix;
        if (!isPathSingleton(front)) {
            isUnix = isUnixPath(front);
        } else if (!isPathSingleton(end)) {
            isUnix = isUnixPath(end);
        } else {
            //Both single; assuming unix
            isUnix = true;
        }

        if (isUnix) {
            return front + "/" + end;
        } else {
            return front + "\\" + end;
        }
    }

    /**
     * Get the relative path from one file to another, specifying the directory separator. 
     * If one of the provided resources does not exist, it is assumed to be a file unless it ends with '/' or
     * '\'.
     * 
     * @param targetPath targetPath is calculated to this file
     * @param basePath basePath is calculated from this file
     * @param pathSeparator directory separator. The platform default is not assumed so that we can test Unix behaviour when running on Windows (for example)
     * @return
     */
    public static String getRelativePath(String targetPath, String basePath, String pathSeparator) {
        // Normalize the paths
        String normalizedTargetPath = FilenameUtils.normalizeNoEndSeparator(targetPath);
        String normalizedBasePath = FilenameUtils.normalizeNoEndSeparator(basePath);

        // Undo the changes to the separators made by normalization
        if (pathSeparator.equals("/")) {
            normalizedTargetPath = FilenameUtils.separatorsToUnix(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToUnix(normalizedBasePath);

        } else if (pathSeparator.equals("\\")) {
            normalizedTargetPath = FilenameUtils.separatorsToWindows(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToWindows(normalizedBasePath);

        } else {
            throw new IllegalArgumentException("Unrecognised dir separator '" + pathSeparator + "'");
        }

        String[] base = normalizedBasePath.split(Pattern.quote(pathSeparator));
        String[] target = normalizedTargetPath.split(Pattern.quote(pathSeparator));

        // First get all the common elements. Store them as a string,
        // and also count how many of them there are.
        StringBuilder common = new StringBuilder();

        int commonIndex = 0;
        while (commonIndex < target.length && commonIndex < base.length
                && target[commonIndex].equals(base[commonIndex])) {
            common.append(target[commonIndex] + pathSeparator);
            commonIndex++;
        }

        if (commonIndex == 0) {
            // No single common path element. This most
            // likely indicates differing drive letters, like C: and D:.
            // These paths cannot be relativized.
            throw new PathResolutionException("No common path element found for '" + normalizedTargetPath
                    + "' and '" + normalizedBasePath + "'");
        }

        // The number of directories we have to backtrack depends on whether the base is a file or a dir
        // For example, the relative path from
        //
        // /foo/bar/baz/gg/ff to /foo/bar/baz
        // 
        // ".." if ff is a file
        // "../.." if ff is a directory
        //
        // The following is a heuristic to figure out if the base refers to a file or dir. It's not perfect, because
        // the resource referred to by this path may not actually exist, but it's the best I can do
        boolean baseIsFile = true;

        File baseResource = new File(normalizedBasePath);

        if (baseResource.exists()) {
            baseIsFile = baseResource.isFile();

        } else if (basePath.endsWith(pathSeparator)) {
            baseIsFile = false;
        }

        StringBuilder relative = new StringBuilder();

        if (base.length != commonIndex) {
            int numDirsUp = baseIsFile ? base.length - commonIndex - 1 : base.length - commonIndex;

            for (int i = 0; i < numDirsUp; i++) {
                relative.append(".." + pathSeparator);
            }
        }
        relative.append(normalizedTargetPath.substring(common.length()));
        return relative.toString();
    }

    static class PathResolutionException extends RuntimeException {
        private static final long serialVersionUID = -1260762639510818413L;

        PathResolutionException(String msg) {
            super(msg);
        }
    }
}