Skip to content

Commit

Permalink
Add Jetifier support. (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
jin authored Dec 27, 2019
1 parent 7badfbe commit 9aec21a
Show file tree
Hide file tree
Showing 28 changed files with 460 additions and 23 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Table of Contents
* [Repository remapping](#repository-remapping)
* [Hiding transitive dependencies](#hiding-transitive-dependencies)
* [Fetch and resolve timeout](#fetch-and-resolve-timeout)
* [Jetifier](#jetifier)
* [Exporting and consuming artifacts from external repositories](#exporting-and-consuming-artifacts-from-external-repositories)
* [Demo](#demo)
* [Projects using rules_jvm_external](#projects-using-rules_jvm_external)
Expand Down Expand Up @@ -778,6 +779,27 @@ maven_install(
)
```

### Jetifier

As part of the [Android
Jetpack](https://medium.com/google-developer-experts/converting-your-android-app-to-jetpack-85aecfce34d3)
migration, convert legacy Android support library (`com.android.support`)
libraries to rely on new AndroidX packages using the
[Jetifier](https://developer.android.com/studio/command-line/jetifier) tool.
Enable jetification by specifying `jetify = True` in `maven_install.`

```python
maven_install(
artifacts = [
# ...
],
repositories = [
# ...
],
jetify = True,
)
```

## Exporting and consuming artifacts from external repositories

If you're writing a library that has dependencies, you should define a constant that
Expand Down
13 changes: 13 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,19 @@ maven_install(
use_unsafe_shared_cache = True,
)

maven_install(
name = "jetify_test",
artifacts = [
"com.google.guava:guava:27.0-jre",
"com.android.support:appcompat-v7:28.0.0"
],
repositories = [
"https://jcenter.bintray.com/",
"https://maven.google.com",
],
jetify = True,
)

RULES_KOTLIN_VERSION = "8ca948548159f288450516a09248dcfb9e957804"

http_archive(
Expand Down
21 changes: 4 additions & 17 deletions coursier.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ package(default_visibility = ["//visibility:{visibility}"])
exports_files(["pin"])
load("@{repository_name}//:jvm_import.bzl", "jvm_import")
load("@rules_jvm_external//private/rules:jvm_import.bzl", "jvm_import")
load("@rules_jvm_external//private/rules:jetifier.bzl", "jetify_aar_import", "jetify_jvm_import")
{imports}
"""
Expand Down Expand Up @@ -327,13 +328,6 @@ def _pinned_coursier_fetch_impl(repository_ctx):
override_targets = repository_ctx.attr.override_targets,
)

repository_ctx.template(
"jvm_import.bzl",
repository_ctx.attr._jvm_import,
substitutions = {},
executable = False, # not executable
)

repository_ctx.template(
"compat_repository.bzl",
repository_ctx.attr._compat_repository,
Expand Down Expand Up @@ -656,13 +650,6 @@ def _coursier_fetch_impl(repository_ctx):
override_targets = repository_ctx.attr.override_targets,
)

repository_ctx.template(
"jvm_import.bzl",
repository_ctx.attr._jvm_import,
substitutions = {},
executable = False, # not executable
)

repository_ctx.file(
"BUILD",
_BUILD.format(
Expand Down Expand Up @@ -764,7 +751,6 @@ def _coursier_fetch_impl(repository_ctx):

pinned_coursier_fetch = repository_rule(
attrs = {
"_jvm_import": attr.label(default = "//:private/jvm_import.bzl"),
"_compat_repository": attr.label(default = "//:private/compat_repository.bzl"),
"artifacts": attr.string_list(), # list of artifact objects, each as json
"fetch_sources": attr.bool(default = False),
Expand All @@ -779,14 +765,14 @@ pinned_coursier_fetch = repository_rule(
""",
default = False,
),
"jetify": attr.bool(doc = "Runs the AndroidX Jetifier tool on all artifacts.", default = False)
},
implementation = _pinned_coursier_fetch_impl,
)

coursier_fetch = repository_rule(
attrs = {
"_sha256_hasher": attr.label(default = "//private/tools/prebuilt:hasher_deploy.jar"),
"_jvm_import": attr.label(default = "//:private/jvm_import.bzl"),
"_pin": attr.label(default = "//:private/pin.sh"),
"_compat_repository": attr.label(default = "//:private/compat_repository.bzl"),
"repositories": attr.string_list(), # list of repository objects, each as json
Expand Down Expand Up @@ -819,6 +805,7 @@ coursier_fetch = repository_rule(
default = False,
),
"resolve_timeout": attr.int(default = 600),
"jetify": attr.bool(doc = "Runs the AndroidX Jetifier tool on all artifacts.", default = False)
},
environ = [
"JAVA_HOME",
Expand Down
6 changes: 5 additions & 1 deletion defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def maven_install(
maven_install_json = None,
override_targets = {},
strict_visibility = False,
resolve_timeout = 600):
resolve_timeout = 600,
jetify = False):
"""Resolves and fetches artifacts transitively from Maven repositories.
This macro runs a repository rule that invokes the Coursier CLI to resolve
Expand Down Expand Up @@ -62,6 +63,7 @@ def maven_install(
are private and invisible to user's rules. If `False`, transitive dependencies are public and
visible to user's rules.
resolve_timeout: The execution timeout of resolving and fetching artifacts.
jetify: Runs the AndroidX jetifier tool on all artifacts.
"""
repositories_json_strings = []
for repository in parse.parse_repository_spec_list(repositories):
Expand Down Expand Up @@ -104,6 +106,7 @@ def maven_install(
strict_visibility = strict_visibility,
maven_install_json = maven_install_json,
resolve_timeout = resolve_timeout,
jetify = jetify,
)

if maven_install_json != None:
Expand All @@ -116,6 +119,7 @@ def maven_install(
generate_compat_repositories = generate_compat_repositories,
override_targets = override_targets,
strict_visibility = strict_visibility,
jetify = jetify,
)

def artifact(a, repository_name = DEFAULT_REPOSITORY_NAME):
Expand Down
3 changes: 2 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ load("@rules_jvm_external//:defs.bzl", "maven_install", "artifact")
maven_install(<a href="#maven_install-name">name</a>, <a href="#maven_install-repositories">repositories</a>, <a href="#maven_install-artifacts">artifacts</a>, <a href="#maven_install-fail_on_missing_checksum">fail_on_missing_checksum</a>, <a href="#maven_install-fetch_sources">fetch_sources</a>,
<a href="#maven_install-use_unsafe_shared_cache">use_unsafe_shared_cache</a>, <a href="#maven_install-excluded_artifacts">excluded_artifacts</a>, <a href="#maven_install-generate_compat_repositories">generate_compat_repositories</a>,
<a href="#maven_install-version_conflict_policy">version_conflict_policy</a>, <a href="#maven_install-maven_install_json">maven_install_json</a>, <a href="#maven_install-override_targets">override_targets</a>, <a href="#maven_install-strict_visibility">strict_visibility</a>,
<a href="#maven_install-resolve_timeout">resolve_timeout</a>)
<a href="#maven_install-resolve_timeout">resolve_timeout</a>, <a href="#maven_install-jetify">jetify</a>)
</pre>

Resolves and fetches artifacts transitively from Maven repositories.
Expand All @@ -57,6 +57,7 @@ and fetch Maven artifacts transitively.
| override_targets | A mapping of <code>group:artifact</code> to Bazel target labels. All occurrences of the target label for <code>group:artifact</code> will be an alias to the specified label, therefore overriding the original generated <code>jvm_import</code> or <code>aar_import</code> target. | <code>{}</code> |
| strict_visibility | Controls visibility of transitive dependencies. If <code>True</code>, transitive dependencies are private and invisible to user's rules. If <code>False</code>, transitive dependencies are public and visible to user's rules. | <code>False</code> |
| resolve_timeout | The execution timeout of resolving and fetching artifacts. | <code>600</code> |
| jetify | Runs the AndroidX jetifier tool on all artifacts. | <code>False</code> |


# Maven specification functions
Expand Down
9 changes: 6 additions & 3 deletions private/dependency_tree_parser.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,22 @@ def _generate_imports(repository_ctx, dep_tree, explicit_artifacts, neverlink_ar

# 1. Generate the rule class.
#
# java_import(
# (jetify_)(jvm|aar)_import(
#
packaging = artifact_path.split(".").pop()
if packaging == "jar":
# Regular `java_import` invokes ijar on all JARs, causing some Scala and
# Kotlin compile interface JARs to be incorrect. We replace java_import
# with a simple jvm_import Starlark rule that skips ijar.
target_import_string = ["jvm_import("]
import_rule = "jvm_import"
jar_versionless_target_labels.append(target_label)
elif packaging == "aar":
target_import_string = ["aar_import("]
import_rule = "aar_import"
else:
fail("Unsupported packaging type: " + packaging)
if repository_ctx.attr.jetify:
import_rule = "jetify_" + import_rule
target_import_string = [import_rule + "("]

# 2. Generate the target label.
#
Expand Down
1 change: 1 addition & 0 deletions private/rules/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports_files(["jvm_import.bzl", "jetifier.bzl"])
59 changes: 59 additions & 0 deletions private/rules/jetifier.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
load(":jvm_import.bzl", "jvm_import")

def _jetify_impl(ctx):
srcs = ctx.attr.srcs
outfiles = []
for src in srcs:
for artifact in src.files.to_list():
jetified_outfile = ctx.actions.declare_file("jetified_" + artifact.basename, sibling = artifact)
jetify_args = ctx.actions.args()
jetify_args.add("-l", "error")
jetify_args.add("-o", jetified_outfile)
jetify_args.add("-i", artifact)
ctx.actions.run(
mnemonic = "Jetify",
inputs = [artifact],
outputs = [jetified_outfile],
progress_message = "Jetifying {}".format(artifact.owner),
executable = ctx.executable._jetifier,
arguments = [jetify_args],
)
outfiles.append(jetified_outfile)

return [DefaultInfo(files = depset(outfiles))]

jetify = rule(
attrs = {
"srcs": attr.label_list(allow_files = [".jar", ".aar"]),
"_jetifier": attr.label(
executable = True,
default = Label("@rules_jvm_external//third_party/jetifier"),
cfg = "host",
),
},
implementation = _jetify_impl,
)

def jetify_aar_import(name, aar, **kwargs):
jetify(
name = "jetified_" + name,
srcs = [aar],
)

native.aar_import(
name = name,
aar = ":jetified_" + name,
**kwargs
)

def jetify_jvm_import(name, jars, **kwargs):
jetify(
name = "jetified_" + name,
srcs = jars,
)

jvm_import(
name = name,
jars = [":jetified_" + name],
**kwargs
)
2 changes: 1 addition & 1 deletion private/jvm_import.bzl → private/rules/jvm_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _jvm_import_impl(ctx):
jar = "%s/bin/jar" % ctx.attr._host_javabase[java_common.JavaRuntimeInfo].java_home,
manifest_update_file = manifest_update_file.path,
output_jar = outjar.path,
)
),
]),
mnemonic = "StampJar",
progress_message = "Stamping manifest of %s" % ctx.label,
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/jetifier/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")

build_test(
name = "jetified_artifacts",
targets = [
"@jetify_test//:com_google_guava_guava",
"@jetify_test//:com_android_support_appcompat_v7",
],
)

genrule(
name = "jetified_support_library_classes",
srcs = ["@jetify_test//:jetified_com_android_support_appcompat_v7"],
outs = ["jetified_classes.jar"],
cmd = "unzip -p $< classes.jar > $@",
)

sh_test(
name = "test_jetified_classes_jar",
size = "small",
srcs = ["jetifier_test.sh"],
data = [":jetified_classes.jar"],
deps = ["@bazel_tools//tools/bash/runfiles"],
)
17 changes: 17 additions & 0 deletions tests/unit/jetifier/jetifier_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# --- begin runfiles.bash initialization v2 ---
# Copy-pasted from the Bazel Bash runfiles library v2.
set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v2 ---

set -euox pipefail

classes_jar=$(rlocation rules_jvm_external/tests/unit/jetifier/jetified_classes.jar)

jar tf $classes_jar | grep "androidx/appcompat"
jar tf $classes_jar | grep -v "android/support/v7"
13 changes: 13 additions & 0 deletions third_party/jetifier/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
java_import(
name = "jetifier_jars",
jars = glob(["jetifier-standalone/lib/*.jar"]),
)

java_binary(
name = "jetifier",
main_class = "com.android.tools.build.jetifier.standalone.Main",
runtime_deps = [
":jetifier_jars"
],
visibility = ["//visibility:public"],
)
5 changes: 5 additions & 0 deletions third_party/jetifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Jetifier

Downloaded from https://developer.android.com/studio/command-line/jetifier.

SHA256: `8ef877e8245f8dcf8f379b2cdc4958ba714147eb8d559d8334a1840e137e5a2c`
Loading

0 comments on commit 9aec21a

Please sign in to comment.