/*
* Copyright 2010 the original author or authors.
*
* 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 org.gradle.api.internal.file;
import groovy.lang.Closure;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.PathValidation;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.util.GFileUtils;
import org.gradle.util.OperatingSystem;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class AbstractFileResolver implements FileResolver {
private static final Pattern URI_SCHEME = Pattern.compile("[a-zA-Z][a-zA-Z0-9+-\\.]*:.+");
private static final Pattern ENCODED_URI = Pattern.compile("%([0-9a-fA-F]{2})");
public FileResolver withBaseDir(Object path) {
return new BaseDirConverter(resolve(path));
}
public File resolve(Object path) {
return resolve(path, PathValidation.NONE);
}
public File resolve(Object path, PathValidation validation) {
File file = doResolve(path);
file = GFileUtils.canonicalise(file);
validate(file, validation);
return file;
}
public FileSource resolveLater(final Object path) {
return new FileSource() {
public File get() {
return resolve(path);
}
};
}
public URI resolveUri(Object path) {
return convertObjectToURI(path);
}
protected abstract File doResolve(Object path);
protected URI convertObjectToURI(Object path) {
Object object = unpack(path);
Object converted = convertToFileOrUri(object);
if (converted instanceof File) {
return resolve(converted).toURI();
}
return (URI) converted;
}
protected File convertObjectToFile(Object path) {
Object object = unpack(path);
if (object == null) {
return null;
}
Object converted = convertToFileOrUri(object);
if (converted instanceof File) {
return (File) converted;
}
throw new InvalidUserDataException(String.format("Cannot convert URL '%s' to a file.", converted));
}
private Object convertToFileOrUri(Object path) {
if (path instanceof File) {
return path;
}
if (path instanceof URL) {
try {
path = ((URL) path).toURI();
} catch (URISyntaxException e) {
throw new UncheckedIOException(e);
}
}
if (path instanceof URI) {
URI uri = (URI) path;
if (uri.getScheme().equals("file")) {
return new File(uri.getPath());
}
return uri;
}
String str = path.toString();
if (str.startsWith("file:")) {
return new File(uriDecode(str.substring(5)));
}
for (File file : File.listRoots()) {
String rootPath = file.getAbsolutePath();
String normalisedStr = str;
if (!OperatingSystem.current().isCaseSensitiveFileSystem()) {
rootPath = rootPath.toLowerCase();
normalisedStr = normalisedStr.toLowerCase();
}
if (normalisedStr.startsWith(rootPath) || normalisedStr.startsWith(rootPath.replace(File.separatorChar,
'/'))) {
return new File(str);
}
}
// Check if string starts with a URI scheme
if (URI_SCHEME.matcher(str).matches()) {
try {
return new URI(str);
} catch (URISyntaxException e) {
throw new UncheckedIOException(e);
}
}
return new File(str);
}
private String uriDecode(String path) {
StringBuffer builder = new StringBuffer();
Matcher matcher = ENCODED_URI.matcher(path);
while (matcher.find()) {
String val = matcher.group(1);
matcher.appendReplacement(builder, String.valueOf((char) (Integer.parseInt(val, 16))));
}
matcher.appendTail(builder);
return builder.toString();
}
private Object unpack(Object path) {
Object current = path;
while (current != null) {
if (current instanceof Closure) {
current = ((Closure) current).call();
} else if (current instanceof Callable) {
try {
current = ((Callable) current).call();
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (current instanceof FileSource) {
return ((FileSource)current).get();
} else {
return current;
}
}
return null;
}
protected void validate(File file, PathValidation validation) {
switch (validation) {
case NONE:
break;
case EXISTS:
if (!file.exists()) {
throw new InvalidUserDataException(String.format("File '%s' does not exist.", file));
}
break;
case FILE:
if (!file.exists()) {
throw new InvalidUserDataException(String.format("File '%s' does not exist.", file));
}
if (!file.isFile()) {
throw new InvalidUserDataException(String.format("File '%s' is not a file.", file));
}
break;
case DIRECTORY:
if (!file.exists()) {
throw new InvalidUserDataException(String.format("Directory '%s' does not exist.", file));
}
if (!file.isDirectory()) {
throw new InvalidUserDataException(String.format("Directory '%s' is not a directory.", file));
}
break;
}
}
public FileCollection resolveFiles(Object... paths) {
if (paths.length == 1 && paths[0] instanceof FileCollection) {
return (FileCollection) paths[0];
}
return new PathResolvingFileCollection(this, null, paths);
}
public FileTree resolveFilesAsTree(Object... paths) {
return resolveFiles(paths).getAsFileTree();
}
}