diff options
author | Xavier Ducrohet <xav@android.com> | 2012-05-10 16:58:03 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2012-05-16 18:19:56 -0700 |
commit | c5578db599c6a1f36369f79411e7dafa030f9f56 (patch) | |
tree | bc2ccca5a919fd4226d7860248c08a462cdc9b92 | |
parent | 71cc6480236e5a6650b7390dbd3fd3ecad3878f0 (diff) | |
download | sdk-c5578db599c6a1f36369f79411e7dafa030f9f56.zip sdk-c5578db599c6a1f36369f79411e7dafa030f9f56.tar.gz sdk-c5578db599c6a1f36369f79411e7dafa030f9f56.tar.bz2 |
Replace current complex delta visitor by pattern based ones.
The build system relies on several different delta visitor that
detect file changes to detect that needs to be rebuilt but the
implementation of those files is based on going through
folders recursively while keeping states. This is complex
and prone to errors.
The new mechanism is simply based on glob-pattern, relative
to the project root.
A set of predefined patterns stored in ChangedFileSet instance
allow quick reuse.
ChangeFileSetHelper stores those as well as allow creating
others that are based on a project config (such as the output
folder).
This first CL replace the previous delta visitors in the
PostCompilerBuilder. Replacing the ones in the PreCompilerBuilder
will require a bit more work so I prefer splitting it in another
CL.
The code that runs the pattern recognition is coming from
Ant and is stored in external/ant-glob. This is not all of Ant
but a subset of the classes for our need.
This CL does include a simple set of tests for the extracted
Ant classes.
Change-Id: I2ad1b116ffb29c9f4195d863d04f8812e87a31ca
17 files changed, 527 insertions, 502 deletions
diff --git a/ant-glob-tests/.classpath b/ant-glob-tests/.classpath new file mode 100644 index 0000000..0a4978e --- /dev/null +++ b/ant-glob-tests/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> + <classpathentry combineaccessrules="false" kind="src" path="/ant-glob"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/ant-glob-tests/.gitignore b/ant-glob-tests/.gitignore new file mode 100644 index 0000000..3826f65 --- /dev/null +++ b/ant-glob-tests/.gitignore @@ -0,0 +1,6 @@ +bin +*~ +*.bak +Thumbs.db +*.class +*.DS_Store diff --git a/ant-glob-tests/.project b/ant-glob-tests/.project new file mode 100644 index 0000000..4686cc9 --- /dev/null +++ b/ant-glob-tests/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>ant-glob-tests</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/ant-glob-tests/src/org/apache/tools/ant/types/selectors/SelectorUtilsTest.java b/ant-glob-tests/src/org/apache/tools/ant/types/selectors/SelectorUtilsTest.java new file mode 100644 index 0000000..943ebd5 --- /dev/null +++ b/ant-glob-tests/src/org/apache/tools/ant/types/selectors/SelectorUtilsTest.java @@ -0,0 +1,37 @@ +/* + * 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 org.apache.tools.ant.types.selectors; + +import junit.framework.TestCase; + + +public class SelectorUtilsTest extends TestCase { + + public void test1() { + assertTrue(SelectorUtils.matchPath("**", "a")); + + assertTrue(SelectorUtils.matchPath("a/**/b", "a/c/d/b")); + assertTrue(SelectorUtils.matchPath("a/**/b", "a/b")); + assertFalse(SelectorUtils.matchPath("a/**/b", "a/b/c")); + + assertTrue(SelectorUtils.matchPath("a/**", "a")); + assertTrue(SelectorUtils.matchPath("a/**", "a/b")); + + assertTrue(SelectorUtils.matchPath("bin/**/*.class", "bin/a/foo.class")); + assertFalse(SelectorUtils.matchPath("bin/**/*.class", "bin/a/fooclass")); + } +} diff --git a/build/product_sdk.mk b/build/product_sdk.mk index f96bcf5..5646668 100644 --- a/build/product_sdk.mk +++ b/build/product_sdk.mk @@ -27,6 +27,7 @@ # Host tools and java libraries that are parts of the SDK. PRODUCT_PACKAGES += \ + ant-glob \ android \ androidprefs \ annotations \ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath index a3376bd..3a203c4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath +++ b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry excluding="Makefile|resources/" kind="src" path="src"/> + <classpathentry exported="true" kind="lib" path="libs/ant-glob.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="lib" path="libs/kxml2-2.3.0.jar"/> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 3de6944..42de1eb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -16,7 +16,8 @@ Bundle-ClassPath: ., libs/lombok-ast-0.2.jar, libs/asm-4.0.jar, libs/asm-tree-4.0.jar, - libs/propertysheet.jar + libs/propertysheet.jar, + libs/ant-glob.jar Bundle-Activator: com.android.ide.eclipse.adt.AdtPlugin Bundle-Vendor: The Android Open Source Project Require-Bundle: com.android.ide.eclipse.base, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index 0b619fb..904c4e6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -23,7 +23,6 @@ import com.android.ide.eclipse.adt.internal.build.builders.ResourceManagerBuilde import com.android.sdklib.SdkConstants; import java.io.File; -import java.util.regex.Pattern; /** * Constant definition class.<br> @@ -140,10 +139,6 @@ public class AdtConstants { public final static String FN_MANIFEST_CLASS = "Manifest.java"; //$NON-NLS-1$ /** Temporary packaged resources file name, i.e. "resources.ap_" */ public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$ - /** Temporary packaged resources file name for a specific set of configuration */ - public final static String FN_RESOURCES_S_AP_ = "resources-%s.ap_"; //$NON-NLS-1$ - public final static Pattern PATTERN_RESOURCES_S_AP_ = - Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$ public final static String FN_TRACEVIEW = (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java new file mode 100644 index 0000000..4f5b47f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.build.builders; + +import com.android.annotations.NonNull; + +import org.apache.tools.ant.types.selectors.SelectorUtils; +import org.eclipse.core.runtime.IPath; + +/** + * Collection of file path or path patterns to be checked for changes. + * + * All paths should be relative to the project they belong to. + * Patterns can use Ant-type glob patterns. + * + * This is an immutable class that does not store any info beyond the list of paths. This is to + * be used in conjunction with {@link PatternBasedDeltaVisitor}. + */ +class ChangedFileSet { + + private final String mLogName; + + private final String[] mInputs; + private String mOutput; + + ChangedFileSet(String logName, String... inputs) { + mLogName = logName; + mInputs = inputs; + } + + public void setOutput(@NonNull String output) { + mOutput = output; + } + + public boolean isInput(@NonNull String path, @NonNull IPath iPath) { + for (String i : mInputs) { + if (SelectorUtils.matchPath(i, path)) { + return true; + } + } + + return false; + } + + public boolean isOutput(@NonNull String path, @NonNull IPath iPath) { + if (mOutput != null) { + return SelectorUtils.matchPath(mOutput, path); + } + + return false; + } + + public String getLogName() { + return mLogName; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java new file mode 100644 index 0000000..36d7397 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.build.builders; + +import com.android.annotations.NonNull; +import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.sdklib.SdkConstants; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class to generate {@link ChangedFileSet} for given projects. + * + * Also contains non project specific {@link ChangedFileSet} such as {@link #MANIFEST} + * and {@link #NATIVE_LIBS} + */ +class ChangedFileSetHelper { + + final static ChangedFileSet MANIFEST; + final static ChangedFileSet NATIVE_LIBS; + + static { + MANIFEST = new ChangedFileSet("manifest", //$NON-NLS-1$ + SdkConstants.FN_ANDROID_MANIFEST_XML); + + // FIXME: move compiled native libs to bin/libs/ + NATIVE_LIBS = new ChangedFileSet( + "nativeLibs", + SdkConstants.FD_NATIVE_LIBS + "/*/*.so", //$NON-NLS-1$ + SdkConstants.FD_NATIVE_LIBS + "/*/" + SdkConstants.FN_GDBSERVER); //$NON-NLS-1$ + } + + /** + * Returns a ChangedFileSet for Java resources inside a given project's source folders. + * @param project the project. + * @return a ChangedFileSet + */ + static ChangedFileSet getJavaResCfs(@NonNull IProject project) { + + // get the source folder for the given project. + IPath projectPath = project.getFullPath(); + + // get the source folders. + List<IPath> srcPaths = BaseProjectHelper.getSourceClasspaths(project); + List<String> paths = new ArrayList<String>(srcPaths.size()); + + // create a pattern for each of them. + for (IPath path : srcPaths) { + paths.add(path.makeRelativeTo(projectPath).toString() + "/**"); //$NON-NLS-1$ + } + + // custom ChangedFileSet to ignore .java files. + return new JavaResChangedSet("javaRes", //$NON-NLS-1$ + paths.toArray(new String[paths.size()])); + } + + /** + * Returns a {@link ChangedFileSet} for all the resources (included assets), and the output + * file (compiled resources + * @param project the project + * @return a ChangeFileSet + */ + static ChangedFileSet getResCfs(@NonNull IProject project) { + ChangedFileSet set = new ChangedFileSet( + "resources", //$NON-NLS-1$ + SdkConstants.FD_RES + "/**", //$NON-NLS-1$ + SdkConstants.FD_ASSETS + "/**"); //$NON-NLS-1$ + + // output file is based on the project's android output folder + String path = getRelativeAndroidOut(project); + set.setOutput(path + '/' + AdtConstants.FN_RESOURCES_AP_); + + return set; + } + + /** + * Returns a {@link ChangedFileSet} for a project's javac output. + * @param project the project + * @return a ChangedFileSet + */ + static ChangedFileSet getByteCodeCfs(@NonNull IProject project) { + // input pattern is based on the project's Java compiler's output folder + String path = getRelativeJavaCOut(project); + + ChangedFileSet set = new ChangedFileSet("bytecode", //$NON-NLS-1$ + path + "/**/*" + AdtConstants.DOT_CLASS); //$NON-NLS-1$ + + return set; + } + + /** + * Returns a {@link ChangedFileSet} for a project's complete resources, including + * generated resources and crunch cache. + * @param project the project + * @return a ChangeFileSet + */ + static ChangedFileSet getFullResCfs(@NonNull IProject project) { + // generated res are in the project's android output folder + String path = getRelativeAndroidOut(project); + + ChangedFileSet set = new ChangedFileSet("libResources", //$NON-NLS-1$ + SdkConstants.FD_RES + "/**", //$NON-NLS-1$ + path + '/' + SdkConstants.FD_RES + "/**"); //$NON-NLS-1$ + + return set; + } + + /** + * Returns a {@link ChangedFileSet} for a project's whole code, including + * compiled bytecode, 3rd party libs, and the output file containing the Dalvik + * bytecode file. + * @param project the project + * @return a ChangeFileSet + */ + static ChangedFileSet getCodeCfs(@NonNull IProject project) { + // input pattern is based on the project's Java compiler's output folder + String path = getRelativeJavaCOut(project); + + ChangedFileSet set = new ChangedFileSet("libResources", //$NON-NLS-1$ + path + "/**/*" + AdtConstants.DOT_CLASS, //$NON-NLS-1$ + SdkConstants.FD_NATIVE_LIBS + "*" + AdtConstants.DOT_JAR); //$NON-NLS-1$ + + // output file is based on the project's android output folder + path = getRelativeAndroidOut(project); + set.setOutput(path + '/' + SdkConstants.FN_APK_CLASSES_DEX); + + return set; + } + + private static String getRelativeAndroidOut(@NonNull IProject project) { + IFolder folder = BaseProjectHelper.getAndroidOutputFolder(project); + return folder.getFullPath().makeRelativeTo(project.getFullPath()).toString(); + } + + private static String getRelativeJavaCOut(@NonNull IProject project) { + IFolder folder = BaseProjectHelper.getJavaOutputFolder(project); + return folder.getFullPath().makeRelativeTo(project.getFullPath()).toString(); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java new file mode 100644 index 0000000..6b257ef --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.build.builders; + +import com.android.annotations.NonNull; +import com.android.sdklib.build.ApkBuilder; + +import org.eclipse.core.runtime.IPath; + +/** + * Custom {@link ChangedFileSet} for java resources. + * + * This builds the set of inputs to be all the source folders of the given project, + * and excludes files that won't be packaged. + * This exclusion can't be easily described as a glob-pattern so it's overriding the default + * behavior instead. + * + */ +class JavaResChangedSet extends ChangedFileSet { + + JavaResChangedSet(String logName, String... inputs) { + super(logName, inputs); + } + + @Override + public boolean isInput(@NonNull String path, @NonNull IPath iPath) { + if (!ApkBuilder.checkFileForPackaging(iPath.lastSegment(), iPath.getFileExtension())) { + return false; + } + return super.isInput(path, iPath); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/LibraryDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/LibraryDeltaVisitor.java deleted file mode 100644 index 61fd383..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/LibraryDeltaVisitor.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.ide.eclipse.adt.internal.build.builders; - -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -/** - * Delta visitor specifically for Library resources. - * The goal is to detect library resource/library changes when compiling the main project - * and trigger a resource recompilation/repackaging. - * - */ -public class LibraryDeltaVisitor implements IResourceDeltaVisitor { - - private boolean mResChange = false; - private boolean mLibChange = false; - - public boolean getResChange() { - return mResChange; - } - - public boolean getLibChange() { - return mLibChange; - } - - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // we are only going to look for changes in res/ - // Since the delta visitor goes through the main - // folder before its children we can check when the path segment - // count is 2 (format will be /$Project/folder) and make sure we are - // processing res/ - - IResource resource = delta.getResource(); - IPath path = resource.getFullPath(); - String[] segments = path.segments(); - - // since the delta visitor also visits the root we return true if - // segments.length = 1 - if (segments.length == 1) { - // this is always the Android project since we call - // Builder#getDelta(IProject) on the project itself. - return true; - } else if (segments.length == 2) { - if (SdkConstants.FD_RESOURCES.equalsIgnoreCase(segments[1])) { - // res folder was changed! - // This is all that matters, we can stop (return false below) - mResChange = true; - } else if (SdkConstants.FD_NATIVE_LIBS.equalsIgnoreCase(segments[1])) { - // libs folder was changed. - // This is all that matters, we can stop (return false below) - mLibChange = true; - } else if (SdkConstants.FD_OUTPUT.equalsIgnoreCase(segments[1])) { - // need to dig into the content of the bin folder. - return true; - } - } else { - // we must be in the bin folder since it's the only case we go deeper. - if (SdkConstants.FD_RESOURCES.equalsIgnoreCase(segments[2])) { - mResChange = true; - } - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java new file mode 100644 index 0000000..7109eb8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.build.builders; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.build.BuildHelper; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Delta visitor checking changed files against given glob-patterns. + * + * The visitor is given {@link ChangedFileSet} objects which contains patterns to detect change + * in input and output files. (Output files are only tested if the delta indicate the file + * was removed). + * + * After the visitor has visited the whole delta, it can be queried to see which ChangedFileSet + * recognized a file change. (ChangedFileSet are immutable and do not record this info). + */ +class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { + + private final boolean DEBUG_LOG = "1".equals( //$NON-NLS-1$ + System.getenv("ANDROID_VISITOR_DEBUG")); //$NON-NLS-1$ + + private final List<ChangedFileSet> mSets = new ArrayList<ChangedFileSet>(); + private final IProject mProject; + + private final Map<ChangedFileSet, Boolean> mResults = new HashMap<ChangedFileSet, Boolean>(); + private final String mLogName; + + PatternBasedDeltaVisitor(IProject project, String logName) { + mProject = project; + mLogName = logName; + } + + void addSet(ChangedFileSet bundle) { + mSets.add(bundle); + } + + boolean checkSet(ChangedFileSet bundle) { + Boolean r = mResults.get(bundle); + if (r != null) { + return r.booleanValue(); + } + + return false; + } + + @Override + public boolean visit(IResourceDelta delta) throws CoreException { + IResource resource = delta.getResource(); + + if (resource.getType() == IResource.FOLDER) { + // always visit the subfolders, unless the folder is not to be included + return BuildHelper.checkFolderForPackaging((IFolder)resource); + + } else if (resource.getType() == IResource.FILE) { + IPath path = resource.getFullPath().makeRelativeTo(mProject.getFullPath()); + + // FIXME: no need to loop through all the sets once they have all said they need something (return false below and above) + for (ChangedFileSet set : mSets) { + // FIXME: should ignore sets that have already returned true. + String pathStr = path.toString(); + + if (set.isInput(pathStr, path)) { + mResults.put(set, Boolean.TRUE); + + if (DEBUG_LOG) { + String cfs_logName = set.getLogName(); + + if (cfs_logName != null) { + AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ + mLogName, cfs_logName, + resource.getFullPath().toString()); + } else { + AdtPlugin.log(IStatus.INFO, "%s: %s", //$NON-NLS-1$ + mLogName, resource.getFullPath().toString()); + } + } + + } else if (delta.getKind() == IResourceDelta.REMOVED && + set.isOutput(pathStr, path)) { + mResults.put(set, Boolean.TRUE); + + if (DEBUG_LOG) { + String cfs_logName = set.getLogName(); + + if (cfs_logName != null) { + AdtPlugin.log(IStatus.INFO, "%s (%s): REMOVED: %s", //$NON-NLS-1$ + mLogName, cfs_logName, + resource.getFullPath().toString()); + } else { + AdtPlugin.log(IStatus.INFO, "%s: REMOVED: %s", //$NON-NLS-1$ + mLogName, + resource.getFullPath().toString()); + } + } + } + } + } + + return true; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java index 8be6863..99f37ad 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java @@ -53,7 +53,6 @@ import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -61,7 +60,6 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.IJavaModelMarker; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; import java.io.File; import java.io.FileInputStream; @@ -115,87 +113,6 @@ public class PostCompilerBuilder extends BaseBuilder { private AndroidPrintStream mOutStream = null; private AndroidPrintStream mErrStream = null; - /** - * Basic Resource Delta Visitor class to check if a referenced project had a change in its - * compiled java files. - */ - private static class ReferencedProjectDeltaVisitor implements IResourceDeltaVisitor { - - private boolean mConvertToDex = false; - private boolean mMakeFinalPackage; - - private IPath mOutputFolder; - private List<IPath> mSourceFolders; - - private ReferencedProjectDeltaVisitor(IJavaProject javaProject) { - try { - mOutputFolder = javaProject.getOutputLocation(); - mSourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - } catch (JavaModelException e) { - } - } - - /** - * {@inheritDoc} - * @throws CoreException - */ - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // no need to keep looking if we already know we need to convert - // to dex and make the final package. - if (mConvertToDex && mMakeFinalPackage) { - return false; - } - - // get the resource and the path segments. - IResource resource = delta.getResource(); - IPath resourceFullPath = resource.getFullPath(); - - if (mOutputFolder.isPrefixOf(resourceFullPath)) { - int type = resource.getType(); - if (type == IResource.FILE) { - String ext = resource.getFileExtension(); - if (AdtConstants.EXT_CLASS.equals(ext)) { - mConvertToDex = true; - } - } - return true; - } else { - for (IPath sourceFullPath : mSourceFolders) { - if (sourceFullPath.isPrefixOf(resourceFullPath)) { - int type = resource.getType(); - if (type == IResource.FILE) { - // check if the file is a valid file that would be - // included during the final packaging. - if (BuildHelper.checkFileForPackaging((IFile)resource)) { - mMakeFinalPackage = true; - } - - return false; - } else if (type == IResource.FOLDER) { - // if this is a folder, we check if this is a valid folder as well. - // If this is a folder that needs to be ignored, we must return false, - // so that we ignore its content. - return BuildHelper.checkFolderForPackaging((IFolder)resource); - } - } - } - } - - return true; - } - - /** - * Returns if one of the .class file was modified. - */ - boolean needDexConvertion() { - return mConvertToDex; - } - - boolean needMakeFinalPackage() { - return mMakeFinalPackage; - } - } private ResourceMarker mResourceMarker = new ResourceMarker() { @Override @@ -261,7 +178,7 @@ public class PostCompilerBuilder extends BaseBuilder { String msg = "BENCHMARK ADT: Ending Compilation \n BENCHMARK ADT: Time Elapsed: " + //$NON-NLS-1$ (System.nanoTime() - BuildHelper.sStartJavaCTime)/Math.pow(10, 6) + "ms"; //$NON-NLS-1$ AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); - msg = "BENCHMARK ADT: Starting PostCompilation"; //$NON-NLS-1$ + msg = "BENCHMARK ADT: Starting PostCompilation"; //$NON-NLS-1$ AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); startBuildTime = System.nanoTime(); } @@ -302,12 +219,8 @@ public class PostCompilerBuilder extends BaseBuilder { IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); IFolder resOutputFolder = androidOutputFolder.getFolder(SdkConstants.FD_RES); - // now we need to get the classpath list - List<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject); - // First thing we do is go through the resource delta to not // lose it if we have to abort the build for any reason. - PostCompilerDeltaVisitor dv = null; if (args.containsKey(POST_C_REQUESTED) && AdtPrefs.getPrefs().getBuildSkipPostCompileOnFileSave()) { // Skip over flag setting @@ -335,51 +248,74 @@ public class PostCompilerBuilder extends BaseBuilder { mConvertToDex = true; mBuildFinalPackage = true; } else { - dv = new PostCompilerDeltaVisitor(this, sourceList, androidOutputFolder); + PatternBasedDeltaVisitor dv = new PatternBasedDeltaVisitor(project, + project.getName()); + dv.addSet(ChangedFileSetHelper.MANIFEST); + ChangedFileSet resCFS = ChangedFileSetHelper.getResCfs(project); + dv.addSet(resCFS); + + ChangedFileSet androidCodeCFS = ChangedFileSetHelper.getCodeCfs(project); + dv.addSet(androidCodeCFS); + + ChangedFileSet javaResCFS = ChangedFileSetHelper.getJavaResCfs(project); + dv.addSet(javaResCFS); + dv.addSet(ChangedFileSetHelper.NATIVE_LIBS); + delta.accept(dv); // save the state - mPackageResources |= dv.getPackageResources(); - mConvertToDex |= dv.getConvertToDex(); - mBuildFinalPackage |= dv.getMakeFinalPackage(); + mPackageResources |= dv.checkSet(ChangedFileSetHelper.MANIFEST) || + dv.checkSet(resCFS); + + mConvertToDex |= dv.checkSet(androidCodeCFS); + + mBuildFinalPackage |= dv.checkSet(javaResCFS) || + dv.checkSet(ChangedFileSetHelper.NATIVE_LIBS); } - // if the main resources didn't change, then we check for the library - // ones (will trigger resource repackaging too) - if ((mPackageResources == false || mBuildFinalPackage == false) && - libProjects.size() > 0) { + // check the libraries + if (libProjects.size() > 0) { for (IProject libProject : libProjects) { delta = getDelta(libProject); if (delta != null) { - LibraryDeltaVisitor visitor = new LibraryDeltaVisitor(); - delta.accept(visitor); + PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( + libProject, project.getName()); - mPackageResources |= visitor.getResChange(); - mBuildFinalPackage |= visitor.getLibChange(); + ChangedFileSet libResCFS = ChangedFileSetHelper.getFullResCfs( + libProject); + visitor.addSet(libResCFS); + visitor.addSet(ChangedFileSetHelper.NATIVE_LIBS); + // FIXME: add check on the library.jar? - if (mPackageResources && mBuildFinalPackage) { - break; - } + delta.accept(visitor); + + mPackageResources |= visitor.checkSet(libResCFS); + mBuildFinalPackage |= visitor.checkSet( + ChangedFileSetHelper.NATIVE_LIBS); } } } - // also go through the delta for all the referenced projects, until we are forced to - // compile anyway + // also go through the delta for all the referenced projects final int referencedCount = referencedJavaProjects.size(); - for (int i = 0 ; i < referencedCount && - (mBuildFinalPackage == false || mConvertToDex == false); i++) { + for (int i = 0 ; i < referencedCount; i++) { IJavaProject referencedJavaProject = referencedJavaProjects.get(i); delta = getDelta(referencedJavaProject.getProject()); if (delta != null) { - ReferencedProjectDeltaVisitor refProjectDv = - new ReferencedProjectDeltaVisitor(referencedJavaProject); + PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( + referencedJavaProject.getProject(), project.getName()); + + ChangedFileSet javaResCFS = ChangedFileSetHelper.getJavaResCfs(project); + visitor.addSet(javaResCFS); - delta.accept(refProjectDv); + ChangedFileSet bytecodeCFS = ChangedFileSetHelper.getByteCodeCfs(project); + visitor.addSet(bytecodeCFS); + + delta.accept(visitor); // save the state - mConvertToDex |= refProjectDv.needDexConvertion(); - mBuildFinalPackage |= refProjectDv.needMakeFinalPackage(); + mConvertToDex |= visitor.checkSet(bytecodeCFS); + mBuildFinalPackage |= visitor.checkSet(javaResCFS); } } } @@ -393,15 +329,6 @@ public class PostCompilerBuilder extends BaseBuilder { // delta changes. abortOnBadSetup(javaProject); - if (dv != null && dv.mXmlError) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Xml_Error); - - // if there was some XML errors, we just return w/o doing - // anything since we've put some markers in the files anyway - return allRefProjects; - } - // remove older packaging markers. removeMarkersFromContainer(javaProject.getProject(), AdtConstants.MARKER_PACKAGING); @@ -495,7 +422,6 @@ public class PostCompilerBuilder extends BaseBuilder { tmp = androidOutputFolder.findMember(AdtConstants.FN_RESOURCES_AP_); if (tmp == null || tmp.exists() == false) { mPackageResources = true; - mBuildFinalPackage = true; } } @@ -504,7 +430,6 @@ public class PostCompilerBuilder extends BaseBuilder { tmp = androidOutputFolder.findMember(SdkConstants.FN_APK_CLASSES_DEX); if (tmp == null || tmp.exists() == false) { mConvertToDex = true; - mBuildFinalPackage = true; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerDeltaVisitor.java deleted file mode 100644 index abb072b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerDeltaVisitor.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.ide.eclipse.adt.internal.build.builders; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; -import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder.BaseDeltaVisitor; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -import java.util.List; - -/** - * Delta resource visitor looking for changes that will trigger a new packaging of an Android - * application. - * <p/> - * This looks for the following changes: - * <ul> - * <li>Any change to the AndroidManifest.xml file</li> - * <li>Any change inside the assets/ folder</li> - * <li>Any file change inside the res/ folder</li> - * <li>Any .class file change inside the output folder</li> - * <li>Any change to the classes.dex inside the output folder</li> - * <li>Any change to the packaged resources file inside the output folder</li> - * <li>Any change to a non java/aidl file inside the source folders</li> - * <li>Any change to .so file inside the lib (native library) folder</li> - * </ul> - */ -public class PostCompilerDeltaVisitor extends BaseDeltaVisitor - implements IResourceDeltaVisitor { - - /** - * compile flag. This is set to true if one of the changed/added/removed - * file is a .class file. Upon visiting all the delta resources, if this - * flag is true, then we know we'll have to make the "classes.dex" file. - */ - private boolean mConvertToDex = false; - - /** - * compile flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resources, if - * this flag is true, then we know we'll have to make the intermediate - * apk file. - */ - private boolean mPackageResources = false; - - /** - * Final package flag. This is set to true if one of the changed/added/removed - * file is a non java file (or aidl) in the resource folder. Upon visiting all the - * delta resources, if this flag is true, then we know we'll have to make the final - * package. - */ - private boolean mMakeFinalPackage = false; - - /** List of source folders. */ - private List<IPath> mSourceFolders; - - private IPath mOutputPath; - - private IPath mAssetPath; - - private IPath mResPath; - - private IPath mLibFolder; - - /** - * Builds the object with a specified output folder. - * @param builder the xml builder using this object to visit the - * resource delta. - * @param sourceFolders the list of source folders for the project, relative to the workspace. - * @param outputfolder the output folder of the project. - */ - public PostCompilerDeltaVisitor(BaseBuilder builder, List<IPath> sourceFolders, - IFolder outputfolder) { - super(builder); - mSourceFolders = sourceFolders; - - if (outputfolder != null) { - mOutputPath = outputfolder.getFullPath(); - } - - IResource assetFolder = builder.getProject().findMember(SdkConstants.FD_ASSETS); - if (assetFolder != null) { - mAssetPath = assetFolder.getFullPath(); - } - - IResource resFolder = builder.getProject().findMember(SdkConstants.FD_RESOURCES); - if (resFolder != null) { - mResPath = resFolder.getFullPath(); - } - - IResource libFolder = builder.getProject().findMember(SdkConstants.FD_NATIVE_LIBS); - if (libFolder != null) { - mLibFolder = libFolder.getFullPath(); - } - } - - public boolean getConvertToDex() { - return mConvertToDex; - } - - public boolean getPackageResources() { - return mPackageResources; - } - - public boolean getMakeFinalPackage() { - return mMakeFinalPackage; - } - - /** - * {@inheritDoc} - * @throws CoreException - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor - * #visit(org.eclipse.core.resources.IResourceDelta) - */ - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // if all flags are true, we can stop going through the resource delta. - if (mConvertToDex && mPackageResources && mMakeFinalPackage) { - return false; - } - - // we are only going to look for changes in res/, src/ and in - // AndroidManifest.xml since the delta visitor goes through the main - // folder before its children we can check when the path segment - // count is 2 (format will be /$Project/folder) and make sure we are - // processing res/, src/ or AndroidManifest.xml - IResource resource = delta.getResource(); - IPath path = resource.getFullPath(); - String[] pathSegments = path.segments(); - int type = resource.getType(); - - // since the delta visitor also visits the root we return true if - // segments.length = 1 - if (pathSegments.length == 1) { - return true; - } - - // check the manifest. - if (pathSegments.length == 2 && - SdkConstants.FN_ANDROID_MANIFEST_XML.equalsIgnoreCase(pathSegments[1])) { - // if the manifest changed we have to repackage the - // resources. - mPackageResources = true; - mMakeFinalPackage = true; - - // we don't want to go to the children, not like they are - // any for this resource anyway. - return false; - } - - // check the other folders. - if (mOutputPath != null && mOutputPath.isPrefixOf(path)) { - // a resource changed inside the output folder. - if (type == IResource.FILE) { - // just check this is a .class file. Any modification will - // trigger a change in the classes.dex file - String ext = resource.getFileExtension(); - if (AdtConstants.EXT_CLASS.equalsIgnoreCase(ext)) { - mConvertToDex = true; - mMakeFinalPackage = true; - - // no need to check the children, as we are in a package - // and there can only be subpackage children containing - // only .class files - return false; - } - - // check for a few files directly in the output folder and force - // rebuild if they have been deleted. - if (delta.getKind() == IResourceDelta.REMOVED) { - IPath parentPath = path.removeLastSegments(1); - if (mOutputPath.equals(parentPath)) { - String resourceName = resource.getName(); - // check if classes.dex was removed - if (resourceName.equalsIgnoreCase(SdkConstants.FN_APK_CLASSES_DEX)) { - mConvertToDex = true; - mMakeFinalPackage = true; - } else if (resourceName.equalsIgnoreCase( - AdtConstants.FN_RESOURCES_AP_) || - AdtConstants.PATTERN_RESOURCES_S_AP_.matcher( - resourceName).matches()) { - // or if the default resources.ap_ or a configured version - // (resources-###.ap_) was removed. - mPackageResources = true; - mMakeFinalPackage = true; - } - } - } - } - - // if this is a folder, we only go visit it if we don't already know - // that we need to convert to dex already. - return mConvertToDex == false; - } else if (mResPath != null && mResPath.isPrefixOf(path)) { - // in the res folder we are looking for any file modification - // (we don't care about folder being added/removed, only content - // is important) - if (type == IResource.FILE) { - mPackageResources = true; - mMakeFinalPackage = true; - return false; - } - - // for folders, return true only if we don't already know we have to - // package the resources. - return mPackageResources == false; - } else if (mAssetPath != null && mAssetPath.isPrefixOf(path)) { - // this is the assets folder that was modified. - // we don't care what content was changed. All we care - // about is that something changed inside. No need to visit - // the children even. - mPackageResources = true; - mMakeFinalPackage = true; - return false; - } else if (mLibFolder != null && mLibFolder.isPrefixOf(path)) { - // inside the native library folder. Test if the changed resource is a .so file. - if (type == IResource.FILE && - (AdtConstants.EXT_NATIVE_LIB.equalsIgnoreCase(path.getFileExtension()) - || SdkConstants.FN_GDBSERVER.equals(resource.getName()))) { - mMakeFinalPackage = true; - return false; // return false for file. - } - - // for folders, return true only if we don't already know we have to make the - // final package. - return mMakeFinalPackage == false; - } else { - // we are in a folder that is neither the resource folders, nor the output. - // check against all the source folders, unless we already know we need to do - // the final package. - // This could be a source folder or a folder leading to a source folder. - // However we only check this if we don't already know that we need to build the - // package anyway - if (mMakeFinalPackage == false) { - for (IPath sourcePath : mSourceFolders) { - if (sourcePath.isPrefixOf(path)) { - // In the source folders, we are looking for any kind of - // modification related to file that are not java files. - // Also excluded are aidl files, and package.html files - if (type == IResource.FOLDER) { - // always visit the subfolders, unless the folder is not to be included - return BuildHelper.checkFolderForPackaging((IFolder)resource); - } else if (type == IResource.FILE) { - if (BuildHelper.checkFileForPackaging((IFile)resource)) { - mMakeFinalPackage = true; - } - - return false; - } - - } - } - } - } - - // if the folder is not inside one of the folders we are interested in (res, assets, output, - // source folders), it could be a folder leading to them, so we return true. - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index b471c3f..232f40f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -121,7 +121,6 @@ public class PreCompilerBuilder extends BaseBuilder { */ private DerivedProgressMonitor mDerivedProgressMonitor; - /** * Progress monitor waiting the end of the process to set a persistent value * in a file. This is typically used in conjunction with <code>IResource.refresh()</code>, @@ -678,7 +677,6 @@ public class PreCompilerBuilder extends BaseBuilder { mLastBuildConfigMode = v; } - IJavaProject javaProject = JavaCore.create(project); // load the source processors @@ -687,7 +685,6 @@ public class PreCompilerBuilder extends BaseBuilder { mGenFolder); mProcessors.add(aidlProcessor); mProcessors.add(renderScriptProcessor); - } catch (Throwable throwable) { AdtPlugin.log(throwable, "Failed to finish PrecompilerBuilder#startupOnInitialize()"); } diff --git a/eclipse/scripts/create_all_symlinks.sh b/eclipse/scripts/create_all_symlinks.sh index 0e11631..e4af2bd 100755 --- a/eclipse/scripts/create_all_symlinks.sh +++ b/eclipse/scripts/create_all_symlinks.sh @@ -124,7 +124,7 @@ CP_FILES="$CP_FILES @:$BASE_PLUGIN_DEST $BASE_PLUGIN_LIBS $BASE_PLUGIN_PREBUILTS ### ADT ### ADT_DEST="sdk/eclipse/plugins/com.android.ide.eclipse.adt/libs" -ADT_LIBS="layoutlib_api lint_api lint_checks ide_common rule_api ninepatch sdkuilib assetstudio propertysheet" +ADT_LIBS="layoutlib_api lint_api lint_checks ide_common rule_api ninepatch sdkuilib assetstudio propertysheet ant-glob" ADT_PREBUILTS="\ prebuilts/misc/common/kxml2/kxml2-2.3.0.jar \ prebuilts/tools/common/asm-tools/asm-4.0.jar \ |