1/*
2* Copyright 2013 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// The SampleGenPlugin source is in the buildSrc directory.
18import com.example.android.samples.build.SampleGenPlugin
19apply plugin: SampleGenPlugin
20
21// Add a preflight task that depends on the "refresh" task that gets
22// added by the SampleGenPlugin.
23task preflight {
24    project.afterEvaluate({preflight.dependsOn(project.refresh)})
25}
26
27task wrapper(type: Wrapper) {
28    gradleVersion = '1.8'
29}
30
31
32String outPath(String buildType) {
33/*
34    def repoInfo = "repo info platform/developers/build".execute().text
35    def buildPath = (repoInfo =~ /Mount path: (.*)/)[0][1]
36*/
37    return "${samplegen.pathToBuild}/out/${buildType}/${samplegen.targetSampleName()}";
38}
39
40/**
41 * Collapse a path "IntelliJ-style" by putting dots rather than slashes between
42 * path components that have only one child. So the two paths
43 *
44 * com/example/android/foo/bar.java
45 * com/example/android/bar/foo.java
46 *
47 * Become
48 * com.example.android/foo/bar.java
49 * com.example.android/bar/foo.java
50 *
51 * @param path
52 * @param roots
53 * @return
54 */
55Map<String,String> collapsePaths(FileTree path, List<String> roots) {
56    Map result = new HashMap<String,String>();
57
58    println ("******************** Collapse *************************")
59
60    path.visit { FileVisitDetails f ->
61        if (f.isDirectory()) return;
62        StringBuilder collapsedPath = new StringBuilder("${f.name}");
63        File current = f.file;
64
65        //
66        // Starting at this file, walk back to the root of the path and
67        // substitute dots for any directory that has only one child.
68        //
69
70        // Don't substitute a dot for the separator between the end of the
71        // path and the filename, even if there's only one file in the directory.
72        if (!f.isDirectory()) {
73            current = current.parentFile;
74            collapsedPath.insert(0, "${current.name}/")
75        }
76
77        // For everything else, use a dot if there's only one child and
78        // a slash otherwise. Filter out the root paths, too--we only want
79        // the relative path. But wait, Groovy/Gradle is capricious and
80        // won't return the proper value from a call to roots.contains(String)!
81        // I'm using roots.sum here instead of tracking down why a list of
82        // strings can't return true from contains() when given a string that
83        // it quite obviously does contain.
84        current = current.parentFile;
85        while((current != null)
86                && (roots.sum {String r-> return r.equals(current.absolutePath) ? 1 : 0 } == 0)) {
87
88            char separator = current.list().length > 1 ? '/' : '.';
89            collapsedPath.insert(0, "${current.name}${separator}");
90            current = current.parentFile;
91        }
92        result.put(f.file.path, collapsedPath.toString());
93    }
94
95    println ("******************** Collapse results *********************")
96
97    result.each {entry -> println("- ${entry}");}
98    return result
99}
100
101
102task emitAnt(type:Copy) {
103    def outputPath = outPath("ant");
104    def inputPath = "${project.projectDir}/${samplegen.targetSampleModule()}"
105    into outputPath
106    includeEmptyDirs
107    ["main", "common", "template"].each { input ->
108        [[ "java", "src"], ["res", "res"]].each { filetype ->
109            def srcPath = "${inputPath}/src/${input}/${filetype[0]}"
110            into("${filetype[1]}") {
111                from(srcPath)
112            }
113        }
114    }
115    from("${inputPath}/src/main") { include "AndroidManifest.xml" }
116    from("${inputPath}/src/template") { include "project.properties" }
117}
118
119task emitGradle(type:Copy) {
120    dependsOn(preflight)
121    def outputPath = outPath("gradle")
122    def inputPath = "${project.projectDir}"
123    // Copy entire sample into output -- since it's already in Gradle format, we'll explicitly exclude content that
124    // doesn't belong here.
125    into outputPath
126    from("${inputPath}") {
127        // Paths to exclude from output
128        exclude ".gradle"
129        exclude "_index.jd"
130        exclude "bin"
131        exclude "buildSrc"
132        exclude "local.properties"
133        exclude "template-params.xml"
134        exclude "*.iml"
135        exclude "**/.idea"
136        exclude "**/build"
137        exclude "**/proguard-project.txt"
138        exclude "${samplegen.targetSampleModule()}/**/README*.txt"
139        exclude "**/README-*.txt"
140
141        // src directory needs to be consolidated, will be done in next section
142        exclude "${samplegen.targetSampleModule()}/src/"
143    }
144
145    // Consolidate source directories
146    ["main", "common", "template"].each { input ->
147        ["java", "res", "assets", "rs"].each { filetype ->
148            def srcPath = "${inputPath}/${samplegen.targetSampleModule()}/src/${input}/${filetype}"
149            into("${samplegen.targetSampleModule()}/src/main/${filetype}") {
150                from(srcPath)
151            }
152        }
153    }
154
155    // Copy AndroidManifest.xml
156    into ("${samplegen.targetSampleModule()}/src/main") {
157        from("${inputPath}/${samplegen.targetSampleModule()}/src/main/AndroidManifest.xml")
158    }
159
160    // Remove BEGIN_EXCLUDE/END_EXCLUDE blocks from source files
161    eachFile { file ->
162        if (file.name.endsWith(".gradle") || file.name.endsWith(".java")) {
163            // TODO(trevorjohns): Outputs a blank newline for each filtered line. Replace with java.io.FilterReader impl.
164            boolean outputLines = true;
165            def removeExcludeBlocksFilter = { line ->
166                if (line ==~ /\/\/ BEGIN_EXCLUDE/) {
167                    outputLines = false;
168                } else if (line ==~ /\/\/ END_EXCLUDE/) {
169                    outputLines = true;
170                } else if (outputLines) {
171                    return line;
172                }
173                return ""
174            }
175            filter(removeExcludeBlocksFilter)
176        }
177    }
178}
179
180task emitBrowseable(type:Copy) {
181    def outputPathRoot = outPath("browseable")
182    def modules = project.childProjects.keySet()
183    def hasMultipleModules = modules.size() > 1
184    println "---------------- modules found in sample: ${modules}"
185    into outputPathRoot
186    from("${project.projectDir}/_index.jd")
187
188    modules.each { moduleName ->
189        // For single module samples (default), we emit the module contents
190        // directly to the root of the browseable sample:
191        def outputPath = "."
192        if (hasMultipleModules) {
193          // For multi module samples, we need an extra directory level
194          // to separate modules:
195          outputPath = "${moduleName}"
196        }
197        println "\n---------------- processing MODULE ${moduleName} to outputPath ${outputPath}"
198        def inputPath = "${project.projectDir}/${moduleName}"
199
200        def srcDirs = ["main", "common", "template"].collect {input -> "${inputPath}/src/${input}" };
201        def javaDirs = srcDirs.collect { input -> "${input}/java"}
202        FileTree javaTree = null;
203        javaDirs.each { dir ->
204            FileTree tree = project.fileTree("${dir}")
205            javaTree = (javaTree == null) ? tree : javaTree.plus(tree)}
206        Map collapsedPaths = collapsePaths(javaTree, javaDirs)
207
208        srcDirs.each { srcPath ->
209            print "** Copying source ${srcPath}...";
210            duplicatesStrategy = 'fail'
211            into("${outputPath}/src") {
212                def javaPath = "${srcPath}/java";
213                from(javaPath)
214                include(["**/*.java", "**/*.xml"])
215                eachFile { FileCopyDetails fcd ->
216                    if (fcd.file.isFile()) {
217                        def filename = fcd.name;
218                        String collapsed = collapsedPaths.get(fcd.file.path);
219                        fcd.path = "${outputPath}/src/${collapsed}";
220                    } else {fcd.exclude()}
221                }
222                println "done"
223            }
224            into("${outputPath}/res") {
225                from("${srcPath}/res")
226            }
227            into("${outputPath}/src/rs") {
228                from("${srcPath}/rs")
229            }
230            into("${outputPath}") {from("${srcPath}/AndroidManifest.xml")}
231        }
232    }
233}
234
235task emitGradleZip(dependsOn: [emitBrowseable, emitGradle], type:Zip) {
236    def outputPath = "${samplegen.pathToBuild}/out/browseable"
237    def folderName = "${samplegen.targetSampleName()}"
238    archiveName = "${samplegen.targetSampleName()}.zip"
239    def inputPath = outPath("gradle")
240    from inputPath
241    into folderName
242    include "**"
243    def outDir = project.file(outputPath)
244    destinationDir = outDir
245}
246