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