def setupTasks()

in gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy [170:374]


    def setupTasks(Project project, File envDir, boolean isApplication, String parserVersion) {
        return { variant ->
            // Get the name of the package as if it were to be used in the R or BuildConfig
            // files. This is required since applications can define different application ids
            // depending on the variant type: the generated API definitions don't need to be
            // different due to that.
            def namespaceProvider = variant.getGenerateBuildConfigProvider().map({ p -> "namespace=${p.namespace.get()}.GleanMetrics" })
            def sourceOutputDir = "${project.buildDir}/generated/source/glean/${variant.dirName}/kotlin"

            def generateKotlinAPI = project.task("${TASK_NAME_PREFIX}SourceFor${variant.name.capitalize()}", type: Exec) {
                description = "Generate the Kotlin code for the Metrics API"

                if (project.ext.has("allowMetricsFromAAR")) {
                    // This is sufficiently lazy to be valid at configuration time.  See the model at
                    // https://github.com/google/protobuf-gradle-plugin/blob/6d99a421c8d15710045e4e8d31a3af6cb0cc3b70/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy#L270-L277
                    inputs.files variant.compileConfiguration.incoming.artifactView {
                        attributes {
                            it.attribute(ArtifactAttributes.ARTIFACT_FORMAT, 'glean-metrics-yaml')
                        }
                    }.files
                }

                // Add local registry files as input to this task. They will be turned
                // into `arg`s later.
                for (String item : getYamlFiles(project)) {
                    if (project.file(item).exists()) {
                        inputs.file item
                    }
                }

                outputs.dir sourceOutputDir

                workingDir project.rootDir
                commandLine getPythonCommand(envDir, isOffline)

                def gleanNamespace = "mozilla.components.service.glean"
                if (project.ext.has("gleanNamespace")) {
                    gleanNamespace = project.ext.get("gleanNamespace")
                }

                args "-c"
                args runPythonScript
                args isOffline ? "offline" : "online"
                args "glean_parser"
                args parserVersion
                args "translate"
                args "--allow-missing-files"
                args "-f"
                args "kotlin"
                args "-o"
                args "$sourceOutputDir"
                args "-s"
                args "glean_namespace=$gleanNamespace"

                // If we're building the Glean library itself (rather than an
                // application using Glean) pass the --allow-reserved flag so we can
                // use metrics in the "glean..." category
                if (project.ext.has("allowGleanInternal")) {
                    args "--allow-reserved"
                }

                // Only generate build info for applications, not for libraries.
                // From android-gradle 7.0 on the `VERSION_CODE` and `VERSION_NAME` fields
                // are not set for libraries anymore
                if (!isApplication) {
                    args "-s"
                    args "with_buildinfo=false"
                } else {
                    // For applications check if they overwrote the build date.
                    if (project.ext.has("gleanBuildDate")) {
                        args "-s"
                        args "build_date=${project.ext.get("gleanBuildDate")}"
                    }
                }

                // Enable expiration by major version, if a major version is provided.
                if (project.ext.has("gleanExpireByVersion")) {
                    args "--expire-by-version=${project.ext.get("gleanExpireByVersion")}"
                }

                doFirst {

                    args "-s"
                    args namespaceProvider.get().toString()

                    // Add the potential 'metrics.yaml' files at evaluation-time, rather than
                    // configuration-time. Otherwise the Gradle build will fail.
                    inputs.files.forEach { file ->
                        logger.lifecycle("Glean SDK - generating API from ${file.path}")
                        args file.path
                    }
                }

                // Only show the output if something went wrong.
                ignoreExitValue = true
                standardOutput = System.out
                errorOutput = System.err
                doLast {
                    if (executionResult.get().exitValue != 0) {
                        throw new GradleException("Glean code generation failed.\n\n${standardOutput.toString()}")
                    }
                }
            }

            def generateGleanMetricsDocs = project.task("${TASK_NAME_PREFIX}DocsFor${variant.name.capitalize()}", type: Exec) {
                description = "Generate the Markdown docs for the collected metrics"

                def gleanDocsDirectory = "${project.projectDir}/docs"
                if (project.ext.has("gleanDocsDirectory")) {
                    gleanDocsDirectory = project.ext.get("gleanDocsDirectory")
                }

                if (project.ext.has("allowMetricsFromAAR")) {
                    // This is sufficiently lazy to be valid at configuration time.  See the model at
                    // https://github.com/google/protobuf-gradle-plugin/blob/6d99a421c8d15710045e4e8d31a3af6cb0cc3b70/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy#L270-L277
                    inputs.files variant.compileConfiguration.incoming.artifactView {
                        attributes {
                            it.attribute(ArtifactAttributes.ARTIFACT_FORMAT, 'glean-metrics-yaml')
                        }
                    }.files
                }

                // Add local registry files as input to this task. They will be turned
                // into `arg`s later.
                for (String item : getYamlFiles(project)) {
                    if (project.file(item).exists()) {
                        inputs.file item
                    }
                }

                outputs.dir gleanDocsDirectory
                workingDir project.rootDir
                commandLine getPythonCommand(envDir, isOffline)

                args "-c"
                args runPythonScript
                args isOffline ? "offline" : "online"
                args "glean_parser"
                args parserVersion
                args "translate"
                args "--allow-missing-files"
                args "-f"
                args "markdown"
                args "-o"
                args gleanDocsDirectory

                // If we're building the Glean library itself (rather than an
                // application using Glean) pass the --allow-reserved flag so we can
                // use metrics in the "glean..." category
                if (project.ext.has("allowGleanInternal")) {
                    args "--allow-reserved"
                }

                // Enable expiration by major version, if a major version is provided.
                if (project.ext.has("gleanExpireByVersion")) {
                    args "--expire-by-version=${project.ext.get("gleanExpireByVersion")}"
                }

                doFirst {
                    // Add the potential 'metrics.yaml' files at evaluation-time, rather than
                    // configuration-time. Otherwise the Gradle build will fail.
                    inputs.files.forEach{ file ->
                        project.logger.lifecycle("Glean SDK - generating docs for ${file.path} in $gleanDocsDirectory")
                        args file.path
                    }
                }

                // Only show the output if something went wrong.
                ignoreExitValue = true
                standardOutput = new ByteArrayOutputStream()
                errorOutput = standardOutput
                doLast {
                    if (executionResult.get().exitValue != 0) {
                        throw new GradleException("Glean documentation generation failed.\n\n${standardOutput.toString()}")
                    }
                }
            }

            // Only attach the generation task if the metrics file is available or we're requested
            // to fetch them from AAR files. We don't need to fail hard otherwise, as some 3rd party
            // project might just want metrics included in Glean and nothing more.
            def yamlFileExists = false
            for (String item : getYamlFiles(project)) {
                if (project.file(item).exists()) {
                    yamlFileExists = true
                    break
                }
            }

            if (yamlFileExists
                || project.ext.has("allowMetricsFromAAR")) {
                // Generate the metrics docs, if requested
                if (project.ext.has("gleanGenerateMarkdownDocs")) {
                    generateKotlinAPI.dependsOn(generateGleanMetricsDocs)
                }

                // This is an Android-Gradle plugin 3+-ism.  Culted from reading the source,
                // searching for "registerJavaGeneratingTask", and finding
                // https://github.com/GoogleCloudPlatform/endpoints-framework-gradle-plugin/commit/2f2b91476fb1c6647791e2c6fe531a47615a1e85.
                // The added directory doesn't appear in the paths listed by the
                // `sourceSets` task, for reasons unknown.
                variant.registerJavaGeneratingTask(generateKotlinAPI, new File(sourceOutputDir))
            }
        }
    }