Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use reparse points to detect Windows installer shims #2284

Merged
merged 1 commit into from
Mar 7, 2024

Conversation

charliermarsh
Copy link
Member

@charliermarsh charliermarsh commented Mar 7, 2024

Summary

This PR enables use of the Windows Store Pythons even with py is not installed. Specifically, we need to ensure that the python.exe and python3.exe executables installed into the C:\Users\crmar\AppData\Local\Microsoft\WindowsApp directory are used when they're not "App execution aliases" (which merely open the Windows Store, to help you install Python).

When py is installed, this isn't strictly necessary, since the "resolved" executables are discovered via py. These look like C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbs5n2kfra8p0\python.exe.

Closes #2264.

Test Plan

  • Removed all Python installations from my Windows machine.
  • Uninstalled py.
  • Enabled "App execution aliases".
  • Verified that for both cargo run venv --python python.exe and cargo run venv --python python3.exe, uv exited with a failure that no Python could be found.
  • Installed Python 3.10 via the Windows Store.
  • Verified that the above commands succeeded without error.
  • Verified that cargo run venv --python python3.10.exe also succeeded.

let mut path_encoded = path
.as_os_str()
.encode_wide()
.chain(std::iter::once(0))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, this wouldn't work for one of the two shims. But adding the null terminator seems to fix it on my machine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the null termination seems correct. OsStr is not null terminated https://doc.rust-lang.org/std/ffi/struct.OsString.html

@charliermarsh charliermarsh force-pushed the charlie/win branch 2 times, most recently from fc4efc5 to 60937ee Compare March 7, 2024 18:45
@charliermarsh charliermarsh added bug Something isn't working windows Specific to the Windows platform labels Mar 7, 2024
@charliermarsh charliermarsh force-pushed the charlie/win branch 2 times, most recently from b0dabce to c8e9a79 Compare March 7, 2024 18:56
@charliermarsh charliermarsh merged commit 996a859 into main Mar 7, 2024
7 checks passed
@charliermarsh charliermarsh deleted the charlie/win branch March 7, 2024 20:47
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this. I should have tested this workflow when improving windows support. And nice find with the null terminator

Have you considered upstreaming this back to Rye.

But what about https://twitter.com/charliermarsh/status/1765750403461689701

std::ptr::null_mut(),
0,
buf.as_mut_ptr().cast(),
buf.len() as u32 * 2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: not a 100 sure but I think we could use mem::size_of here (or size_of_value) to avoid the * 2

CloseHandle(reparse_handle);
}

success && String::from_utf16_lossy(&buf).contains("\\AppInstallerPythonRedirector.exe")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this buf be sliced to bytes returned? It might not matter because it only tests startswidth but might still be good practice

if !path.is_absolute() {
return false;
}

// The path must point to something like:
// `C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\python3.exe`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse the uv-fs function instead of reimplementing the check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're actually different checks (sigh). The one in uv-fs needs to accept python3.12.exe and friends. The one here only accepts python3.exe and python.exe, since those are the only ones that get added as app redirects.

return false;
}
// Ex) `WindowsApps`
if !components
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified to using components.ends_with("Microsoft/WindowsApps") after having done the fuzzy python.exe check

@@ -130,7 +130,7 @@ fn find_python(
for name in possible_names.iter().flatten() {
if let Ok(paths) = which::which_in_global(&**name, Some(&path)) {
for path in paths {
if cfg!(windows) && windows::is_windows_store_shim(&path) {
if windows::is_windows_store_shim(&path) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to make code suggestions on ipad…

I would add #[cfg(windows)] to the if block instead of having an empty non-windows implementation in the windows module

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh, I originally did this but the cross-platform Clippy warnings were so brutal.

@charliermarsh
Copy link
Member Author

But what about https://twitter.com/charliermarsh/status/1765750403461689701

This does NOT apply to Windows Store Python.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working windows Specific to the Windows platform
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Python discovery still broken for Microsoft Store
2 participants