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