/* * 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 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.

For example, the module root for directory * package/apps/Contacts/src is packages/apps/Contacts * * @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 findSourceDirs(File file) { Preconditions.checkNotNull(file); if (!file.exists()) { return ImmutableList.of(); } if (!file.isDirectory()) { file = file.getParentFile(); } ImmutableList.Builder 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 dirs = findSourceDirs(child); // filter out the third case. Collection filteredDirs = Collections2.filter(dirs, new Predicate() { @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 findExcludeDirs(File file) { Preconditions.checkNotNull(file); if (!file.exists()) { return ImmutableList.of(); } if (!file.isDirectory()) { file = file.getParentFile(); } ImmutableList.Builder 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()); } }