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