com.sap.prd.mobile.ios.mios.FileUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.sap.prd.mobile.ios.mios.FileUtils.java

Source

/*
 * #%L
 * xcode-maven-plugin
 * %%
 * Copyright (C) 2012 SAP AG
 * %%
 * 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.
 * #L%
 */
package com.sap.prd.mobile.ios.mios;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;

public class FileUtils {

    private final static String DOT = ".";

    public static void mkdirs(final File f) throws IOException {
        if (f.exists() && !f.isDirectory())
            throw new IOException(String.format("'%s' does already exist but is not a directory.", f));

        if (!f.exists() && !f.mkdirs())
            throw new IOException("Could not create folder '" + f + "'.");
    }

    public static void deleteDirectory(final File directory) throws IOException {
        org.codehaus.plexus.util.FileUtils.deleteDirectory(directory);
    }

    /**
     * 
     * @param parent
     *          The parent directory
     * @param child
     *          The child direcory
     * @return the part of the path that represents the delta between <code>parent</code> and
     *         <code>child</code>.
     * @throws IllegalStateExcpetion
     *           in case <code>child</code> is not a child of <code>parent</code>.
     */
    public static String getDelta(File parent, File child) {

        final List<String> _parent = split(parent.getAbsoluteFile());
        final List<String> _child = split(child.getAbsoluteFile());

        if (!isChild(_parent, _child))
            throw new IllegalStateException(
                    "Child directory '" + child + "' is not a child of the base directory '" + parent + "'.");

        StringBuilder path = new StringBuilder();

        int index = getNumberOfCommonElements(_parent, _child);

        for (int size = _child.size(); index < size; index++) {

            if (path.length() != 0)
                path.append(File.separator);
            path.append(_child.get(index));
        }

        return path.toString();
    }

    private static int getNumberOfCommonElements(List<String> _parent, List<String> _child) {
        int index = 0;

        for (int size = Math.min(_parent.size(), _child.size()); index < size; index++)
            if (!_parent.get(index).equals(_child.get(index)))
                break;

        return index;
    }

    private static List<String> split(File dir) {

        List<String> result = new ArrayList<String>();

        do {

            result.add(dir.getName());
            dir = dir.getParentFile();

        } while (dir != null);

        Collections.reverse(result);

        return result;

    }

    /**
     * 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
     * '\'.
     * 
     * Copied from http://stackoverflow.com/a/3054692/933106.
     * 
     * @param target
     *          targetPath is calculated to this file
     * @param base
     *          basePath is calculated from this file
     * @param separator
     *          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 = -6747166042664389937L;

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

    public static boolean isSymbolicLink(File file) throws IOException {
        if (file == null || !file.exists())
            return false;

        PrintStream printStream = new PrintStream(new ByteArrayOutputStream(), true,
                Charset.defaultCharset().name());
        try {
            int result = Forker.forkProcess(printStream, file.getParentFile(), "test", "-L", file.getName());
            return result == 0;
        } finally {
            IOUtils.closeQuietly(printStream);
        }
    }

    public static void createSymbolicLink(final File source, final File target) throws IOException {
        System.out.println("[INFO] Creating symbolic link. Source:" + source.getAbsolutePath() + ", target: "
                + target.getAbsolutePath() + ".");

        mkdirs(target.getParentFile());

        int returnValue = Forker.forkProcess(System.out, null, "ln", "-sf", source.getAbsolutePath(),
                target.getAbsolutePath());
        if (returnValue != 0) {
            throw new RuntimeException("Cannot create symbolic link from '" + source + "' to '" + target
                    + "'. Return value:" + returnValue);
        }
    }

    public static boolean isChild(File parent, File child) {
        return isChild(split(parent.getAbsoluteFile()), split(child.getAbsoluteFile()));
    }

    private static boolean isChild(List<String> parent, List<String> child) {

        if (child.size() < parent.size())
            return false;

        for (int index = 0, size = parent.size(); index < size; index++)
            if (!parent.get(index).equals(child.get(index)))
                return false;

        return true;

    }

    public static String ensureLeadingSlash(final String path) {
        return path.startsWith("/") ? path : "/" + path;
    }

    public static String getAppendix(final File f) {

        final String fileName = f.getName();
        int indexOfLastDot = fileName.lastIndexOf(DOT);

        if (indexOfLastDot < 0) {
            return null;
        }

        return fileName.substring(indexOfLastDot + DOT.length());
    }

    static void unarchive(final ArchiverManager archiverManager, final String archiverId, final File source,
            final File destinationDirectory) {
        try {
            UnArchiver unarchiver = archiverManager.getUnArchiver(archiverId);
            unarchiver.setSourceFile(source);
            unarchiver.setDestDirectory(destinationDirectory);
            unarchiver.extract();
        } catch (NoSuchArchiverException e) {
            throw new RuntimeException(e);
        } catch (ArchiverException e) {
            throw new RuntimeException(e);
        }
    }

    static String getCanonicalPath(File f) throws IORuntimeException {
        try {
            return f.getCanonicalPath();
        } catch (final IOException ex) {
            throw new IORuntimeException(ex.getMessage(), ex);
        }
    }

    static File getCanonicalFile(File f) throws IORuntimeException {
        try {
            return f.getCanonicalFile();
        } catch (final IOException ex) {
            throw new IORuntimeException(ex.getMessage(), ex);
        }
    }

    public static class IORuntimeException extends RuntimeException {

        /**
         * 
         */
        private static final long serialVersionUID = -833352788241793404L;

        public IORuntimeException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}