diff --git a/menuinst/platforms/linux.py b/menuinst/platforms/linux.py index 27373651..ed24c519 100644 --- a/menuinst/platforms/linux.py +++ b/menuinst/platforms/linux.py @@ -254,7 +254,7 @@ def _write_desktop_file(self): working_dir = self.render_key("working_dir") if working_dir: - Path(working_dir).mkdir(parents=True, exist_ok=True) + Path(os.path.expandvars(working_dir)).mkdir(parents=True, exist_ok=True) lines.append(f"Path={working_dir}") for key in menuitem_defaults["platforms"]["linux"]: diff --git a/menuinst/platforms/osx.py b/menuinst/platforms/osx.py index 783d3b42..5f23ee1b 100644 --- a/menuinst/platforms/osx.py +++ b/menuinst/platforms/osx.py @@ -194,7 +194,7 @@ def _command(self) -> str: working_dir = self.render_key("working_dir") if working_dir: - Path(working_dir).mkdir(parents=True, exist_ok=True) + Path(os.path.expandvars(working_dir)).mkdir(parents=True, exist_ok=True) lines.append(f'cd "{working_dir}"') precommand = self.render_key("precommand") diff --git a/menuinst/platforms/win.py b/menuinst/platforms/win.py index e31c4a65..2bff6390 100644 --- a/menuinst/platforms/win.py +++ b/menuinst/platforms/win.py @@ -159,9 +159,15 @@ def create(self) -> Tuple[Path, ...]: target_path, *arguments = self._process_command() working_dir = self.render_key("working_dir") if working_dir: - Path(working_dir).mkdir(parents=True, exist_ok=True) + Path(os.path.expandvars(working_dir)).mkdir(parents=True, exist_ok=True) + # There are two possible interpretations of HOME on Windows: + # `%USERPROFILE%` and `%HOMEDRIVE%%HOMEPATH%`. + # Follow os.path.expanduser logic here, but keep the variables + # so that Windows can resolve them at runtime in case the drives change. + elif "USERPROFILE" in os.environ: + working_dir = "%USERPROFILE%" else: - working_dir = "%HOMEPATH%" + working_dir = "%HOMEDRIVE%%HOMEPATH%" icon = self.render_key("icon") or "" diff --git a/news/212-improve-working-dir-handling b/news/212-improve-working-dir-handling new file mode 100644 index 00000000..563406a0 --- /dev/null +++ b/news/212-improve-working-dir-handling @@ -0,0 +1,19 @@ +### Enhancements + +* + +### Bug fixes + +* Expand variables when creating `working_dir` and use `os.path.expanduser` logic for default `working_dir` on Windows. (#211 via #212) + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/data/jsons/working-dir.json b/tests/data/jsons/working-dir.json new file mode 100644 index 00000000..6d68b21c --- /dev/null +++ b/tests/data/jsons/working-dir.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema", + "$id": "https://schemas.conda.io/menuinst-1.schema.json", + "menu_name": "Sys.Prefix {{ DISTRIBUTION_NAME }}", + "menu_items": [ + { + "name": "Sys.Prefix", + "description": "This will install to Windows and Linux with default options. MacOS has a custom option.", + "icon": null, + "command": [ + "{{ PYTHON }}", + "-c", + "import sys; print(sys.prefix)" + ], + "platforms": { + "win": { + "command": [ + "{{ PYTHON }}", + "-c", + "import sys; f = open(r'__OUTPUT_FILE__', 'w'); f.write(sys.prefix); f.close()" + ], + "description": "Note how __OUTPUT_FILE__ is using raw-strings. Otherwise the backslashes are not properly escaped.", + "working_dir": "%TEMP%/working_dir_test" + }, + "linux": { + "working_dir": "${TMP}/working_dir_test" + }, + "osx": { + "CFBundleName": "Sys Prefix", + "working_dir": "${TMPDIR}/working_dir_test" + } + } + } + ] +} diff --git a/tests/test_api.py b/tests/test_api.py index 08659698..495b7bd0 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -396,3 +396,21 @@ def test_name_dictionary(target_env_is_base): assert item_names == expected finally: remove(abs_json_path, target_prefix=tmp_target_path, base_prefix=tmp_base_path) + + +def test_vars_in_working_dir(tmp_path, monkeypatch, delete_files): + if PLATFORM == "win": + expected_directory = Path(os.environ["TEMP"], "working_dir_test") + elif PLATFORM == "osx": + expected_directory = Path(os.environ["TMPDIR"], "working_dir_test") + else: + # Linux often does not have an environment variable for the tmp directory + monkeypatch.setenv("TMP", "/tmp") + expected_directory = Path("/tmp/working_dir_test") + delete_files.append(expected_directory) + datafile = str(DATA / "jsons" / "working-dir.json") + try: + install(datafile, base_prefix=tmp_path, target_prefix=tmp_path) + assert expected_directory.exists() + finally: + remove(datafile, base_prefix=tmp_path, target_prefix=tmp_path)