• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Common utilities useful for unifying the behavior of different parts of `cargo-bazel`."""
2
3# buildifier: disable=bzl-visibility
4load("//cargo/private:cargo_utils.bzl", _rust_get_rust_tools = "get_rust_tools")
5load("//rust/platform:triple.bzl", _get_host_triple = "get_host_triple")
6
7get_host_triple = _get_host_triple
8
9CARGO_BAZEL_ISOLATED = "CARGO_BAZEL_ISOLATED"
10CARGO_BAZEL_REPIN = "CARGO_BAZEL_REPIN"
11CARGO_BAZEL_DEBUG = "CARGO_BAZEL_DEBUG"
12REPIN = "REPIN"
13
14CARGO_BAZEL_REPIN_ONLY = "CARGO_BAZEL_REPIN_ONLY"
15
16REPIN_ENV_VARS = [
17    CARGO_BAZEL_REPIN,
18    REPIN,
19]
20
21REPIN_ALLOWLIST_ENV_VAR = CARGO_BAZEL_REPIN_ONLY
22
23_EXECUTE_ERROR_MESSAGE = """\
24Command {args} failed with exit code {exit_code}.
25STDOUT ------------------------------------------------------------------------
26{stdout}
27STDERR ------------------------------------------------------------------------
28{stderr}
29"""
30
31def execute(repository_ctx, args, env = {}):
32    """A heler macro for executing some arguments and displaying nicely formatted errors
33
34    Args:
35        repository_ctx (repository_ctx): The rule's context object.
36        args (list): A list of strings which act as `argv` for execution.
37        env (dict, optional): Environment variables to set in the execution environment.
38
39    Returns:
40        struct: The results of `repository_ctx.execute`
41    """
42
43    quiet = repository_ctx.attr.quiet
44    if repository_ctx.os.environ.get(CARGO_BAZEL_DEBUG, None):
45        quiet = False
46
47    result = repository_ctx.execute(
48        args,
49        environment = env,
50        quiet = quiet,
51    )
52
53    if result.return_code:
54        fail(_EXECUTE_ERROR_MESSAGE.format(
55            args = args,
56            exit_code = result.return_code,
57            stdout = result.stdout,
58            stderr = result.stderr,
59        ))
60
61    return result
62
63def get_rust_tools(repository_ctx, host_triple):
64    """Retrieve a cargo and rustc binary based on the host triple.
65
66    Args:
67        repository_ctx (repository_ctx): The rule's context object.
68        host_triple (struct): A `@rules_rust//rust:triple.bzl%triple` object.
69
70    Returns:
71        struct: A struct containing the expected rust tools
72    """
73
74    # This is a bit hidden but to ensure Cargo behaves consistently based
75    # on the user provided config file, the config file is installed into
76    # the `CARGO_HOME` path. This is done so here since fetching tools
77    # is expected to always occur before any subcommands are run.
78    if repository_ctx.attr.isolated and repository_ctx.attr.cargo_config:
79        cargo_home = _cargo_home_path(repository_ctx)
80        cargo_home_config = repository_ctx.path("{}/config.toml".format(cargo_home))
81        cargo_config = repository_ctx.path(repository_ctx.attr.cargo_config)
82        repository_ctx.symlink(cargo_config, cargo_home_config)
83
84    if repository_ctx.attr.rust_version.startswith(("beta", "nightly")):
85        channel, _, version = repository_ctx.attr.rust_version.partition("/")
86    else:
87        channel = "stable"
88        version = repository_ctx.attr.rust_version
89
90    return _rust_get_rust_tools(
91        cargo_template = repository_ctx.attr.rust_toolchain_cargo_template,
92        rustc_template = repository_ctx.attr.rust_toolchain_rustc_template,
93        host_triple = host_triple,
94        channel = channel,
95        version = version,
96    )
97
98def _cargo_home_path(repository_ctx):
99    """Define a path within the repository to use in place of `CARGO_HOME`
100
101    Args:
102        repository_ctx (repository_ctx): The rules context object
103
104    Returns:
105        path: The path to a directory to use as `CARGO_HOME`
106    """
107    return repository_ctx.path(".cargo_home")
108
109def cargo_environ(repository_ctx):
110    """Define Cargo environment varables for use with `cargo-bazel`
111
112    Args:
113        repository_ctx (repository_ctx): The rules context object
114
115    Returns:
116        dict: A set of environment variables for `cargo-bazel` executions
117    """
118    env = dict()
119
120    if CARGO_BAZEL_ISOLATED in repository_ctx.os.environ:
121        if repository_ctx.os.environ[CARGO_BAZEL_ISOLATED].lower() in ["true", "1", "yes", "on"]:
122            env.update({
123                "CARGO_HOME": str(_cargo_home_path(repository_ctx)),
124            })
125    elif repository_ctx.attr.isolated:
126        env.update({
127            "CARGO_HOME": str(_cargo_home_path(repository_ctx)),
128        })
129
130    return env
131
132def parse_alias_rule(value):
133    """Attempts to parse an `AliasRule` from supplied string.
134
135    Args:
136        value (str): String value to be parsed.
137
138    Returns:
139        value: A Rust compatible `AliasRule`.
140    """
141    if value == None:
142        return None
143
144    if value == "alias" or value == "dbg" or value == "fastbuild" or value == "opt":
145        return value
146
147    if value.count(":") != 2:
148        fail("Invalid custom value for `alias_rule`.\n{}\nValues must be in the format '<label to .bzl>:<rule>'.".format(value))
149
150    split = value.rsplit(":", 1)
151    bzl = Label(split[0])
152    rule = split[1]
153
154    if rule == "alias":
155        fail("Custom value rule cannot be named `alias`.\n{}".format(value))
156
157    return struct(
158        bzl = str(bzl),
159        rule = rule,
160    )
161