Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ jobs:
download_dir="$i\_cache";
global_dir="$i\_bin";
} | Out-File $env:PYTHON_MANAGER_CONFIG -Encoding utf8
pymanager exec
pymanager install --configure -y
if ($?) { pymanager list }
env:
PYTHON_MANAGER_INCLUDE_UNMANAGED: false
Expand Down
2 changes: 1 addition & 1 deletion ci/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ stages:
download_dir="$i\_cache";
global_dir="$i\_bin";
} | Out-File $env:PYTHON_MANAGER_CONFIG -Encoding utf8
pymanager exec
pymanager install --configure -y
if ($?) { pymanager list }
displayName: 'Emulate first launch'
env:
Expand Down
1 change: 1 addition & 0 deletions src/manage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ def execute(self):
self.show_welcome()
if self.configure:
cmd = FirstRun(["**first_run", "--explicit"], self.root)
cmd.confirm = self.confirm
cmd.execute()
else:
from .install_command import execute
Expand Down
81 changes: 55 additions & 26 deletions src/manage/firstrun.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
import time
import winreg

from . import logging
from .pathutils import Path
Expand Down Expand Up @@ -51,14 +52,20 @@
LOGGER.debug("Check passed: aliases are correct")
return True

_LONG_PATH_KEY = r"System\CurrentControlSet\Control\FileSystem"
_LONG_PATH_VALUENAME = "LongPathsEnabled"

def check_long_paths(cmd):
def check_long_paths(
cmd,
*,
hive=winreg.HKEY_LOCAL_MACHINE,
keyname=_LONG_PATH_KEY,
valuename=_LONG_PATH_VALUENAME,
):
LOGGER.debug("Checking long paths setting")
import winreg
try:
with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE,
r"System\CurrentControlSet\Control\FileSystem") as key:
if winreg.QueryValueEx(key, "LongPathsEnabled") == (1, winreg.REG_DWORD):
with winreg.OpenKeyEx(hive, keyname) as key:
if winreg.QueryValueEx(key, valuename) == (1, winreg.REG_DWORD):
LOGGER.debug("Check passed: registry key is OK")
return True
except FileNotFoundError:
Expand All @@ -67,6 +74,42 @@
return False


def do_configure_long_paths(
cmd,
*,
hive=winreg.HKEY_LOCAL_MACHINE,
keyname=_LONG_PATH_KEY,
valuename=_LONG_PATH_VALUENAME,
startfile=os.startfile,
):
LOGGER.debug("Updating long paths setting")
try:
with winreg.CreateKeyEx(hive, keyname) as key:
winreg.SetValueEx(key, valuename, None, winreg.REG_DWORD, 1)
LOGGER.info("The setting has been successfully updated, and will "
"take effect after the next reboot.")
return
except OSError:
pass
if not cmd.confirm:
# Without confirmation, we assume we can't elevate, so attempt
# as the current user and if it fails just print a message.
LOGGER.warn("The setting has not been updated. Please rerun '!B!py "

Check warning on line 97 in src/manage/firstrun.py

View check run for this annotation

Codecov / codecov/patch

src/manage/firstrun.py#L97

Added line #L97 was not covered by tests
"install --configure!W! with administrative privileges.")
return

Check warning on line 99 in src/manage/firstrun.py

View check run for this annotation

Codecov / codecov/patch

src/manage/firstrun.py#L99

Added line #L99 was not covered by tests
startfile(sys.executable, "runas", "**configure-long-paths", show_cmd=0)
for _ in range(5):
time.sleep(0.25)
if check_long_paths(cmd):
LOGGER.info("The setting has been successfully updated, and will "
"take effect after the next reboot.")
break
else:
LOGGER.warn("The setting may not have been updated. Please "

Check warning on line 108 in src/manage/firstrun.py

View check run for this annotation

Codecov / codecov/patch

src/manage/firstrun.py#L108

Added line #L108 was not covered by tests
"visit the additional help link at the end for "
"more assistance.")


def check_py_on_path(cmd):
LOGGER.debug("Checking for legacy py.exe on PATH")
from _native import read_alias_package
Expand Down Expand Up @@ -120,7 +163,6 @@


def _check_global_dir_registry(cmd):
import winreg
with winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, "Environment") as key:
path, kind = winreg.QueryValueEx(key, "Path")
LOGGER.debug("Current registry path: %s", path)
Expand All @@ -139,7 +181,6 @@


def do_global_dir_on_path(cmd):
import winreg
added = notified = False
try:
LOGGER.debug("Adding %s to PATH", cmd.global_dir)
Expand Down Expand Up @@ -290,17 +331,8 @@
"may need an administrator to approve, and will require a "
"reboot. Some packages may fail to install without long "
"path support enabled.\n", wrap=True)
if cmd.confirm and not cmd.ask_ny("Update setting now?"):
os.startfile(sys.executable, "runas", "**configure-long-paths", show_cmd=0)
for _ in range(5):
time.sleep(0.25)
if check_long_paths(cmd):
LOGGER.info("The setting has been successfully updated.")
break
else:
LOGGER.warn("The setting may not have been updated. Please "
"visit the additional help link at the end for "
"more assistance.")
if not cmd.confirm or not cmd.ask_ny("Update setting now?"):
do_configure_long_paths(cmd)

Check warning on line 335 in src/manage/firstrun.py

View check run for this annotation

Codecov / codecov/patch

src/manage/firstrun.py#L335

Added line #L335 was not covered by tests
elif cmd.explicit:
LOGGER.info("Checked system long paths setting")

Expand All @@ -314,10 +346,7 @@
LOGGER.print("\nThis may interfere with launching the new 'py' "
"command, and may be resolved by uninstalling "
"'!B!Python launcher!W!'.\n", wrap=True)
if (
cmd.confirm and
not cmd.ask_ny("Open Installed apps now?")
):
if cmd.confirm and not cmd.ask_ny("Open Installed apps now?"):
os.startfile("ms-settings:appsfeatures")
elif cmd.explicit:
if r == "skip":
Expand All @@ -342,7 +371,7 @@
"must manually edit environment variables to later "
"remove the entry.\n", wrap=True)
if (
cmd.confirm and
not cmd.confirm or
not cmd.ask_ny("Add commands directory to your PATH now?")
):
do_global_dir_on_path(cmd)
Expand All @@ -352,7 +381,7 @@
else:
LOGGER.info("Checked PATH for versioned commands directory")

# This check must be last, because 'do_install' will exit the program.
# This check must be last, because a failed install may exit the program.
if cmd.check_any_install:
if not check_any_install(cmd):
welcome()
Expand All @@ -361,11 +390,11 @@
LOGGER.print("!Y!You do not have any Python runtimes installed.!W!",
level=logging.WARN)
LOGGER.print("\nInstall the current latest version of CPython? If "
"not, you can use !B!py install default!W! later to "
"not, you can use '!B!py install default!W!' later to "
"install, or one will be installed automatically when "
"needed.\n", wrap=True)
LOGGER.info("")
if cmd.ask_yn("Install CPython now?"):
if not cmd.confirm or cmd.ask_yn("Install CPython now?"):
do_install(cmd)
elif cmd.explicit:
LOGGER.info("Checked for any Python installs")
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def localserver():
class FakeConfig:
def __init__(self, global_dir, installs=[]):
self.global_dir = global_dir
self.confirm = False
self.installs = list(installs)
self.shebang_can_run_anything = True
self.shebang_can_run_anything_silently = False
Expand Down
22 changes: 22 additions & 0 deletions tests/test_firstrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,25 @@ def test_do_global_dir_path_fail_broadcast(protect_reg, fake_config, assert_log,
monkeypatch.setattr(winreg, "SetValueEx", lambda *a: None)
firstrun.do_global_dir_on_path(fake_config)
assert_log(assert_log.skip_until("Failed to notify of PATH environment.+"))


def test_check_long_paths(registry, fake_config):
assert not firstrun.check_long_paths(fake_config, hive=registry.hive, keyname=registry.root)
registry.setup(LongPathsEnabled=1)
assert firstrun.check_long_paths(fake_config, hive=registry.hive, keyname=registry.root)


def test_do_configure_long_paths(registry, fake_config, monkeypatch):
firstrun.do_configure_long_paths(fake_config, hive=registry.hive, keyname=registry.root, startfile=_raise_oserror)
assert winreg.QueryValueEx(registry.key, "LongPathsEnabled") == (1, winreg.REG_DWORD)


def test_do_configure_long_paths_elevated(protect_reg, fake_config, monkeypatch):
startfile_calls = []
def startfile(*a, **kw):
startfile_calls.append((a, kw))
# Pretend we can interact, so that os.startfile gets called
fake_config.confirm = True
firstrun.do_configure_long_paths(fake_config, startfile=startfile)
assert startfile_calls
assert startfile_calls[0][0][1:] == ("runas", "**configure-long-paths")