am e2962681: Merge "Overhaul of intellij-gen script."
* commit 'e2962681b6f73dba3ff2ac7e63a6f70901fc1751': Overhaul of intellij-gen script.
This commit is contained in:
@@ -38,8 +38,8 @@ if [ ! -e $root_dir/.repo ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
tmp_file=tmp.txt
|
||||
dest_file=module-index.txt
|
||||
tmp_file=${root_dir}/tmp.txt
|
||||
dest_file=${root_dir}/module-index.txt
|
||||
|
||||
echo "Generating index file $dest_file..."
|
||||
start=$(($(date +%s%N) / 1000000))
|
||||
|
||||
@@ -32,13 +32,15 @@
|
||||
set -e
|
||||
|
||||
progname=`basename $0`
|
||||
if [ $# -ne 1 ]
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
echo "Usage: $progname <module_name>"
|
||||
echo "Usage: $progname project_dir module_dir <module_dir>..."
|
||||
exit 1
|
||||
fi
|
||||
module_name=$1
|
||||
|
||||
project_dir=${PWD}/$1
|
||||
shift
|
||||
module_dirs=$@
|
||||
echo $module_dirs
|
||||
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
root_dir=$PWD
|
||||
if [ ! -e $root_dir/.repo ]; then
|
||||
@@ -63,8 +65,8 @@ fi
|
||||
|
||||
echo "Checking for $idegenjar"
|
||||
if [ -e "$idegenjar" ]; then
|
||||
echo "Generating project files for $module_name"
|
||||
cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $module_name"
|
||||
echo "Generating project files for $module_dirs"
|
||||
cmd="java -cp $idegenjar com.android.idegen.IntellijProject $index_file $project_dir $module_dirs"
|
||||
echo $cmd
|
||||
$cmd
|
||||
else
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Module while is a composition of many other modules.
|
||||
* <p>
|
||||
* This is needed since intellij does not allow two modules to share the same content root.
|
||||
*/
|
||||
public class AggregatedModule extends Module {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AggregatedModule.class.getName());
|
||||
|
||||
private String aggregatedModuleName;
|
||||
private Set<Module> modules;
|
||||
private HashSet<String> directDependencies = Sets.newHashSet();
|
||||
|
||||
public AggregatedModule(String aggregatedName, Set<Module> modules) {
|
||||
this.aggregatedModuleName = Preconditions.checkNotNull(aggregatedName);
|
||||
this.modules = Preconditions.checkNotNull(modules);
|
||||
}
|
||||
|
||||
public void build() throws IOException {
|
||||
// Create an iml file that contains all the srcs of modules.
|
||||
buildDependentModules();
|
||||
buildDirectDependencies();
|
||||
//buildImlFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getDir() {
|
||||
// All modules should be in the same directory so just pull the first.
|
||||
return modules.iterator().next().getDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAndroidModule() {
|
||||
for (Module module : modules) {
|
||||
if (module.isAndroidModule()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<File> getIntermediatesDirs() {
|
||||
List<File> result = Lists.newArrayList();
|
||||
for (Module module : modules) {
|
||||
Iterables.addAll(result, module.getIntermediatesDirs());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void buildDirectDependencies() {
|
||||
for (Module module : modules) {
|
||||
Set<String> deps = module.getDirectDependencies();
|
||||
directDependencies.addAll(deps);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getDirectDependencies() {
|
||||
return directDependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImmutableList<File> getSourceDirs() {
|
||||
ImmutableList.Builder<File> builder = ImmutableList.builder();
|
||||
for (Module module : modules) {
|
||||
builder.addAll(module.getSourceDirs());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ImmutableList<File> getExcludeDirs() {
|
||||
ImmutableList.Builder<File> builder = ImmutableList.builder();
|
||||
for (Module module : modules) {
|
||||
builder.addAll(module.getExcludeDirs());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> getAllDependentImlFiles() {
|
||||
Set<File> result = Sets.newHashSet();
|
||||
for (Module module : modules) {
|
||||
result.addAll(module.getAllDependentImlFiles());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRepoRoot() {
|
||||
return modules.iterator().next().getRepoRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return aggregatedModuleName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ 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.HashSet;
|
||||
import java.util.logging.Level;
|
||||
@@ -37,7 +38,8 @@ public class DirectorySearch {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
|
||||
|
||||
private static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
|
||||
public static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
|
||||
|
||||
static {
|
||||
SOURCE_DIRS.add("src");
|
||||
SOURCE_DIRS.add("java");
|
||||
@@ -50,38 +52,72 @@ public class DirectorySearch {
|
||||
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 File findRepoRoot(File file) {
|
||||
public static void findAndInitRepoRoot(File file) {
|
||||
Preconditions.checkNotNull(file);
|
||||
if (repoRoot != null) {
|
||||
return repoRoot;
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
if (".repo".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return ".repo".equals(name);
|
||||
}
|
||||
});
|
||||
if (files.length > 0) {
|
||||
repoRoot = file;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
File parent = file.getParentFile();
|
||||
if (parent == null) {
|
||||
return null;
|
||||
throw new IllegalStateException("Repo root not found from starting point " +
|
||||
file.getPath());
|
||||
}
|
||||
return findRepoRoot(parent);
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,10 +141,19 @@ public class DirectorySearch {
|
||||
File[] children = file.listFiles();
|
||||
for (File child : children) {
|
||||
if (child.isDirectory()) {
|
||||
if (SOURCE_DIRS.contains(child.getName())) {
|
||||
builder.add(child);
|
||||
// Recurse further down the tree first to cover case of:
|
||||
//
|
||||
// src/java
|
||||
// or
|
||||
// java/src
|
||||
//
|
||||
// In either of these cases, we don't want the parent.
|
||||
ImmutableList<File> dirs = findSourceDirs(child);
|
||||
if (dirs.isEmpty()) {
|
||||
if (SOURCE_DIRS.contains(child.getName())) {
|
||||
builder.add(child);
|
||||
}
|
||||
} else {
|
||||
ImmutableList<File> dirs = findSourceDirs(child);
|
||||
builder.addAll(dirs);
|
||||
}
|
||||
}
|
||||
@@ -151,20 +196,28 @@ public class DirectorySearch {
|
||||
private static File templateDirCurrent = null;
|
||||
private static File templateDirRoot = null;
|
||||
|
||||
public static File findTemplateDir() throws FileNotFoundException {
|
||||
public static File findTemplateDir() throws IOException {
|
||||
// Cache optimization.
|
||||
if (templateDirCurrent != null && templateDirCurrent.exists()) return templateDirCurrent;
|
||||
if (templateDirRoot != null && templateDirRoot.exists()) return templateDirRoot;
|
||||
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();
|
||||
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()) {
|
||||
@@ -178,7 +231,7 @@ public class DirectorySearch {
|
||||
}
|
||||
throw new FileNotFoundException(
|
||||
"Unable to find template dir. Tried the following locations:\n" +
|
||||
templateDirCurrent.getAbsolutePath() + "\n" +
|
||||
templateDirRoot.getAbsolutePath());
|
||||
templateDirCurrent.getCanonicalPath() + "\n" +
|
||||
templateDirRoot.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,33 +16,35 @@
|
||||
|
||||
package com.android.idegen;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Special module used for framework to build one off resource directory.
|
||||
*/
|
||||
public class FrameworkModule extends StandardModule {
|
||||
public class FrameworkModule extends Module {
|
||||
|
||||
// Framework needs a special constant for it's intermediates because it does not follow
|
||||
// normal conventions.
|
||||
private static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
|
||||
|
||||
public FrameworkModule(String moduleName, String makeFile) {
|
||||
super(IntellijProject.FRAMEWORK_MODULE, makeFile, true);
|
||||
public FrameworkModule(File moduleDir) throws IOException {
|
||||
super(Preconditions.checkNotNull(moduleDir), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String buildIntermediates() {
|
||||
protected String buildIntermediates() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
File intermediates = new File(repoRoot,
|
||||
File intermediates = new File(DirectorySearch.getRepoRoot(),
|
||||
REL_OUT_APP_DIR + File.separator + FRAMEWORK_INTERMEDIATES);
|
||||
ImmutableList<File> intermediateSrcDirs = DirectorySearch.findSourceDirs(intermediates);
|
||||
sb.append(" <content url=\"file://").append(intermediates).append("\">\n");
|
||||
for (File src : intermediateSrcDirs) {
|
||||
sb.append(" <sourceFolder url=\"file://")
|
||||
.append(src.getAbsolutePath()).append("\" isTestSource=\"false\" />\n");
|
||||
.append(src.getCanonicalPath()).append("\" isTestSource=\"false\" />\n");
|
||||
}
|
||||
sb.append(" </content>\n");
|
||||
return sb.toString();
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
package com.android.idegen;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class IntellijProject {
|
||||
|
||||
public static final String FRAMEWORK_MODULE = "framework";
|
||||
public static final String FRAMEWORK_MODULE_DIR = "frameworks/base";
|
||||
public static final Charset CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private static final Logger logger = Logger.getLogger(IntellijProject.class.getName());
|
||||
@@ -42,147 +42,116 @@ public class IntellijProject {
|
||||
|
||||
ModuleCache cache = ModuleCache.getInstance();
|
||||
|
||||
boolean buildFramework;
|
||||
File indexFile;
|
||||
File repoRoot;
|
||||
File projectIdeaDir;
|
||||
String moduleName;
|
||||
File projectPath;
|
||||
ArrayList<String> moduleDirs;
|
||||
|
||||
public IntellijProject(String indexFile, String moduleName) {
|
||||
public IntellijProject(String indexFile, String projectPath, ArrayList<String> moduleDirs,
|
||||
boolean buildFramework) {
|
||||
this.indexFile = new File(Preconditions.checkNotNull(indexFile));
|
||||
this.moduleName = Preconditions.checkNotNull(moduleName);
|
||||
}
|
||||
|
||||
private void init() throws IOException {
|
||||
repoRoot = DirectorySearch.findRepoRoot(indexFile);
|
||||
cache.init(indexFile);
|
||||
this.projectPath = new File(Preconditions.checkNotNull(projectPath));
|
||||
this.moduleDirs = Preconditions.checkNotNull(moduleDirs);
|
||||
this.buildFramework = buildFramework;
|
||||
DirectorySearch.findAndInitRepoRoot(this.indexFile);
|
||||
}
|
||||
|
||||
public void build() throws IOException {
|
||||
init();
|
||||
buildFrameWorkModule();
|
||||
|
||||
// First pass, find all dependencies and cache them.
|
||||
Module module = cache.getAndCache(moduleName);
|
||||
if (module == null) {
|
||||
logger.info("Module '" + moduleName + "' not found." +
|
||||
" Module names are case senstive.");
|
||||
return;
|
||||
}
|
||||
projectIdeaDir = new File(module.getDir(), ".idea");
|
||||
projectIdeaDir.mkdir();
|
||||
copyTemplates();
|
||||
|
||||
// Second phase, build aggregate modules.
|
||||
Set<String> deps = module.getAllDependencies();
|
||||
for (String dep : deps) {
|
||||
cache.buildAndCacheAggregatedModule(dep);
|
||||
cache.init(indexFile);
|
||||
File repoRoot = DirectorySearch.getRepoRoot();
|
||||
if (buildFramework) {
|
||||
File frameworkDir = new File(repoRoot, FRAMEWORK_MODULE_DIR);
|
||||
// Some unbundled apps/branches do not include the framework.
|
||||
if (frameworkDir.exists()) {
|
||||
buildFrameWorkModule(new File(repoRoot, FRAMEWORK_MODULE_DIR));
|
||||
}
|
||||
}
|
||||
|
||||
// Third phase, replace individual modules with aggregated modules
|
||||
Iterable<Module> modules = cache.getModules();
|
||||
for (Module mod : modules) {
|
||||
replaceWithAggregate(mod);
|
||||
for (String moduleDir : moduleDirs) {
|
||||
// First pass, find all dependencies and cache them.
|
||||
File dir = new File(repoRoot, moduleDir);
|
||||
if (!dir.exists()) {
|
||||
logger.info("Directory " + moduleDir + " does not exist in " + repoRoot +
|
||||
". Are you sure the directory is correct?");
|
||||
return;
|
||||
}
|
||||
Module module = cache.getAndCacheByDir(dir);
|
||||
if (module == null) {
|
||||
logger.info("Module '" + dir.getPath() + "' not found." +
|
||||
" Module names are case senstive.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally create iml files for dependencies
|
||||
Iterable<Module> modules = cache.getModules();
|
||||
for (Module mod : modules) {
|
||||
mod.buildImlFile();
|
||||
}
|
||||
|
||||
createModulesFile(module);
|
||||
createVcsFile(module);
|
||||
createNameFile(moduleName);
|
||||
createProjectFiles();
|
||||
}
|
||||
|
||||
private void replaceWithAggregate(Module module) {
|
||||
replaceWithAggregate(module.getDirectDependencies(), module.getName());
|
||||
replaceWithAggregate(module.getAllDependencies(), module.getName());
|
||||
|
||||
}
|
||||
|
||||
private void replaceWithAggregate(Set<String> deps, String moduleName) {
|
||||
for (String dep : Sets.newHashSet(deps)) {
|
||||
String replacement = cache.getAggregateReplacementName(dep);
|
||||
if (replacement != null) {
|
||||
|
||||
deps.remove(dep);
|
||||
// There could be dependencies on self due to aggregation.
|
||||
// Only add if the replacement is not self.
|
||||
if (!replacement.equals(moduleName)) {
|
||||
deps.add(replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void createProjectFiles() throws IOException {
|
||||
File ideaDir = new File(projectPath, ".idea");
|
||||
ideaDir.mkdirs();
|
||||
copyTemplates(ideaDir);
|
||||
createModulesFile(ideaDir, cache.getModules());
|
||||
createVcsFile(ideaDir, cache.getModules());
|
||||
createNameFile(ideaDir, projectPath.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Framework module needs special handling due to one off resource path:
|
||||
* frameworks/base/Android.mk
|
||||
*/
|
||||
private void buildFrameWorkModule() throws IOException {
|
||||
String makeFile = cache.getMakeFile(FRAMEWORK_MODULE);
|
||||
if (makeFile == null) {
|
||||
logger.warning("Unable to find framework module: " + FRAMEWORK_MODULE +
|
||||
". Skipping.");
|
||||
} else {
|
||||
logger.info("makefile: " + makeFile);
|
||||
StandardModule frameworkModule = new FrameworkModule(FRAMEWORK_MODULE,
|
||||
makeFile);
|
||||
frameworkModule.build();
|
||||
cache.put(frameworkModule);
|
||||
}
|
||||
private void buildFrameWorkModule(File frameworkModuleDir) throws IOException {
|
||||
FrameworkModule frameworkModule = new FrameworkModule(frameworkModuleDir);
|
||||
frameworkModule.build();
|
||||
cache.put(frameworkModule);
|
||||
}
|
||||
|
||||
private void createModulesFile(Module module) throws IOException {
|
||||
String modulesContent = Files.toString(
|
||||
new File(DirectorySearch.findTemplateDir(),
|
||||
"idea" + File.separator + MODULES_TEMPLATE_FILE_NAME),
|
||||
CHARSET);
|
||||
private void createModulesFile(File ideaDir, Iterable<Module> modules) throws IOException {
|
||||
String modulesContent = Files.toString(new File(DirectorySearch.findTemplateDir(),
|
||||
"idea" + File.separator + MODULES_TEMPLATE_FILE_NAME), CHARSET);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
File moduleIml = module.getImlFile();
|
||||
sb.append(" <module fileurl=\"file://").append(moduleIml.getAbsolutePath())
|
||||
.append("\" filepath=\"").append(moduleIml.getAbsolutePath()).append("\" />\n");
|
||||
for (String name : module.getAllDependencies()) {
|
||||
Module mod = cache.getAndCache(name);
|
||||
for (Module mod : modules) {
|
||||
File iml = mod.getImlFile();
|
||||
sb.append(" <module fileurl=\"file://").append(iml.getAbsolutePath())
|
||||
.append("\" filepath=\"").append(iml.getAbsolutePath()).append("\" />\n");
|
||||
sb.append(" <module fileurl=\"file://").append(iml.getCanonicalPath()).append(
|
||||
"\" filepath=\"").append(iml.getCanonicalPath()).append("\" />\n");
|
||||
}
|
||||
modulesContent = modulesContent.replace("@MODULES@", sb.toString());
|
||||
|
||||
File out = new File(projectIdeaDir, "modules.xml");
|
||||
logger.info("Creating " + out.getAbsolutePath());
|
||||
File out = new File(ideaDir, "modules.xml");
|
||||
logger.info("Creating " + out.getCanonicalPath());
|
||||
Files.write(modulesContent, out, CHARSET);
|
||||
}
|
||||
|
||||
private void createVcsFile(Module module) throws IOException {
|
||||
String vcsTemplate = Files.toString(
|
||||
new File(DirectorySearch.findTemplateDir(),
|
||||
"idea" + File.separator + VCS_TEMPLATE_FILE_NAME),
|
||||
CHARSET);
|
||||
private void createVcsFile(File ideaDir, Iterable<Module> modules) throws IOException {
|
||||
String vcsTemplate = Files.toString(new File(DirectorySearch.findTemplateDir(),
|
||||
"idea" + File.separator + VCS_TEMPLATE_FILE_NAME), CHARSET);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String name : module.getAllDependencies()) {
|
||||
Module mod = cache.getAndCache(name);
|
||||
for (Module mod : modules) {
|
||||
File dir = mod.getDir();
|
||||
File gitRoot = new File(dir, ".git");
|
||||
if (gitRoot.exists()) {
|
||||
sb.append(" <mapping directory=\"").append(dir.getAbsolutePath())
|
||||
.append("\" vcs=\"Git\" />\n");
|
||||
sb.append(" <mapping directory=\"").append(dir.getCanonicalPath()).append(
|
||||
"\" vcs=\"Git\" />\n");
|
||||
}
|
||||
}
|
||||
vcsTemplate = vcsTemplate.replace("@VCS@", sb.toString());
|
||||
Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), CHARSET);
|
||||
Files.write(vcsTemplate, new File(ideaDir, "vcs.xml"), CHARSET);
|
||||
}
|
||||
|
||||
private void createNameFile(String name) throws IOException {
|
||||
File out = new File(projectIdeaDir, ".name");
|
||||
private void createNameFile(File ideaDir, String name) throws IOException {
|
||||
File out = new File(ideaDir, ".name");
|
||||
Files.write(name, out, CHARSET);
|
||||
}
|
||||
|
||||
private void copyTemplates() throws IOException {
|
||||
private void copyTemplates(File ideaDir) throws IOException {
|
||||
File templateDir = DirectorySearch.findTemplateDir();
|
||||
copyTemplates(new File(templateDir, "idea"), projectIdeaDir);
|
||||
copyTemplates(new File(templateDir, "idea"), ideaDir);
|
||||
}
|
||||
|
||||
private void copyTemplates(File fromDir, File toDir) throws IOException {
|
||||
@@ -191,11 +160,14 @@ public class IntellijProject {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
File destDir = new File(toDir, file.getName());
|
||||
if (!destDir.exists()) {
|
||||
destDir.mkdirs();
|
||||
}
|
||||
copyTemplates(file, destDir);
|
||||
} else {
|
||||
File toFile = new File(toDir, file.getName());
|
||||
logger.info("copying " + file.getAbsolutePath() + " to " +
|
||||
toFile.getAbsolutePath());
|
||||
logger.info("copying " + file.getCanonicalPath() + " to " +
|
||||
toFile.getCanonicalPath());
|
||||
Files.copy(file, toFile);
|
||||
}
|
||||
}
|
||||
@@ -204,10 +176,32 @@ public class IntellijProject {
|
||||
public static void main(String[] args) {
|
||||
logger.info("Args: " + Arrays.toString(args));
|
||||
|
||||
String indexFile = args[0];
|
||||
String module = args[1];
|
||||
if (args.length < 3) {
|
||||
logger.severe("Not enough input arguments. Aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
IntellijProject intellij = new IntellijProject(indexFile, module);
|
||||
boolean buildFramework = true;
|
||||
int argIndex = 0;
|
||||
String arg = args[argIndex];
|
||||
while (arg.startsWith("--")) {
|
||||
if (arg.equals("--no-framework")) {
|
||||
buildFramework = false;
|
||||
}
|
||||
argIndex++;
|
||||
arg = args[argIndex];
|
||||
}
|
||||
|
||||
String indexFile = args[argIndex++];
|
||||
String projectPath = args[argIndex++];
|
||||
// Remaining args are module directories
|
||||
ArrayList<String> moduleDirs = Lists.newArrayList();
|
||||
for (int i = argIndex; i < args.length; i++) {
|
||||
moduleDirs.add(args[i]);
|
||||
}
|
||||
|
||||
IntellijProject intellij = new IntellijProject(indexFile, projectPath, moduleDirs,
|
||||
buildFramework);
|
||||
try {
|
||||
intellij.build();
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.io.LineProcessor;
|
||||
|
||||
@@ -29,7 +30,9 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -41,16 +44,7 @@ public class MakeFileParser {
|
||||
private static final Logger logger = Logger.getLogger(MakeFileParser.class.getName());
|
||||
public static final String VALUE_DELIMITER = "|";
|
||||
|
||||
private enum State {
|
||||
NEW, CONTINUE
|
||||
}
|
||||
private enum ModuleNameKey {
|
||||
LOCAL_PACKAGE_NAME,
|
||||
LOCAL_MODULE
|
||||
};
|
||||
|
||||
private File makeFile;
|
||||
private String moduleName;
|
||||
private HashMap<String, String> values;
|
||||
|
||||
/**
|
||||
@@ -59,11 +53,9 @@ public class MakeFileParser {
|
||||
* A make file may contain multiple modules.
|
||||
*
|
||||
* @param makeFile The make file to parse.
|
||||
* @param moduleName The module to extract.
|
||||
*/
|
||||
public MakeFileParser(File makeFile, String moduleName) {
|
||||
public MakeFileParser(File makeFile) {
|
||||
this.makeFile = Preconditions.checkNotNull(makeFile);
|
||||
this.moduleName = Preconditions.checkNotNull(moduleName);
|
||||
}
|
||||
|
||||
public Iterable<String> getValues(String key) {
|
||||
@@ -71,163 +63,214 @@ public class MakeFileParser {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
return Splitter.on(VALUE_DELIMITER)
|
||||
.trimResults()
|
||||
.omitEmptyStrings()
|
||||
.split(str);
|
||||
return Splitter.on(VALUE_DELIMITER).trimResults().omitEmptyStrings().split(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the relevant portion of the make file and converts into key value pairs.
|
||||
* <p>
|
||||
* Since each make file may contain multiple build targets (modules), this method will determine
|
||||
* which part is the correct portion for the given module name.
|
||||
*
|
||||
* @throws IOException
|
||||
* Extracts the relevant portion of the make file and converts into key value pairs. <p> Since
|
||||
* each make file may contain multiple build targets (modules), this method will determine which
|
||||
* part is the correct portion for the given module name.
|
||||
*/
|
||||
public void parse() throws IOException {
|
||||
values = Maps.newHashMap();
|
||||
logger.info("Parsing " + makeFile.getAbsolutePath() + " for module " + moduleName);
|
||||
logger.info("Parsing " + makeFile.getCanonicalPath());
|
||||
|
||||
Files.readLines(makeFile, Charset.forName("UTF-8"), new LineProcessor<Object>() {
|
||||
|
||||
private String key;
|
||||
|
||||
private State state = State.NEW;
|
||||
|
||||
@Override
|
||||
public boolean processLine(String line) throws IOException {
|
||||
String trimmed = line.trim();
|
||||
if (Strings.isNullOrEmpty(trimmed)) {
|
||||
state = State.NEW;
|
||||
return true;
|
||||
}
|
||||
if (trimmed.equals("include $(CLEAR_VARS)")) {
|
||||
// See if we are in the right module.
|
||||
if (moduleName.equals(getModuleName())) {
|
||||
return false;
|
||||
} else {
|
||||
values.clear();
|
||||
}
|
||||
} else {
|
||||
switch (state) {
|
||||
case NEW:
|
||||
trimmed = checkContinue(trimmed);
|
||||
if (trimmed.contains("=")) {
|
||||
String[] arr;
|
||||
if (trimmed.contains(":")) {
|
||||
arr = trimmed.split(":=");
|
||||
} else {
|
||||
arr = trimmed.split("\\+=");
|
||||
}
|
||||
if (arr.length > 2) {
|
||||
logger.info("Malformed line " + line);
|
||||
} else {
|
||||
// Store the key in case the line continues
|
||||
this.key = arr[0].trim();
|
||||
if (arr.length == 2) {
|
||||
// There may be multiple values on one line.
|
||||
List<String> valuesArr = tokenizeValue(arr[1].trim());
|
||||
for (String value : valuesArr) {
|
||||
appendValue(this.key, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//logger.info("Skipping line " + line);
|
||||
}
|
||||
break;
|
||||
case CONTINUE:
|
||||
// append
|
||||
trimmed = checkContinue(trimmed);
|
||||
appendValue(key, trimmed);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<String> tokenizeValue(String value) {
|
||||
// Value may contain function calls such as "$(call all-java-files-under)".
|
||||
// Tokens are separated by spaces unless it's between parens.
|
||||
StringBuilder token = new StringBuilder();
|
||||
ArrayList<String> tokens = Lists.newArrayList();
|
||||
int parenCount = 0;
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (parenCount == 0 && ch == ' ') {
|
||||
// Not in a paren and delimiter encountered.
|
||||
// end token
|
||||
if (token.length() > 0) {
|
||||
tokens.add(token.toString());
|
||||
token = new StringBuilder();
|
||||
}
|
||||
} else {
|
||||
token.append(ch);
|
||||
}
|
||||
if (ch == '(') {
|
||||
parenCount++;
|
||||
} else if (ch == ')') {
|
||||
parenCount--;
|
||||
}
|
||||
}
|
||||
// end of line check
|
||||
if (token.length() > 0) {
|
||||
tokens.add(token.toString());
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private String getModuleName() {
|
||||
for (ModuleNameKey key : ModuleNameKey.values()) {
|
||||
String name = values.get(key.name());
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String checkContinue(String value) {
|
||||
// Check for continuation character
|
||||
if (value.charAt(value.length() - 1) == '\\') {
|
||||
state = State.CONTINUE;
|
||||
return value.substring(0, value.length() - 1);
|
||||
}
|
||||
state = State.NEW;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to the hash map. If the key already exists, will append instead of
|
||||
* over-writing the existing value.
|
||||
*
|
||||
* @param key The hashmap key
|
||||
* @param newValue The value to append.
|
||||
*/
|
||||
private void appendValue(String key, String newValue) {
|
||||
String value = values.get(key);
|
||||
if (value == null) {
|
||||
values.put(key, newValue);
|
||||
} else {
|
||||
values.put(key, value + VALUE_DELIMITER + newValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
Files.readLines(makeFile, Charset.forName("UTF-8"), new MakeFileLineProcessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("values", values)
|
||||
.toString();
|
||||
return Objects.toStringHelper(this).add("values", values).toString();
|
||||
}
|
||||
|
||||
private class MakeFileLineProcessor implements LineProcessor<Object> {
|
||||
|
||||
private StringBuilder lineBuffer;
|
||||
|
||||
// Keep a list of LOCAL_ variables to clear when CLEAR_VARS is encountered.
|
||||
private HashSet<String> localVars = Sets.newHashSet();
|
||||
|
||||
@Override
|
||||
public boolean processLine(String line) throws IOException {
|
||||
String trimmed = line.trim();
|
||||
// Skip comments.
|
||||
if (!trimmed.isEmpty() && trimmed.charAt(0) == '#') {
|
||||
return true;
|
||||
}
|
||||
appendPartialLine(trimmed);
|
||||
|
||||
if (!trimmed.isEmpty() && trimmed.charAt(trimmed.length() - 1) == '\\') {
|
||||
// This is a partial line. Do not process yet.
|
||||
return true;
|
||||
}
|
||||
|
||||
String completeLine = lineBuffer.toString().trim();
|
||||
// Reset the line buffer.
|
||||
lineBuffer = null;
|
||||
|
||||
if (Strings.isNullOrEmpty(completeLine)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
processKeyValuePairs(completeLine);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void processKeyValuePairs(String line) {
|
||||
if (line.contains("=")) {
|
||||
String[] arr;
|
||||
if (line.contains(":")) {
|
||||
arr = line.split(":=");
|
||||
} else {
|
||||
arr = line.split("\\+=");
|
||||
}
|
||||
if (arr.length > 2) {
|
||||
logger.info("Malformed line " + line);
|
||||
} else {
|
||||
// Store the key in case the line continues
|
||||
String key = arr[0].trim();
|
||||
if (arr.length == 2) {
|
||||
// There may be multiple values on one line.
|
||||
List<String> valuesArr = tokenizeValue(arr[1]);
|
||||
for (String value : valuesArr) {
|
||||
appendValue(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//logger.info("Skipping line " + line);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendPartialLine(String line) {
|
||||
if (lineBuffer == null) {
|
||||
lineBuffer = new StringBuilder();
|
||||
} else {
|
||||
lineBuffer.append(" ");
|
||||
}
|
||||
if (line.endsWith("\\")) {
|
||||
lineBuffer.append(line.substring(0, line.length() - 2).trim());
|
||||
} else {
|
||||
lineBuffer.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> tokenizeValue(String rawValue) {
|
||||
String value = rawValue.trim();
|
||||
ArrayList<String> result = Lists.newArrayList();
|
||||
if (value.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Value may contain function calls such as "$(call all-java-files-under)" or refer
|
||||
// to variables such as "$(my_var)"
|
||||
value = findVariables(value);
|
||||
|
||||
String[] tokens = value.split(" ");
|
||||
Collections.addAll(result, tokens);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String findVariables(String value) {
|
||||
|
||||
int variableStart = value.indexOf('$');
|
||||
// Keep going until we substituted all variables.
|
||||
while (variableStart > -1) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(value.substring(0, variableStart));
|
||||
|
||||
// variable found
|
||||
int variableEnd = findClosingParen(value, variableStart);
|
||||
if (variableEnd > variableStart) {
|
||||
String result = substituteVariables(value.substring(variableStart + 2, variableEnd));
|
||||
sb.append(result);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Malformed variable reference in make file: " + value);
|
||||
}
|
||||
if (variableEnd + 1 < value.length()) {
|
||||
sb.append(value.substring(variableEnd + 1));
|
||||
}
|
||||
value = sb.toString();
|
||||
variableStart = value.indexOf('$');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private int findClosingParen(String value, int startIndex) {
|
||||
int openParenCount = 0;
|
||||
for (int i = startIndex; i < value.length(); i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == ')') {
|
||||
openParenCount--;
|
||||
if (openParenCount == 0) {
|
||||
return i;
|
||||
}
|
||||
} else if (ch == '(') {
|
||||
openParenCount++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for and handle $(...) variables.
|
||||
*/
|
||||
private String substituteVariables(String rawValue) {
|
||||
if (rawValue.isEmpty()) {
|
||||
return rawValue;
|
||||
}
|
||||
String value = rawValue;
|
||||
if (value.startsWith("call all-java-files-under")) {
|
||||
// Ignore the call and function, keep the args.
|
||||
value = value.substring(25).trim();
|
||||
} else if (value.startsWith("call")) {
|
||||
value = value.substring(4).trim();
|
||||
}
|
||||
|
||||
// Check for single variable
|
||||
if (value.indexOf(' ') == -1) {
|
||||
// Substitute.
|
||||
value = values.get(value);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
return value;
|
||||
} else {
|
||||
return findVariables(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to the hash map. If the key already exists, will append instead of
|
||||
* over-writing the existing value.
|
||||
*
|
||||
* @param key The hashmap key
|
||||
* @param newValue The value to append.
|
||||
*/
|
||||
private void appendValue(String key, String newValue) {
|
||||
String value = values.get(key);
|
||||
if (value == null) {
|
||||
values.put(key, newValue);
|
||||
} else {
|
||||
values.put(key, value + VALUE_DELIMITER + newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
MakeFileParser parser = new MakeFileParser(new File(args[0]));
|
||||
try {
|
||||
parser.parse();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println(parser.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,24 +17,44 @@
|
||||
package com.android.idegen;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Super class for all modules.
|
||||
* Module constructed from a make file.
|
||||
*
|
||||
* TODO: read the make file and understand included source dirs in addition to searching
|
||||
* sub-directories. Make files can include sources that are not sub-directories. For example, the
|
||||
* framework module includes sources from:
|
||||
*
|
||||
* external/libphonenumber/java/src
|
||||
*
|
||||
* to provide:
|
||||
*
|
||||
* com.android.i18n.phonenumbers.PhoneNumberUtil;
|
||||
*/
|
||||
public abstract class Module {
|
||||
public class Module {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Module.class.getName());
|
||||
|
||||
public static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
|
||||
|
||||
private static final String IML_TEMPLATE_FILE_NAME = "module-template.iml";
|
||||
private static final String[] AUTO_DEPENDENCIES = new String[]{"framework", "libcore"};
|
||||
private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{"packages", "vendor",
|
||||
"frameworks/ex", "frameworks/opt", "frameworks/support"};
|
||||
|
||||
/**
|
||||
* All possible attributes for the make file.
|
||||
@@ -45,31 +65,155 @@ public abstract class Module {
|
||||
LOCAL_SRC_FILES
|
||||
}
|
||||
|
||||
ModuleCache moduleCache = ModuleCache.getInstance();
|
||||
private ModuleCache moduleCache = ModuleCache.getInstance();
|
||||
|
||||
private File imlFile;
|
||||
|
||||
private Set<String> allDependencies = Sets.newHashSet(); // direct + indirect
|
||||
|
||||
private Set<File> allDependentImlFiles = Sets.newHashSet();
|
||||
|
||||
protected abstract void build() throws IOException;
|
||||
private File makeFile;
|
||||
private File moduleRoot;
|
||||
private HashSet<File> sourceFiles = Sets.newHashSet();
|
||||
|
||||
protected abstract String getName();
|
||||
// Module dependencies come from LOCAL_STATIC_JAVA_LIBRARIES or LOCAL_JAVA_LIBRARIES
|
||||
Set<String> explicitModuleNameDependencies = Sets.newHashSet();
|
||||
// Implicit module dependencies come from src files that fall outside the module root directory.
|
||||
// For example, if packages/apps/Contacts includes src files from packages/apps/ContactsCommon,
|
||||
// that is an implicit module dependency. It's not a module dependency from the build
|
||||
// perspective but it needs to be a separate module in intellij so that the src files can be
|
||||
// shared by multiple intellij modules.
|
||||
Set<File> implicitModulePathDependencies = Sets.newHashSet();
|
||||
|
||||
protected abstract File getDir();
|
||||
String relativeIntermediatesDir;
|
||||
MakeFileParser makeFileParser;
|
||||
boolean parseMakeFileForSource;
|
||||
|
||||
protected abstract boolean isAndroidModule();
|
||||
public Module(File moduleDir) throws IOException {
|
||||
this(moduleDir, true);
|
||||
}
|
||||
|
||||
protected abstract List<File> getIntermediatesDirs();
|
||||
public Module(File moduleDir, boolean parseMakeFileForSource) throws IOException {
|
||||
this.moduleRoot = Preconditions.checkNotNull(moduleDir);
|
||||
this.makeFile = new File(moduleDir, "Android.mk");
|
||||
this.relativeIntermediatesDir = calculateRelativePartToRepoRoot() + REL_OUT_APP_DIR +
|
||||
File.separatorChar + getName() + "_intermediates" + File.separator + "src";
|
||||
this.parseMakeFileForSource = parseMakeFileForSource;
|
||||
|
||||
public abstract Set<String> getDirectDependencies();
|
||||
// TODO: auto-detect when framework dependency is needed instead of using coded list.
|
||||
for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
|
||||
// length + 2 to account for slash
|
||||
boolean isDir = makeFile.getCanonicalPath().startsWith(
|
||||
DirectorySearch.getRepoRoot() + "/" + dir);
|
||||
if (isDir) {
|
||||
Collections.addAll(this.explicitModuleNameDependencies, AUTO_DEPENDENCIES);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ImmutableList<File> getSourceDirs();
|
||||
makeFileParser = new MakeFileParser(makeFile);
|
||||
}
|
||||
|
||||
protected abstract ImmutableList<File> getExcludeDirs();
|
||||
private String calculateRelativePartToRepoRoot() throws IOException {
|
||||
String rel = moduleRoot.getCanonicalPath().substring(
|
||||
DirectorySearch.getRepoRoot().getCanonicalPath().length());
|
||||
int count = 0;
|
||||
// Count the number of slashes to determine how far back to go.
|
||||
for (int i = 0; i < rel.length(); i++) {
|
||||
if (rel.charAt(i) == '/') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append("../");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public abstract File getRepoRoot();
|
||||
public void build() throws IOException {
|
||||
makeFileParser.parse();
|
||||
buildDependencyList();
|
||||
buildDependentModules();
|
||||
logger.info("Done building module " + moduleRoot);
|
||||
logger.info(toString());
|
||||
}
|
||||
|
||||
public File getDir() {
|
||||
return moduleRoot;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return moduleRoot.getName();
|
||||
}
|
||||
|
||||
private List<String> getRelativeIntermediatesDirs() throws IOException {
|
||||
return Lists.newArrayList(relativeIntermediatesDir);
|
||||
}
|
||||
|
||||
private ImmutableList<File> getSourceDirs() {
|
||||
return ImmutableList.copyOf(sourceFiles);
|
||||
}
|
||||
|
||||
private ImmutableList<File> getExcludeDirs() {
|
||||
return DirectorySearch.findExcludeDirs(makeFile);
|
||||
}
|
||||
|
||||
private boolean isAndroidModule() {
|
||||
File manifest = new File(moduleRoot, "AndroidManifest.xml");
|
||||
return manifest.exists();
|
||||
}
|
||||
|
||||
private void findSourceFilesAndImplicitDependencies() throws IOException {
|
||||
Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
File src = new File(moduleRoot, value);
|
||||
|
||||
// value may contain garbage at this point due to relaxed make file parsing.
|
||||
// filter by existing file.
|
||||
if (src.exists()) {
|
||||
// Look for directories outside the current module directory.
|
||||
if (value.contains("..")) {
|
||||
// Find the closest Android make file.
|
||||
File moduleRoot = DirectorySearch.findModuleRoot(src);
|
||||
implicitModulePathDependencies.add(moduleRoot);
|
||||
} else {
|
||||
if (parseMakeFileForSource) {
|
||||
// Check if source files are subdirectories of generic parent src
|
||||
// directories. If so, no need to add since they are already included.
|
||||
boolean alreadyIncluded = false;
|
||||
for (String parentDir : DirectorySearch.SOURCE_DIRS) {
|
||||
if (value.startsWith(parentDir)) {
|
||||
alreadyIncluded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyIncluded) {
|
||||
sourceFiles.add(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceFiles.addAll(DirectorySearch.findSourceDirs(moduleRoot));
|
||||
}
|
||||
|
||||
private void buildDependencyList() throws IOException {
|
||||
parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
|
||||
parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
|
||||
findSourceFilesAndImplicitDependencies();
|
||||
}
|
||||
|
||||
private void parseDirectDependencies(Key key) {
|
||||
Iterable<String> names = makeFileParser.getValues(key.name());
|
||||
if (names != null) {
|
||||
for (String dependency : names) {
|
||||
explicitModuleNameDependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void buildImlFile() throws IOException {
|
||||
String imlTemplate = Files.toString(
|
||||
@@ -82,19 +226,24 @@ public abstract class Module {
|
||||
}
|
||||
imlTemplate = imlTemplate.replace("@FACETS@", facetXml);
|
||||
|
||||
String moduleDir = getDir().getAbsolutePath();
|
||||
String moduleDir = getDir().getCanonicalPath();
|
||||
|
||||
StringBuilder sourceDirectories = new StringBuilder();
|
||||
sourceDirectories.append(" <content url=\"file://$MODULE_DIR$\">\n");
|
||||
ImmutableList<File> srcDirs = getSourceDirs();
|
||||
for (File src : srcDirs) {
|
||||
String relative = src.getAbsolutePath().substring(moduleDir.length());
|
||||
String relative = src.getCanonicalPath().substring(moduleDir.length());
|
||||
boolean isTestSource = false;
|
||||
if (relative.startsWith("/test")) {
|
||||
isTestSource = true;
|
||||
}
|
||||
sourceDirectories.append(" <sourceFolder url=\"file://$MODULE_DIR$")
|
||||
.append(relative).append("\" isTestSource=\"false\" />\n");
|
||||
.append(relative).append("\" isTestSource=\"").append(isTestSource)
|
||||
.append("\" />\n");
|
||||
}
|
||||
ImmutableList<File> excludeDirs = getExcludeDirs();
|
||||
for (File src : excludeDirs) {
|
||||
String relative = src.getAbsolutePath().substring(moduleDir.length());
|
||||
String relative = src.getCanonicalPath().substring(moduleDir.length());
|
||||
sourceDirectories.append(" <excludeFolder url=\"file://$MODULE_DIR$")
|
||||
.append(relative).append("\"/>\n");
|
||||
}
|
||||
@@ -106,43 +255,62 @@ public abstract class Module {
|
||||
imlTemplate = imlTemplate.replace("@SOURCES@", sourceDirectories.toString());
|
||||
|
||||
StringBuilder moduleDependencies = new StringBuilder();
|
||||
for (String dependency : getDirectDependencies()) {
|
||||
for (String dependency : getAllDependencies()) {
|
||||
Module module = moduleCache.getAndCacheByDir(new File(dependency));
|
||||
moduleDependencies.append(" <orderEntry type=\"module\" module-name=\"")
|
||||
.append(dependency).append("\" />\n");
|
||||
.append(module.getName()).append("\" />\n");
|
||||
}
|
||||
imlTemplate = imlTemplate.replace("@MODULE_DEPENDENCIES@", moduleDependencies.toString());
|
||||
|
||||
imlFile = new File(moduleDir, getName() + ".iml");
|
||||
logger.info("Creating " + imlFile.getAbsolutePath());
|
||||
logger.info("Creating " + imlFile.getCanonicalPath());
|
||||
Files.write(imlTemplate, imlFile, IntellijProject.CHARSET);
|
||||
}
|
||||
|
||||
protected String buildIntermediates() {
|
||||
protected String buildIntermediates() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (File intermediatesDir : getIntermediatesDirs()) {
|
||||
sb.append(" <content url=\"file://").append(intermediatesDir).append("\">\n");
|
||||
sb.append(" <sourceFolder url=\"file://")
|
||||
.append(intermediatesDir.getAbsolutePath())
|
||||
for (String intermediatesDir : getRelativeIntermediatesDirs()) {
|
||||
sb.append(" <content url=\"file://$MODULE_DIR$/").append(intermediatesDir)
|
||||
.append("\">\n");
|
||||
sb.append(" <sourceFolder url=\"file://$MODULE_DIR$/")
|
||||
.append(intermediatesDir)
|
||||
.append("\" isTestSource=\"false\" />\n");
|
||||
sb.append(" </content>\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected void buildDependentModules() throws IOException {
|
||||
Set<String> directDependencies = getDirectDependencies();
|
||||
String[] copy = directDependencies.toArray(new String[directDependencies.size()]);
|
||||
for (String dependency : copy) {
|
||||
private void buildDependentModules() throws IOException {
|
||||
Set<String> moduleNameDependencies = explicitModuleNameDependencies;
|
||||
|
||||
Module child = moduleCache.getAndCache(dependency);
|
||||
String[] copy = moduleNameDependencies.toArray(new String[moduleNameDependencies.size()]);
|
||||
for (String dependency : copy) {
|
||||
logger.info("Building dependency " + dependency);
|
||||
Module child = moduleCache.getAndCacheByName(dependency);
|
||||
if (child == null) {
|
||||
directDependencies.remove(dependency);
|
||||
moduleNameDependencies.remove(dependency);
|
||||
} else {
|
||||
addAllDependencies(dependency);
|
||||
addAllDependencies(child.getAllDependencies());
|
||||
allDependencies.add(child.getDir().getCanonicalPath());
|
||||
//allDependencies.addAll(child.getAllDependencies());
|
||||
//logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
|
||||
allDependentImlFiles.add(child.getImlFile());
|
||||
allDependentImlFiles.addAll(child.getAllDependentImlFiles());
|
||||
//allDependentImlFiles.addAll(child.getAllDependentImlFiles());
|
||||
}
|
||||
}
|
||||
// Don't include self. The current module may have been brought in by framework
|
||||
// dependencies which will create a circular reference.
|
||||
allDependencies.remove(this.getDir().getCanonicalPath());
|
||||
allDependentImlFiles.remove(this.getImlFile());
|
||||
|
||||
// TODO: add implicit dependencies. Convert all modules to be based on directory.
|
||||
for (File dependency : implicitModulePathDependencies) {
|
||||
Module child = moduleCache.getAndCacheByDir(dependency);
|
||||
if (child != null) {
|
||||
allDependencies.add(child.getDir().getCanonicalPath());
|
||||
//allDependencies.addAll(child.getAllDependencies());
|
||||
//logger.info("Adding iml " + child.getName() + " " + child.getImlFile());
|
||||
allDependentImlFiles.add(child.getImlFile());
|
||||
//allDependentImlFiles.addAll(child.getAllDependentImlFiles());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,29 +323,22 @@ public abstract class Module {
|
||||
return allDependencies;
|
||||
}
|
||||
|
||||
public void addAllDependencies(String dependency) {
|
||||
this.allDependencies.add(dependency);
|
||||
}
|
||||
|
||||
public void addAllDependencies(Set<String> dependencies) {
|
||||
this.allDependencies.addAll(dependencies);
|
||||
}
|
||||
|
||||
public Set<File> getAllDependentImlFiles() {
|
||||
return allDependentImlFiles;
|
||||
}
|
||||
|
||||
private String buildAndroidFacet() {
|
||||
private String buildAndroidFacet() throws IOException {
|
||||
// Not sure how to handle android facet for multi-module since there could be more than
|
||||
// one intermediates directory.
|
||||
String dir = getIntermediatesDirs().get(0).getAbsolutePath();
|
||||
String dir = getRelativeIntermediatesDirs().get(0);
|
||||
String xml = ""
|
||||
+ " <component name=\"FacetManager\">\n"
|
||||
+ " <facet type=\"android\" name=\"Android\">\n"
|
||||
+ " <configuration>\n"
|
||||
+ " <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" + dir + "\" />\n"
|
||||
+ " <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" + dir
|
||||
+ "\" />\n"
|
||||
+ " <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"" +
|
||||
dir + "\" />\n"
|
||||
+ " <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"" +
|
||||
dir + "\" />\n"
|
||||
+ " <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\""
|
||||
+ "/AndroidManifest.xml\" />\n"
|
||||
+ " <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/res\" />\n"
|
||||
@@ -199,13 +360,34 @@ public abstract class Module {
|
||||
return xml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Module other = (Module) obj;
|
||||
return Objects.equal(getName(), other.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(Module.class)
|
||||
return Objects.toStringHelper(this)
|
||||
.add("name", getName())
|
||||
.add("allDependencies", allDependencies)
|
||||
.add("iml files", allDependentImlFiles)
|
||||
.add("imlFile", imlFile)
|
||||
.add("iml files", allDependentImlFiles).add("imlFile", imlFile)
|
||||
.add("makeFileParser", makeFileParser)
|
||||
.add("explicitModuleNameDependencies", Iterables.toString(
|
||||
explicitModuleNameDependencies))
|
||||
.add("implicitModulePathDependencies", Iterables.toString(
|
||||
implicitModulePathDependencies))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,10 @@ package com.android.idegen;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
@@ -37,7 +35,9 @@ public class ModuleCache {
|
||||
|
||||
ModuleIndexes indexes;
|
||||
|
||||
HashMap<String, Module> modulesByName = Maps.newHashMap();
|
||||
// Mapping of canonical module directory to module. Use string instead of File since File
|
||||
// does not provide equality based on canonical path.
|
||||
HashMap<String, Module> modulesByPath = Maps.newHashMap();
|
||||
|
||||
private ModuleCache() {
|
||||
}
|
||||
@@ -51,57 +51,48 @@ public class ModuleCache {
|
||||
indexes.build();
|
||||
}
|
||||
|
||||
public Module getAndCache(String moduleName) throws IOException {
|
||||
Preconditions.checkState(indexes != null, "You must call init() first.");
|
||||
public Module getAndCacheByDir(File moduleDir) throws IOException {
|
||||
Preconditions.checkNotNull(moduleDir);
|
||||
|
||||
Module module = modulesByName.get(moduleName);
|
||||
if (module == null) {
|
||||
String makeFile = indexes.getMakeFile(moduleName);
|
||||
if (makeFile == null) {
|
||||
logger.warning("Unable to find make file for module: " + moduleName);
|
||||
} else {
|
||||
module = new StandardModule(moduleName, makeFile);
|
||||
if (moduleDir.exists()) {
|
||||
Module module = getModule(moduleDir);
|
||||
if (module == null) {
|
||||
module = new Module(moduleDir);
|
||||
// Must put module before building it. Otherwise infinite loop.
|
||||
putModule(moduleDir, module);
|
||||
module.build();
|
||||
modulesByName.put(moduleName, module);
|
||||
}
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
public void buildAndCacheAggregatedModule(String moduleName) throws IOException {
|
||||
if (indexes.isPartOfAggregatedModule(moduleName)) {
|
||||
Set<String> moduleNames = indexes.getAggregatedModules(moduleName);
|
||||
Set<Module> modules = Sets.newHashSet();
|
||||
for (String name : moduleNames) {
|
||||
Module m = modulesByName.get(name);
|
||||
if (m != null) {
|
||||
modules.add(m);
|
||||
}
|
||||
}
|
||||
String aggregatedName = indexes.getAggregateName(moduleName);
|
||||
AggregatedModule module = new AggregatedModule(aggregatedName, modules);
|
||||
module.build();
|
||||
modulesByName.put(aggregatedName, module);
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<Module> getModules() {
|
||||
return modulesByName.values();
|
||||
}
|
||||
|
||||
public String getMakeFile(String moduleName) {
|
||||
return indexes.getMakeFile(moduleName);
|
||||
}
|
||||
|
||||
public void put(StandardModule module) {
|
||||
Preconditions.checkNotNull(module);
|
||||
modulesByName.put(module.getName(), module);
|
||||
}
|
||||
|
||||
public String getAggregateReplacementName(String moduleName) {
|
||||
if (indexes.isPartOfAggregatedModule(moduleName)) {
|
||||
return indexes.getAggregateName(moduleName);
|
||||
return module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Module getAndCacheByName(String moduleName) throws IOException {
|
||||
Preconditions.checkState(indexes != null, "You must call init() first.");
|
||||
Preconditions.checkNotNull(moduleName);
|
||||
|
||||
String makeFile = indexes.getMakeFile(moduleName);
|
||||
if (makeFile == null) {
|
||||
logger.warning("Unable to find make file for module: " + moduleName);
|
||||
return null;
|
||||
}
|
||||
return getAndCacheByDir(new File(makeFile).getParentFile());
|
||||
}
|
||||
|
||||
private void putModule(File moduleDir, Module module) throws IOException {
|
||||
modulesByPath.put(moduleDir.getCanonicalPath(), module);
|
||||
}
|
||||
|
||||
private Module getModule(File moduleDir) throws IOException {
|
||||
return modulesByPath.get(moduleDir.getCanonicalPath());
|
||||
}
|
||||
|
||||
public Iterable<Module> getModules() {
|
||||
return modulesByPath.values();
|
||||
}
|
||||
|
||||
public void put(Module module) throws IOException {
|
||||
Preconditions.checkNotNull(module);
|
||||
putModule(module.getDir(), module);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class ModuleIndexes {
|
||||
|
||||
moduleNameToMakeFileMap = Maps.newHashMap();
|
||||
makeFileToModuleNamesMap = Maps.newHashMap();
|
||||
logger.info("Building index from " + indexFile.getAbsolutePath());
|
||||
logger.info("Building index from " + indexFile.getCanonicalPath());
|
||||
Files.readLines(indexFile, Charset.forName("UTF-8"),
|
||||
new LineProcessor<Object>() {
|
||||
int count = 0;
|
||||
@@ -84,7 +84,7 @@ public class ModuleIndexes {
|
||||
makeFileToModuleNamesMap.put(makeFile, moduleNames);
|
||||
} else {
|
||||
// Create a aggregate module place holder.
|
||||
//moduleNameToMakeFileMap.put(getAggregateName(moduleName), makeFile);
|
||||
//moduleNameToMakeFileMap.put(getAggregateName(moduleDir), makeFile);
|
||||
}
|
||||
moduleNames.add(moduleName);
|
||||
}
|
||||
@@ -92,31 +92,7 @@ public class ModuleIndexes {
|
||||
public String getMakeFile(String moduleName) {
|
||||
Preconditions.checkState(moduleNameToMakeFileMap != null,
|
||||
"Index not built. Call build() first.");
|
||||
|
||||
return moduleNameToMakeFileMap.get(moduleName);
|
||||
}
|
||||
|
||||
public Set<String> getAggregatedModules(String moduleName) {
|
||||
Preconditions.checkState(makeFileToModuleNamesMap != null,
|
||||
"Index not built. Call build() first.");
|
||||
String makeFile = getMakeFile(moduleName);
|
||||
return makeFileToModuleNamesMap.get(makeFile);
|
||||
}
|
||||
|
||||
public boolean isPartOfAggregatedModule(String moduleName) {
|
||||
String makeFile = getMakeFile(moduleName);
|
||||
if (makeFile == null) {
|
||||
return false;
|
||||
}
|
||||
Set<String> moduleNames = makeFileToModuleNamesMap.get(makeFile);
|
||||
if (moduleNames == null) {
|
||||
return false;
|
||||
}
|
||||
return moduleNames.size() > 1;
|
||||
}
|
||||
|
||||
public String getAggregateName(String moduleName) {
|
||||
String fileName = getMakeFile(moduleName);
|
||||
File file = new File(fileName);
|
||||
return file.getParentFile().getName() + "-aggregate";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* 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.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Module constructed from a make file.
|
||||
*
|
||||
* TODO: read the make file and understand included source dirs in addition to searching
|
||||
* sub-directories. Make files can include sources that are not sub-directories. For example,
|
||||
* the framework module includes sources from:
|
||||
*
|
||||
* external/libphonenumber/java/src
|
||||
*
|
||||
* to provide:
|
||||
*
|
||||
* com.android.i18n.phonenumbers.PhoneNumberUtil;
|
||||
*/
|
||||
public class StandardModule extends Module {
|
||||
|
||||
static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(StandardModule.class.getName());
|
||||
|
||||
private static final Pattern SRC_PATTERN = Pattern.compile(
|
||||
".*\\(call all-java-files-under, (.*)\\)");
|
||||
private static final String[] AUTO_DEPENDENCIES = new String[]{
|
||||
IntellijProject.FRAMEWORK_MODULE, "libcore"
|
||||
};
|
||||
private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{
|
||||
"packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
|
||||
};
|
||||
|
||||
String moduleName;
|
||||
File makeFile;
|
||||
File moduleRoot;
|
||||
File repoRoot;
|
||||
|
||||
Set<String> directDependencies = Sets.newHashSet();
|
||||
|
||||
File intermediatesDir;
|
||||
MakeFileParser makeFileParser;
|
||||
boolean searchForSrc;
|
||||
|
||||
public StandardModule(String moduleName, String makeFile) {
|
||||
this(moduleName, new File(makeFile), false);
|
||||
}
|
||||
|
||||
public StandardModule(String moduleName, String makeFile, boolean searchForSrc) {
|
||||
this(Preconditions.checkNotNull(moduleName), new File(Preconditions.checkNotNull(makeFile)),
|
||||
searchForSrc);
|
||||
}
|
||||
|
||||
public StandardModule(String moduleName, File makeFile, boolean searchForSrc) {
|
||||
this.moduleName = moduleName;
|
||||
this.makeFile = makeFile;
|
||||
this.moduleRoot = makeFile.getParentFile();
|
||||
this.repoRoot = DirectorySearch.findRepoRoot(makeFile);
|
||||
this.intermediatesDir = new File(repoRoot.getAbsolutePath() + File.separator +
|
||||
REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
|
||||
File.separator + "src");
|
||||
this.searchForSrc = searchForSrc;
|
||||
|
||||
// TODO: auto-detect when framework dependency is needed instead of using coded list.
|
||||
for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
|
||||
// length + 2 to account for slash
|
||||
boolean isDir = makeFile.getAbsolutePath().startsWith(repoRoot + "/" + dir);
|
||||
if (isDir) {
|
||||
for (String dependency : AUTO_DEPENDENCIES) {
|
||||
this.directDependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeFileParser = new MakeFileParser(makeFile, moduleName);
|
||||
}
|
||||
|
||||
protected void build() throws IOException {
|
||||
makeFileParser.parse();
|
||||
buildDependencyList();
|
||||
buildDependentModules();
|
||||
//buildImlFile();
|
||||
logger.info("Done building module " + moduleName);
|
||||
logger.info(toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getDir() {
|
||||
return moduleRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<File> getIntermediatesDirs() {
|
||||
return Lists.newArrayList(intermediatesDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getRepoRoot() {
|
||||
return this.repoRoot;
|
||||
}
|
||||
|
||||
public Set<String> getDirectDependencies() {
|
||||
return this.directDependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImmutableList<File> getSourceDirs() {
|
||||
ImmutableList<File> srcDirs;
|
||||
if (searchForSrc) {
|
||||
srcDirs = DirectorySearch.findSourceDirs(makeFile);
|
||||
} else {
|
||||
srcDirs = parseSourceFiles(makeFile);
|
||||
}
|
||||
return srcDirs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImmutableList<File> getExcludeDirs() {
|
||||
return DirectorySearch.findExcludeDirs(makeFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAndroidModule() {
|
||||
File manifest = new File(moduleRoot, "AndroidManifest.xml");
|
||||
return manifest.exists();
|
||||
}
|
||||
|
||||
private ImmutableList<File> parseSourceFiles(File root) {
|
||||
ImmutableList.Builder<File> builder = ImmutableList.builder();
|
||||
File rootDir;
|
||||
if (root.isFile()) {
|
||||
rootDir = root.getParentFile();
|
||||
} else {
|
||||
rootDir = root;
|
||||
}
|
||||
|
||||
Iterable<String> values = makeFileParser.getValues(Key.LOCAL_SRC_FILES.name());
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
Matcher matcher = SRC_PATTERN.matcher(value);
|
||||
if (matcher.matches()) {
|
||||
String dir = matcher.group(1);
|
||||
builder.add(new File(rootDir, dir));
|
||||
} else if (value.contains("/")) {
|
||||
// Treat as individual file.
|
||||
builder.add(new File(rootDir, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void buildDependencyList() {
|
||||
parseDirectDependencies(Key.LOCAL_STATIC_JAVA_LIBRARIES);
|
||||
parseDirectDependencies(Key.LOCAL_JAVA_LIBRARIES);
|
||||
}
|
||||
|
||||
private void parseDirectDependencies(Key key) {
|
||||
Iterable<String> names = makeFileParser.getValues(key.name());
|
||||
if (names != null) {
|
||||
for (String dependency : names) {
|
||||
directDependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
StandardModule other = (StandardModule) obj;
|
||||
return Objects.equal(getName(), other.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("super", super.toString())
|
||||
.add("makeFileParser", makeFileParser)
|
||||
.add("directDependencies", Iterables.toString(directDependencies))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user