Use direct registry access to set environment variables on Windows when --global is specified. This fixes #4121 by not expanding %var%s in PATH.

This commit is contained in:
Jukka Jylänki
2016-02-20 14:47:54 +02:00
parent f6756fc26f
commit 9e68e895bd

53
emsdk
View File

@@ -120,6 +120,33 @@ def remove_tree(d):
if VERBOSE: print('remove_tree threw an exception, ignoring: ' + str(e))
pass
def win_set_environment_variable_direct(key, value, system=True):
prev_path = os.environ['PATH']
try:
py = find_used_python()
if py:
py_path = to_native_path(py.expand_vars(py.activated_path))
os.environ['PATH'] = os.environ['PATH'] + ';' + py_path
import win32api, win32con
if system: # Read globally from ALL USERS section.
folder = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', 0, win32con.KEY_ALL_ACCESS)
else: # Register locally from CURRENT USER section.
folder = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, 'Environment', 0, win32con.KEY_ALL_ACCESS)
win32api.RegSetValueEx(folder, key, 0, win32con.REG_EXPAND_SZ, value)
except Exception as e:
if e[0] == 5 or e[2] == 'Access is denied.':
print('Error! Failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.')
sys.exit(1)
if e[0] != 2: # 'The system cannot find the file specified.'
print('Failed to write environment variable ' + key + ':', file=sys.stderr)
print(str(e), file=sys.stderr)
win32api.RegCloseKey(folder)
os.environ['PATH'] = prev_path
return None
win32api.RegCloseKey(folder)
os.environ['PATH'] = prev_path
win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
def win_get_environment_variable(key, system=True):
prev_path = os.environ['PATH']
try:
@@ -172,9 +199,15 @@ def win_set_environment_variable(key, value, system=True):
try:
if system:
cmd = ['bin/elevate.exe', 'SETX', '/M']
win_set_environment_variable_direct(key, value, system)
return
else:
cmd = ['SETX']
if len(value) < 1024:
cmd = ['SETX']
else:
print('ERROR! The new environment variable ' + key + ' is more than 1024 characters long! A value this long cannot be set via command line: please add the environment variable specified above to system environment manually via Control Panel.', file=sys.stderr)
sys.exit(1)
if WINDOWS: value = value.replace('%', '^%') # Escape % signs so that we don't expand references to environment variables.
retcode = subprocess.call(cmd + [key, value], stdout=subprocess.PIPE)
if retcode is not 0:
print('ERROR! Failed to set environment variable ' + key + '=' + value + '. You may need to set it manually.', file=sys.stderr)
@@ -1388,12 +1421,9 @@ def set_active_tools(tools_to_activate, permanently_activate):
tool.win_activate_env_vars(permanently_activate=True)
# PATH variable
newpath, added_items = adjusted_path(tools_to_activate)
newpath, added_items = adjusted_path(tools_to_activate, system_path_only=True)
if newpath != os.environ['PATH']: # Are there any actual changes?
if len(newpath) < 1024:
win_set_environment_variable('PATH', newpath, system=True)
else:
print('ERROR! The new PATH is more than 1024 characters long! A PATH this long cannot be set via command line: please add the PATHs specified above to system PATH manually via Control Panel.', file=sys.stderr)
win_set_environment_variable('PATH', newpath, system=True)
return tools_to_activate
@@ -1426,11 +1456,16 @@ def normalized_contains(lst, elem):
# Looks at the current PATH and adds and removes entries so that the PATH reflects
# the set of given active tools.
def adjusted_path(tools_to_activate, log_additions=False):
def adjusted_path(tools_to_activate, log_additions=False, system_path_only=False):
# These directories should be added to PATH
path_add = get_required_path(tools_to_activate)
# These already exist.
existing_path = os.environ['PATH'].split(ENVPATH_SEPARATOR)
if WINDOWS:
existing_path = win_get_environment_variable('PATH', system=True)
if not system_path_only: existing_path += ENVPATH_SEPARATOR + win_get_environment_variable('PATH', system=False)
existing_path = existing_path.split(ENVPATH_SEPARATOR)
else:
existing_path = os.environ['PATH'].split(ENVPATH_SEPARATOR)
emsdk_root_path = to_unix_path(emsdk_path())
existing_emsdk_tools = [item for item in existing_path if to_unix_path(item).startswith(emsdk_root_path)]