Skip to content

Commit 597eec7

Browse files
committed
Improve the error message when erlang_package deps conflict
non sem-ver versions (common for git deps) now produce a more readable message when there is a conflict
1 parent 29ef2cb commit 597eec7

File tree

3 files changed

+84
-56
lines changed

3 files changed

+84
-56
lines changed

bzlmod/extensions.bzl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
load(
22
":hex_pm.bzl",
33
"hex_package_info",
4-
"newest",
54
"satisfies",
65
)
76
load(
@@ -12,6 +11,11 @@ load(
1211
"log",
1312
"without_requirement",
1413
)
14+
load(
15+
":semver.bzl",
16+
"lt",
17+
"version_from_string",
18+
)
1519
load(
1620
"//:rules_erlang.bzl",
1721
"xref_runner_sources",
@@ -76,6 +80,23 @@ def _resolve_hex_pm(ctx, packages):
7680
return resolved
7781
fail("Dependencies were not resolved after {} passes.".format(_RESOLVE_MAX_PASSES))
7882

83+
def _newest(a, b):
84+
if a.version == b.version:
85+
return a
86+
87+
a_version = version_from_string(a.version)
88+
b_version = version_from_string(b.version)
89+
if a_version == None or b_version == None:
90+
fail("A version of {} & {} for {} cannot be resolved".format(
91+
a.version,
92+
b.version,
93+
a.name,
94+
))
95+
elif lt(a_version, b_version):
96+
return b
97+
else:
98+
return a
99+
79100
def _resolve_local(packages):
80101
deduped = []
81102
packages_by_name = {}
@@ -87,7 +108,7 @@ def _resolve_local(packages):
87108
for (_, dupes) in packages_by_name.items():
88109
p = dupes[0]
89110
for dupe in dupes[1:]:
90-
p = newest(p, dupe)
111+
p = _newest(p, dupe)
91112
deduped.append(p)
92113
return deduped
93114

bzlmod/hex_pm.bzl

Lines changed: 14 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
load(
2+
":semver.bzl",
3+
"Version",
4+
"eq",
5+
"gte",
6+
"lt",
7+
"version_from_string",
8+
)
9+
110
def hex_package_info(ctx, name):
211
curl = ctx.which("curl")
312
endpoint = "https://hex.pm/api/packages/{}".format(name)
@@ -20,68 +29,19 @@ def hex_release_info(ctx, name, version):
2029
fail("hex.pm api returned {} for {}".format(response.return_code, endpoint))
2130
return json.decode(response.stdout)
2231

23-
Version = provider(fields = ["major", "minor", "patch"])
24-
25-
def _version(version):
26-
[major, minor, patch] = version.split(".", 2)
27-
if not patch.isdigit():
28-
return None
29-
return Version(
30-
major = int(major),
31-
minor = int(minor),
32-
patch = int(patch),
33-
)
34-
35-
def _gte(a, b):
36-
if a.major > b.major:
37-
return True
38-
elif a.major == b.major:
39-
if a.minor > b.minor:
40-
return True
41-
elif a.minor == b.minor:
42-
return a.patch >= b.patch
43-
else:
44-
return False
45-
else:
46-
return False
47-
48-
def _lt(a, b):
49-
if a.major < b.major:
50-
return True
51-
elif a.major == b.major:
52-
if a.minor < b.minor:
53-
return True
54-
elif a.minor == b.minor:
55-
return a.patch < b.patch
56-
else:
57-
return False
58-
else:
59-
return False
60-
61-
def _eq(a, b):
62-
return a.major == b.major and a.minor == b.minor and a.patch == b.patch
63-
64-
def newest(a, b):
65-
if a.version == b.version:
66-
return a
67-
if _lt(_version(a.version), _version(b.version)):
68-
return b
69-
else:
70-
return a
71-
7232
def satisfies(version, requirement):
73-
v = _version(version)
33+
v = version_from_string(version)
7434
if v == None:
7535
# print("Ignoring version", version)
7636
return False
7737
if requirement.startswith("~>"):
78-
min = _version(requirement.removeprefix("~>").lstrip())
38+
min = version_from_string(requirement.removeprefix("~>").lstrip())
7939
if min == None:
8040
print("Ignoring requirement", requirement)
8141
return False
8242
max = Version(major = min.major, minor = min.minor + 1, patch = 0)
83-
return _gte(v, min) and _lt(v, max)
84-
elif _version(requirement) != None:
85-
return _eq(v, _version(requirement))
43+
return gte(v, min) and lt(v, max)
44+
elif version_from_string(requirement) != None:
45+
return eq(v, version_from_string(requirement))
8646
else:
8747
fail(requirement)

bzlmod/semver.bzl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Version = provider(fields = ["major", "minor", "patch"])
2+
3+
def version_from_string(version):
4+
parts = version.split(".", 2)
5+
if len(parts) != 3:
6+
return None
7+
[major, minor, patch] = parts
8+
if not major.isdigit():
9+
return None
10+
if not minor.isdigit():
11+
return None
12+
if not patch.isdigit():
13+
return None
14+
return Version(
15+
major = int(major),
16+
minor = int(minor),
17+
patch = int(patch),
18+
)
19+
20+
def gte(a, b):
21+
if a.major > b.major:
22+
return True
23+
elif a.major == b.major:
24+
if a.minor > b.minor:
25+
return True
26+
elif a.minor == b.minor:
27+
return a.patch >= b.patch
28+
else:
29+
return False
30+
else:
31+
return False
32+
33+
def lt(a, b):
34+
if a.major < b.major:
35+
return True
36+
elif a.major == b.major:
37+
if a.minor < b.minor:
38+
return True
39+
elif a.minor == b.minor:
40+
return a.patch < b.patch
41+
else:
42+
return False
43+
else:
44+
return False
45+
46+
def eq(a, b):
47+
return a.major == b.major and a.minor == b.minor and a.patch == b.patch

0 commit comments

Comments
 (0)