Skip to content

Commit

Permalink
Fix check for outdated Rust library (#17861)
Browse files Browse the repository at this point in the history
This failed when install with poetry, so let's properly try and detect
what's going on.
  • Loading branch information
erikjohnston authored Oct 29, 2024
1 parent e9f9625 commit d427403
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 22 deletions.
1 change: 1 addition & 0 deletions changelog.d/17861.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix detection when the built Rust library was outdated when using source installations.
87 changes: 65 additions & 22 deletions synapse/util/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
#
#

import json
import os
import sys
import urllib.parse
from hashlib import blake2b
from importlib.metadata import Distribution, PackageNotFoundError
from typing import Optional

import synapse
from synapse.synapse_rust import get_rust_file_digest
Expand All @@ -32,22 +35,17 @@ def check_rust_lib_up_to_date() -> None:
be rebuilt.
"""

if not _dist_is_editable():
return

synapse_dir = os.path.dirname(synapse.__file__)
synapse_root = os.path.abspath(os.path.join(synapse_dir, ".."))

# Double check we've not gone into site-packages...
if os.path.basename(synapse_root) == "site-packages":
return

# ... and it looks like the root of a python project.
if not os.path.exists("pyproject.toml"):
return
# Get the location of the editable install.
synapse_root = get_synapse_source_directory()
if synapse_root is None:
return None

# Get the hash of all Rust source files
hash = _hash_rust_files_in_directory(os.path.join(synapse_root, "rust", "src"))
rust_path = os.path.join(synapse_root, "rust", "src")
if not os.path.exists(rust_path):
return None

hash = _hash_rust_files_in_directory(rust_path)

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


def _dist_is_editable() -> bool:
"""Is distribution an editable install?"""
for path_item in sys.path:
egg_link = os.path.join(path_item, "matrix-synapse.egg-link")
if os.path.isfile(egg_link):
return True
return False
def get_synapse_source_directory() -> Optional[str]:
"""Try and find the source directory of synapse for editable installs (like
those used in development).
Returns None if not an editable install (or otherwise can't find the source
directory).
"""

# Try and find the installed matrix-synapse package.
try:
package = Distribution.from_name("matrix-synapse")
except PackageNotFoundError:
# The package is not found, so it's not installed and so must be being
# pulled out from a local directory (usually the current one).
synapse_dir = os.path.dirname(synapse.__file__)
synapse_root = os.path.abspath(os.path.join(synapse_dir, ".."))

# Double check we've not gone into site-packages...
if os.path.basename(synapse_root) == "site-packages":
return None

# ... and it looks like the root of a python project.
if not os.path.exists("pyproject.toml"):
return None

return synapse_root

# Read the `direct_url.json` metadata for the package. This won't exist for
# packages installed via a repository/etc.
# c.f. https://packaging.python.org/en/latest/specifications/direct-url/
direct_url_json = package.read_text("direct_url.json")
if direct_url_json is None:
return None

# c.f. https://packaging.python.org/en/latest/specifications/direct-url/ for
# the format
direct_url_dict: dict = json.loads(direct_url_json)

# `url` must exist as a key, and point to where we fetched the repo from.
project_url = urllib.parse.urlparse(direct_url_dict["url"])

# If its not a local file then we must have built the rust libs either a)
# after we downloaded the package, or b) we built the download wheel.
if project_url.scheme != "file":
return None

# And finally if its not an editable install then the files can't have
# changed since we installed the package.
if not direct_url_dict.get("dir_info", {}).get("editable", False):
return None

return project_url.path

0 comments on commit d427403

Please sign in to comment.