Skip to content

Commit 765edd9

Browse files
committed
Rust: Find rust-analyzer git tag more robustly
Previously we assumed that the release date of a rust-analyzer crate would match a git tag. However, these dates may not line up exactly which we now handle.
1 parent a27305a commit 765edd9

1 file changed

Lines changed: 59 additions & 15 deletions

File tree

‎rust/scripts/update_rust_analyzer.py‎

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import base64
44
import hashlib
5+
import itertools
56
import json
67
import re
78
import shlex
@@ -65,33 +66,67 @@ def fetch(url: str) -> bytes:
6566
return response.read()
6667

6768

68-
def get_rust_analyzer_release_date(rust_analyzer_version: str) -> str:
69-
"""Get the release date of a rust-analyzer crate version."""
69+
def get_rust_analyzer_crate_release_date(rust_analyzer_version: str) -> str:
70+
"""Get the creation date of a rust-analyzer crate version."""
7071
crate_url = f"https://crates.io/api/v1/crates/ra_ap_syntax/{rust_analyzer_version}"
7172
crate = json.loads(fetch(crate_url))
7273
return crate["version"]["created_at"].split("T")[0]
7374

7475

75-
def update_rust_analyzer_sources(rust_analyzer_version: str) -> None:
76+
def get_rust_analyzer_release_tag(rust_analyzer_version: str) -> str:
7677
"""
77-
Update the rust-analyzer source archive used by the AST generator.
78+
Get the latest rust-analyzer release tag in the git repository before or at
79+
the crate publication.
7880
79-
Concretely, this updates `RUST_ANALYZER_SRC_TAG` and
80-
`RUST_ANALYZER_SRC_INTEGRITY` in the MODULE.bazel file.
81+
Empirically, the rust-analyzer crates are published after the corresponding
82+
git tag. We hence look for the latest git tag that is before or at the crate
83+
publication date.
8184
"""
85+
crate_release_date = get_rust_analyzer_crate_release_date(rust_analyzer_version)
86+
87+
for page in itertools.count(1):
88+
tags_url = (
89+
"https://api.github.com/repos/rust-lang/rust-analyzer/tags"
90+
f"?per_page=100&page={page}"
91+
)
92+
tags = json.loads(fetch(tags_url))
93+
if not tags:
94+
raise RuntimeError(
95+
"could not find a rust-analyzer release tag published no later than "
96+
f"ra_ap_syntax {rust_analyzer_version}"
97+
)
98+
99+
for tag in tags:
100+
name = tag["name"]
101+
match = re.fullmatch(r"(\d{4}-\d{2}-\d{2})(?:\.(\d+))?", name)
102+
if match and match[1] <= crate_release_date:
103+
return name
104+
82105

83-
release_date = get_rust_analyzer_release_date(rust_analyzer_version)
106+
def get_rust_analyzer_source_integrity(release_tag: str) -> str:
107+
"""Download and compute the integrity of a rust-analyzer source archive."""
84108
archive_url = (
85109
"https://github.com/rust-lang/rust-analyzer/archive/refs/tags/"
86-
f"{release_date}.tar.gz"
110+
f"{release_tag}.tar.gz"
87111
)
88112
archive = fetch(archive_url)
89-
integrity = "sha256-" + base64.b64encode(hashlib.sha256(archive).digest()).decode()
113+
return "sha256-" + base64.b64encode(hashlib.sha256(archive).digest()).decode()
114+
115+
116+
def update_rust_analyzer_sources(
117+
rust_analyzer_release_tag: str, integrity: str
118+
) -> None:
119+
"""
120+
Update the rust-analyzer source archive used by the AST generator.
121+
122+
Concretely, this updates `RUST_ANALYZER_SRC_TAG` and
123+
`RUST_ANALYZER_SRC_INTEGRITY` in the MODULE.bazel file.
124+
"""
90125

91126
module = MODULE_BAZEL.read_text()
92127
module, tag_replacements = re.subn(
93128
r'RUST_ANALYZER_SRC_TAG = "[^"]+"',
94-
f'RUST_ANALYZER_SRC_TAG = "{release_date}"',
129+
f'RUST_ANALYZER_SRC_TAG = "{rust_analyzer_release_tag}"',
95130
module,
96131
)
97132
if tag_replacements != 1:
@@ -102,13 +137,15 @@ def update_rust_analyzer_sources(rust_analyzer_version: str) -> None:
102137
module,
103138
)
104139
if integrity_replacements != 1:
105-
raise RuntimeError("expected exactly one RUST_ANALYZER_SRC_INTEGRITY assignment")
140+
raise RuntimeError(
141+
"expected exactly one RUST_ANALYZER_SRC_INTEGRITY assignment"
142+
)
106143
MODULE_BAZEL.write_text(module)
107144

108145

109-
def get_compatible_rust_toolchain(rust_analyzer_version: str) -> str:
146+
def get_compatible_rust_toolchain(rust_analyzer_release_tag: str) -> str:
110147
"""Get the latest Rust toolchain released no later than rust-analyzer."""
111-
rust_analyzer_release = get_rust_analyzer_release_date(rust_analyzer_version)
148+
rust_analyzer_release = rust_analyzer_release_tag[:10]
112149

113150
# `manifests.txt` is a list of all toolchains. The one we're interested in looks like
114151
# ```
@@ -204,18 +241,25 @@ def main() -> None:
204241
print("No new rust-analyzer version available.")
205242
return
206243

244+
rust_analyzer_release_tag = get_rust_analyzer_release_tag(new_rust_analyzer_version)
245+
rust_analyzer_source_integrity = get_rust_analyzer_source_integrity(
246+
rust_analyzer_release_tag
247+
)
248+
207249
aligned_manifest, manifest_changed = align_rust_analyzer_versions(manifest)
208250
if manifest_changed:
209251
RUST_EXTRACTOR_MANIFEST.write_text(aligned_manifest)
210252
run("cargo", "update")
211253
commit_all("Cargo: Upgrade dependencies")
212254

213255
print_step(2, "Update the rust-analyzer sources used by the AST generator")
214-
update_rust_analyzer_sources(new_rust_analyzer_version)
256+
update_rust_analyzer_sources(
257+
rust_analyzer_release_tag, rust_analyzer_source_integrity
258+
)
215259
commit_all("Rust: Update rust-analyzer sources")
216260

217261
print_step(3, "Update the fixed Rust toolchain used by the extractor")
218-
rust_toolchain = get_compatible_rust_toolchain(new_rust_analyzer_version)
262+
rust_toolchain = get_compatible_rust_toolchain(rust_analyzer_release_tag)
219263
update_fixed_rust_toolchain_versions(rust_toolchain)
220264
commit_all("Rust: Update fixed toolchain")
221265

0 commit comments

Comments
 (0)