Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 165 additions & 16 deletions rules/android_sdk_repository/rule.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,52 @@ _DIRS_TO_LINK = [

_MIN_BUILD_TOOLS_VERSION = parse_android_revision("30.0.0")

def sdk_package(
linux_url = None,
linux_sha256 = None,
darwin_url = None,
darwin_sha256 = None,
windows_url = None,
windows_sha256 = None,
strip_prefix = None,
add_prefix = None):
"""Creates a dictionary for an SDK package for multiple platforms.

Args:
linux_url: The download URL for the Linux package.
linux_sha256: The SHA256 checksum for the Linux package.
darwin_url: The download URL for the Darwin (macOS) package.
darwin_sha256: The SHA256 checksum for the Darwin (macOS) package.
windows_url: The download URL for the Windows package.
windows_sha256: The SHA256 checksum for the Windows package.
strip_prefix: A directory prefix to strip from the extracted files.
add_prefix: A directory prefix to add to the output path.

Returns:
A dictionary formatted for the android_sdk_repository rule.
"""
package = {}
if linux_url:
if not linux_sha256:
fail("linux_sha256 must be provided with linux_url")
package["linux_url"] = linux_url
package["linux_sha256"] = linux_sha256
if darwin_url:
if not darwin_sha256:
fail("darwin_sha256 must be provided with darwin_url")
package["darwin_url"] = darwin_url
package["darwin_sha256"] = darwin_sha256
if windows_url:
if not windows_sha256:
fail("windows_sha256 must be provided with windows_url")
package["windows_url"] = windows_url
package["windows_sha256"] = windows_sha256
if strip_prefix:
package["strip_prefix"] = strip_prefix
if add_prefix:
package["add_prefix"] = add_prefix
return package

def _read_api_levels(repo_ctx, android_sdk_path):
platforms_dir = "%s/%s" % (android_sdk_path, _PLATFORMS_DIR)
api_levels = []
Expand Down Expand Up @@ -90,23 +136,18 @@ def _find_system_images(repo_ctx, android_sdk_path):

return system_images

def _android_sdk_repository_impl(repo_ctx):
# Determine the SDK path to use, either from the attribute or the environment.
android_sdk_path = repo_ctx.attr.path
if not android_sdk_path:
android_sdk_path = repo_ctx.getenv("ANDROID_HOME")
if not android_sdk_path:
# Create an empty repository that allows non-Android code to build.
repo_ctx.template("BUILD.bazel", _EMPTY_SDK_REPO_TEMPLATE)
return None
if android_sdk_path.startswith("$WORKSPACE_ROOT"):
android_sdk_path = str(repo_ctx.workspace_root) + android_sdk_path.removeprefix("$WORKSPACE_ROOT")
def _get_platform_key(repo_ctx):
os_name = repo_ctx.os.name.lower()
if "linux" in os_name:
return "linux"
if "mac os x" in os_name:
return "darwin"
if "windows" in os_name:
return "windows"
fail("Unsupported operating system: " + repo_ctx.os.name)

# Symlink the needed contents to this repository.
for dir_to_link in _DIRS_TO_LINK:
source = "%s/%s" % (android_sdk_path, dir_to_link)
dest = dir_to_link
repo_ctx.symlink(source, dest)
def _configure_sdk_repository(repo_ctx, android_sdk_path):
"""Common logic for configuring the Android SDK repository."""

# Read list of supported SDK levels
api_levels = _read_api_levels(repo_ctx, android_sdk_path)
Expand Down Expand Up @@ -164,6 +205,114 @@ def _android_sdk_repository_impl(repo_ctx):
# repo is reproducible
return None

def _sandboxed_android_sdk_repository_impl(repo_ctx):
platform_key = _get_platform_key(repo_ctx)

sdk_packages = {
"build_tools": _BUILD_TOOLS_DIR,
"cmdline_tools": "cmdline-tools",
"emulator": "emulator",
"ndk": "ndk",
"platform_tools": "platform-tools",
"platforms": _PLATFORMS_DIR,
}
for attr_name, output_dir in sdk_packages.items():
attr_value = getattr(repo_ctx.attr, attr_name)
url_key = platform_key + "_url"
sha256_key = platform_key + "_sha256"
if url_key not in attr_value:
fail("Missing URL for package '{}' on platform '{}'".format(attr_name, platform_key))

output_path = output_dir
add_prefix = attr_value.get("add_prefix")
if add_prefix:
output_path = output_path + "/" + add_prefix

repo_ctx.download_and_extract(
url = attr_value[url_key],
sha256 = attr_value[sha256_key],
output = output_path,
stripPrefix = attr_value.get("strip_prefix", ""),
)

return _configure_sdk_repository(repo_ctx, "./")

_sandboxed_android_sdk_repository = repository_rule(
implementation = _sandboxed_android_sdk_repository_impl,
attrs = {
"api_level": attr.int(default = 0),
"build_tools_version": attr.string(),
"build_tools": attr.string_dict(mandatory = True),
"cmdline_tools": attr.string_dict(mandatory = True),
"emulator": attr.string_dict(mandatory = True),
"ndk": attr.string_dict(mandatory = True),
"platform_tools": attr.string_dict(mandatory = True),
"platforms": attr.string_dict(mandatory = True),
},
local = True,
)

def sandboxed_android_sdk_repository(
name,
build_tools,
cmdline_tools,
emulator,
ndk,
platform_tools,
platforms,
api_level = 0,
build_tools_version = ""):
"""Create a repository with Android SDK toolchains.

This rule downloads the Android SDK components from the provided URLs.

Args:
name: The repository name.
build_tools: A dictionary with "url" and "sha256" for the build tools.
cmdline_tools: A dictionary with "url" and "sha256" for the command-line tools.
emulator: A dictionary with "url" and "sha256" for the emulator.
ndk: A dictionary with "url" and "sha256" for the NDK.
platform_tools: A dictionary with "url" and "sha256" for the platform tools.
platforms: A dictionary with "url" and "sha256" for the platforms.
api_level: The SDK API level to use.
build_tools_version: The build_tools in the SDK to use.
"""

_sandboxed_android_sdk_repository(
name = name,
build_tools = build_tools,
cmdline_tools = cmdline_tools,
emulator = emulator,
ndk = ndk,
platform_tools = platform_tools,
platforms = platforms,
api_level = api_level,
build_tools_version = build_tools_version,
)

native.register_toolchains("@%s//:sdk-toolchain" % name)
native.register_toolchains("@%s//:all" % name)

def _android_sdk_repository_impl(repo_ctx):
# Determine the SDK path to use, either from the attribute or the environment.
android_sdk_path = repo_ctx.attr.path
if not android_sdk_path:
android_sdk_path = repo_ctx.os.environ.get("ANDROID_HOME")
if not android_sdk_path:
# Create an empty repository that allows non-Android code to build.
repo_ctx.template("BUILD.bazel", _EMPTY_SDK_REPO_TEMPLATE)
return None
if android_sdk_path.startswith("$WORKSPACE_ROOT"):
android_sdk_path = str(repo_ctx.workspace_root) + android_sdk_path.removeprefix("$WORKSPACE_ROOT")

# Symlink the needed contents to this repository.
for dir_to_link in _DIRS_TO_LINK:
source = "%s/%s" % (android_sdk_path, dir_to_link)
dest = dir_to_link
repo_ctx.symlink(source, dest)

return _configure_sdk_repository(repo_ctx, android_sdk_path)

_android_sdk_repository = repository_rule(
implementation = _android_sdk_repository_impl,
attrs = {
Expand Down
16 changes: 10 additions & 6 deletions rules/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

# Don't use relative paths since this file is coppied to //android/rules.bzl.

load(
"//providers:providers.bzl",
_AndroidAppsInfo = "AndroidAppsInfo",
_ApkInfo = "ApkInfo",
_StarlarkApkInfo = "StarlarkApkInfo",
)
load(
"//rules:android_sdk.bzl",
_android_sdk = "android_sdk",
Expand All @@ -27,12 +33,6 @@ load(
"//rules:instrumented_app_info_aspect.bzl",
_instrumented_app_info_aspect = "instrumented_app_info_aspect",
)
load(
"//providers:providers.bzl",
_AndroidAppsInfo = "AndroidAppsInfo",
_ApkInfo = "ApkInfo",
_StarlarkApkInfo = "StarlarkApkInfo",
)
load(
"//rules/aar_import:rule.bzl",
_aar_import = "aar_import",
Expand Down Expand Up @@ -68,6 +68,8 @@ load(
load(
"//rules/android_sdk_repository:rule.bzl",
_android_sdk_repository = "android_sdk_repository",
_sandboxed_android_sdk_repository = "sandboxed_android_sdk_repository",
_sdk_package = "sdk_package",
)

# Current version. Tools may check this to determine compatibility.
Expand All @@ -82,6 +84,8 @@ android_sandboxed_sdk = _android_sandboxed_sdk
android_sandboxed_sdk_bundle = _android_sandboxed_sdk_bundle
android_sdk = _android_sdk
android_sdk_repository = _android_sdk_repository
sandboxed_android_sdk_repository = _sandboxed_android_sdk_repository
sdk_package = _sdk_package
android_tools_defaults_jar = _android_tools_defaults_jar
asar_import = _asar_import
instrumented_app_info_aspect = _instrumented_app_info_aspect
Expand Down