Skip to content

Commit

Permalink
Revert "Never install dxtbx into conda_base/ when running under libtbx (
Browse files Browse the repository at this point in the history
#474)" (#483)

This reverts commit cbe9fa9.
  • Loading branch information
graeme-winter authored Feb 11, 2022
1 parent cbe9fa9 commit 2010053
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 16 deletions.
91 changes: 76 additions & 15 deletions libtbx_refresh.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import inspect
import os
import random
import site
import subprocess
import sys
from pathlib import Path

import libtbx
import libtbx.pkg_utils
Expand All @@ -19,31 +22,54 @@
pkg_resources = None


def _install_setup_readonly_fallback(package_name: str):
def _install_dxtbx_setup():
"""Install xia2 as a regular/editable python package"""

# We need to find this from libtbx.env because libtbx doesn't read
# this properly, as a module - it's just eval'd in scope
dxtbx_root_path = libtbx.env.dist_path("dxtbx")

# Call pip
subprocess.run(
[
sys.executable,
"-m",
"pip",
"install",
"--no-build-isolation",
"--no-deps",
"-e",
dxtbx_root_path,
],
check=True,
)


def _install_dxtbx_setup_readonly_fallback():
"""
Partially install package in the libtbx build folder.
This is a less complete installation - base python console_scripts
entrypoints will not be installed, but the basic package metadata
and other entrypoints will be enumerable through dispatcher black magic
"""
root_path = libtbx.env.dist_path(package_name)
import_path = os.path.join(root_path, "src")
dxtbx_root_path = libtbx.env.dist_path("dxtbx")
dxtbx_import_path = os.path.join(dxtbx_root_path, "src")

# Install this into a build/dxtbx subfolder
build_path = abs(libtbx.env.build_path / package_name)
dxtbx_build_path = abs(libtbx.env.build_path / "dxtbx")
subprocess.run(
[
sys.executable,
"-m",
"pip",
"install",
"--prefix",
build_path,
dxtbx_build_path,
"--no-build-isolation",
"--no-deps",
"-e",
root_path,
dxtbx_root_path,
],
check=True,
)
Expand All @@ -54,27 +80,49 @@ def _install_setup_readonly_fallback(package_name: str):
# Update the libtbx environment pythonpaths to point to the source
# location which now has an .egg-info folder; this will mean that
# the PYTHONPATH is written into the libtbx dispatchers
rel_path = libtbx.env.as_relocatable_path(import_path)
rel_path = libtbx.env.as_relocatable_path(dxtbx_import_path)
if rel_path not in env.pythonpath:
env.pythonpath.insert(0, rel_path)

# Update the sys.path so that we can find the .egg-info in this process
# if we do a full reconstruction of the working set
if import_path not in sys.path:
sys.path.insert(0, import_path)
if dxtbx_import_path not in sys.path:
sys.path.insert(0, dxtbx_import_path)

# ...and add to the existing pkg_resources working_set
if pkg_resources:
pkg_resources.working_set.add_entry(import_path)
pkg_resources.working_set.add_entry(dxtbx_import_path)

# Also, since we can't re-export dispatchers, add the src/ folder
# as an extra command_line_locations.
#
# This is already generated by this point, but will get picked up
# on the second libtbx.refresh.
module = env.module_dict[package_name]
if f"src/{package_name}" not in module.extra_command_line_locations:
module.extra_command_line_locations.append(f"src/{package_name}")
module = env.module_dict["dxtbx"]
if "src/dxtbx" not in module.extra_command_line_locations:
module.extra_command_line_locations.append("src/dxtbx")


def _test_writable_dir(path: Path) -> bool:
"""Test a path is writable. Based on pip's _test_writable_dir_win."""
# os.access doesn't work on windows
# os.access won't always work with network filesystems
# pip doesn't use tempfile on windows because https://bugs.python.org/issue22107
basename = "test_site_packages_writable_dxtbx_"
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"
for _ in range(10):
name = basename + "".join(random.choice(alphabet) for _ in range(6))
file = path / name
try:
fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL)
except FileExistsError:
pass
except PermissionError:
return False
else:
os.close(fd)
os.unlink(file)
return True


def _get_real_env_hack_hack_hack():
Expand Down Expand Up @@ -105,5 +153,18 @@ def _get_real_env_hack_hack_hack():
raise RuntimeError("Could not determine real libtbx.env_config.environment object")


# When building in libtbx, always assume it's unsafe to write to base/
_install_setup_readonly_fallback("dxtbx")
# Detect case where base python environment is read-only
# e.g. on an LCLS session on a custom cctbx installation where the
# source is editable but the conda_base is read-only
#
# We need to check before trying to install as pip does os.access-based
# checks then installs with --user if it fails. We don't want that.
# Additionally, if the CCTBX_INSTALL_PACKAGE_BUILD environment variable
# is set, then we explicitly want to do the readonly fallback.
if ("CCTBX_INSTALL_PACKAGE_BUILD" not in os.environ) and _test_writable_dir(
Path(site.getsitepackages()[0])
):
_install_dxtbx_setup()
else:
print("Python site directory not writable - falling back to tbx install")
_install_dxtbx_setup_readonly_fallback()
1 change: 0 additions & 1 deletion newsfragments/474.feature

This file was deleted.

0 comments on commit 2010053

Please sign in to comment.