Skip to content

Commit

Permalink
Add experimental api crate_deps and all_crate_deps macro for gath…
Browse files Browse the repository at this point in the history
…ering package dependencies (#319)

* The crates.bzl can be used to locate crates

* Updated smoketest

* Updated examples

* It should not be an error that no dependencies are found.

The use case here is users might want to stub out all the dependency sections of their crates such that subsequent runs of `cargo raze` will automatically add new dependencies.

* Updated examples

* New API has been flagged experimental

* Updated examples

* Updated more comments

* Updated examples

* Updated documentation

* Addressed PR feedback.

* Updated examples

* Addressed PR feedback

* Updated examples

* Addressed PR feedback

* Updated examples

* Fixed typo

* Updated

* Added experimental_api flag

* Updated smoketest

* Updated examples

* Fixed buildifier defects

* Updated examples

* Addressed PR feedback

* Updated examples

* Addressed PR feedback

* Updated examples

* Addressed PR feedback

* Updated examples

* updated smoketest

* Updated examples

* Cleanup

* Updated examples

* Updated macros `crates` -> `crate_deps` and `all_crates` -> `all_crate_deps`

* Updated examples
  • Loading branch information
UebelAndre authored Dec 29, 2020
1 parent 0c49c1f commit 9d01e89
Show file tree
Hide file tree
Showing 32 changed files with 927 additions and 71 deletions.
5 changes: 2 additions & 3 deletions examples/remote/binary_dependencies/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
load("//remote/binary_dependencies/cargo:crates.bzl", "all_crate_deps")

package(default_visibility = ["//visibility:public"])

Expand All @@ -8,7 +9,5 @@ rust_binary(
data = [
"//remote/binary_dependencies/cargo:cargo_bin_texture_synthesis",
],
deps = [
"//remote/binary_dependencies/cargo:ferris_says",
],
deps = all_crate_deps(),
)
1 change: 1 addition & 0 deletions examples/remote/binary_dependencies/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ gen_workspace_prefix = "remote_binary_dependencies"
genmode = "Remote"
default_gen_buildrs = true
package_aliases_dir = "cargo"
experimental_api = true

[package.metadata.raze.binary_deps]
texture-synthesis-cli = "0.8.0"
Expand Down
158 changes: 158 additions & 0 deletions examples/remote/binary_dependencies/cargo/crates.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,164 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") # bui
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # buildifier: disable=load
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") # buildifier: disable=load

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of normal dependencies for the Rust targets of that package.
_DEPENDENCIES = {
"remote/binary_dependencies": {
"ferris-says": "@remote_binary_dependencies__ferris_says__0_2_0//:ferris_says",
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of proc_macro dependencies for the Rust targets of that package.
_PROC_MACRO_DEPENDENCIES = {
"remote/binary_dependencies": {
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of normal dev dependencies for the Rust targets of that package.
_DEV_DEPENDENCIES = {
"remote/binary_dependencies": {
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of proc_macro dev dependencies for the Rust targets of that package.
_DEV_PROC_MACRO_DEPENDENCIES = {
"remote/binary_dependencies": {
},
}

def crate_deps(deps, package_name = None):
"""EXPERIMENTAL -- MAY CHANGE AT ANY TIME: Finds the fully qualified label of the requested crates for the package where this macro is called.
WARNING: This macro is part of an expeirmental API and is subject to change.
Args:
deps (list): The desired list of crate targets.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()`.
Returns:
list: A list of labels to cargo-raze generated targets (str)
"""

if not package_name:
package_name = native.package_name()

# Join both sets of dependencies
dependencies = _flatten_dependency_maps([
_DEPENDENCIES,
_PROC_MACRO_DEPENDENCIES,
_DEV_DEPENDENCIES,
_DEV_PROC_MACRO_DEPENDENCIES,
])

if not deps:
return []

missing_crates = []
crate_targets = []
for crate_target in deps:
if crate_target not in dependencies[package_name]:
missing_crates.append(crate_target)
else:
crate_targets.append(dependencies[package_name][crate_target])

if missing_crates:
fail("Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`".format(
missing_crates,
package_name,
dependencies[package_name],
))

return crate_targets

def all_crate_deps(normal = False, normal_dev = False, proc_macro = False, proc_macro_dev = False, package_name = None):
"""EXPERIMENTAL -- MAY CHANGE AT ANY TIME: Finds the fully qualified label of all requested direct crate dependencies \
for the package where this macro is called.
If no parameters are set, all normal dependencies are returned. Setting any one flag will
otherwise impact the contents of the returned list.
Args:
normal (bool, optional): If True, normal dependencies are included in the
output list. Defaults to False.
normal_dev (bool, optional): If True, normla dev dependencies will be
included in the output list. Defaults to False.
proc_macro (bool, optional): If True, proc_macro dependencies are included
in the output list. Defaults to False.
proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are
included in the output list. Defaults to False.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()`.
Returns:
list: A list of labels to cargo-raze generated targets (str)
"""

if not package_name:
package_name = native.package_name()

# Determine the relevant maps to use
all_dependency_maps = []
if normal:
all_dependency_maps.append(_DEPENDENCIES)
if normal_dev:
all_dependency_maps.append(_DEV_DEPENDENCIES)
if proc_macro:
all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)
if proc_macro_dev:
all_dependency_maps.append(_DEV_PROC_MACRO_DEPENDENCIES)

# Default to always using normal dependencies
if not all_dependency_maps:
all_dependency_maps.append(_DEPENDENCIES)

dependencies = _flatten_dependency_maps(all_dependency_maps)

if not dependencies:
return []

return dependencies[package_name].values()

def _flatten_dependency_maps(all_dependency_maps):
"""Flatten a list of dependency maps into one dictionary.
Dependency maps have the following structure:
```python
DEPENDENCIES_MAP = {
# The first key in the map is a Bazel package
# name of the workspace this file is defined in.
"package_name": {
# An alias to a crate target. # The label of the crate target the
# Aliases are only crate names. # alias refers to.
"alias": "@full//:label",
}
}
```
Args:
all_dependency_maps (list): A list of dicts as described above
Returns:
dict: A dictionary as described above
"""
dependencies = {}

for dep_map in all_dependency_maps:
for pkg_name in dep_map:
if pkg_name not in dependencies:
# Add a non-frozen dict to the collection of dependencies
dependencies.setdefault(pkg_name, dict(dep_map[pkg_name].items()))
continue

duplicate_crate_aliases = [key for key in dependencies[pkg_name] if key in dep_map[pkg_name]]
if duplicate_crate_aliases:
fail("There should be no duplicate crate aliases: {}".format(duplicate_crate_aliases))

dependencies[pkg_name].update(dep_map[pkg_name])

return dependencies

def remote_binary_dependencies_fetch_remote_crates():
"""This function defines a collection of repos and should be called in a WORKSPACE file"""
maybe(
Expand Down
1 change: 1 addition & 0 deletions examples/remote/cargo_workspace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ gen_workspace_prefix = "remote_cargo_workspace"
genmode = "Remote"
default_gen_buildrs = true
package_aliases_dir = "cargo"
experimental_api = true
176 changes: 176 additions & 0 deletions examples/remote/cargo_workspace/cargo/crates.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,182 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") # bui
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # buildifier: disable=load
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") # buildifier: disable=load

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of normal dependencies for the Rust targets of that package.
_DEPENDENCIES = {
"remote/cargo_workspace/num_printer": {
"clap": "@remote_cargo_workspace__clap__2_33_3//:clap",
},
"remote/cargo_workspace/printer": {
"ferris-says": "@remote_cargo_workspace__ferris_says__0_2_0//:ferris_says",
},
"remote/cargo_workspace/rng": {
"rand": "@remote_cargo_workspace__rand__0_7_3//:rand",
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of proc_macro dependencies for the Rust targets of that package.
_PROC_MACRO_DEPENDENCIES = {
"remote/cargo_workspace/num_printer": {
},
"remote/cargo_workspace/printer": {
},
"remote/cargo_workspace/rng": {
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of normal dev dependencies for the Rust targets of that package.
_DEV_DEPENDENCIES = {
"remote/cargo_workspace/num_printer": {
},
"remote/cargo_workspace/printer": {
},
"remote/cargo_workspace/rng": {
},
}

# EXPERIMENTAL -- MAY CHANGE AT ANY TIME: A mapping of package names to a set of proc_macro dev dependencies for the Rust targets of that package.
_DEV_PROC_MACRO_DEPENDENCIES = {
"remote/cargo_workspace/num_printer": {
},
"remote/cargo_workspace/printer": {
},
"remote/cargo_workspace/rng": {
},
}

def crate_deps(deps, package_name = None):
"""EXPERIMENTAL -- MAY CHANGE AT ANY TIME: Finds the fully qualified label of the requested crates for the package where this macro is called.
WARNING: This macro is part of an expeirmental API and is subject to change.
Args:
deps (list): The desired list of crate targets.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()`.
Returns:
list: A list of labels to cargo-raze generated targets (str)
"""

if not package_name:
package_name = native.package_name()

# Join both sets of dependencies
dependencies = _flatten_dependency_maps([
_DEPENDENCIES,
_PROC_MACRO_DEPENDENCIES,
_DEV_DEPENDENCIES,
_DEV_PROC_MACRO_DEPENDENCIES,
])

if not deps:
return []

missing_crates = []
crate_targets = []
for crate_target in deps:
if crate_target not in dependencies[package_name]:
missing_crates.append(crate_target)
else:
crate_targets.append(dependencies[package_name][crate_target])

if missing_crates:
fail("Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`".format(
missing_crates,
package_name,
dependencies[package_name],
))

return crate_targets

def all_crate_deps(normal = False, normal_dev = False, proc_macro = False, proc_macro_dev = False, package_name = None):
"""EXPERIMENTAL -- MAY CHANGE AT ANY TIME: Finds the fully qualified label of all requested direct crate dependencies \
for the package where this macro is called.
If no parameters are set, all normal dependencies are returned. Setting any one flag will
otherwise impact the contents of the returned list.
Args:
normal (bool, optional): If True, normal dependencies are included in the
output list. Defaults to False.
normal_dev (bool, optional): If True, normla dev dependencies will be
included in the output list. Defaults to False.
proc_macro (bool, optional): If True, proc_macro dependencies are included
in the output list. Defaults to False.
proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are
included in the output list. Defaults to False.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()`.
Returns:
list: A list of labels to cargo-raze generated targets (str)
"""

if not package_name:
package_name = native.package_name()

# Determine the relevant maps to use
all_dependency_maps = []
if normal:
all_dependency_maps.append(_DEPENDENCIES)
if normal_dev:
all_dependency_maps.append(_DEV_DEPENDENCIES)
if proc_macro:
all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)
if proc_macro_dev:
all_dependency_maps.append(_DEV_PROC_MACRO_DEPENDENCIES)

# Default to always using normal dependencies
if not all_dependency_maps:
all_dependency_maps.append(_DEPENDENCIES)

dependencies = _flatten_dependency_maps(all_dependency_maps)

if not dependencies:
return []

return dependencies[package_name].values()

def _flatten_dependency_maps(all_dependency_maps):
"""Flatten a list of dependency maps into one dictionary.
Dependency maps have the following structure:
```python
DEPENDENCIES_MAP = {
# The first key in the map is a Bazel package
# name of the workspace this file is defined in.
"package_name": {
# An alias to a crate target. # The label of the crate target the
# Aliases are only crate names. # alias refers to.
"alias": "@full//:label",
}
}
```
Args:
all_dependency_maps (list): A list of dicts as described above
Returns:
dict: A dictionary as described above
"""
dependencies = {}

for dep_map in all_dependency_maps:
for pkg_name in dep_map:
if pkg_name not in dependencies:
# Add a non-frozen dict to the collection of dependencies
dependencies.setdefault(pkg_name, dict(dep_map[pkg_name].items()))
continue

duplicate_crate_aliases = [key for key in dependencies[pkg_name] if key in dep_map[pkg_name]]
if duplicate_crate_aliases:
fail("There should be no duplicate crate aliases: {}".format(duplicate_crate_aliases))

dependencies[pkg_name].update(dep_map[pkg_name])

return dependencies

def remote_cargo_workspace_fetch_remote_crates():
"""This function defines a collection of repos and should be called in a WORKSPACE file"""
maybe(
Expand Down
4 changes: 2 additions & 2 deletions examples/remote/cargo_workspace/num_printer/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
load("//remote/cargo_workspace/cargo:crates.bzl", "all_crate_deps")

package(default_visibility = ["//visibility:public"])

Expand All @@ -7,7 +8,6 @@ rust_binary(
srcs = ["src/main.rs"],
edition = "2018",
deps = [
"//remote/cargo_workspace/num_printer/cargo:clap",
"//remote/cargo_workspace/printer",
],
] + all_crate_deps(),
)
Loading

0 comments on commit 9d01e89

Please sign in to comment.