Skip to content

Commit 054fd1e

Browse files
committed
vsenv: Use a python script to pickle env
This is safer than parsing env from stdout
1 parent bc591f7 commit 054fd1e

File tree

2 files changed

+29
-46
lines changed

2 files changed

+29
-46
lines changed

mesonbuild/scripts/pickle_env.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import os
2+
import pickle
3+
import typing as T
4+
5+
def run(args: T.List[str]) -> int:
6+
with open(args[0], "wb") as f:
7+
pickle.dump(dict(os.environ), f)
8+
return 0

mesonbuild/utils/vsenv.py

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,19 @@
99
import pathlib
1010
import shutil
1111
import tempfile
12-
import locale
12+
import pickle
1313

1414
from .. import mlog
1515
from .core import MesonException
16-
from .universal import is_windows, windows_detect_native_arch
16+
from .universal import (is_windows, windows_detect_native_arch, windows_proof_rm,
17+
get_meson_command, join_args)
1718

1819

1920
__all__ = [
2021
'setup_vsenv',
2122
]
2223

2324

24-
bat_template = '''@ECHO OFF
25-
26-
call "{}"
27-
28-
ECHO {}
29-
SET
30-
'''
31-
3225
# If on Windows and VS is installed but not set up in the environment,
3326
# set it to be runnable. In this way Meson can be directly invoked
3427
# from any shell, VS Code etc.
@@ -91,42 +84,24 @@ def _setup_vsenv(force: bool) -> bool:
9184
raise MesonException(f'Could not find {bat_path}')
9285

9386
mlog.log('Activating VS', bat_info[0]['catalog']['productDisplayVersion'])
94-
bat_separator = '---SPLIT---'
95-
bat_contents = bat_template.format(bat_path, bat_separator)
96-
bat_file = tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False)
97-
bat_file.write(bat_contents)
98-
bat_file.flush()
99-
bat_file.close()
100-
bat_output = subprocess.check_output(bat_file.name, universal_newlines=True,
101-
encoding=locale.getpreferredencoding(False))
102-
os.unlink(bat_file.name)
103-
bat_lines = bat_output.split('\n')
104-
bat_separator_seen = False
105-
for bat_line in bat_lines:
106-
if bat_line == bat_separator:
107-
bat_separator_seen = True
108-
continue
109-
if not bat_separator_seen:
110-
continue
111-
if not bat_line:
112-
continue
113-
try:
114-
k, v = bat_line.split('=', 1)
115-
except ValueError:
116-
# there is no "=", ignore junk data
117-
pass
118-
else:
119-
try:
120-
os.environ[k] = v
121-
except ValueError:
122-
# FIXME: When a value contains a newline, the output of SET
123-
# command is impossible to parse because it makes not escaping.
124-
# `VAR="Hello\n=World"` gets split into two lines:
125-
# `VAR=Hello` and `=World`. That 2nd line will cause ValueError
126-
# exception here. Just ignore for now because variables we do
127-
# care won't have multiline values.
128-
pass
129-
87+
# Write a bat file that first activates VS environment, and then calls
88+
# a Meson script that pickles the environment into a temp file.
89+
with tempfile.NamedTemporaryFile(delete=False) as env_file:
90+
pass
91+
vcvars_cmd = ['call', str(bat_path)]
92+
pickle_cmd = get_meson_command() + ['--internal', 'pickle_env', env_file.name]
93+
with tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) as bat_file:
94+
bat_file.write(join_args(vcvars_cmd) + '\n')
95+
bat_file.write(join_args(pickle_cmd))
96+
try:
97+
subprocess.check_call([bat_file.name], stdout=subprocess.DEVNULL)
98+
with open(env_file.name, 'rb') as f:
99+
vsenv = pickle.load(f)
100+
for k, v in vsenv.items():
101+
os.environ[k] = v
102+
finally:
103+
windows_proof_rm(env_file.name)
104+
windows_proof_rm(bat_file.name)
130105
return True
131106

132107
def setup_vsenv(force: bool = False) -> bool:

0 commit comments

Comments
 (0)