Home | History | Annotate | Download | only in idegen
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.idegen;
     18 
     19 import com.google.common.base.Preconditions;
     20 import com.google.common.collect.ImmutableList;
     21 import com.google.common.collect.Sets;
     22 
     23 import java.io.File;
     24 import java.io.FileNotFoundException;
     25 import java.io.FilenameFilter;
     26 import java.io.IOException;
     27 import java.net.URISyntaxException;
     28 import java.util.HashSet;
     29 import java.util.logging.Level;
     30 import java.util.logging.Logger;
     31 import java.util.regex.Matcher;
     32 import java.util.regex.Pattern;
     33 
     34 /**
     35  * Find directories utility.
     36  */
     37 public class DirectorySearch {
     38 
     39     private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
     40 
     41     public static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
     42 
     43     static {
     44         SOURCE_DIRS.add("src");
     45         SOURCE_DIRS.add("java");
     46     }
     47 
     48     private static final Pattern EXCLUDE_PATTERN = Pattern.compile("values-..(-.*)*");
     49 
     50     private static File repoRoot = null;
     51     public static final String REL_TEMPLATE_DIR = "templates";
     52     public static final String REL_TEMPLATE_PATH_FROM_ROOT = "development/tools/idegen/"
     53             + REL_TEMPLATE_DIR;
     54 
     55     /**
     56      * Returns the previously initialized repo root.
     57      */
     58     public static File getRepoRoot() {
     59         Preconditions.checkNotNull(repoRoot, "repoRoot has not been initialized yet.  Call "
     60                 + "findAndInitRepoRoot() first.");
     61         return repoRoot;
     62     }
     63 
     64     /**
     65      * Find the repo root.  This is the root branch directory of a full repo checkout.
     66      *
     67      * @param file any file inside the root.
     68      * @return the root directory.
     69      */
     70     public static void findAndInitRepoRoot(File file) {
     71         Preconditions.checkNotNull(file);
     72         if (repoRoot != null) {
     73             return;
     74         }
     75 
     76         if (file.isDirectory()) {
     77             File[] files = file.listFiles(new FilenameFilter() {
     78                 @Override
     79                 public boolean accept(File dir, String name) {
     80                     return ".repo".equals(name);
     81                 }
     82             });
     83             if (files.length > 0) {
     84                 repoRoot = file;
     85             }
     86         }
     87         File parent = file.getParentFile();
     88         if (parent == null) {
     89             throw new IllegalStateException("Repo root not found from starting point " +
     90                     file.getPath());
     91         }
     92         findAndInitRepoRoot(parent);
     93     }
     94 
     95     /**
     96      * Searches up the parent chain to find the closes module root directory. A module root is one
     97      * with an Android.mk file in it. <p> For example, the module root for directory
     98      * <code>package/apps/Contacts/src</code> is <code>packages/apps/Contacts</code>
     99      *
    100      * @return the module root.
    101      * @throws IOException when module root is not found.
    102      */
    103     public static File findModuleRoot(File path) throws IOException {
    104         Preconditions.checkNotNull(path);
    105         File dir;
    106         if (path.isFile()) {
    107             dir = path.getParentFile();
    108         } else {
    109             dir = path;
    110         }
    111         while (dir != null) {
    112             File makeFile = new File(dir, "Android.mk");
    113             if (makeFile.exists()) {
    114                 return dir;
    115             } else {
    116                 dir = dir.getParentFile();
    117             }
    118         }
    119         // At this point, there are no parents and we have not found a module. Error.
    120         throw new IOException("Module root not found for path " + path.getCanonicalPath());
    121     }
    122 
    123     /**
    124      * Find all source directories from a given root file.
    125      *
    126      * If the root file is a file, the directory of that file will be used as the starting
    127      * location.
    128      *
    129      * @param file The starting location. Can be a file or directory.
    130      * @return List of
    131      */
    132     public static ImmutableList<File> findSourceDirs(File file) {
    133         Preconditions.checkNotNull(file);
    134         if (!file.exists()) {
    135             return ImmutableList.of();
    136         }
    137         if (!file.isDirectory()) {
    138             file = file.getParentFile();
    139         }
    140         ImmutableList.Builder<File> builder = ImmutableList.builder();
    141         File[] children = file.listFiles();
    142         for (File child : children) {
    143             if (child.isDirectory()) {
    144                 // Recurse further down the tree first to cover case of:
    145                 //
    146                 // src/java
    147                 //   or
    148                 // java/src
    149                 //
    150                 // In either of these cases, we don't want the parent.
    151                 ImmutableList<File> dirs = findSourceDirs(child);
    152                 if (dirs.isEmpty()) {
    153                     if (SOURCE_DIRS.contains(child.getName())) {
    154                         builder.add(child);
    155                     }
    156                 } else {
    157                     builder.addAll(dirs);
    158                 }
    159             }
    160         }
    161 
    162         return builder.build();
    163     }
    164 
    165     public static ImmutableList<File> findExcludeDirs(File file) {
    166         Preconditions.checkNotNull(file);
    167         if (!file.exists()) {
    168             return ImmutableList.of();
    169         }
    170         if (!file.isDirectory()) {
    171             file = file.getParentFile();
    172         }
    173         ImmutableList.Builder<File> builder = ImmutableList.builder();
    174         // Go into the res folder
    175         File resFile = new File(file, "res");
    176         if (resFile.exists()) {
    177 
    178             File[] children = resFile.listFiles();
    179             for (File child : children) {
    180                 if (child.isDirectory()) {
    181                     Matcher matcher = EXCLUDE_PATTERN.matcher(child.getName());
    182                     if (matcher.matches()) {
    183                         // Exclude internationalization language folders.
    184                         // ex: values-zh
    185                         // But don't exclude values-land.  Assume all language folders are two
    186                         // letters.
    187                         builder.add(child);
    188                     }
    189                 }
    190             }
    191         }
    192 
    193         return builder.build();
    194     }
    195 
    196     private static File templateDirCurrent = null;
    197     private static File templateDirRoot = null;
    198 
    199     public static File findTemplateDir() throws IOException {
    200         // Cache optimization.
    201         if (templateDirCurrent != null && templateDirCurrent.exists()) {
    202             return templateDirCurrent;
    203         }
    204         if (templateDirRoot != null && templateDirRoot.exists()) {
    205             return templateDirRoot;
    206         }
    207 
    208         File currentDir = null;
    209         try {
    210             currentDir = new File(
    211                     IntellijProject.class.getProtectionDomain().getCodeSource().getLocation()
    212                             .toURI().getPath()).getParentFile();
    213         } catch (URISyntaxException e) {
    214             logger.log(Level.SEVERE, "Could not get jar location.", e);
    215             return null;
    216         }
    217         // Support for program execution in intellij.
    218         if (currentDir.getPath().endsWith("out/production")) {
    219             return new File(currentDir.getParentFile().getParentFile(), REL_TEMPLATE_DIR);
    220         }
    221         // First check relative to current run directory.
    222         templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
    223         if (templateDirCurrent.exists()) {
    224             return templateDirCurrent;
    225         } else {
    226             // Then check relative to root directory.
    227             templateDirRoot = new File(repoRoot, REL_TEMPLATE_PATH_FROM_ROOT);
    228             if (templateDirRoot.exists()) {
    229                 return templateDirRoot;
    230             }
    231         }
    232         throw new FileNotFoundException(
    233                 "Unable to find template dir. Tried the following locations:\n" +
    234                         templateDirCurrent.getCanonicalPath() + "\n" +
    235                         templateDirRoot.getCanonicalPath());
    236     }
    237 }
    238