-
Notifications
You must be signed in to change notification settings - Fork 11
/
hex_archive.bzl
180 lines (159 loc) · 6.88 KB
/
hex_archive.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
load(
"@bazel_tools//tools/build_defs/repo:utils.bzl",
"patch",
"read_netrc",
"update_attrs",
"use_netrc",
"workspace_and_buildfile",
)
_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
If a URL's host name is present in this dict the value will be used as a pattern when
generating the authorization header for the http request. This enables the use of custom
authorization schemes used in a lot of common cloud storage providers.
The pattern currently supports 2 tokens: <code><login></code> and
<code><password></code>, which are replaced with their equivalent value
in the netrc file for the same host name. After formatting, the result is set
as the value for the <code>Authorization</code> field of the HTTP request.
Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
<pre>
auth_patterns = {
"storage.cloudprovider.com": "Bearer <password>"
}
</pre>
netrc:
<pre>
machine storage.cloudprovider.com
password RANDOM-TOKEN
</pre>
The final HTTP request would have the following header:
<pre>
Authorization: Bearer RANDOM-TOKEN
</pre>
"""
def _get_auth(ctx, urls):
"""Given the list of URLs obtain the correct auth dict."""
if ctx.attr.netrc:
netrc = read_netrc(ctx, ctx.attr.netrc)
return use_netrc(netrc, urls, ctx.attr.auth_patterns)
if "HOME" in ctx.os.environ and not ctx.os.name.startswith("windows"):
netrcfile = "%s/.netrc" % (ctx.os.environ["HOME"])
if ctx.execute(["test", "-f", netrcfile]).return_code == 0:
netrc = read_netrc(ctx, netrcfile)
return use_netrc(netrc, urls, ctx.attr.auth_patterns)
if "USERPROFILE" in ctx.os.environ and ctx.os.name.startswith("windows"):
netrcfile = "%s/.netrc" % (ctx.os.environ["USERPROFILE"])
if ctx.path(netrcfile).exists:
netrc = read_netrc(ctx, netrcfile)
return use_netrc(netrc, urls, ctx.attr.auth_patterns)
return {}
def _impl(ctx):
if ctx.attr.build_file and ctx.attr.build_file_content:
fail("Only one of build_file and build_file_content can be provided.")
# we have package_name, because with bzlmod, the name is rewritten
# prior to download with a namespace
name = ctx.attr.package_name or ctx.attr.name
all_urls = ["https://repo.hex.pm/tarballs/{}-{}.tar".format(name, ctx.attr.version)]
auth = _get_auth(ctx, all_urls)
download_info = ctx.download_and_extract(
all_urls,
".",
ctx.attr.sha256,
"tar",
canonical_id = ctx.attr.canonical_id,
auth = auth,
)
ctx.extract("contents.tar.gz")
workspace_and_buildfile(ctx)
patch(ctx)
return update_attrs(ctx.attr, _hex_archive_attrs.keys(), {"sha256": download_info.sha256})
_hex_archive_attrs = {
"package_name": attr.string(),
"version": attr.string(mandatory = True),
"sha256": attr.string(
doc = """The expected SHA-256 of the file downloaded.
This must match the SHA-256 of the file downloaded. _It is a security risk
to omit the SHA-256 as remote files can change._ At best omitting this
field will make your build non-hermetic. It is optional to make development
easier but should be set before shipping.""",
),
"canonical_id": attr.string(
doc = """A canonical id of the archive downloaded.
If specified and non-empty, bazel will not take the archive from cache,
unless it was added to the cache by a request with the same canonical id.
""",
),
"netrc": attr.string(
doc = "Location of the .netrc file to use for authentication",
),
"auth_patterns": attr.string_dict(
doc = _AUTH_PATTERN_DOC,
),
"patches": attr.label_list(
default = [],
doc =
"A list of files that are to be applied as patches after " +
"extracting the archive. By default, it uses the Bazel-native patch implementation " +
"which doesn't support fuzz match and binary patch, but Bazel will fall back to use " +
"patch command line tool if `patch_tool` attribute is specified or there are " +
"arguments other than `-p` in `patch_args` attribute.",
),
"patch_tool": attr.string(
default = "",
doc = "The patch(1) utility to use. If this is specified, Bazel will use the specifed " +
"patch tool instead of the Bazel-native patch implementation.",
),
"patch_args": attr.string_list(
default = ["-p0"],
doc =
"The arguments given to the patch tool. Defaults to -p0, " +
"however -p1 will usually be needed for patches generated by " +
"git. If multiple -p arguments are specified, the last one will take effect." +
"If arguments other than -p are specified, Bazel will fall back to use patch " +
"command line tool instead of the Bazel-native patch implementation. When falling " +
"back to patch command line tool and patch_tool attribute is not specified, " +
"`patch` will be used.",
),
"patch_cmds": attr.string_list(
default = [],
doc = "Sequence of Bash commands to be applied on Linux/Macos after patches are applied.",
),
"patch_cmds_win": attr.string_list(
default = [],
doc = "Sequence of Powershell commands to be applied on Windows after patches are " +
"applied. If this attribute is not set, patch_cmds will be executed on Windows, " +
"which requires Bash binary to exist.",
),
"build_file": attr.label(
allow_single_file = True,
doc =
"The file to use as the BUILD file for this repository." +
"This attribute is an absolute label (use '@//' for the main " +
"repo). The file does not need to be named BUILD, but can " +
"be (something like BUILD.new-repo-name may work well for " +
"distinguishing it from the repository's actual BUILD files. " +
"Either build_file or build_file_content can be specified, but " +
"not both.",
),
"build_file_content": attr.string(
doc =
"The content for the BUILD file for this repository. " +
"Either build_file or build_file_content can be specified, but " +
"not both.",
),
"workspace_file": attr.label(
doc =
"The file to use as the `WORKSPACE` file for this repository. " +
"Either `workspace_file` or `workspace_file_content` can be " +
"specified, or neither, but not both.",
),
"workspace_file_content": attr.string(
doc =
"The content for the WORKSPACE file for this repository. " +
"Either `workspace_file` or `workspace_file_content` can be " +
"specified, or neither, but not both.",
),
}
hex_archive = repository_rule(
implementation = _impl,
attrs = _hex_archive_attrs,
)