Skip to content

Commit 074ed36

Browse files
authored
Merge pull request #71 from rabbitmq/static-erlang-installations
Allow configuration of "static" external erlangs on the host
2 parents 469bdf6 + 523c62d commit 074ed36

File tree

4 files changed

+160
-98
lines changed

4 files changed

+160
-98
lines changed

bzlmod/extensions.bzl

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ load(
2222
)
2323
load(
2424
"//repositories:erlang_config.bzl",
25+
"INSTALLATION_TYPE_EXTERNAL",
26+
"INSTALLATION_TYPE_INTERNAL",
2527
_erlang_config_rule = "erlang_config",
2628
)
2729
load(
@@ -31,44 +33,55 @@ load(
3133
)
3234

3335
def _erlang_config(ctx):
34-
internal_erlangs = []
36+
types = {}
37+
versions = {}
38+
urls = {}
39+
strip_prefixs = {}
40+
sha256s = {}
41+
erlang_homes = {}
42+
3543
for mod in ctx.modules:
44+
for erlang in mod.tags.external_erlang_from_path:
45+
types[erlang.name] = INSTALLATION_TYPE_EXTERNAL
46+
versions[erlang.name] = erlang.version
47+
erlang_homes[erlang.name] = erlang.erlang_home
48+
3649
for erlang in mod.tags.internal_erlang_from_http_archive:
37-
internal_erlangs.append(struct(
38-
name = erlang.name,
39-
version = erlang.version,
40-
url = erlang.url,
41-
strip_prefix = erlang.strip_prefix,
42-
sha256 = erlang.sha256,
43-
))
50+
types[erlang.name] = INSTALLATION_TYPE_INTERNAL
51+
versions[erlang.name] = erlang.version
52+
urls[erlang.name] = erlang.url
53+
strip_prefixs[erlang.name] = erlang.strip_prefix
54+
sha256s[erlang.name] = erlang.sha256
55+
4456
for erlang in mod.tags.internal_erlang_from_github_release:
4557
url = "https://github.com/erlang/otp/releases/download/OTP-{v}/otp_src_{v}.tar.gz".format(
4658
v = erlang.version,
4759
)
4860
strip_prefix = "otp_src_{}".format(erlang.version)
4961

50-
internal_erlangs.append(struct(
51-
name = erlang.name,
52-
version = erlang.version,
53-
url = url,
54-
strip_prefix = strip_prefix,
55-
sha256 = erlang.sha256,
56-
))
57-
58-
versions = {c.name: c.version for c in internal_erlangs}
59-
urls = {c.name: c.url for c in internal_erlangs}
60-
strip_prefixs = {c.name: c.strip_prefix for c in internal_erlangs if c.strip_prefix}
61-
sha256s = {c.name: c.sha256 for c in internal_erlangs if c.sha256}
62+
types[erlang.name] = INSTALLATION_TYPE_INTERNAL
63+
versions[erlang.name] = erlang.version
64+
urls[erlang.name] = url
65+
strip_prefixs[erlang.name] = strip_prefix
66+
sha256s[erlang.name] = erlang.sha256
6267

6368
_erlang_config_rule(
6469
name = "erlang_config",
6570
rules_erlang_workspace = "@rules_erlang",
71+
types = types,
6672
versions = versions,
6773
urls = urls,
6874
strip_prefixs = strip_prefixs,
6975
sha256s = sha256s,
76+
erlang_homes = erlang_homes,
7077
)
7178

79+
external_erlang_from_path = tag_class(attrs = {
80+
"name": attr.string(),
81+
"version": attr.string(),
82+
"erlang_home": attr.string(),
83+
})
84+
7285
internal_erlang_from_http_archive = tag_class(attrs = {
7386
"name": attr.string(),
7487
"version": attr.string(),
@@ -92,6 +105,7 @@ internal_erlang_from_github_release = tag_class(attrs = {
92105
erlang_config = module_extension(
93106
implementation = _erlang_config,
94107
tag_classes = {
108+
"external_erlang_from_path": external_erlang_from_path,
95109
"internal_erlang_from_http_archive": internal_erlang_from_http_archive,
96110
"internal_erlang_from_github_release": internal_erlang_from_github_release,
97111
},

presubmit.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,27 @@ tasks:
1414
- ./kerl update releases
1515
- ./kerl build ${ERLANG_VERSION}
1616
- ./kerl install ${ERLANG_VERSION} ~/kerl/${ERLANG_VERSION}
17+
- ERLANG_HOME="$(realpath ~/kerl/${ERLANG_VERSION})"
1718
- |
18-
export ERLANG_HOME="$(realpath ~/kerl/${ERLANG_VERSION})"
19+
cat << EOF >> $(ls MODULE*)
20+
erlang_config_extension = use_extension(
21+
"@rules_erlang//bzlmod:extensions.bzl",
22+
"erlang_config",
23+
)
24+
25+
erlang_config_extension.external_erlang_from_path(
26+
name = "static",
27+
version = "${ERLANG_VERSION}",
28+
erlang_home = "${ERLANG_HOME}",
29+
)
30+
31+
use_repo(
32+
erlang_config_extension,
33+
"erlang_config",
34+
)
35+
EOF
1936
build_flags:
2037
- --incompatible_strict_action_env
21-
- --extra_toolchains=@erlang_config//external:toolchain
38+
- --extra_toolchains=@erlang_config//static:toolchain
2239
build_targets:
2340
- '@rules_erlang//...'

repositories/erlang_config.bzl

Lines changed: 104 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -6,74 +6,63 @@ load(
66
ERLANG_HOME_ENV_VAR = "ERLANG_HOME"
77
DEFAULT_ERL_PATH = "/usr/bin/erl"
88

9-
_EXTERNAL_ERLANG_PACKAGE = "external"
9+
_DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME = "external"
10+
11+
INSTALLATION_TYPE_EXTERNAL = "external"
12+
INSTALLATION_TYPE_INTERNAL = "internal"
1013

1114
def _impl(repository_ctx):
1215
rules_erlang_workspace = repository_ctx.attr.rules_erlang_workspace
1316

14-
erlang_installations = {}
15-
16-
if ERLANG_HOME_ENV_VAR in repository_ctx.os.environ:
17-
erlang_home = repository_ctx.os.environ[ERLANG_HOME_ENV_VAR]
18-
else:
19-
if repository_ctx.os.name.find("windows") > 0:
20-
erl_path = repository_ctx.which("erl.exe")
21-
else:
22-
erl_path = repository_ctx.which("erl")
23-
if erl_path == None:
24-
erl_path = repository_ctx.path(DEFAULT_ERL_PATH)
25-
erlang_home = str(erl_path.dirname.dirname)
26-
27-
erl_path = path_join(erlang_home, "bin", "erl")
28-
version = repository_ctx.execute(
29-
[
30-
erl_path,
31-
"-noshell",
32-
"-eval",
33-
'{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().',
34-
],
35-
timeout = 10,
36-
)
37-
if version.return_code == 0:
38-
erlang_version = version.stdout.strip("\n")
39-
(major, _, _) = erlang_version.partition(".")
40-
erlang_installations[_EXTERNAL_ERLANG_PACKAGE] = major
41-
repository_ctx.template(
42-
"{}/BUILD.bazel".format(_EXTERNAL_ERLANG_PACKAGE),
43-
Label("//repositories:BUILD_external.tpl"),
44-
{
45-
"%{ERLANG_HOME}": erlang_home,
46-
"%{ERLANG_VERSION}": erlang_version,
47-
"%{ERLANG_MAJOR}": major,
48-
"%{RULES_ERLANG_WORKSPACE}": rules_erlang_workspace,
49-
},
50-
False,
51-
)
52-
53-
for name in repository_ctx.attr.versions.keys():
54-
if name == _EXTERNAL_ERLANG_PACKAGE:
55-
fail("'{}' is not allowed as an internal erlang name".format(
56-
_EXTERNAL_ERLANG_PACKAGE,
17+
erlang_installations = _default_erlang_dict(repository_ctx)
18+
for name in repository_ctx.attr.types.keys():
19+
if name == _DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME:
20+
fail("'{}' is reserved as an erlang name".format(
21+
_DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME,
5722
))
58-
59-
version = repository_ctx.attr.versions.get(name)
23+
version = repository_ctx.attr.versions[name]
6024
(major, _, _) = version.partition(".")
61-
erlang_installations[name] = major
62-
63-
repository_ctx.template(
64-
"{}/BUILD.bazel".format(name),
65-
Label("//repositories:BUILD_internal.tpl"),
66-
{
67-
"%{ERLANG_VERSION}": version,
68-
"%{URL}": repository_ctx.attr.urls.get(name),
69-
"%{STRIP_PREFIX}": repository_ctx.attr.strip_prefixs.get(name, ""),
70-
"%{SHA_256}": repository_ctx.attr.sha256s.get(name, ""),
71-
"%{ERLANG_MAJOR}": major,
72-
"%{RULES_ERLANG_WORKSPACE}": rules_erlang_workspace,
73-
},
74-
False,
25+
erlang_installations[name] = struct(
26+
type = repository_ctx.attr.types[name],
27+
version = version,
28+
major = major,
29+
url = repository_ctx.attr.urls.get(name, None),
30+
strip_prefix = repository_ctx.attr.strip_prefixs.get(name, None),
31+
sha256 = repository_ctx.attr.sha256s.get(name, None),
32+
erlang_home = repository_ctx.attr.erlang_homes.get(name, None),
7533
)
7634

35+
for (name, props) in erlang_installations.items():
36+
if props.type == INSTALLATION_TYPE_EXTERNAL:
37+
repository_ctx.template(
38+
"{}/BUILD.bazel".format(name),
39+
Label("//repositories:BUILD_external.tpl"),
40+
{
41+
"%{ERLANG_HOME}": props.erlang_home,
42+
"%{ERLANG_VERSION}": props.version,
43+
"%{ERLANG_MAJOR}": props.major,
44+
"%{RULES_ERLANG_WORKSPACE}": rules_erlang_workspace,
45+
},
46+
False,
47+
)
48+
else:
49+
repository_ctx.template(
50+
"{}/BUILD.bazel".format(name),
51+
Label("//repositories:BUILD_internal.tpl"),
52+
{
53+
"%{ERLANG_VERSION}": props.version,
54+
"%{URL}": props.url,
55+
"%{STRIP_PREFIX}": props.strip_prefix or "",
56+
"%{SHA_256}": props.sha256 or "",
57+
"%{ERLANG_MAJOR}": props.major,
58+
"%{RULES_ERLANG_WORKSPACE}": rules_erlang_workspace,
59+
},
60+
False,
61+
)
62+
63+
if len(erlang_installations) == 0:
64+
fail("No erlang installations configured")
65+
7766
repository_ctx.file(
7867
"BUILD.bazel",
7968
_build_file_content(erlang_installations),
@@ -101,23 +90,67 @@ erlang_config = repository_rule(
10190
implementation = _impl,
10291
attrs = {
10392
"rules_erlang_workspace": attr.string(),
93+
"types": attr.string_dict(),
10494
"versions": attr.string_dict(),
10595
"urls": attr.string_dict(),
10696
"strip_prefixs": attr.string_dict(),
10797
"sha256s": attr.string_dict(),
98+
"erlang_homes": attr.string_dict(),
10899
},
109100
environ = [
110101
"ERLANG_HOME",
111102
],
112103
)
113104

105+
def _default_erlang_dict(repository_ctx):
106+
if ERLANG_HOME_ENV_VAR in repository_ctx.os.environ:
107+
erlang_home = repository_ctx.os.environ[ERLANG_HOME_ENV_VAR]
108+
else:
109+
if repository_ctx.os.name.find("windows") > 0:
110+
erl_path = repository_ctx.which("erl.exe")
111+
else:
112+
erl_path = repository_ctx.which("erl")
113+
if erl_path == None:
114+
erl_path = repository_ctx.path(DEFAULT_ERL_PATH)
115+
erlang_home = str(erl_path.dirname.dirname)
116+
117+
erl_path = path_join(erlang_home, "bin", "erl")
118+
version = repository_ctx.execute(
119+
[
120+
erl_path,
121+
"-noshell",
122+
"-eval",
123+
'{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().',
124+
],
125+
timeout = 10,
126+
)
127+
if version.return_code == 0:
128+
version = version.stdout.strip("\n")
129+
(major, _, _) = version.partition(".")
130+
return {
131+
_DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME: struct(
132+
type = INSTALLATION_TYPE_EXTERNAL,
133+
version = version,
134+
major = major,
135+
erlang_home = erlang_home,
136+
),
137+
}
138+
else:
139+
return {}
140+
114141
def _build_file_content(erlang_installations):
115-
if _EXTERNAL_ERLANG_PACKAGE in erlang_installations:
116-
default_internal_external = "external"
117-
default_major = erlang_installations[_EXTERNAL_ERLANG_PACKAGE]
142+
external_installations = {
143+
name: props
144+
for (name, props) in erlang_installations.items()
145+
if props.type == INSTALLATION_TYPE_EXTERNAL
146+
}
147+
148+
if _DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME in erlang_installations:
149+
default_installation = erlang_installations[_DEFAULT_EXTERNAL_ERLANG_PACKAGE_NAME]
150+
elif len(external_installations) > 0:
151+
default_installation = external_installations[0]
118152
else:
119-
default_internal_external = "internal"
120-
default_major = erlang_installations[0]
153+
default_installation = erlang_installations[0]
121154

122155
build_file_content = """\
123156
package(
@@ -135,17 +168,12 @@ constraint_setting(
135168
)
136169
137170
""".format(
138-
default_internal_external = default_internal_external,
139-
default_major = default_major,
171+
default_internal_external = default_installation.type,
172+
default_major = default_installation.major,
140173
)
141174

142-
should_have_external = False
143-
should_have_internal = False
144-
if _EXTERNAL_ERLANG_PACKAGE in erlang_installations:
145-
should_have_external = True
146-
should_have_internal = len(erlang_installations) > 1
147-
else:
148-
should_have_internal = len(erlang_installations) > 0
175+
should_have_external = len(external_installations) > 0
176+
should_have_internal = len(erlang_installations) > len(external_installations)
149177

150178
if should_have_external:
151179
build_file_content += """\
@@ -166,8 +194,8 @@ constraint_value(
166194
"""
167195

168196
unique_majors = {
169-
v: n
170-
for (n, v) in erlang_installations.items()
197+
props.major: name
198+
for (name, props) in erlang_installations.items()
171199
}.keys()
172200
for major in unique_majors:
173201
build_file_content += """\

rules_erlang.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ load(
44
)
55
load(
66
"//repositories:erlang_config.bzl",
7+
"INSTALLATION_TYPE_INTERNAL",
78
_erlang_config = "erlang_config",
89
)
910
load(
@@ -56,6 +57,7 @@ filegroup(
5657
def erlang_config(
5758
rules_erlang_workspace = "@rules_erlang",
5859
internal_erlang_configs = []):
60+
types = {c.name: INSTALLATION_TYPE_INTERNAL for c in internal_erlang_configs}
5961
versions = {c.name: c.version for c in internal_erlang_configs}
6062
urls = {c.name: c.url for c in internal_erlang_configs}
6163
strip_prefixs = {c.name: c.strip_prefix for c in internal_erlang_configs if c.strip_prefix}
@@ -64,6 +66,7 @@ def erlang_config(
6466
_erlang_config(
6567
name = "erlang_config",
6668
rules_erlang_workspace = rules_erlang_workspace,
69+
types = types,
6770
versions = versions,
6871
urls = urls,
6972
strip_prefixs = strip_prefixs,

0 commit comments

Comments
 (0)