Home | History | Annotate | Download | only in ant
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ant;
     18 
     19 import com.android.ant.DependencyHelper.LibraryProcessorFor3rdPartyJars;
     20 import com.android.io.FileWrapper;
     21 import com.android.sdklib.SdkConstants;
     22 import com.android.sdklib.internal.project.IPropertySource;
     23 import com.android.sdklib.xml.AndroidManifest;
     24 
     25 import org.apache.tools.ant.BuildException;
     26 import org.apache.tools.ant.Project;
     27 import org.apache.tools.ant.types.Path;
     28 import org.apache.tools.ant.types.Path.PathElement;
     29 
     30 import java.io.File;
     31 import java.util.List;
     32 
     33 /**
     34  * Computes the dependency of the current project.
     35  *
     36  * Out params:
     37  * <code>libraryResFolderPathOut</code>: the Path object containing the res folder for all the
     38  * library projects in the order needed by aapt.
     39  *
     40  * <code>libraryPackagesOut</code>: a simple property containing ;-separated package name from
     41  * the library projects.
     42  *
     43  * <code>jarLibraryPathOut</code>: the Path object containing all the 3rd party jar files.
     44  *
     45  * <code>libraryNativeFolderPathOut</code>: the Path with all the native folder for the library
     46  * projects.
     47  *
     48  *
     49  * In params:
     50  * <code>targetApi</code>: the compilation target api.
     51  * <code>verbose</code>: whether the build is verbose.
     52  *
     53  */
     54 public class ComputeDependencyTask extends GetLibraryListTask {
     55 
     56     private String mLibraryManifestFilePathOut;
     57     private String mLibraryResFolderPathOut;
     58     private String mLibraryPackagesOut;
     59     private String mJarLibraryPathOut;
     60     private String mLibraryNativeFolderPathOut;
     61     private int mTargetApi = -1;
     62     private boolean mVerbose = false;
     63 
     64     public void setLibraryManifestFilePathOut(String libraryManifestFilePathOut) {
     65         mLibraryManifestFilePathOut = libraryManifestFilePathOut;
     66     }
     67 
     68     public void setLibraryResFolderPathOut(String libraryResFolderPathOut) {
     69         mLibraryResFolderPathOut = libraryResFolderPathOut;
     70     }
     71 
     72     public void setLibraryPackagesOut(String libraryPackagesOut) {
     73         mLibraryPackagesOut = libraryPackagesOut;
     74     }
     75 
     76     public void setJarLibraryPathOut(String jarLibraryPathOut) {
     77         mJarLibraryPathOut = jarLibraryPathOut;
     78     }
     79 
     80     public void setLibraryNativeFolderPathOut(String libraryNativeFolderPathOut) {
     81         mLibraryNativeFolderPathOut = libraryNativeFolderPathOut;
     82     }
     83 
     84     public void setTargetApi(int targetApi) {
     85         mTargetApi = targetApi;
     86     }
     87 
     88     /**
     89      * Sets the value of the "verbose" attribute.
     90      * @param verbose the value.
     91      */
     92     public void setVerbose(boolean verbose) {
     93         mVerbose = verbose;
     94     }
     95 
     96     @Override
     97     public void execute() throws BuildException {
     98         if (mLibraryManifestFilePathOut == null) {
     99             throw new BuildException("Missing attribute libraryManifestFilePathOut");
    100         }
    101         if (mLibraryResFolderPathOut == null) {
    102             throw new BuildException("Missing attribute libraryResFolderPathOut");
    103         }
    104         if (mLibraryPackagesOut == null) {
    105             throw new BuildException("Missing attribute libraryPackagesOut");
    106         }
    107         if (mJarLibraryPathOut == null) {
    108             throw new BuildException("Missing attribute jarLibraryPathOut");
    109         }
    110         if (mLibraryNativeFolderPathOut == null) {
    111             throw new BuildException("Missing attribute libraryNativeFolderPathOut");
    112         }
    113         if (mTargetApi == -1) {
    114             throw new BuildException("Missing attribute targetApi");
    115         }
    116 
    117         final Project antProject = getProject();
    118 
    119         // get the SDK location
    120         File sdkDir = TaskHelper.getSdkLocation(antProject);
    121 
    122         // prepare several paths for future tasks
    123         final Path manifestFilePath = new Path(antProject);
    124         final Path resFolderPath = new Path(antProject);
    125         final Path nativeFolderPath = new Path(antProject);
    126         final StringBuilder packageStrBuilder = new StringBuilder();
    127 
    128         LibraryProcessorFor3rdPartyJars processor = new LibraryProcessorFor3rdPartyJars() {
    129             @Override
    130             public void processLibrary(String libRootPath) {
    131                 // let the super class handle the jar files
    132                 super.processLibrary(libRootPath);
    133 
    134                 // get the AndroidManifest.xml path.
    135                 // FIXME: support renamed location.
    136                 PathElement element = manifestFilePath.createPathElement();
    137                 element.setPath(libRootPath + "/" + SdkConstants.FN_ANDROID_MANIFEST_XML);
    138 
    139                 // get the res path. $PROJECT/res as well as the crunch cache.
    140                 // FIXME: support renamed folders.
    141                 element = resFolderPath.createPathElement();
    142                 element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT +
    143                         "/" + SdkConstants.FD_RES);
    144                 element = resFolderPath.createPathElement();
    145                 element.setPath(libRootPath + "/" + SdkConstants.FD_RESOURCES);
    146 
    147 
    148                 // get the folder for the native libraries. Always $PROJECT/libs
    149                 // FIXME: support renamed folder.
    150                 element = nativeFolderPath.createPathElement();
    151                 element.setPath(libRootPath + "/" + SdkConstants.FD_NATIVE_LIBS);
    152 
    153                 // get the package from the manifest.
    154                 FileWrapper manifest = new FileWrapper(libRootPath,
    155                         SdkConstants.FN_ANDROID_MANIFEST_XML);
    156 
    157                 try {
    158                     String value = AndroidManifest.getPackage(manifest);
    159                     if (value != null) { // aapt will complain if it's missing.
    160                         packageStrBuilder.append(';');
    161                         packageStrBuilder.append(value);
    162                     }
    163                 } catch (Exception e) {
    164                     throw new BuildException(e);
    165                 }
    166             }
    167         };
    168 
    169         // list of all the jars that are on the classpath. This will receive the
    170         // project's libs/*.jar files, the Library Projects output and their own libs/*.jar
    171         List<File> jars = processor.getJars();
    172 
    173 
    174         // in case clean has been called before a build type target, the list of
    175         // libraries has already been computed so we don't need to compute it again.
    176         Path libraryFolderPath = (Path) antProject.getReference(getLibraryFolderPathOut());
    177         if (libraryFolderPath == null) {
    178             execute(processor);
    179         } else {
    180             // this contains the list of library folder in reverse order (compilation order).
    181             // We need to process it in the normal order (res order).
    182             System.out.println("Ordered libraries:");
    183 
    184             String[] libraries = libraryFolderPath.list();
    185             for (int i = libraries.length - 1 ; i >= 0 ; i--) {
    186                 String libRootPath = libraries[i];
    187                 System.out.println(libRootPath);
    188 
    189                 processor.processLibrary(libRootPath);
    190             }
    191         }
    192 
    193         boolean hasLibraries = jars.size() > 0;
    194 
    195         if (mTargetApi <= 15) {
    196             System.out.println("\n------------------");
    197             System.out.println("API<=15: Adding annotations.jar to the classpath.");
    198 
    199             jars.add(new File(sdkDir, SdkConstants.FD_TOOLS +
    200                     "/" + SdkConstants.FD_SUPPORT +
    201                     "/" + SdkConstants.FN_ANNOTATIONS_JAR));
    202 
    203         }
    204 
    205         // even with no libraries, always setup these so that various tasks in Ant don't complain
    206         // (the task themselves can handle a ref to an empty Path)
    207         antProject.addReference(mLibraryNativeFolderPathOut, nativeFolderPath);
    208         antProject.addReference(mLibraryManifestFilePathOut, manifestFilePath);
    209 
    210         // the rest is done only if there's a library.
    211         if (hasLibraries) {
    212             antProject.addReference(mLibraryResFolderPathOut, resFolderPath);
    213             antProject.setProperty(mLibraryPackagesOut, packageStrBuilder.toString());
    214         }
    215 
    216         File projectFolder = antProject.getBaseDir();
    217 
    218         // add the project's own content of libs/*.jar
    219         File libsFolder = new File(projectFolder, SdkConstants.FD_NATIVE_LIBS);
    220         File[] jarFiles = libsFolder.listFiles(processor.getFilter());
    221         if (jarFiles != null) {
    222             for (File jarFile : jarFiles) {
    223                 jars.add(jarFile);
    224             }
    225         }
    226 
    227         // now sanitize the path to remove dups
    228         jars = DependencyHelper.sanitizePaths(projectFolder, new IPropertySource() {
    229             @Override
    230             public String getProperty(String name) {
    231                 return antProject.getProperty(name);
    232             }
    233         }, jars);
    234 
    235         // and create a Path object for them
    236         Path jarsPath = new Path(antProject);
    237         if (mVerbose) {
    238             System.out.println("\n------------------\nSanitized jar list:");
    239         }
    240         for (File f : jars) {
    241             if (mVerbose) {
    242                 System.out.println("- " + f.getAbsolutePath());
    243             }
    244             PathElement element = jarsPath.createPathElement();
    245             element.setPath(f.getAbsolutePath());
    246         }
    247         antProject.addReference(mJarLibraryPathOut, jarsPath);
    248 
    249         if (mVerbose) {
    250             System.out.println();
    251         }
    252 
    253     }
    254 }
    255