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
5 changes: 4 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Release Notes

## 0.15.0-unreleased
## 0.15.0

This release adds defaults for Linux and Windows for the `platform_release` environment marker when
generating platform details via `pexrc platform python <spec>`. Now the only `<unknown>` marker
when using a spec is the `platform_version` which is actively antagonistic to any likely real-world
use.

This release also fixes injected windowed PEXes launched with `pythonw.exe` on Windows. Previously
these would incorrectly re-exec with `python.exe` and display a console.

## 0.14.0

This release adds `pexrc platform {info,python}` for displaying both local and foreign platform
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cargo-features = ["profile-rustflags"]

[package]
name = "pexrc"
version = "0.15.0-unreleased"
version = "0.15.0"
edition = { workspace = true }
publish = false

Expand Down
40 changes: 27 additions & 13 deletions crates/pexrs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,31 @@ fn prepare_boot(
argv: Vec<String>,
) -> anyhow::Result<Command> {
let venv = prepare_venv(
python,
python.as_ref(),
pex.as_ref(),
#[cfg(unix)]
env::var_os("_PEXRC_SH_BOOT_SEED_DIR").map(PathBuf::from),
)?;
let mut command = Command::new(&venv.interpreter.details.path);

let mut command = {
#[cfg(windows)]
{
let python_exe = {
if let Some(file_name) = python.as_ref().file_name().and_then(OsStr::to_str)
// N.B.: This could be either pythonw.exe or pypyw.exe (or pypy<version>w.exe).
&& file_name.ends_with("w.exe")
{
// Either way, our venv machinery ensures "pythonw.exe" exists.
Cow::Owned(venv.interpreter.details.path.with_file_name("pythonw.exe"))
} else {
Cow::Borrowed(&venv.interpreter.details.path)
}
};
Command::new(python_exe.as_ref())
}
#[cfg(unix)]
Command::new(&venv.interpreter.details.path)
};
command
.args(python_args)
.arg(venv.prefix().as_os_str())
Expand All @@ -153,7 +172,7 @@ pub fn mount(python: impl AsRef<Path>, pex: impl AsRef<Path>) -> anyhow::Result<
Err(err) => bail!("Failed to obtain PEXRC cache read lock: {err}"),
};
prepare_venv(
python,
python.as_ref(),
pex.as_ref(),
#[cfg(unix)]
None,
Expand All @@ -163,23 +182,18 @@ pub fn mount(python: impl AsRef<Path>, pex: impl AsRef<Path>) -> anyhow::Result<

#[time("debug", "{}")]
fn prepare_venv<'a>(
python: impl AsRef<Path>,
pex: impl AsRef<Path>,
python: &Path,
pex: &Path,
#[cfg(unix)] sh_boot_seed_dir: Option<PathBuf>,
) -> anyhow::Result<Virtualenv<'a>> {
let pex = Pex::load(pex.as_ref())?;
let pex = Pex::load(pex)?;
let pex_path = PexPath::from_pex_info(&pex.info, true);
let pex_info = pex.info.raw();
let additional_pexes = pex_path.load_pexes()?;
let search_path = SearchPath::from_env()?;
let venv_dir = venv_dir(Some(python.as_ref()), &pex, &search_path, &additional_pexes)?;
let venv_dir = venv_dir(Some(python), &pex, &search_path, &additional_pexes)?;
if let Some(venv_interpreter) = atomic_dir(&venv_dir, |work_dir| {
let mut resolve = pex.resolve(
Some(python.as_ref()),
additional_pexes.iter(),
search_path,
None,
)?;
let mut resolve = pex.resolve(Some(python), additional_pexes.iter(), search_path, None)?;
let venv = Virtualenv::create(
resolve.interpreter,
Cow::Borrowed(work_dir),
Expand Down
10 changes: 8 additions & 2 deletions crates/scripts/src/venv-pex.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ def exec_function(
return locals_map


if sys.platform == "win32":
IS_WINDOWS = sys.platform == "win32"


if IS_WINDOWS:

def safe_execv(argv):
# type: (List[str]) -> NoReturn
Expand Down Expand Up @@ -113,11 +116,14 @@ def boot(
venv_dir = os.path.abspath(os.path.dirname(__file__))
venv_bin_dir = os.path.join(venv_dir, venv_bin_dir)
python = os.path.join(venv_bin_dir, os.path.basename(shebang_python))
venv_pythons = [python, shebang_python]
if IS_WINDOWS:
venv_pythons.append(os.path.join(venv_bin_dir, "pythonw.exe"))

def iter_valid_venv_pythons():
# Allow for both the known valid venv pythons and their fully resolved venv path
# version in the case their parent directories contain symlinks.
for python_binary in (python, shebang_python):
for python_binary in venv_pythons:
yield python_binary
yield os.path.join(
os.path.realpath(os.path.dirname(python_binary)), os.path.basename(python_binary)
Expand Down