Skip to content

Commit

Permalink
Hardcode exe returned for windows store envs (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonJayamanne authored Jul 3, 2024
1 parent 721ebdd commit f33a69b
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 43 deletions.
50 changes: 44 additions & 6 deletions crates/pet-core/src/python_environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

use log::error;
use pet_fs::path::norm_case;
use pet_python_utils::executable::get_shortest_executable;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

Expand Down Expand Up @@ -317,8 +316,10 @@ impl PythonEnvironmentBuilder {
Some(all.clone())
};
if let Some(executable) = &self.executable {
self.executable =
Some(get_shortest_executable(&Some(all.clone())).unwrap_or(executable.clone()));
self.executable = Some(
get_shortest_executable(&self.category, &Some(all.clone()))
.unwrap_or(executable.clone()),
);
}
}

Expand All @@ -338,9 +339,9 @@ impl PythonEnvironmentBuilder {
} else {
Some(all.clone())
};
let executable = self
.executable
.map(|executable| get_shortest_executable(&Some(all.clone())).unwrap_or(executable));
let executable = self.executable.map(|executable| {
get_shortest_executable(&self.category, &Some(all.clone())).unwrap_or(executable)
});

PythonEnvironment {
display_name: self.display_name,
Expand All @@ -358,6 +359,43 @@ impl PythonEnvironmentBuilder {
}
}

// Given a list of executables, return the one with the shortest path.
// The shortest path is the most likely to be most user friendly.
fn get_shortest_executable(
category: &PythonEnvironmentCategory,
exes: &Option<Vec<PathBuf>>,
) -> Option<PathBuf> {
// For windows store, the exe should always be the one in the WindowsApps folder.
if *category == PythonEnvironmentCategory::WindowsStore {
if let Some(exes) = exes {
if let Some(exe) = exes.iter().find(|e| {
e.to_string_lossy().contains("AppData")
&& e.to_string_lossy().contains("Local")
&& e.to_string_lossy().contains("Microsoft")
&& e.to_string_lossy().contains("WindowsApps")
}) {
return Some(exe.clone());
}
}
}

// Ensure the executable always points to the shorted path.
if let Some(mut exes) = exes.clone() {
exes.sort_by(|a, b| {
a.to_str()
.unwrap_or_default()
.len()
.cmp(&b.to_str().unwrap_or_default().len())
});
if exes.is_empty() {
return None;
}
Some(exes[0].clone())
} else {
None
}
}

pub fn get_environment_key(env: &PythonEnvironment) -> Option<PathBuf> {
if let Some(exe) = &env.executable {
Some(exe.clone())
Expand Down
9 changes: 7 additions & 2 deletions crates/pet-python-utils/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use log::{error, trace};
use pet_fs::path::norm_case;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::{
path::{Path, PathBuf},
time::SystemTime,
};

use crate::pyvenv_cfg::PyVenvCfg;

Expand Down Expand Up @@ -90,6 +93,7 @@ impl ResolvedPythonEnv {
pub fn from(executable: &Path) -> Option<Self> {
// Spawn the python exe and get the version, sys.prefix and sys.executable.
let executable = executable.to_str()?;
let start = SystemTime::now();
trace!("Executing Python: {} -c {}", executable, PYTHON_INFO_CMD);
let result = std::process::Command::new(executable)
.args(["-c", PYTHON_INFO_CMD])
Expand All @@ -98,8 +102,9 @@ impl ResolvedPythonEnv {
Ok(output) => {
let output = String::from_utf8(output.stdout).unwrap().trim().to_string();
trace!(
"Python Execution for {:?} produced an output {:?}",
"Executed Python {:?} in {:?} & produced an output {:?}",
executable,
start.elapsed(),
output
);
if let Some((_, output)) = output.split_once(PYTHON_INFO_JSON_SEPARATOR) {
Expand Down
20 changes: 0 additions & 20 deletions crates/pet-python-utils/src/executable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,6 @@ fn is_python_executable_name(exe: &Path) -> bool {
}
}

// Given a list of executables, return the one with the shortest path.
// The shortest path is the most likely to be most user friendly.
pub fn get_shortest_executable(exes: &Option<Vec<PathBuf>>) -> Option<PathBuf> {
// Ensure the executable always points to the shorted path.
if let Some(mut exes) = exes.clone() {
exes.sort_by(|a, b| {
a.to_str()
.unwrap_or_default()
.len()
.cmp(&b.to_str().unwrap_or_default().len())
});
if exes.is_empty() {
return None;
}
Some(exes[0].clone())
} else {
None
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 3 additions & 1 deletion crates/pet-reporter/src/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{environment::Environment, manager::Manager};
use env_logger::Builder;
use log::LevelFilter;
use log::{trace, LevelFilter};
use pet_core::{manager::EnvManager, python_environment::PythonEnvironment, reporter::Reporter};
use pet_jsonrpc::send_message;
use serde::{Deserialize, Serialize};
Expand All @@ -12,10 +12,12 @@ pub struct JsonRpcReporter {}

impl Reporter for JsonRpcReporter {
fn report_manager(&self, manager: &EnvManager) {
trace!("Reporting Manager {:?}", manager);
send_message("manager", Manager::from(manager).into())
}

fn report_environment(&self, env: &PythonEnvironment) {
trace!("Reporting Environment {:?}", env);
send_message("environment", Environment::from(env).into())
}
}
Expand Down
9 changes: 5 additions & 4 deletions crates/pet-windows-store/src/environments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@ impl PotentialPython {
} else {
None
})
.version(Some(self.version.clone()))
// We only have the partial version, no point returning bogus info.
// .version(Some(self.version.clone()))
.symlinks(Some(vec![
parent.join(format!("python{:?}.exe", self.version)),
parent.join(format!("python{}.exe", self.version)),
path.join("python.exe"),
path.join("python3.exe"),
path.join(format!("python{:?}.exe", self.version)),
path.join(format!("python{}.exe", self.version)),
env_path.join("python.exe"),
env_path.join(format!("python{:?}.exe", self.version)),
env_path.join(format!("python{}.exe", self.version)),
]))
.build(),
)
Expand Down
5 changes: 3 additions & 2 deletions crates/pet/src/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,12 @@ pub fn handle_resolve(context: Arc<Context>, id: u32, params: Value) {
&resolved,
);

trace!("Resolved env {:?} as {:?}", executable, resolved);
send_reply(id, Some(ResolveResult::new(&resolved, now.elapsed())));
} else {
error!(
"Failed to resolve env, returning discovered env {:?}",
executable
"Failed to resolve env {:?}, returning discovered env {:?}",
executable, result.discovered
);
send_reply(
id,
Expand Down
28 changes: 20 additions & 8 deletions crates/pet/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::{path::PathBuf, sync::Arc};

use log::{trace, warn};
use pet_core::{
arch::Architecture, os_environment::EnvironmentApi, python_environment::PythonEnvironment,
arch::Architecture,
os_environment::EnvironmentApi,
python_environment::{PythonEnvironment, PythonEnvironmentBuilder},
Locator,
};
use pet_env_var_path::get_search_paths_from_env_variables;
Expand Down Expand Up @@ -43,23 +45,33 @@ pub fn resolve_environment(
info
);
let discovered = env.clone();
let mut resolved = env.clone();
let mut symlinks = resolved.symlinks.clone().unwrap_or_default();

let mut symlinks = env.symlinks.clone().unwrap_or_default();
symlinks.push(info.executable.clone());
symlinks.append(&mut info.symlink.clone().unwrap_or_default());
symlinks.sort();
symlinks.dedup();

resolved.symlinks = Some(symlinks);
resolved.version = Some(info.version);
resolved.prefix = Some(info.prefix);
resolved.arch = Some(if info.is64_bit {
let version = Some(info.version);
let prefix = Some(info.prefix);
let arch = Some(if info.is64_bit {
Architecture::X64
} else {
Architecture::X86
});

let resolved = PythonEnvironmentBuilder::new(env.category)
.arch(arch)
.display_name(env.display_name)
.executable(Some(info.executable))
.manager(env.manager)
.name(env.name)
.prefix(prefix)
.project(env.project)
.search_path(env.search_path)
.symlinks(Some(symlinks))
.version(version)
.build();

Some(ResolvedEnvironment {
discovered,
resolved: Some(resolved),
Expand Down

0 comments on commit f33a69b

Please sign in to comment.