blob: d2599424ba779d39a072dc0f158bccb3e019a976 [file]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.android.idegen;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Find directories utility.
*/
public class DirectorySearch {
private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
public static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
static {
SOURCE_DIRS.add("src");
SOURCE_DIRS.add("java");
}
private static final Pattern EXCLUDE_PATTERN = Pattern.compile("values-..(-.*)*");
private static File repoRoot = null;
public static final String REL_TEMPLATE_DIR = "templates";
public static final String REL_TEMPLATE_PATH_FROM_ROOT = "development/tools/idegen/"
+ REL_TEMPLATE_DIR;
/**
* Returns the previously initialized repo root.
*/
public static File getRepoRoot() {
Preconditions.checkNotNull(repoRoot, "repoRoot has not been initialized yet. Call "
+ "findAndInitRepoRoot() first.");
return repoRoot;
}
/**
* Find the repo root. This is the root branch directory of a full repo checkout.
*
* @param file any file inside the root.
* @return the root directory.
*/
public static void findAndInitRepoRoot(File file) {
Preconditions.checkNotNull(file);
if (repoRoot != null) {
return;
}
if (file.isDirectory()) {
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return ".repo".equals(name);
}
});
if (files.length > 0) {
repoRoot = file;
}
}
File parent = file.getParentFile();
if (parent == null) {
throw new IllegalStateException("Repo root not found from starting point " +
file.getPath());
}
findAndInitRepoRoot(parent);
}
/**
* Searches up the parent chain to find the closes module root directory. A module root is one
* with an Android.mk file in it. <p> For example, the module root for directory
* <code>package/apps/Contacts/src</code> is <code>packages/apps/Contacts</code>
*
* @return the module root.
* @throws IOException when module root is not found.
*/
public static File findModuleRoot(File path) throws IOException {
Preconditions.checkNotNull(path);
File dir;
if (path.isFile()) {
dir = path.getParentFile();
} else {
dir = path;
}
while (dir != null) {
File makeFile = new File(dir, "Android.mk");
if (makeFile.exists()) {
return dir;
} else {
dir = dir.getParentFile();
}
}
// At this point, there are no parents and we have not found a module. Error.
throw new IOException("Module root not found for path " + path.getCanonicalPath());
}
/**
* Find all source directories from a given root file.
*
* If the root file is a file, the directory of that file will be used as the starting
* location.
*
* @param file The starting location. Can be a file or directory.
* @return List of
*/
public static ImmutableList<File> findSourceDirs(File file) {
Preconditions.checkNotNull(file);
if (!file.exists()) {
return ImmutableList.of();
}
if (!file.isDirectory()) {
file = file.getParentFile();
}
ImmutableList.Builder<File> builder = ImmutableList.builder();
File[] children = file.listFiles();
for (File child : children) {
if (child.isDirectory()) {
// Recurse further down the tree first to cover case of:
//
// src/java
// or
// java/src
// or
// src/main/java/java
//
// In first two cases, we don't want the parent.
// In third case we want the parent of the last "java", the last "java" is actually
// part of namespace.
ImmutableList<File> dirs = findSourceDirs(child);
// filter out the third case.
Collection<File> filteredDirs = Collections2.filter(dirs, new Predicate<File>() {
@Override
public boolean apply(File input) {
return !input.getAbsolutePath().endsWith("java/java");
}
});
if (filteredDirs.isEmpty()) {
if (SOURCE_DIRS.contains(child.getName())) {
builder.add(child);
}
} else {
builder.addAll(filteredDirs);
}
}
}
return builder.build();
}
public static ImmutableList<File> findExcludeDirs(File file) {
Preconditions.checkNotNull(file);
if (!file.exists()) {
return ImmutableList.of();
}
if (!file.isDirectory()) {
file = file.getParentFile();
}
ImmutableList.Builder<File> builder = ImmutableList.builder();
// Go into the res folder
File resFile = new File(file, "res");
if (resFile.exists()) {
File[] children = resFile.listFiles();
for (File child : children) {
if (child.isDirectory()) {
Matcher matcher = EXCLUDE_PATTERN.matcher(child.getName());
if (matcher.matches()) {
// Exclude internationalization language folders.
// ex: values-zh
// But don't exclude values-land. Assume all language folders are two
// letters.
builder.add(child);
}
}
}
}
return builder.build();
}
private static File templateDirCurrent = null;
private static File templateDirRoot = null;
public static File findTemplateDir() throws IOException {
// Cache optimization.
if (templateDirCurrent != null && templateDirCurrent.exists()) {
return templateDirCurrent;
}
if (templateDirRoot != null && templateDirRoot.exists()) {
return templateDirRoot;
}
File currentDir = null;
try {
currentDir = new File(
IntellijProject.class.getProtectionDomain().getCodeSource().getLocation()
.toURI().getPath()).getParentFile();
} catch (URISyntaxException e) {
logger.log(Level.SEVERE, "Could not get jar location.", e);
return null;
}
// Support for program execution in intellij.
if (currentDir.getPath().endsWith("out/production")) {
return new File(currentDir.getParentFile().getParentFile(), REL_TEMPLATE_DIR);
}
// First check relative to current run directory.
templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
if (templateDirCurrent.exists()) {
return templateDirCurrent;
} else {
// Then check relative to root directory.
templateDirRoot = new File(repoRoot, REL_TEMPLATE_PATH_FROM_ROOT);
if (templateDirRoot.exists()) {
return templateDirRoot;
}
}
throw new FileNotFoundException(
"Unable to find template dir. Tried the following locations:\n" +
templateDirCurrent.getCanonicalPath() + "\n" +
templateDirRoot.getCanonicalPath());
}
}