Source code
Revision control
Copy as Markdown
Other Tools
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# If --with-gradle is specified, build mobile/android with Gradle. If no
# Gradle binary is specified use the in tree Gradle wrapper. The wrapper
# downloads and installs Gradle, which is good for local developers but not
# good in automation.
option(
"--without-gradle",
nargs="?",
help="Disable building mobile/android with Gradle "
"(argument: location of binary or wrapper (gradle/gradlew))",
)
@depends("--with-gradle")
def with_gradle(value):
if not value:
die(
"Building --without-gradle is no longer supported: "
)
if value:
return True
@depends(host, "--with-gradle", build_environment)
@imports(_from="os.path", _import="isfile")
def gradle(host, value, build_env):
if len(value):
gradle = value[0]
else:
gradle = os.path.join(build_env.topsrcdir, "gradlew")
if host.os == "WINNT":
gradle = gradle + ".bat"
# TODO: verify that $GRADLE is executable.
if not isfile(gradle):
die("GRADLE must be executable: %s", gradle)
return gradle
set_config("GRADLE", gradle)
@dependable
@imports(_from="itertools", _import="chain")
def gradle_android_build_config():
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
def variant(buildType):
return namespace(
buildType=buildType,
# Like 'Debug'
name="".join(capitalize(t) for t in chain((buildType,))),
)
return namespace(
geckoview=namespace(
variant=variant("debug"),
),
geckoview_example=namespace(
variant=variant("debug"),
),
fenix=namespace(
variant=variant("debug"),
),
focus=namespace(
variant=variant("debug"),
),
)
@depends(gradle_android_build_config)
def gradle_android_intermediates_folder(build_config):
"""Path to intermediates classes folder."""
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
buildType = uncapitalize(build_config.geckoview.variant.buildType)
return "gradle/build/mobile/android/geckoview/intermediates/javac/{}".format(
buildType,
)
set_config(
"GRADLE_ANDROID_GECKOVIEW_APILINT_FOLDER", gradle_android_intermediates_folder
)
@depends(gradle_android_build_config)
def gradle_android_geckoview_test_runner_bundle(build_config):
"""Path to intermediates classes folder."""
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
buildType = uncapitalize(build_config.geckoview.variant.buildType)
variant = uncapitalize(build_config.geckoview.variant.name)
return "gradle/build/mobile/android/test_runner/outputs/bundle/{}/test_runner-{}.aab".format(
variant,
buildType,
)
set_config(
"GRADLE_ANDROID_GECKOVIEW_TEST_RUNNER_BUNDLE",
gradle_android_geckoview_test_runner_bundle,
)
@depends(gradle_android_build_config)
def gradle_android_geckoview_example_bundle(build_config):
"""Path to intermediates classes folder."""
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
buildType = uncapitalize(build_config.geckoview.variant.buildType)
variant = uncapitalize(build_config.geckoview.variant.name)
return "gradle/build/mobile/android/geckoview_example/outputs/bundle/{}/geckoview_example-{}.aab".format(
variant,
buildType,
)
set_config(
"GRADLE_ANDROID_GECKOVIEW_EXAMPLE_BUNDLE", gradle_android_geckoview_example_bundle
)
@depends(gradle_android_build_config)
def gradle_android_variant_name(build_config):
"""Like "Debug"."""
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
return namespace(
geckoview=uncapitalize(build_config.geckoview.variant.name),
)
set_config(
"GRADLE_ANDROID_GECKOVIEW_VARIANT_NAME", gradle_android_variant_name.geckoview
)
@depends(gradle_android_build_config)
def gradle_android_app_tasks(build_config):
"""Gradle tasks run by |mach android assemble-app|."""
return [
"geckoview:generateJNIWrappersForGenerated{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_APP_TASKS", gradle_android_app_tasks)
@dependable
def gradle_android_generate_sdk_bindings_tasks():
"""Gradle tasks run by |mach android generate-sdk-bindings|."""
return [
"geckoview:generateSDKBindings",
]
set_config(
"GRADLE_ANDROID_GENERATE_SDK_BINDINGS_TASKS",
gradle_android_generate_sdk_bindings_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_generate_generated_jni_wrappers_tasks(build_config):
"""Gradle tasks run by |mach android generate-generated-jni-wrappers|."""
return [
"geckoview:generateJNIWrappersForGenerated{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config(
"GRADLE_ANDROID_GENERATE_GENERATED_JNI_WRAPPERS_TASKS",
gradle_android_generate_generated_jni_wrappers_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_test_tasks(build_config):
"""Gradle tasks run by |mach android test|."""
return [
"geckoview:test{geckoview.variant.name}UnitTest".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_TEST_TASKS", gradle_android_test_tasks)
@depends(gradle_android_build_config)
def gradle_android_lint_tasks(build_config):
"""Gradle tasks run by |mach android lint|."""
return [
"geckoview:lint{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_LINT_TASKS", gradle_android_lint_tasks)
@depends(gradle_android_build_config)
def gradle_android_api_lint_tasks(build_config):
"""Gradle tasks run by |mach android api-lint|."""
return [
"geckoview:apiLint{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_API_LINT_TASKS", gradle_android_api_lint_tasks)
set_config(
"GRADLE_ANDROID_FORMAT_LINT_FIX_TASKS", ["spotlessJavaApply", "spotlessKotlinApply"]
)
@dependable
def gradle_android_format_lint_check_tasks():
return ["spotlessJavaCheck", "spotlessKotlinCheck"]
set_config(
"GRADLE_ANDROID_FORMAT_LINT_CHECK_TASKS", gradle_android_format_lint_check_tasks
)
set_config(
"GRADLE_ANDROID_FORMAT_LINT_FOLDERS",
[
"mobile/android/annotations",
"mobile/android/geckoview",
"mobile/android/geckoview_example",
"mobile/android/test_runner",
"mobile/android/examples/messaging_example",
"mobile/android/examples/port_messaging_example",
],
)
@depends(gradle_android_build_config)
def gradle_android_checkstyle_tasks(build_config):
"""Gradle tasks run by |mach android checkstyle|."""
return [
"geckoview:checkstyle{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_CHECKSTYLE_TASKS", gradle_android_checkstyle_tasks)
@depends(gradle_android_build_config)
def gradle_android_checkstyle_output_files(build_config):
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
variant = uncapitalize(build_config.geckoview.variant.name)
"""Output folder for checkstyle"""
return [
"gradle/build/mobile/android/geckoview/reports/checkstyle/{}.xml".format(
variant
),
]
set_config(
"GRADLE_ANDROID_CHECKSTYLE_OUTPUT_FILES", gradle_android_checkstyle_output_files
)
option(
"--disable-android-bundle",
help="{Enable|Disable} AAB build",
)
imply_option("--disable-android-bundle", False, when="--enable-address-sanitizer")
@depends(gradle_android_build_config)
def gradle_android_archive_geckoview_tasks(build_config):
"""Gradle tasks run by |mach android archive-geckoview|."""
tasks = [
"geckoview:assemble{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
"geckoview:assemble{geckoview.variant.name}AndroidTest".format(
geckoview=build_config.geckoview
),
"messaging_example:assemble{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"port_messaging_example:assemble{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"geckoview:publish{geckoview.variant.name}PublicationToMavenRepository".format(
geckoview=build_config.geckoview
),
"exoplayer2:publishDebugPublicationToMavenRepository",
]
return tasks
set_config(
"GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS", gradle_android_archive_geckoview_tasks
)
@depends(gradle_android_build_config, "--disable-android-bundle")
def gradle_android_archive_geckoview_subproject_tasks(build_config, aab_enabled):
"""Gradle tasks run by |mach android archive-geckoview| if just building geckoview."""
tasks = [
"test_runner:assemble{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"geckoview_example:assemble{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
]
if aab_enabled:
tasks += [
"test_runner:bundle{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"geckoview_example:bundle{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
]
return tasks
set_config(
"GRADLE_ANDROID_ARCHIVE_GECKOVIEW_SUBPROJECT_TASKS",
gradle_android_archive_geckoview_subproject_tasks,
)
@depends(gradle_android_build_config, "--disable-android-bundle")
def gradle_android_archive_fenix_subproject_tasks(build_config, aab_enabled):
"""Gradle tasks run by |mach android archive-geckoview| if just building fenix."""
tasks = [
"fenix:assemble{fenix.variant.name}".format(fenix=build_config.fenix),
]
if aab_enabled:
tasks += [
"fenix:bundle{fenix.variant.name}".format(fenix=build_config.fenix),
]
return tasks
set_config(
"GRADLE_ANDROID_ARCHIVE_FENIX_SUBPROJECT_TASKS",
gradle_android_archive_fenix_subproject_tasks,
)
@depends(gradle_android_build_config, "--disable-android-bundle")
def gradle_android_archive_focus_subproject_tasks(build_config, aab_enabled):
"""Gradle tasks run by |mach android archive-geckoview| if just building focus."""
tasks = [
"focus-android:assemble{focus.variant.name}".format(focus=build_config.focus),
]
if aab_enabled:
tasks += [
"focus-android:bundle{focus.variant.name}".format(focus=build_config.focus),
]
return tasks
set_config(
"GRADLE_ANDROID_ARCHIVE_FOCUS_SUBPROJECT_TASKS",
gradle_android_archive_focus_subproject_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_geckoview_docs_tasks(build_config):
"""Gradle tasks run by |mach android geckoview-docs|."""
return [
"geckoview:javadoc{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config("GRADLE_ANDROID_GECKOVIEW_DOCS_TASKS", gradle_android_geckoview_docs_tasks)
@depends(gradle_android_build_config)
def gradle_android_geckoview_docs_archive_tasks(build_config):
"""Gradle tasks run by |mach android geckoview-docs --archive| or |... --upload."""
return [
"geckoview:javadocCopyJar{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config(
"GRADLE_ANDROID_GECKOVIEW_DOCS_ARCHIVE_TASKS",
gradle_android_geckoview_docs_archive_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_geckoview_docs_output_files(build_config):
"""Output files for GeckoView javadoc."""
def uncapitalize(s):
if s:
return s[0].lower() + s[1:]
else:
return s
variant = uncapitalize(build_config.geckoview.variant.name)
return [
"gradle/build/mobile/android/geckoview/reports/javadoc-results-{}.json".format(
variant
),
]
set_config(
"GRADLE_ANDROID_GECKOVIEW_DOCS_OUTPUT_FILES",
gradle_android_geckoview_docs_output_files,
)
@depends(gradle_android_build_config)
def gradle_android_archive_coverage_artifacts_tasks(build_config):
"""Gradle tasks run by |mach android archive-coverage-artifacts|."""
return [
"geckoview:archiveClassfiles{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
"geckoview:copyCoverageDependencies",
]
set_config(
"GRADLE_ANDROID_ARCHIVE_COVERAGE_ARTIFACTS_TASKS",
gradle_android_archive_coverage_artifacts_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_build_geckoview_example_tasks(build_config):
"""Gradle tasks run by |mach android build-geckoview_example|."""
return [
"geckoview_example:assemble{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"geckoview_example:bundle{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
"geckoview:assemble{geckoview.variant.name}AndroidTest".format(
geckoview=build_config.geckoview
),
"test_runner:assemble{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
"test_runner:bundle{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config(
"GRADLE_ANDROID_BUILD_GECKOVIEW_EXAMPLE_TASKS",
gradle_android_build_geckoview_example_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_compile_all_tasks(build_config):
"""Gradle tasks run by |mach android compile-all|.
This is the list of all compile* tasks output by `gradlew tasks`.
Some of those tasks names are shared between multiple projects, for instance passing compileSources to Gradle will trigger all of:
- geckoview:compileSources
- geckoview_example:compileSources
- test_runner:compileSources
- messaging_example:compileSources
- port_messaging_example:compileSources
"""
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
buildType = capitalize(build_config.geckoview.variant.buildType)
tasks = [
f"compileJava",
f"compileTestJava",
f"compileKotlin",
f"compileTestKotlin",
]
# "" is for GeckoView
for app in ["", "Fenix", "Focus", "Klar"]:
tasks += [
f"compile{app}{buildType}Sources",
f"compile{app}{buildType}UnitTestSources",
]
# those tasks do not appear to have a Release variant
if buildType == "Debug":
for app in ["", "Fenix", "Focus", "Klar"]:
tasks += [
f"compile{app}{buildType}AndroidTestSources",
]
for app in ["Gecko", "System"]:
tasks += [
f"compile{app}{buildType}Sources",
f"compile{app}{buildType}UnitTestSources",
f"compile{app}{buildType}AndroidTestSources",
]
return tasks
set_config(
"GRADLE_ANDROID_COMPILE_ALL_TASKS",
gradle_android_compile_all_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_install_geckoview_test_runner_tasks(build_config):
"""Gradle tasks run by |mach android install-geckoview-test_runner|."""
return [
"test_runner:install{geckoview.variant.name}".format(
geckoview=build_config.geckoview
),
]
set_config(
"GRADLE_ANDROID_INSTALL_GECKOVIEW_TEST_RUNNER_TASKS",
gradle_android_install_geckoview_test_runner_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_install_geckoview_test_tasks(build_config):
"""Gradle tasks run by |mach android install-geckoview-test|."""
return [
"geckoview:install{geckoview.variant.name}AndroidTest".format(
geckoview=build_config.geckoview
),
]
set_config(
"GRADLE_ANDROID_INSTALL_GECKOVIEW_TEST_TASKS",
gradle_android_install_geckoview_test_tasks,
)
@depends(gradle_android_build_config)
def gradle_android_install_geckoview_example_tasks(build_config):
"""Gradle tasks run by |mach android install-geckoview_example|."""
return [
"geckoview_example:install{geckoview_example.variant.name}".format(
geckoview_example=build_config.geckoview_example
),
]
set_config(
"GRADLE_ANDROID_INSTALL_GECKOVIEW_EXAMPLE_TASKS",
gradle_android_install_geckoview_example_tasks,
)
@depends(
gradle_android_api_lint_tasks,
gradle_android_format_lint_check_tasks,
gradle_android_checkstyle_tasks,
)
@imports(_from="itertools", _import="chain")
def gradle_android_dependencies_tasks(*tasks):
"""Gradle tasks run by |mach android dependencies|."""
# The union, plus a bit more, of all of the Gradle tasks
# invoked by the android-* automation jobs.
return list(t for t in chain(*tasks))
set_config("GRADLE_ANDROID_DEPENDENCIES_TASKS", gradle_android_dependencies_tasks)
# Automation uses this to change log levels, not use the daemon, and use
# offline mode.
option(env="GRADLE_FLAGS", default="", help="Flags to pass to Gradle")
@depends("GRADLE_FLAGS")
def gradle_flags(value):
return value[0] if value else ""
set_config("GRADLE_FLAGS", gradle_flags)
# Local developer default is (maven.google.com).
option(
env="GRADLE_MAVEN_REPOSITORIES",
nargs="+",
default=(
),
help="Comma-separated URLs of Maven repositories containing Gradle dependencies",
)
option(
"--allow-insecure-gradle-repositories",
help="Gradle is allowed to connect to insecure Maven repositories",
)
set_config(
"ALLOW_INSECURE_GRADLE_REPOSITORIES",
True,
when="--allow-insecure-gradle-repositories",
)
option(
"--download-all-gradle-dependencies",
help="Download all dependencies, even those that are conditionally used",
)
set_config(
"DOWNLOAD_ALL_GRADLE_DEPENDENCIES",
True,
when="--download-all-gradle-dependencies",
)
@depends("GRADLE_MAVEN_REPOSITORIES")
@imports(_from="os.path", _import="isdir")
def gradle_maven_repositories(values):
if not values:
die("GRADLE_MAVEN_REPOSITORIES must not be empty")
if not all(values):
die("GRADLE_MAVEN_REPOSITORIES entries must not be empty")
return values
set_config("GRADLE_MAVEN_REPOSITORIES", gradle_maven_repositories)
@imports(_from="sys", _import="prefix")
def gradle_glean_parser_venv():
return prefix
set_config("GRADLE_GLEAN_PARSER_VENV", gradle_glean_parser_venv())