FileUtils.java
/*
* #%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);
}
}
}