1 /*
<lambda>null2  * Copyright 2022 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 androidx.build
18 
19 import java.io.File
20 import org.gradle.api.DefaultTask
21 import org.gradle.api.tasks.Internal
22 import org.gradle.api.tasks.TaskAction
23 import org.gradle.work.DisableCachingByDefault
24 
25 // This task prints the coordinates (group/artifact/version) of a project
26 @DisableCachingByDefault(because = "The purpose of this task is to print information")
27 abstract class PrintProjectCoordinatesTask : DefaultTask() {
28 
29     fun configureWithAndroidXExtension(androidXExtension: AndroidXExtension) {
30         projectGroup = androidXExtension.mavenGroup
31         groupExplanation = androidXExtension.explainMavenGroup()
32         projectName = project.name
33         version = project.version.toString()
34         projectDir = project.projectDir.relativeTo(project.rootDir)
35         projectPath = project.path
36     }
37 
38     @Internal // Task is always out-of-date: no need to track inputs
39     var projectGroup: LibraryGroup? = null
40 
41     @Internal // Task is always out-of-date: no need to track inputs
42     var groupExplanation: List<String>? = null
43 
44     @Internal // Task is always out-of-date: no need to track inputs
45     var projectName: String? = null
46 
47     @Internal // Task is always out-of-date: no need to track inputs
48     var version: String? = null
49 
50     @Internal // Task is always out-of-date: no need to track inputs
51     var projectDir: File? = null
52 
53     @Internal // Task is always out-of-date: no need to track inputs
54     var projectPath: String? = null
55 
56     @TaskAction
57     fun printInformation() {
58         val projectGroup = projectGroup
59         val versionFrom =
60             if (projectGroup?.atomicGroupVersion == null) {
61                 "build.gradle: mavenVersion"
62             } else {
63                 "group.atomicGroupVersion"
64             }
65 
66         val groupExplanation = groupExplanation!!
67         val lines =
68             mutableListOf(listOf("filepath: $projectDir/build.gradle ", "(from settings.gradle)"))
69         // put each component of the explanation on its own line
70         groupExplanation.forEachIndexed { i, component ->
71             if (i == 0) lines.add(listOf("group   : ${projectGroup?.group} ", component))
72             else lines.add(listOf("", component))
73         }
74         lines.add(listOf("artifact: $projectName ", "(from project name)"))
75         lines.add(listOf("version : $version ", "(from $versionFrom)"))
76         printTable(lines)
77     }
78 
79     private fun printTable(lines: List<List<String>>) {
80         val columnSizes = getColumnSizes(lines)
81         for (line in lines) {
82             println(formatRow(line, columnSizes))
83         }
84     }
85 
86     private fun formatRow(line: List<String>, columnSizes: List<Int>): String {
87         var result = ""
88         for (i in line.indices) {
89             val word = line[i]
90             val columnSize = columnSizes[i]
91             // only have to pad columns before the last column
92             result += if (i != line.size - 1) word.padEnd(columnSize) else word
93         }
94         return result
95     }
96 
97     private fun getColumnSizes(lines: List<List<String>>): List<Int> {
98         val maxLengths = mutableListOf<Int>()
99         for (line in lines) {
100             for (i in line.indices) {
101                 val word = line[i]
102                 if (maxLengths.size <= i) maxLengths.add(0)
103                 if (maxLengths[i] < word.length) maxLengths[i] = word.length
104             }
105         }
106         return maxLengths
107     }
108 
109     private fun formatTableLine(prefix: String, suffix: String): String {
110         return prefix.padEnd(10) + suffix
111     }
112 }
113