Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions devDocs/buildSystemNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Version numbers for dependencies should be used to lock in a version.
The virtual environment is recreated if it is outdated, either due to:
- Python version.
- `pip` requirements.
- It was originally created at a different location to where it is now.

The user is consulted before modifying / removing a virtual environment that can't be identified
as having been created by NVDA's build system.
Expand Down
33 changes: 33 additions & 0 deletions venvUtils/ensureVenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@
venv_python_version_path: str = os.path.join(venv_path, "python_version")


def verifyExistingVenvPath():
"""
Verifies that the Python virtual environment at c{VENV_PATH} was actually created at that location,
and not just copied or moved there.
"""
# Activate the Python virtual environment and capture the content of the VIRTUAL_ENV environment variable.
existingPath = subprocess.check_output(
[
os.path.join(venv_path, "scripts", "activate.bat"),
"&&",
"call", "echo", "%VIRTUAL_ENV%",
],
shell=True,
).decode('oem').rstrip()
Comment on lines +30 to +37

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could you add a comment here to show an example of the output for this command? If the output changes, this will make it easier to verify.

existingPath = os.path.normpath(existingPath)
expectedPath = os.path.normpath(venv_path)
if existingPath != expectedPath:
print(f"Python virtual environment originally created at {existingPath},")
print(f"Then moved or copied to {expectedPath}.")
return False
return True


def askYesNoQuestion(message: str) -> bool:
"""
Displays the given message to the user and accepts y or n as input.
Expand Down Expand Up @@ -101,6 +124,16 @@ def ensureVenvAndRequirements():
if not os.path.exists(venv_path):
print("Virtual environment does not exist.")
return createVenvAndPopulate()
if not verifyExistingVenvPath():
if askYesNoQuestion(
"A Python virtual environment cannot be activated from a different location "
"to where it was originally created.\n"
"Should the virtual environment be recreated with the updated location?"
):
return createVenvAndPopulate()
else:
print("Aborting")
sys.exit(1)
if (
not os.path.exists(venv_python_version_path)
or not os.path.exists(venv_orig_requirements_path)
Expand Down