Skip to content

Commit d427403

Browse files
authored
Fix check for outdated Rust library (#17861)
This failed when install with poetry, so let's properly try and detect what's going on.
1 parent e9f9625 commit d427403

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

changelog.d/17861.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix detection when the built Rust library was outdated when using source installations.

synapse/util/rust.py

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
#
2020
#
2121

22+
import json
2223
import os
23-
import sys
24+
import urllib.parse
2425
from hashlib import blake2b
26+
from importlib.metadata import Distribution, PackageNotFoundError
27+
from typing import Optional
2528

2629
import synapse
2730
from synapse.synapse_rust import get_rust_file_digest
@@ -32,22 +35,17 @@ def check_rust_lib_up_to_date() -> None:
3235
be rebuilt.
3336
"""
3437

35-
if not _dist_is_editable():
36-
return
37-
38-
synapse_dir = os.path.dirname(synapse.__file__)
39-
synapse_root = os.path.abspath(os.path.join(synapse_dir, ".."))
40-
41-
# Double check we've not gone into site-packages...
42-
if os.path.basename(synapse_root) == "site-packages":
43-
return
44-
45-
# ... and it looks like the root of a python project.
46-
if not os.path.exists("pyproject.toml"):
47-
return
38+
# Get the location of the editable install.
39+
synapse_root = get_synapse_source_directory()
40+
if synapse_root is None:
41+
return None
4842

4943
# Get the hash of all Rust source files
50-
hash = _hash_rust_files_in_directory(os.path.join(synapse_root, "rust", "src"))
44+
rust_path = os.path.join(synapse_root, "rust", "src")
45+
if not os.path.exists(rust_path):
46+
return None
47+
48+
hash = _hash_rust_files_in_directory(rust_path)
5149

5250
if hash != get_rust_file_digest():
5351
raise Exception("Rust module outdated. Please rebuild using `poetry install`")
@@ -82,10 +80,55 @@ def _hash_rust_files_in_directory(directory: str) -> str:
8280
return hasher.hexdigest()
8381

8482

85-
def _dist_is_editable() -> bool:
86-
"""Is distribution an editable install?"""
87-
for path_item in sys.path:
88-
egg_link = os.path.join(path_item, "matrix-synapse.egg-link")
89-
if os.path.isfile(egg_link):
90-
return True
91-
return False
83+
def get_synapse_source_directory() -> Optional[str]:
84+
"""Try and find the source directory of synapse for editable installs (like
85+
those used in development).
86+
87+
Returns None if not an editable install (or otherwise can't find the source
88+
directory).
89+
"""
90+
91+
# Try and find the installed matrix-synapse package.
92+
try:
93+
package = Distribution.from_name("matrix-synapse")
94+
except PackageNotFoundError:
95+
# The package is not found, so it's not installed and so must be being
96+
# pulled out from a local directory (usually the current one).
97+
synapse_dir = os.path.dirname(synapse.__file__)
98+
synapse_root = os.path.abspath(os.path.join(synapse_dir, ".."))
99+
100+
# Double check we've not gone into site-packages...
101+
if os.path.basename(synapse_root) == "site-packages":
102+
return None
103+
104+
# ... and it looks like the root of a python project.
105+
if not os.path.exists("pyproject.toml"):
106+
return None
107+
108+
return synapse_root
109+
110+
# Read the `direct_url.json` metadata for the package. This won't exist for
111+
# packages installed via a repository/etc.
112+
# c.f. https://packaging.python.org/en/latest/specifications/direct-url/
113+
direct_url_json = package.read_text("direct_url.json")
114+
if direct_url_json is None:
115+
return None
116+
117+
# c.f. https://packaging.python.org/en/latest/specifications/direct-url/ for
118+
# the format
119+
direct_url_dict: dict = json.loads(direct_url_json)
120+
121+
# `url` must exist as a key, and point to where we fetched the repo from.
122+
project_url = urllib.parse.urlparse(direct_url_dict["url"])
123+
124+
# If its not a local file then we must have built the rust libs either a)
125+
# after we downloaded the package, or b) we built the download wheel.
126+
if project_url.scheme != "file":
127+
return None
128+
129+
# And finally if its not an editable install then the files can't have
130+
# changed since we installed the package.
131+
if not direct_url_dict.get("dir_info", {}).get("editable", False):
132+
return None
133+
134+
return project_url.path

0 commit comments

Comments
 (0)