• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
getRepoRoot()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      */
findAndInitRepoRoot(File file)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      */
findModuleRoot(File path)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      */
findSourceDirs(File file)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 
findExcludeDirs(File file)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 
findTemplateDir()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