From 958979ed98b3c717340e7e272c578fd287cb1ee5 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 06:58:56 +1000 Subject: [PATCH 01/24] Fixes to in-memory caching --- crates/pet-python-utils/src/cache.rs | 32 ++++++++-------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index cbaf446c..d710a5a8 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -64,20 +64,14 @@ impl CacheImpl { self.cache_dir.lock().unwrap().replace(cache_dir); } fn create_cache(&self, executable: PathBuf) -> LockableCacheEntry { - if let Some(cache_directory) = self.cache_dir.lock().unwrap().as_ref() { - match self.locks.lock().unwrap().entry(executable.clone()) { - Entry::Occupied(lock) => lock.get().clone(), - Entry::Vacant(lock) => { - let cache = - Box::new(CacheEntryImpl::create(cache_directory.clone(), executable)) - as Box<(dyn CacheEntry + 'static)>; - lock.insert(Arc::new(Mutex::new(cache))).clone() - } + let cache_directory = self.cache_dir.lock().unwrap().clone(); + match self.locks.lock().unwrap().entry(executable.clone()) { + Entry::Occupied(lock) => lock.get().clone(), + Entry::Vacant(lock) => { + let cache = Box::new(CacheEntryImpl::create(cache_directory.clone(), executable)) + as Box<(dyn CacheEntry + 'static)>; + lock.insert(Arc::new(Mutex::new(cache))).clone() } - } else { - Arc::new(Mutex::new(Box::new(CacheEntryImpl::empty( - executable.clone(), - )))) } } } @@ -92,17 +86,9 @@ struct CacheEntryImpl { symlinks: Arc>>, } impl CacheEntryImpl { - pub fn create(cache_directory: PathBuf, executable: PathBuf) -> impl CacheEntry { - CacheEntryImpl { - cache_directory: Some(cache_directory), - executable, - envoronment: Arc::new(Mutex::new(None)), - symlinks: Arc::new(Mutex::new(Vec::new())), - } - } - pub fn empty(executable: PathBuf) -> impl CacheEntry { + pub fn create(cache_directory: Option, executable: PathBuf) -> impl CacheEntry { CacheEntryImpl { - cache_directory: None, + cache_directory, executable, envoronment: Arc::new(Mutex::new(None)), symlinks: Arc::new(Mutex::new(Vec::new())), From 7dbafa9b757f2275bb0e0c9eb67f99f543d6d3e3 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 07:19:56 +1000 Subject: [PATCH 02/24] Enable logging in tests --- crates/pet/tests/ci_homebrew_container.rs | 15 +++++++++++++++ crates/pet/tests/ci_poetry.rs | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/crates/pet/tests/ci_homebrew_container.rs b/crates/pet/tests/ci_homebrew_container.rs index 6e868bf3..54fa0bc1 100644 --- a/crates/pet/tests/ci_homebrew_container.rs +++ b/crates/pet/tests/ci_homebrew_container.rs @@ -1,8 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +use std::sync::Once; + mod common; +static INIT: Once = Once::new(); + +/// Setup function that is only run once, even if called multiple times. +fn setup() { + INIT.call_once(|| { + env_logger::builder() + .filter(None, log::LevelFilter::Trace) + .init(); + }); +} + #[cfg(unix)] #[cfg_attr(feature = "ci-homebrew-container", test)] #[allow(dead_code)] @@ -17,6 +30,8 @@ fn verify_python_in_homebrew_contaner() { use pet_reporter::{cache::CacheReporter, collect}; use std::{path::PathBuf, sync::Arc}; + setup(); + let reporter = Arc::new(collect::create_reporter()); let environment = EnvironmentApi::new(); let conda_locator = Arc::new(Conda::from(&environment)); diff --git a/crates/pet/tests/ci_poetry.rs b/crates/pet/tests/ci_poetry.rs index ba95fe52..8c14d3b0 100644 --- a/crates/pet/tests/ci_poetry.rs +++ b/crates/pet/tests/ci_poetry.rs @@ -1,11 +1,24 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +use std::sync::Once; + use pet_poetry::Poetry; use pet_reporter::{cache::CacheReporter, collect}; mod common; +static INIT: Once = Once::new(); + +/// Setup function that is only run once, even if called multiple times. +fn setup() { + INIT.call_once(|| { + env_logger::builder() + .filter(None, log::LevelFilter::Trace) + .init(); + }); +} + #[cfg_attr(any(feature = "ci-poetry-global", feature = "ci-poetry-custom"), test)] #[allow(dead_code)] /// This is a test with Poetry for current directory with Python 3.12 and 3.11 and envs are created in regular global cache directory @@ -20,6 +33,8 @@ fn verify_ci_poetry_global() { }; use std::{env, path::PathBuf, sync::Arc}; + setup(); + let workspace_dir = PathBuf::from(env::var("GITHUB_WORKSPACE").unwrap_or_default()); let reporter = Arc::new(collect::create_reporter()); let environment = EnvironmentApi::new(); @@ -88,6 +103,8 @@ fn verify_ci_poetry_project() { }; use std::{env, path::PathBuf, sync::Arc}; + setup(); + let workspace_dir = PathBuf::from(env::var("GITHUB_WORKSPACE").unwrap_or_default()); let reporter = Arc::new(collect::create_reporter()); let environment = EnvironmentApi::new(); From 7d3bf9598ca6e7a2917d0019170ff79fb01a93e1 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 07:20:40 +1000 Subject: [PATCH 03/24] oops --- crates/pet-conda/tests/ci_test.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/pet-conda/tests/ci_test.rs b/crates/pet-conda/tests/ci_test.rs index 3722bd1f..0bfd0a6a 100644 --- a/crates/pet-conda/tests/ci_test.rs +++ b/crates/pet-conda/tests/ci_test.rs @@ -310,10 +310,7 @@ fn detect_new_conda_env_created_with_p_flag_with_python() { use pet_core::{ os_environment::EnvironmentApi, python_environment::PythonEnvironmentKind, Locator, }; - use pet_reporter::{ - cache::{self, CacheReporter}, - collect, - }; + use pet_reporter::{cache::CacheReporter, collect}; setup(); let env_name = "env_with_python3"; From cac5faa4bcaf4a3e603ed064631c26ac3c401111 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 07:40:50 +1000 Subject: [PATCH 04/24] ci logging --- crates/pet/tests/ci_homebrew_container.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/pet/tests/ci_homebrew_container.rs b/crates/pet/tests/ci_homebrew_container.rs index 54fa0bc1..70dae08c 100644 --- a/crates/pet/tests/ci_homebrew_container.rs +++ b/crates/pet/tests/ci_homebrew_container.rs @@ -79,6 +79,7 @@ fn verify_python_in_homebrew_contaner() { }; assert_eq!(environments.len(), 2); + println!("Discovered environments: {:?}", environments); for env in [python3_11, python3_12].iter() { let python_env = environments From 73792c85b38e192d4b55aed8b177de7b769a9f34 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 07:54:49 +1000 Subject: [PATCH 05/24] more logging --- crates/pet-homebrew/src/environments.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/pet-homebrew/src/environments.rs b/crates/pet-homebrew/src/environments.rs index 2b8861e3..e1e44303 100644 --- a/crates/pet-homebrew/src/environments.rs +++ b/crates/pet-homebrew/src/environments.rs @@ -3,6 +3,7 @@ use crate::sym_links::get_known_symlinks; use lazy_static::lazy_static; +use log::trace; use pet_core::python_environment::{ PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind, }; @@ -19,6 +20,11 @@ pub fn get_python_info( python_exe_from_bin_dir: &Path, resolved_exe: &Path, ) -> Option { + trace!( + "Getting homebrew python info for {:?} => {:?}", + python_exe_from_bin_dir, + resolved_exe + ); // let user_friendly_exe = python_exe_from_bin_dir; let python_version = resolved_exe.to_string_lossy().to_string(); let version = match PYTHON_VERSION.captures(&python_version) { From 36b055d9b52a4fa57690f6b34a795536cd126eab Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 08:00:02 +1000 Subject: [PATCH 06/24] wip --- crates/pet-homebrew/src/environments.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/pet-homebrew/src/environments.rs b/crates/pet-homebrew/src/environments.rs index e1e44303..50dd1b69 100644 --- a/crates/pet-homebrew/src/environments.rs +++ b/crates/pet-homebrew/src/environments.rs @@ -31,7 +31,7 @@ pub fn get_python_info( Some(captures) => captures.get(1).map(|version| version.as_str().to_string()), None => None, }; - + println!("version: {:?}", version); let mut symlinks = vec![ python_exe_from_bin_dir.to_path_buf(), resolved_exe.to_path_buf(), @@ -60,6 +60,7 @@ pub fn get_python_info( .prefix(get_prefix(resolved_exe)) .symlinks(Some(symlinks)) .build(); + println!("env: {:?}", env); Some(env) } From 4938efe84fcbc1c3c5b1d9c0bf85613d116cd06c Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 08:20:13 +1000 Subject: [PATCH 07/24] wip --- crates/pet-homebrew/src/environments.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pet-homebrew/src/environments.rs b/crates/pet-homebrew/src/environments.rs index 50dd1b69..9dbe5f06 100644 --- a/crates/pet-homebrew/src/environments.rs +++ b/crates/pet-homebrew/src/environments.rs @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; lazy_static! { static ref PYTHON_VERSION: Regex = - Regex::new(r"/(\d+\.\d+\.\d+)/").expect("error parsing Version regex for Homebrew"); + Regex::new(r"/(\d+\.\d+\.\d+)").expect("error parsing Version regex for Homebrew"); } pub fn get_python_info( From eb2e0e115f3cc70c54d37d5377644d3f0f4e9a75 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 09:16:09 +1000 Subject: [PATCH 08/24] misc --- crates/pet-homebrew/src/environments.rs | 46 ++++++++++++++++++++----- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/crates/pet-homebrew/src/environments.rs b/crates/pet-homebrew/src/environments.rs index 9dbe5f06..a2e727ac 100644 --- a/crates/pet-homebrew/src/environments.rs +++ b/crates/pet-homebrew/src/environments.rs @@ -20,18 +20,15 @@ pub fn get_python_info( python_exe_from_bin_dir: &Path, resolved_exe: &Path, ) -> Option { + let version = get_version(resolved_exe); + trace!( - "Getting homebrew python info for {:?} => {:?}", + "Getting homebrew python info for {:?} => {:?} with version {:?}", python_exe_from_bin_dir, - resolved_exe + resolved_exe, + version ); - // let user_friendly_exe = python_exe_from_bin_dir; - let python_version = resolved_exe.to_string_lossy().to_string(); - let version = match PYTHON_VERSION.captures(&python_version) { - Some(captures) => captures.get(1).map(|version| version.as_str().to_string()), - None => None, - }; - println!("version: {:?}", version); + let mut symlinks = vec![ python_exe_from_bin_dir.to_path_buf(), resolved_exe.to_path_buf(), @@ -64,6 +61,14 @@ pub fn get_python_info( Some(env) } +fn get_version(resolved_exe: &Path) -> Option { + let python_version = resolved_exe.to_string_lossy().to_string(); + match PYTHON_VERSION.captures(&python_version) { + Some(captures) => captures.get(1).map(|version| version.as_str().to_string()), + None => None, + } +} + fn get_prefix(_resolved_file: &Path) -> Option { // NOTE: // While testing found that on Mac Intel @@ -142,3 +147,26 @@ fn get_prefix(_resolved_file: &Path) -> Option { // } None } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(unix)] + fn extract_version() { + assert_eq!( + get_version(&PathBuf::from( + "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.4/bin/python3" + )), + Some("3.12.4".to_string()) + ); + + assert_eq!( + get_version(&PathBuf::from( + "/home/linuxbrew/.linuxbrew/Cellar/python@3.11/3.11.9_1/bin/python3.11" + )), + Some("3.11.9".to_string()) + ); + } +} From a04d3b57457a6d0a40e887a14e19b1ecbe332212 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 10:53:49 +1000 Subject: [PATCH 09/24] Updates --- crates/pet-python-utils/src/cache.rs | 24 ++- crates/pet-python-utils/src/fs_cache.rs | 25 ++- crates/pet-python-utils/src/lib.rs | 2 +- crates/pet-python-utils/tests/cache_test.rs | 175 ++++++++++++++++++ .../conda_without_python/conda-meta/history | 3 + .../tests/unix/cache/python3.9.9/bin/python3 | 0 .../unix/cache/python3.9.9/bin/python3.9.9 | 0 .../cache/python3.9.9/include/patchlevel.h | 35 ++++ crates/pet/src/jsonrpc.rs | 25 +-- 9 files changed, 266 insertions(+), 23 deletions(-) create mode 100644 crates/pet-python-utils/tests/cache_test.rs create mode 100644 crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history create mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 create mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 create mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index d710a5a8..7c5380e5 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -2,9 +2,10 @@ // Licensed under the MIT License. use lazy_static::lazy_static; -use log::trace; +use log::{trace, warn}; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, + io, path::PathBuf, sync::{Arc, Mutex}, time::SystemTime, @@ -12,7 +13,7 @@ use std::{ use crate::{ env::ResolvedPythonEnv, - fs_cache::{get_cache_from_file, store_cache_in_file}, + fs_cache::{delete_cache_file, get_cache_from_file, store_cache_in_file}, }; lazy_static! { @@ -25,6 +26,10 @@ pub trait CacheEntry: Send + Sync { fn track_symlinks(&self, symlinks: Vec); } +pub fn clear_cache() -> io::Result<()> { + CACHE.clear() +} + pub fn create_cache(executable: PathBuf) -> Arc>> { CACHE.create_cache(executable) } @@ -61,8 +66,20 @@ impl CacheImpl { /// Once a cache directory has been set, you cannot change it. /// No point supporting such a scenario. fn set_cache_directory(&self, cache_dir: PathBuf) { + if self.cache_dir.lock().unwrap().is_some() { + warn!("Cache directory has already been set. Cannot change it now."); + return; + } self.cache_dir.lock().unwrap().replace(cache_dir); } + fn clear(&self) -> io::Result<()> { + self.locks.lock().unwrap().clear(); + if let Some(cache_directory) = self.cache_dir.lock().unwrap().clone() { + std::fs::remove_dir_all(&cache_directory) + } else { + Ok(()) + } + } fn create_cache(&self, executable: PathBuf) -> LockableCacheEntry { let cache_directory = self.cache_dir.lock().unwrap().clone(); match self.locks.lock().unwrap().entry(executable.clone()) { @@ -102,6 +119,9 @@ impl CacheEntryImpl { || metadata.created().ok() != symlink_info.2 { self.envoronment.lock().unwrap().take(); + if let Some(cache_directory) = &self.cache_directory { + delete_cache_file(cache_directory, &self.executable); + } } } } diff --git a/crates/pet-python-utils/src/fs_cache.rs b/crates/pet-python-utils/src/fs_cache.rs index 2d359420..1f6df867 100644 --- a/crates/pet-python-utils/src/fs_cache.rs +++ b/crates/pet-python-utils/src/fs_cache.rs @@ -23,10 +23,15 @@ struct CacheEntry { pub symlinks: Vec, } -fn generate_cache_file(cache_directory: &Path, executable: &PathBuf) -> PathBuf { +pub fn generate_cache_file(cache_directory: &Path, executable: &PathBuf) -> PathBuf { cache_directory.join(format!("{}.1.json", generate_hash(executable))) } +pub fn delete_cache_file(cache_directory: &Path, executable: &PathBuf) { + let cache_file = generate_cache_file(cache_directory, executable); + let _ = fs::remove_file(cache_file); +} + pub fn get_cache_from_file( cache_directory: &Path, executable: &PathBuf, @@ -36,6 +41,24 @@ pub fn get_cache_from_file( let reader = BufReader::new(file); let cache: CacheEntry = serde_json::from_reader(reader).ok()?; + // Account for conflicts in the cache file + // i.e. the hash generated is same for another file, remember we only take the first 16 chars. + if !cache + .environment + .clone() + .symlinks + .unwrap_or_default() + .contains(executable) + { + trace!( + "Cache file {:?} {:?}, does not match executable {:?} (possible hash collision)", + cache_file, + cache.environment, + executable + ); + return None; + } + // Check if any of the exes have changed since we last cached them. let cache_is_valid = cache.symlinks.iter().all(|symlink| { if let Ok(metadata) = symlink.0.metadata() { diff --git a/crates/pet-python-utils/src/lib.rs b/crates/pet-python-utils/src/lib.rs index 9a6aedfa..2f3cdda5 100644 --- a/crates/pet-python-utils/src/lib.rs +++ b/crates/pet-python-utils/src/lib.rs @@ -4,7 +4,7 @@ pub mod cache; pub mod env; pub mod executable; -mod fs_cache; +pub mod fs_cache; mod headers; pub mod platform_dirs; pub mod version; diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs new file mode 100644 index 00000000..76b7a7c7 --- /dev/null +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +mod common; +use std::path::PathBuf; + +use common::resolve_test_path; + +#[cfg(unix)] +#[test] +fn verify_cache() { + use std::{env, fs}; + + use pet_python_utils::{ + cache::{clear_cache, create_cache, set_cache_directory}, + env::ResolvedPythonEnv, + fs_cache::generate_cache_file, + }; + + let cache_dir = env::temp_dir().join("pet_cache"); + set_cache_directory(cache_dir.clone()); + + let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let bin = prefix.join("bin"); + let python = bin.join("python"); + let python3 = bin.join("python3"); + let resolve_env = ResolvedPythonEnv { + executable: python.clone(), + version: "3.9.9".to_string(), + prefix: prefix.clone(), + is64_bit: true, + symlinks: Some(vec![python.clone(), python3.clone()]), + }; + + // Ensure the file does not exist. + let cache_file = generate_cache_file(&cache_dir, &resolve_env.executable); + let _ = fs::remove_file(&cache_file); + + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + // No cache file, so we should not have a value. + assert!(cache.get().is_none()); + assert!(!cache_file.exists()); + + // Store the value in cache and verify the file exists. + cache.store(resolve_env.clone()); + + assert!(cache.get().is_some()); + assert!(cache_file.exists()); + drop(cache); + + // Creating a new cache should load the value from the file. + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + assert!(cache.get().is_some()); + assert!(cache_file.exists()); + drop(cache); + + // Deleting the cache file and Creating a new cache should not load the value from the file. + let _ = clear_cache(); + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + assert!(cache.get().is_none()); + assert!(!cache_file.exists()); +} + +#[cfg(unix)] +#[test] +fn verify_invalidating_cache() { + use std::{env, fs, time::SystemTime}; + + use pet_python_utils::{ + cache::{create_cache, set_cache_directory}, + env::ResolvedPythonEnv, + fs_cache::generate_cache_file, + }; + + let cache_dir = env::temp_dir().join("pet_cache"); + set_cache_directory(cache_dir.clone()); + + let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let bin = prefix.join("bin"); + let python = bin.join("python"); + let python3 = bin.join("python3"); + let resolve_env = ResolvedPythonEnv { + executable: python.clone(), + version: "3.9.9".to_string(), + prefix: prefix.clone(), + is64_bit: true, + symlinks: Some(vec![python.clone(), python3.clone()]), + }; + + // Ensure the file does not exist. + let cache_file = generate_cache_file(&cache_dir, &resolve_env.executable); + let _ = fs::remove_file(&cache_file); + + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + // Store the value in cache and verify the file exists. + cache.store(resolve_env.clone()); + + assert!(cache.get().is_some()); + assert!(cache_file.exists()); + + // Next update the executable, so as to cause the mtime to change. + // As a result of this the cache should no longer be valid. + let _ = fs::write(python.clone(), format!("{:?}", SystemTime::now())); + assert!(cache.get().is_none()); + assert!(!cache_file.exists()); +} + +#[cfg(unix)] +#[test] +fn verify_invalidating_cache_due_to_hash_conflicts() { + use std::{env, fs}; + + use pet_python_utils::{ + cache::{clear_cache, create_cache, set_cache_directory}, + env::ResolvedPythonEnv, + fs_cache::generate_cache_file, + }; + + let cache_dir = env::temp_dir().join("pet_cache"); + set_cache_directory(cache_dir.clone()); + + let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let bin = prefix.join("bin"); + let python = bin.join("python"); + let python3 = bin.join("python3"); + let resolve_env = ResolvedPythonEnv { + executable: python.clone(), + version: "3.9.9".to_string(), + prefix: prefix.clone(), + is64_bit: true, + symlinks: Some(vec![python.clone(), python3.clone()]), + }; + + // Ensure the file does not exist. + let cache_file = generate_cache_file(&cache_dir, &resolve_env.executable); + let _ = fs::remove_file(&cache_file); + + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + // Store the value in cache and verify the file exists. + cache.store(resolve_env.clone()); + + assert!(cache.get().is_some()); + assert!(cache_file.exists()); + drop(cache); + + // Simulate a hash collision by changing the executable to a different value. + // I.e. the cached file points to another executable. + let contents = fs::read_to_string(&cache_file.clone()).unwrap(); + let contents = contents.replace( + python.to_string_lossy().to_string().as_str(), + "/usr/bin/python", + ); + let contents = contents.replace( + python3.to_string_lossy().to_string().as_str(), + "/usr/bin/python3", + ); + + let _ = clear_cache(); // Clear in memory cache as well as the files.. + let _ = fs::create_dir_all(&cache_dir).unwrap(); + let _ = fs::write(&cache_file, contents); // Create the cache file with the invalid details. + let cache = create_cache(resolve_env.executable.clone()); + let cache = cache.lock().unwrap(); + + assert!(cache.get().is_none()); +} diff --git a/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history b/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history new file mode 100644 index 00000000..2db66a21 --- /dev/null +++ b/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history @@ -0,0 +1,3 @@ +==> 2024-02-29 08:48:22 <== +# cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda7 -y +# conda version: 23.11.0 diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 b/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 b/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h b/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h new file mode 100644 index 00000000..293e51a2 --- /dev/null +++ b/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h @@ -0,0 +1,35 @@ + +/* Python version identification scheme. + + When the major or minor version changes, the VERSION variable in + configure.ac must also be changed. + + There is also (independent) API version information in modsupport.h. +*/ + +/* Values for PY_RELEASE_LEVEL */ +#define PY_RELEASE_LEVEL_ALPHA 0xA +#define PY_RELEASE_LEVEL_BETA 0xB +#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ +#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ + /* Higher for patch releases */ + +/* Version parsed out into numeric values */ +/*--start constants--*/ +#define PY_MAJOR_VERSION 3 +#define PY_MINOR_VERSION 9 +#define PY_MICRO_VERSION 9 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 + +/* Version as a string */ +#define PY_VERSION "3.9.9" +/*--end constants--*/ + +/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. + Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ +#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ + (PY_MINOR_VERSION << 16) | \ + (PY_MICRO_VERSION << 8) | \ + (PY_RELEASE_LEVEL << 4) | \ + (PY_RELEASE_SERIAL << 0)) diff --git a/crates/pet/src/jsonrpc.rs b/crates/pet/src/jsonrpc.rs index 990b8fdb..b89ce36e 100644 --- a/crates/pet/src/jsonrpc.rs +++ b/crates/pet/src/jsonrpc.rs @@ -26,6 +26,7 @@ use pet_jsonrpc::{ }; use pet_poetry::Poetry; use pet_poetry::PoetryLocator; +use pet_python_utils::cache::clear_cache; use pet_python_utils::cache::set_cache_directory; use pet_reporter::collect; use pet_reporter::{cache::CacheReporter, jsonrpc}; @@ -384,27 +385,13 @@ pub fn handle_conda_telemetry(context: Arc, id: u32, _params: Value) { }); } -pub fn handle_clear_cache(context: Arc, id: u32, _params: Value) { +pub fn handle_clear_cache(_context: Arc, id: u32, _params: Value) { thread::spawn(move || { - if let Some(cache_directory) = context - .configuration - .read() - .unwrap() - .cache_directory - .clone() - { - if let Err(e) = std::fs::remove_dir_all(&cache_directory) { - error!("Failed to clear cache {:?}: {}", cache_directory, e); - send_error( - Some(id), - -4, - format!("Failed to clear cache {:?}: {}", cache_directory, e), - ); - } else { - info!("Cleared cache {:?}", cache_directory); - send_reply(id, None::<()>); - } + if let Err(e) = clear_cache() { + error!("Failed to clear cache {:?}", e); + send_error(Some(id), -4, format!("Failed to clear cache {:?}", e)); } else { + info!("Cleared cache"); send_reply(id, None::<()>); } }); From a5228f53efcba3d3fbd6b4b690ff2b69fb704842 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:02:15 +1000 Subject: [PATCH 10/24] oops --- crates/pet-homebrew/src/environments.rs | 1 - crates/pet/tests/ci_homebrew_container.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/pet-homebrew/src/environments.rs b/crates/pet-homebrew/src/environments.rs index a2e727ac..905b35a9 100644 --- a/crates/pet-homebrew/src/environments.rs +++ b/crates/pet-homebrew/src/environments.rs @@ -57,7 +57,6 @@ pub fn get_python_info( .prefix(get_prefix(resolved_exe)) .symlinks(Some(symlinks)) .build(); - println!("env: {:?}", env); Some(env) } diff --git a/crates/pet/tests/ci_homebrew_container.rs b/crates/pet/tests/ci_homebrew_container.rs index 70dae08c..54fa0bc1 100644 --- a/crates/pet/tests/ci_homebrew_container.rs +++ b/crates/pet/tests/ci_homebrew_container.rs @@ -79,7 +79,6 @@ fn verify_python_in_homebrew_contaner() { }; assert_eq!(environments.len(), 2); - println!("Discovered environments: {:?}", environments); for env in [python3_11, python3_12].iter() { let python_env = environments From 897f5e02702353ec2525355d175459cf8a3c0231 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:22:16 +1000 Subject: [PATCH 11/24] fixes --- crates/pet/src/jsonrpc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/pet/src/jsonrpc.rs b/crates/pet/src/jsonrpc.rs index b89ce36e..d4d24f50 100644 --- a/crates/pet/src/jsonrpc.rs +++ b/crates/pet/src/jsonrpc.rs @@ -83,7 +83,7 @@ pub fn start_jsonrpc_server() { handlers.add_request_handler("resolve", handle_resolve); handlers.add_request_handler("find", handle_find); handlers.add_request_handler("condaInfo", handle_conda_telemetry); - handlers.add_request_handler("clearCache", handle_clear_cache); + handlers.add_request_handler("clear", handle_clear_cache); start_server(&handlers) } @@ -320,6 +320,7 @@ pub fn handle_resolve(context: Arc, id: u32, params: Value) { } #[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct FindOptions { /// Search path, can be a directory or a Python executable as well. /// If passing a directory, the assumption is that its a project directory (workspace folder). From 94e39ee3320146f39b1031761fd76c344f38136c Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:24:12 +1000 Subject: [PATCH 12/24] logging --- crates/pet-python-utils/src/cache.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index 7c5380e5..f6449cfd 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -70,6 +70,7 @@ impl CacheImpl { warn!("Cache directory has already been set. Cannot change it now."); return; } + trace!("Setting cache directory to {:?}", cache_dir); self.cache_dir.lock().unwrap().replace(cache_dir); } fn clear(&self) -> io::Result<()> { From 9d84c5cf9be096947dff07b0dc13c9b2676a861a Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:28:05 +1000 Subject: [PATCH 13/24] tests --- crates/pet-python-utils/Cargo.toml | 1 + crates/pet-python-utils/tests/cache_test.rs | 61 ++++++++++++++++++--- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/crates/pet-python-utils/Cargo.toml b/crates/pet-python-utils/Cargo.toml index a782b5a6..c4174140 100644 --- a/crates/pet-python-utils/Cargo.toml +++ b/crates/pet-python-utils/Cargo.toml @@ -15,3 +15,4 @@ serde = { version = "1.0.152", features = ["derive"] } log = "0.4.21" serde_json = "1.0.93" sha2 = "0.10.6" +env_logger = "0.10.2" \ No newline at end of file diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 76b7a7c7..06e1d0e7 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -2,12 +2,33 @@ // Licensed under the MIT License. mod common; -use std::path::PathBuf; +use std::{path::PathBuf, sync::Once}; use common::resolve_test_path; -#[cfg(unix)] -#[test] +static INIT: Once = Once::new(); + +/// Setup function that is only run once, even if called multiple times. +fn setup() { + INIT.call_once(|| { + env_logger::builder() + .filter(None, log::LevelFilter::Trace) + .init(); + }); +} + +#[cfg_attr( + any( + feature = "ci", + feature = "ci-jupyter-container", + feature = "ci-homebrew-container", + feature = "ci-poetry-global", + feature = "ci-poetry-project", + feature = "ci-poetry-custom", + ), + test +)] +#[allow(dead_code)] fn verify_cache() { use std::{env, fs}; @@ -17,6 +38,8 @@ fn verify_cache() { fs_cache::generate_cache_file, }; + setup(); + let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); @@ -67,8 +90,18 @@ fn verify_cache() { assert!(!cache_file.exists()); } -#[cfg(unix)] -#[test] +#[cfg_attr( + any( + feature = "ci", + feature = "ci-jupyter-container", + feature = "ci-homebrew-container", + feature = "ci-poetry-global", + feature = "ci-poetry-project", + feature = "ci-poetry-custom", + ), + test +)] +#[allow(dead_code)] fn verify_invalidating_cache() { use std::{env, fs, time::SystemTime}; @@ -78,6 +111,8 @@ fn verify_invalidating_cache() { fs_cache::generate_cache_file, }; + setup(); + let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); @@ -113,8 +148,18 @@ fn verify_invalidating_cache() { assert!(!cache_file.exists()); } -#[cfg(unix)] -#[test] +#[cfg_attr( + any( + feature = "ci", + feature = "ci-jupyter-container", + feature = "ci-homebrew-container", + feature = "ci-poetry-global", + feature = "ci-poetry-project", + feature = "ci-poetry-custom", + ), + test +)] +#[allow(dead_code)] fn verify_invalidating_cache_due_to_hash_conflicts() { use std::{env, fs}; @@ -124,6 +169,8 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { fs_cache::generate_cache_file, }; + setup(); + let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); From bb0783050025a126148cada367579d1f71eab9d2 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:29:29 +1000 Subject: [PATCH 14/24] oops --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 0a080d37..fde7bebd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -564,6 +564,7 @@ dependencies = [ name = "pet-python-utils" version = "0.1.0" dependencies = [ + "env_logger", "lazy_static", "log", "msvc_spectre_libs", From d19af57c84a5d96232a98184aae0622687ec9f23 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 11:31:24 +1000 Subject: [PATCH 15/24] fixes --- crates/pet-python-utils/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index f6449cfd..036ed895 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -76,7 +76,7 @@ impl CacheImpl { fn clear(&self) -> io::Result<()> { self.locks.lock().unwrap().clear(); if let Some(cache_directory) = self.cache_dir.lock().unwrap().clone() { - std::fs::remove_dir_all(&cache_directory) + std::fs::remove_dir_all(cache_directory) } else { Ok(()) } From 7cd319b1c6fc39e82edbbd73fea286c95094d55c Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 12:37:38 +1000 Subject: [PATCH 16/24] fixes --- crates/pet-python-utils/Cargo.toml | 10 ++++- crates/pet-python-utils/src/cache.rs | 36 +++++++++++------ crates/pet-python-utils/src/fs_cache.rs | 39 ++++++++++++------- crates/pet-python-utils/tests/cache_test.rs | 13 ++++--- .../conda_without_python/conda-meta/history | 3 -- .../tests/unix/cache/python3.9.9/bin/python3 | 0 .../unix/cache/python3.9.9/bin/python3.9.9 | 0 .../cache/python3.9.9/include/patchlevel.h | 35 ----------------- 8 files changed, 67 insertions(+), 69 deletions(-) delete mode 100644 crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history delete mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 delete mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 delete mode 100644 crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h diff --git a/crates/pet-python-utils/Cargo.toml b/crates/pet-python-utils/Cargo.toml index c4174140..f99d6b15 100644 --- a/crates/pet-python-utils/Cargo.toml +++ b/crates/pet-python-utils/Cargo.toml @@ -15,4 +15,12 @@ serde = { version = "1.0.152", features = ["derive"] } log = "0.4.21" serde_json = "1.0.93" sha2 = "0.10.6" -env_logger = "0.10.2" \ No newline at end of file +env_logger = "0.10.2" + +[features] +ci = [] +ci-jupyter-container = [] +ci-homebrew-container = [] +ci-poetry-global = [] +ci-poetry-project = [] +ci-poetry-custom = [] diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index 036ed895..00b64282 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -66,14 +66,18 @@ impl CacheImpl { /// Once a cache directory has been set, you cannot change it. /// No point supporting such a scenario. fn set_cache_directory(&self, cache_dir: PathBuf) { - if self.cache_dir.lock().unwrap().is_some() { - warn!("Cache directory has already been set. Cannot change it now."); + if let Some(cache_dir) = self.cache_dir.lock().unwrap().clone() { + warn!( + "Cache directory has already been set to {:?}. Cannot change it now.", + cache_dir + ); return; } trace!("Setting cache directory to {:?}", cache_dir); self.cache_dir.lock().unwrap().replace(cache_dir); } fn clear(&self) -> io::Result<()> { + trace!("Clearing cache"); self.locks.lock().unwrap().clear(); if let Some(cache_directory) = self.cache_dir.lock().unwrap().clone() { std::fs::remove_dir_all(cache_directory) @@ -94,7 +98,7 @@ impl CacheImpl { } } -type FilePathWithMTimeCTime = (PathBuf, Option, Option); +type FilePathWithMTimeCTime = (PathBuf, SystemTime, SystemTime); struct CacheEntryImpl { cache_directory: Option, @@ -116,9 +120,17 @@ impl CacheEntryImpl { // Check if any of the exes have changed since we last cached this. for symlink_info in self.symlinks.lock().unwrap().iter() { if let Ok(metadata) = symlink_info.0.metadata() { - if metadata.modified().ok() != symlink_info.1 - || metadata.created().ok() != symlink_info.2 + if metadata.modified().ok() != Some(symlink_info.1) + || metadata.created().ok() != Some(symlink_info.2) { + trace!( + "Symlink {:?} has changed since we last cached it. original mtime & ctime {:?}, {:?}, current mtime & ctime {:?}, {:?}", + symlink_info.0, + symlink_info.1, + symlink_info.2, + metadata.modified().ok(), + metadata.created().ok() + ); self.envoronment.lock().unwrap().take(); if let Some(cache_directory) = &self.cache_directory { delete_cache_file(cache_directory, &self.executable); @@ -156,11 +168,12 @@ impl CacheEntry for CacheEntryImpl { let mut symlinks = vec![]; for symlink in environment.symlinks.clone().unwrap_or_default().iter() { if let Ok(metadata) = symlink.metadata() { - symlinks.push(( - symlink.clone(), - metadata.modified().ok(), - metadata.created().ok(), - )); + // We only care if we have the information + if let (Some(modified), Some(created)) = + (metadata.modified().ok(), metadata.created().ok()) + { + symlinks.push((symlink.clone(), modified, created)); + } } } @@ -174,8 +187,9 @@ impl CacheEntry for CacheEntryImpl { .unwrap() .replace(environment.clone()); + trace!("Caching interpreter info for {:?}", self.executable); + if let Some(ref cache_directory) = self.cache_directory { - trace!("Storing cache for {:?}", self.executable); store_cache_in_file(cache_directory, &self.executable, &environment, symlinks) } } diff --git a/crates/pet-python-utils/src/fs_cache.rs b/crates/pet-python-utils/src/fs_cache.rs index 1f6df867..276a144a 100644 --- a/crates/pet-python-utils/src/fs_cache.rs +++ b/crates/pet-python-utils/src/fs_cache.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use log::trace; +use log::{error, trace}; use pet_fs::path::norm_case; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -14,7 +14,7 @@ use std::{ use crate::env::ResolvedPythonEnv; -type FilePathWithMTimeCTime = (PathBuf, Option, Option); +type FilePathWithMTimeCTime = (PathBuf, SystemTime, SystemTime); #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -24,7 +24,7 @@ struct CacheEntry { } pub fn generate_cache_file(cache_directory: &Path, executable: &PathBuf) -> PathBuf { - cache_directory.join(format!("{}.1.json", generate_hash(executable))) + cache_directory.join(format!("{}.2.json", generate_hash(executable))) } pub fn delete_cache_file(cache_directory: &Path, executable: &PathBuf) { @@ -62,7 +62,8 @@ pub fn get_cache_from_file( // Check if any of the exes have changed since we last cached them. let cache_is_valid = cache.symlinks.iter().all(|symlink| { if let Ok(metadata) = symlink.0.metadata() { - metadata.modified().ok() == symlink.1 && metadata.created().ok() == symlink.2 + metadata.modified().ok() == Some(symlink.1) + && metadata.created().ok() == Some(symlink.2) } else { // File may have been deleted. false @@ -85,15 +86,27 @@ pub fn store_cache_in_file( symlinks_with_times: Vec, ) { let cache_file = generate_cache_file(cache_directory, executable); - let _ = std::fs::create_dir_all(cache_directory); - - let cache = CacheEntry { - environment: environment.clone(), - symlinks: symlinks_with_times, - }; - if let Ok(file) = std::fs::File::create(cache_file.clone()) { - trace!("Caching {:?} in {:?}", executable, cache_file); - let _ = serde_json::to_writer_pretty(file, &cache).ok(); + match std::fs::create_dir_all(cache_directory) { + Ok(_) => { + let cache = CacheEntry { + environment: environment.clone(), + symlinks: symlinks_with_times, + }; + match std::fs::File::create(cache_file.clone()) { + Ok(file) => { + trace!("Caching {:?} in {:?}", executable, cache_file); + match serde_json::to_writer_pretty(file, &cache) { + Ok(_) => (), + Err(err) => error!("Error writing cache file {:?} {:?}", cache_file, err), + } + } + Err(err) => error!("Error creating cache file {:?} {:?}", cache_file, err), + } + } + Err(err) => error!( + "Error creating cache directory {:?} {:?}", + cache_directory, err + ), } } diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 06e1d0e7..aa869fca 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -5,6 +5,7 @@ mod common; use std::{path::PathBuf, sync::Once}; use common::resolve_test_path; +use log::trace; static INIT: Once = Once::new(); @@ -19,7 +20,7 @@ fn setup() { #[cfg_attr( any( - feature = "ci", + feature = "ci", // Try to run this in all ci jobs/environments feature = "ci-jupyter-container", feature = "ci-homebrew-container", feature = "ci-poetry-global", @@ -43,7 +44,7 @@ fn verify_cache() { let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); - let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); @@ -92,7 +93,7 @@ fn verify_cache() { #[cfg_attr( any( - feature = "ci", + feature = "ci", // Try to run this in all ci jobs/environments feature = "ci-jupyter-container", feature = "ci-homebrew-container", feature = "ci-poetry-global", @@ -116,7 +117,7 @@ fn verify_invalidating_cache() { let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); - let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); @@ -150,7 +151,7 @@ fn verify_invalidating_cache() { #[cfg_attr( any( - feature = "ci", + feature = "ci", // Try to run this in all ci jobs/environments feature = "ci-jupyter-container", feature = "ci-homebrew-container", feature = "ci-poetry-global", @@ -174,7 +175,7 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); - let prefix: PathBuf = resolve_test_path(&["unix", "cache", ".venv"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); diff --git a/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history b/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history deleted file mode 100644 index 2db66a21..00000000 --- a/crates/pet-python-utils/tests/unix/cache/conda_without_python/conda-meta/history +++ /dev/null @@ -1,3 +0,0 @@ -==> 2024-02-29 08:48:22 <== -# cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda7 -y -# conda version: 23.11.0 diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 b/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3 deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 b/crates/pet-python-utils/tests/unix/cache/python3.9.9/bin/python3.9.9 deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h b/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h deleted file mode 100644 index 293e51a2..00000000 --- a/crates/pet-python-utils/tests/unix/cache/python3.9.9/include/patchlevel.h +++ /dev/null @@ -1,35 +0,0 @@ - -/* Python version identification scheme. - - When the major or minor version changes, the VERSION variable in - configure.ac must also be changed. - - There is also (independent) API version information in modsupport.h. -*/ - -/* Values for PY_RELEASE_LEVEL */ -#define PY_RELEASE_LEVEL_ALPHA 0xA -#define PY_RELEASE_LEVEL_BETA 0xB -#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ -#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ - /* Higher for patch releases */ - -/* Version parsed out into numeric values */ -/*--start constants--*/ -#define PY_MAJOR_VERSION 3 -#define PY_MINOR_VERSION 9 -#define PY_MICRO_VERSION 9 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 - -/* Version as a string */ -#define PY_VERSION "3.9.9" -/*--end constants--*/ - -/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. - Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ -#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ - (PY_MINOR_VERSION << 16) | \ - (PY_MICRO_VERSION << 8) | \ - (PY_RELEASE_LEVEL << 4) | \ - (PY_RELEASE_SERIAL << 0)) From 024cadc8a02a6909a581371ecb1cc5d2bb1bddf9 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 12:45:02 +1000 Subject: [PATCH 17/24] create multiple venvs --- crates/pet-python-utils/tests/cache_test.rs | 5 ++--- .../tests/unix/executables/.venv2/bin/python | 0 .../tests/unix/executables/.venv2/bin/python3 | 0 .../tests/unix/executables/.venv2/pyvenv.cfg | 5 +++++ .../tests/unix/executables/.venv3/bin/python | 0 .../tests/unix/executables/.venv3/bin/python3 | 0 .../tests/unix/executables/.venv3/pyvenv.cfg | 5 +++++ 7 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/bin/python create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/bin/python create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 create mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index aa869fca..5397a900 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -5,7 +5,6 @@ mod common; use std::{path::PathBuf, sync::Once}; use common::resolve_test_path; -use log::trace; static INIT: Once = Once::new(); @@ -117,7 +116,7 @@ fn verify_invalidating_cache() { let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); - let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv2"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); @@ -175,7 +174,7 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { let cache_dir = env::temp_dir().join("pet_cache"); set_cache_directory(cache_dir.clone()); - let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv3"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python b/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 b/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg b/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg new file mode 100644 index 00000000..860b12e2 --- /dev/null +++ b/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin +include-system-site-packages = false +version = 3.12.1 +executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 +command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python b/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 b/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 new file mode 100644 index 00000000..e69de29b diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg b/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg new file mode 100644 index 00000000..860b12e2 --- /dev/null +++ b/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin +include-system-site-packages = false +version = 3.12.1 +executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 +command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv From 7b22622dcf58dddf07339494383bb35f6366fe63 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 13:27:13 +1000 Subject: [PATCH 18/24] updates --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f3f71df4..c8db9e06 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ target/ .DS_Store # Testing directories -.venv/ +./.venv/ tmp/ temp/ docs/node_modules/ From 3dedc79d9a9c47de90a9b12b7c113931c209d0b1 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 13:47:55 +1000 Subject: [PATCH 19/24] udpatges --- .github/workflows/pr-check.yml | 600 +++++++++--------- crates/pet-python-utils/src/fs_cache.rs | 2 +- crates/pet-python-utils/tests/cache_test.rs | 33 +- .../tests/unix/executables/.venv/bin/python | 1 + .../tests/unix/executables/.venv2/bin/python | 0 .../tests/unix/executables/.venv2/bin/python3 | 0 .../tests/unix/executables/.venv2/pyvenv.cfg | 5 - .../tests/unix/executables/.venv3/bin/python | 0 .../tests/unix/executables/.venv3/bin/python3 | 0 .../tests/unix/executables/.venv3/pyvenv.cfg | 5 - 10 files changed, 316 insertions(+), 330 deletions(-) delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/bin/python delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/bin/python delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 delete mode 100644 crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index a1cbdfb4..b5daf3d1 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -15,183 +15,183 @@ on: - release-* jobs: - tests: - # Very generic tests, we don't verify whether the envs are discovered correctly or not. - # However we do ensure that envs that are discovered are valid. - # See other jobs for specific tests. - name: Tests - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: windows-latest - target: x86_64-pc-windows-msvc - run_cli: "yes" - - os: ubuntu-latest - target: x86_64-unknown-linux-musl - run_cli: "yes" - - os: macos-latest - target: x86_64-apple-darwin - run_cli: "yes" - - os: macos-14 - target: aarch64-apple-darwin - run_cli: "yes" - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set Python to PATH - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Homebrew Python - if: startsWith( matrix.os, 'macos') - run: brew install python - shell: bash - - - name: Add Conda to PATH - if: startsWith( matrix.os, 'windows') - run: | - $path = $env:PATH + ";" + $env:CONDA + "\condabin" - echo "PATH=$path" >> $env:GITHUB_ENV - - - name: Add Conda to PATH - if: startsWith( matrix.os, 'ubuntu') - run: echo "PATH=$PATH:$CONDA/condabin" >> $GITHUB_ENV - shell: bash - - - name: Install Conda + add to PATH - if: startsWith( matrix.os, 'macos') - run: | - curl -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh - bash ~/miniconda.sh -b -p ~/miniconda - echo "PATH=$PATH:$HOME/miniconda/bin" >> $GITHUB_ENV - echo "CONDA=$HOME/miniconda" >> $GITHUB_ENV - shell: bash - - - name: Check Conda version - run: conda info --all - - - name: Create Conda Environments - run: | - conda create -n test-env1 python=3.12 -y - conda create -n test-env-no-python -y - conda create -p ./prefix-envs/.conda1 python=3.12 -y - conda create -p ./prefix-envs/.conda-nopy -y - - - name: Install pipenv - run: pip install pipenv - - - name: Check pipenv version - run: pipenv --version - - - name: Create a Pipenv Environment - run: pipenv install - - - name: Install virtualenvwrapper - # Activation of the script doesn't work on mac for some reason (didn't check why yet) - # But linux is sufficient for the tests - if: startsWith( matrix.os, 'ubuntu') - run: | - pip install virtualenvwrapper - echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV - mkdir -p $HOME/.virtualenvs - source virtualenvwrapper.sh - mkvirtualenv venv_wrapper_env1 - shell: bash - - - name: Install virtualenvwrapper-win - if: startsWith( matrix.os, 'windows') - run: | - pip install virtualenvwrapper-win - echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV - shell: bash - - - name: Install pyenv - if: startsWith( matrix.os, 'windows') - run: | - choco install pyenv-win -y - echo "PATH=$PATH;$HOME/.pyenv/pyenv-win/bin;$HOME/.pyenv/pyenv-win/shims" >> $GITHUB_ENV - echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV - shell: bash - - - name: Install pyenv and pyenv-virtualenv - if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - run: | - curl https://pyenv.run | bash - echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV - echo "PATH=$HOME/.pyenv/bin:$PATH" >> $GITHUB_ENV - shell: bash - - - name: Check Pyenv version - run: pyenv --version - shell: bash - - - name: Install Pyenv Python(s) - if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - run: | - pyenv install --list - pyenv install 3.12.4 3.8.19 - shell: bash - - # pyenv-win install list has not updated for a while - - name: Install Pyenv Python(s) - if: startsWith( matrix.os, 'windows') - run: | - pyenv install --list - pyenv install 3.10.5 3.8.10 - shell: bash - - - name: Create pyenv-virtualenv envs - if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - run: | - eval "$(pyenv virtualenv-init -)" - pyenv virtualenv 3.12 pyenv-virtualenv-env1 - shell: bash - - # region venv - - name: Create .venv - # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - run: | - python -m venv .venv - shell: bash - - - name: Create .venv2 - # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - run: | - python -m venv .venv2 - shell: bash - - # endregion venv - - # Rust - - name: Rust Tool Chain setup - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - targets: ${{ matrix.target }} - - - name: Cargo Fetch - run: cargo fetch - shell: bash - - - name: Find Environments - if: matrix.run_cli == 'yes' - run: cargo run --release --target ${{ matrix.target }} - shell: bash - - - name: Run Tests - # Run integration tests in a single thread, - # We end up creating conda envs and running multiple tests in parallel - # that creat conda envs simultaneously causes issues (sometimes the conda envs do not seem to get created) - # Similar issues were identified in vscode-jupyter tests as well (something to do with conda lock files or the like) - run: cargo test --frozen --features ci -- --nocapture --test-threads=1 - env: - RUST_BACKTRACE: 1 - RUST_LOG: trace - shell: bash + # tests: + # # Very generic tests, we don't verify whether the envs are discovered correctly or not. + # # However we do ensure that envs that are discovered are valid. + # # See other jobs for specific tests. + # name: Tests + # runs-on: ${{ matrix.os }} + # strategy: + # fail-fast: false + # matrix: + # include: + # - os: windows-latest + # target: x86_64-pc-windows-msvc + # run_cli: "yes" + # - os: ubuntu-latest + # target: x86_64-unknown-linux-musl + # run_cli: "yes" + # - os: macos-latest + # target: x86_64-apple-darwin + # run_cli: "yes" + # - os: macos-14 + # target: aarch64-apple-darwin + # run_cli: "yes" + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Set Python to PATH + # uses: actions/setup-python@v5 + # with: + # python-version: "3.x" + + # - name: Homebrew Python + # if: startsWith( matrix.os, 'macos') + # run: brew install python + # shell: bash + + # - name: Add Conda to PATH + # if: startsWith( matrix.os, 'windows') + # run: | + # $path = $env:PATH + ";" + $env:CONDA + "\condabin" + # echo "PATH=$path" >> $env:GITHUB_ENV + + # - name: Add Conda to PATH + # if: startsWith( matrix.os, 'ubuntu') + # run: echo "PATH=$PATH:$CONDA/condabin" >> $GITHUB_ENV + # shell: bash + + # - name: Install Conda + add to PATH + # if: startsWith( matrix.os, 'macos') + # run: | + # curl -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh + # bash ~/miniconda.sh -b -p ~/miniconda + # echo "PATH=$PATH:$HOME/miniconda/bin" >> $GITHUB_ENV + # echo "CONDA=$HOME/miniconda" >> $GITHUB_ENV + # shell: bash + + # - name: Check Conda version + # run: conda info --all + + # - name: Create Conda Environments + # run: | + # conda create -n test-env1 python=3.12 -y + # conda create -n test-env-no-python -y + # conda create -p ./prefix-envs/.conda1 python=3.12 -y + # conda create -p ./prefix-envs/.conda-nopy -y + + # - name: Install pipenv + # run: pip install pipenv + + # - name: Check pipenv version + # run: pipenv --version + + # - name: Create a Pipenv Environment + # run: pipenv install + + # - name: Install virtualenvwrapper + # # Activation of the script doesn't work on mac for some reason (didn't check why yet) + # # But linux is sufficient for the tests + # if: startsWith( matrix.os, 'ubuntu') + # run: | + # pip install virtualenvwrapper + # echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV + # mkdir -p $HOME/.virtualenvs + # source virtualenvwrapper.sh + # mkvirtualenv venv_wrapper_env1 + # shell: bash + + # - name: Install virtualenvwrapper-win + # if: startsWith( matrix.os, 'windows') + # run: | + # pip install virtualenvwrapper-win + # echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV + # shell: bash + + # - name: Install pyenv + # if: startsWith( matrix.os, 'windows') + # run: | + # choco install pyenv-win -y + # echo "PATH=$PATH;$HOME/.pyenv/pyenv-win/bin;$HOME/.pyenv/pyenv-win/shims" >> $GITHUB_ENV + # echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + # shell: bash + + # - name: Install pyenv and pyenv-virtualenv + # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + # run: | + # curl https://pyenv.run | bash + # echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + # echo "PATH=$HOME/.pyenv/bin:$PATH" >> $GITHUB_ENV + # shell: bash + + # - name: Check Pyenv version + # run: pyenv --version + # shell: bash + + # - name: Install Pyenv Python(s) + # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + # run: | + # pyenv install --list + # pyenv install 3.12.4 3.8.19 + # shell: bash + + # # pyenv-win install list has not updated for a while + # - name: Install Pyenv Python(s) + # if: startsWith( matrix.os, 'windows') + # run: | + # pyenv install --list + # pyenv install 3.10.5 3.8.10 + # shell: bash + + # - name: Create pyenv-virtualenv envs + # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + # run: | + # eval "$(pyenv virtualenv-init -)" + # pyenv virtualenv 3.12 pyenv-virtualenv-env1 + # shell: bash + + # # region venv + # - name: Create .venv + # # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + # run: | + # python -m venv .venv + # shell: bash + + # - name: Create .venv2 + # # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + # run: | + # python -m venv .venv2 + # shell: bash + + # # endregion venv + + # # Rust + # - name: Rust Tool Chain setup + # uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: stable + # targets: ${{ matrix.target }} + + # - name: Cargo Fetch + # run: cargo fetch + # shell: bash + + # - name: Find Environments + # if: matrix.run_cli == 'yes' + # run: cargo run --release --target ${{ matrix.target }} + # shell: bash + + # - name: Run Tests + # # Run integration tests in a single thread, + # # We end up creating conda envs and running multiple tests in parallel + # # that creat conda envs simultaneously causes issues (sometimes the conda envs do not seem to get created) + # # Similar issues were identified in vscode-jupyter tests as well (something to do with conda lock files or the like) + # run: cargo test --frozen --features ci -- --nocapture --test-threads=1 + # env: + # RUST_BACKTRACE: 1 + # RUST_LOG: trace + # shell: bash isolated-tests: # Some of these tests are very specific and need to be run in isolation. @@ -203,24 +203,24 @@ jobs: fail-fast: false matrix: include: + # - feature: ci-poetry-global # Poetry tests with envs stored in standard location + # os: ubuntu-latest + # target: x86_64-unknown-linux-musl + # - feature: ci-poetry-project # Poetry tests, with poetry envs in project + # os: ubuntu-latest + # target: x86_64-unknown-linux-musl + # - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location + # os: ubuntu-latest + # target: x86_64-unknown-linux-musl - feature: ci-poetry-global # Poetry tests with envs stored in standard location - os: ubuntu-latest - target: x86_64-unknown-linux-musl - - feature: ci-poetry-project # Poetry tests, with poetry envs in project - os: ubuntu-latest - target: x86_64-unknown-linux-musl - - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location - os: ubuntu-latest - target: x86_64-unknown-linux-musl - - feature: ci-poetry-global # Poetry tests with envs stored in standard location - os: windows-latest - target: x86_64-pc-windows-msvc - - feature: ci-poetry-project # Poetry tests, with poetry envs in project - os: windows-latest - target: x86_64-pc-windows-msvc - - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location os: windows-latest target: x86_64-pc-windows-msvc + # - feature: ci-poetry-project # Poetry tests, with poetry envs in project + # os: windows-latest + # target: x86_64-pc-windows-msvc + # - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location + # os: windows-latest + # target: x86_64-pc-windows-msvc steps: - name: Checkout uses: actions/checkout@v4 @@ -365,111 +365,111 @@ jobs: RUST_LOG: trace shell: bash - container-tests: - # These tests are required as its not easy/possible to use the previous jobs. - # E.g. we need to test against the jupyter container, as we found some issues specific to that env. - name: Tests in Containers - container: - image: ${{ matrix.image }} - options: --user=root - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - feature: ci-jupyter-container - os: ubuntu-latest - # For Tests again the container used in https://github.com/github/codespaces-jupyter - image: mcr.microsoft.com/devcontainers/universal:2.11.1 - target: x86_64-unknown-linux-musl - - feature: ci-homebrew-container - os: ubuntu-latest - # For Homebrew in Ubuntu - image: homebrew/brew - target: x86_64-unknown-linux-musl - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Homebrew - - name: Homebrew Python - if: startsWith( matrix.image, 'homebrew') - run: brew install python@3.12 python@3.11 - shell: bash - - # Rust - - name: Rust Tool Chain setup - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - targets: ${{ matrix.target }} - - - name: Cargo Fetch - run: cargo fetch - shell: bash - - - name: Find Environments - run: cargo run --release --target ${{ matrix.target }} - shell: bash - - - name: Run Tests - run: cargo test --frozen --features ${{ matrix.feature }} -- --nocapture - shell: bash - - builds: - name: Builds - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: windows-latest - target: x86_64-pc-windows-msvc - - os: windows-latest - target: aarch64-pc-windows-msvc - - os: ubuntu-latest - target: x86_64-unknown-linux-musl - run_cli: "yes" - # - os: ubuntu-latest - # target: aarch64-unknown-linux-gnu - # - os: ubuntu-latest - # target: arm-unknown-linux-gnueabihf - - os: macos-latest - target: x86_64-apple-darwin - run_cli: "yes" - - os: macos-14 - target: aarch64-apple-darwin - run_cli: "yes" - # - os: ubuntu-latest - # target: x86_64-unknown-linux-gnu - # - os: ubuntu-latest - # target: aarch64-unknown-linux-musl - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Rust Tool Chain setup - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - targets: ${{ matrix.target }} - - - name: Cargo Fetch - run: cargo fetch - shell: bash - - - name: Run Tests - # We do not want to run all features, CI is only for tests with Python - # Thats a separate job. - run: cargo test --frozen - shell: bash - - - name: Build - run: cargo build --release --target ${{ matrix.target }} - shell: bash - - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: pet-${{ matrix.target }} - path: target/${{ matrix.target }}/release/pet* + # container-tests: + # # These tests are required as its not easy/possible to use the previous jobs. + # # E.g. we need to test against the jupyter container, as we found some issues specific to that env. + # name: Tests in Containers + # container: + # image: ${{ matrix.image }} + # options: --user=root + # runs-on: ${{ matrix.os }} + # strategy: + # fail-fast: false + # matrix: + # include: + # - feature: ci-jupyter-container + # os: ubuntu-latest + # # For Tests again the container used in https://github.com/github/codespaces-jupyter + # image: mcr.microsoft.com/devcontainers/universal:2.11.1 + # target: x86_64-unknown-linux-musl + # - feature: ci-homebrew-container + # os: ubuntu-latest + # # For Homebrew in Ubuntu + # image: homebrew/brew + # target: x86_64-unknown-linux-musl + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # # Homebrew + # - name: Homebrew Python + # if: startsWith( matrix.image, 'homebrew') + # run: brew install python@3.12 python@3.11 + # shell: bash + + # # Rust + # - name: Rust Tool Chain setup + # uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: stable + # targets: ${{ matrix.target }} + + # - name: Cargo Fetch + # run: cargo fetch + # shell: bash + + # - name: Find Environments + # run: cargo run --release --target ${{ matrix.target }} + # shell: bash + + # - name: Run Tests + # run: cargo test --frozen --features ${{ matrix.feature }} -- --nocapture + # shell: bash + + # builds: + # name: Builds + # runs-on: ${{ matrix.os }} + # strategy: + # fail-fast: false + # matrix: + # include: + # - os: windows-latest + # target: x86_64-pc-windows-msvc + # - os: windows-latest + # target: aarch64-pc-windows-msvc + # - os: ubuntu-latest + # target: x86_64-unknown-linux-musl + # run_cli: "yes" + # # - os: ubuntu-latest + # # target: aarch64-unknown-linux-gnu + # # - os: ubuntu-latest + # # target: arm-unknown-linux-gnueabihf + # - os: macos-latest + # target: x86_64-apple-darwin + # run_cli: "yes" + # - os: macos-14 + # target: aarch64-apple-darwin + # run_cli: "yes" + # # - os: ubuntu-latest + # # target: x86_64-unknown-linux-gnu + # # - os: ubuntu-latest + # # target: aarch64-unknown-linux-musl + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Rust Tool Chain setup + # uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: stable + # targets: ${{ matrix.target }} + + # - name: Cargo Fetch + # run: cargo fetch + # shell: bash + + # - name: Run Tests + # # We do not want to run all features, CI is only for tests with Python + # # Thats a separate job. + # run: cargo test --frozen + # shell: bash + + # - name: Build + # run: cargo build --release --target ${{ matrix.target }} + # shell: bash + + # - name: Upload Artifact + # uses: actions/upload-artifact@v4 + # with: + # name: pet-${{ matrix.target }} + # path: target/${{ matrix.target }}/release/pet* diff --git a/crates/pet-python-utils/src/fs_cache.rs b/crates/pet-python-utils/src/fs_cache.rs index 276a144a..be28ab50 100644 --- a/crates/pet-python-utils/src/fs_cache.rs +++ b/crates/pet-python-utils/src/fs_cache.rs @@ -40,7 +40,7 @@ pub fn get_cache_from_file( let file = File::open(cache_file.clone()).ok()?; let reader = BufReader::new(file); let cache: CacheEntry = serde_json::from_reader(reader).ok()?; - + println!("cache from {:?} is {:?}", cache_file, cache.environment); // Account for conflicts in the cache file // i.e. the hash generated is same for another file, remember we only take the first 16 chars. if !cache diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 5397a900..185c1f19 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -2,9 +2,10 @@ // Licensed under the MIT License. mod common; -use std::{path::PathBuf, sync::Once}; +use std::{env, path::PathBuf, sync::Once, time::SystemTime}; use common::resolve_test_path; +use pet_python_utils::cache::{get_cache_directory, set_cache_directory}; static INIT: Once = Once::new(); @@ -14,6 +15,8 @@ fn setup() { env_logger::builder() .filter(None, log::LevelFilter::Trace) .init(); + + set_cache_directory(env::temp_dir().join("pet_cache")); }); } @@ -30,19 +33,17 @@ fn setup() { )] #[allow(dead_code)] fn verify_cache() { - use std::{env, fs}; + use std::fs; use pet_python_utils::{ - cache::{clear_cache, create_cache, set_cache_directory}, + cache::{clear_cache, create_cache}, env::ResolvedPythonEnv, fs_cache::generate_cache_file, }; setup(); - let cache_dir = env::temp_dir().join("pet_cache"); - set_cache_directory(cache_dir.clone()); - + let cache_dir = get_cache_directory().unwrap(); let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); @@ -103,19 +104,15 @@ fn verify_cache() { )] #[allow(dead_code)] fn verify_invalidating_cache() { - use std::{env, fs, time::SystemTime}; + use std::{fs, time::SystemTime}; use pet_python_utils::{ - cache::{create_cache, set_cache_directory}, - env::ResolvedPythonEnv, - fs_cache::generate_cache_file, + cache::create_cache, env::ResolvedPythonEnv, fs_cache::generate_cache_file, }; setup(); - let cache_dir = env::temp_dir().join("pet_cache"); - set_cache_directory(cache_dir.clone()); - + let cache_dir = get_cache_directory().unwrap(); let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv2"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); @@ -161,19 +158,17 @@ fn verify_invalidating_cache() { )] #[allow(dead_code)] fn verify_invalidating_cache_due_to_hash_conflicts() { - use std::{env, fs}; + use std::fs; use pet_python_utils::{ - cache::{clear_cache, create_cache, set_cache_directory}, + cache::{clear_cache, create_cache}, env::ResolvedPythonEnv, fs_cache::generate_cache_file, }; setup(); - let cache_dir = env::temp_dir().join("pet_cache"); - set_cache_directory(cache_dir.clone()); - + let cache_dir = get_cache_directory().unwrap(); let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv3"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); @@ -195,7 +190,6 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { // Store the value in cache and verify the file exists. cache.store(resolve_env.clone()); - assert!(cache.get().is_some()); assert!(cache_file.exists()); drop(cache); @@ -215,6 +209,7 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { let _ = clear_cache(); // Clear in memory cache as well as the files.. let _ = fs::create_dir_all(&cache_dir).unwrap(); let _ = fs::write(&cache_file, contents); // Create the cache file with the invalid details. + println!("UPDATED CACHE CONTENTS: {:?}", cache_file); let cache = create_cache(resolve_env.executable.clone()); let cache = cache.lock().unwrap(); diff --git a/crates/pet-python-utils/tests/unix/executables/.venv/bin/python b/crates/pet-python-utils/tests/unix/executables/.venv/bin/python index e69de29b..a59f7c83 100644 --- a/crates/pet-python-utils/tests/unix/executables/.venv/bin/python +++ b/crates/pet-python-utils/tests/unix/executables/.venv/bin/python @@ -0,0 +1 @@ +SystemTime { tv_sec: 1721186754, tv_nsec: 324707000 } \ No newline at end of file diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python b/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 b/crates/pet-python-utils/tests/unix/executables/.venv2/bin/python3 deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg b/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg deleted file mode 100644 index 860b12e2..00000000 --- a/crates/pet-python-utils/tests/unix/executables/.venv2/pyvenv.cfg +++ /dev/null @@ -1,5 +0,0 @@ -home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin -include-system-site-packages = false -version = 3.12.1 -executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 -command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python b/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 b/crates/pet-python-utils/tests/unix/executables/.venv3/bin/python3 deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg b/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg deleted file mode 100644 index 860b12e2..00000000 --- a/crates/pet-python-utils/tests/unix/executables/.venv3/pyvenv.cfg +++ /dev/null @@ -1,5 +0,0 @@ -home = /Users/donjayamanne/.pyenv/versions/3.12.1/bin -include-system-site-packages = false -version = 3.12.1 -executable = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python3.12 -command = /Users/donjayamanne/.pyenv/versions/3.12.1/bin/python -m venv /Users/donjayamanne/demo/.venv From ac7c508c4e440c325fca6006dee545a7874751cd Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 13:57:06 +1000 Subject: [PATCH 20/24] fix paths in JSON windows --- crates/pet-python-utils/tests/cache_test.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 185c1f19..e458e858 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -201,10 +201,26 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { python.to_string_lossy().to_string().as_str(), "/usr/bin/python", ); + let contents = contents.replace( + python + .to_string_lossy() + .to_string() + .replace("\\", "\\\\") // For windows paths stored in JSON + .as_str(), + "/usr/bin/python", + ); let contents = contents.replace( python3.to_string_lossy().to_string().as_str(), "/usr/bin/python3", ); + let contents = contents.replace( + python3 + .to_string_lossy() + .to_string() + .replace("\\", "\\\\") // For windows paths stored in JSON + .as_str(), + "/usr/bin/python3", + ); let _ = clear_cache(); // Clear in memory cache as well as the files.. let _ = fs::create_dir_all(&cache_dir).unwrap(); From 817d3e25ebc5344750bddbd37b0115695ee591dd Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 14:06:46 +1000 Subject: [PATCH 21/24] logging --- crates/pet-python-utils/tests/cache_test.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index e458e858..11ec573a 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -2,7 +2,7 @@ // Licensed under the MIT License. mod common; -use std::{env, path::PathBuf, sync::Once, time::SystemTime}; +use std::{env, path::PathBuf, sync::Once}; use common::resolve_test_path; use pet_python_utils::cache::{get_cache_directory, set_cache_directory}; @@ -224,8 +224,11 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { let _ = clear_cache(); // Clear in memory cache as well as the files.. let _ = fs::create_dir_all(&cache_dir).unwrap(); - let _ = fs::write(&cache_file, contents); // Create the cache file with the invalid details. - println!("UPDATED CACHE CONTENTS: {:?}", cache_file); + let _ = fs::write(&cache_file, contents.clone()); // Create the cache file with the invalid details. + println!( + "UPDATED CACHE CONTENTS: {:?} with {:?}", + cache_file, contents + ); let cache = create_cache(resolve_env.executable.clone()); let cache = cache.lock().unwrap(); From 580c84c20eb3cdf392bf834f9d8f42fc6bfb1fde Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 14:18:43 +1000 Subject: [PATCH 22/24] wip --- crates/pet-python-utils/src/cache.rs | 8 ++++++++ crates/pet-python-utils/tests/cache_test.rs | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index 00b64282..079e64cf 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -120,6 +120,14 @@ impl CacheEntryImpl { // Check if any of the exes have changed since we last cached this. for symlink_info in self.symlinks.lock().unwrap().iter() { if let Ok(metadata) = symlink_info.0.metadata() { + println!( + "Mtime and ctime for {:?} is {:?} & {:?} and expected {:?} & {:?}", + metadata.modified().ok(), + metadata.created().ok(), + symlink_info.0, + symlink_info.1, + symlink_info.2 + ); if metadata.modified().ok() != Some(symlink_info.1) || metadata.created().ok() != Some(symlink_info.2) { diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 11ec573a..3b02a1dd 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -141,6 +141,12 @@ fn verify_invalidating_cache() { // Next update the executable, so as to cause the mtime to change. // As a result of this the cache should no longer be valid. let _ = fs::write(python.clone(), format!("{:?}", SystemTime::now())); + println!( + "UPDATED EXECUTABLE: {:?}, mtime and ctime are {:?} and {:?}", + python, + python.metadata().unwrap().modified().unwrap(), + python.metadata().unwrap().created().unwrap() + ); assert!(cache.get().is_none()); assert!(!cache_file.exists()); } From 735dd3a007ceb8fc2a5cc629f44e68215e3ccf77 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 14:25:59 +1000 Subject: [PATCH 23/24] fixes --- crates/pet-python-utils/tests/cache_test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 3b02a1dd..8fc5c615 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -113,7 +113,7 @@ fn verify_invalidating_cache() { setup(); let cache_dir = get_cache_directory().unwrap(); - let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv2"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); @@ -175,7 +175,7 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { setup(); let cache_dir = get_cache_directory().unwrap(); - let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv3"]).into(); + let prefix: PathBuf = resolve_test_path(&["unix", "executables", ".venv"]).into(); let bin = prefix.join("bin"); let python = bin.join("python"); let python3 = bin.join("python3"); From 2cbe60390dbd5846d35aa7592883f485b995a18b Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Jul 2024 14:29:50 +1000 Subject: [PATCH 24/24] restore --- .github/workflows/pr-check.yml | 600 ++++++++++---------- crates/pet-python-utils/src/cache.rs | 8 - crates/pet-python-utils/src/fs_cache.rs | 1 - crates/pet-python-utils/tests/cache_test.rs | 10 - 4 files changed, 300 insertions(+), 319 deletions(-) diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index b5daf3d1..a1cbdfb4 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -15,183 +15,183 @@ on: - release-* jobs: - # tests: - # # Very generic tests, we don't verify whether the envs are discovered correctly or not. - # # However we do ensure that envs that are discovered are valid. - # # See other jobs for specific tests. - # name: Tests - # runs-on: ${{ matrix.os }} - # strategy: - # fail-fast: false - # matrix: - # include: - # - os: windows-latest - # target: x86_64-pc-windows-msvc - # run_cli: "yes" - # - os: ubuntu-latest - # target: x86_64-unknown-linux-musl - # run_cli: "yes" - # - os: macos-latest - # target: x86_64-apple-darwin - # run_cli: "yes" - # - os: macos-14 - # target: aarch64-apple-darwin - # run_cli: "yes" - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - - # - name: Set Python to PATH - # uses: actions/setup-python@v5 - # with: - # python-version: "3.x" - - # - name: Homebrew Python - # if: startsWith( matrix.os, 'macos') - # run: brew install python - # shell: bash - - # - name: Add Conda to PATH - # if: startsWith( matrix.os, 'windows') - # run: | - # $path = $env:PATH + ";" + $env:CONDA + "\condabin" - # echo "PATH=$path" >> $env:GITHUB_ENV - - # - name: Add Conda to PATH - # if: startsWith( matrix.os, 'ubuntu') - # run: echo "PATH=$PATH:$CONDA/condabin" >> $GITHUB_ENV - # shell: bash - - # - name: Install Conda + add to PATH - # if: startsWith( matrix.os, 'macos') - # run: | - # curl -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh - # bash ~/miniconda.sh -b -p ~/miniconda - # echo "PATH=$PATH:$HOME/miniconda/bin" >> $GITHUB_ENV - # echo "CONDA=$HOME/miniconda" >> $GITHUB_ENV - # shell: bash - - # - name: Check Conda version - # run: conda info --all - - # - name: Create Conda Environments - # run: | - # conda create -n test-env1 python=3.12 -y - # conda create -n test-env-no-python -y - # conda create -p ./prefix-envs/.conda1 python=3.12 -y - # conda create -p ./prefix-envs/.conda-nopy -y - - # - name: Install pipenv - # run: pip install pipenv - - # - name: Check pipenv version - # run: pipenv --version - - # - name: Create a Pipenv Environment - # run: pipenv install - - # - name: Install virtualenvwrapper - # # Activation of the script doesn't work on mac for some reason (didn't check why yet) - # # But linux is sufficient for the tests - # if: startsWith( matrix.os, 'ubuntu') - # run: | - # pip install virtualenvwrapper - # echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV - # mkdir -p $HOME/.virtualenvs - # source virtualenvwrapper.sh - # mkvirtualenv venv_wrapper_env1 - # shell: bash - - # - name: Install virtualenvwrapper-win - # if: startsWith( matrix.os, 'windows') - # run: | - # pip install virtualenvwrapper-win - # echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV - # shell: bash - - # - name: Install pyenv - # if: startsWith( matrix.os, 'windows') - # run: | - # choco install pyenv-win -y - # echo "PATH=$PATH;$HOME/.pyenv/pyenv-win/bin;$HOME/.pyenv/pyenv-win/shims" >> $GITHUB_ENV - # echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV - # shell: bash - - # - name: Install pyenv and pyenv-virtualenv - # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - # run: | - # curl https://pyenv.run | bash - # echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV - # echo "PATH=$HOME/.pyenv/bin:$PATH" >> $GITHUB_ENV - # shell: bash - - # - name: Check Pyenv version - # run: pyenv --version - # shell: bash - - # - name: Install Pyenv Python(s) - # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - # run: | - # pyenv install --list - # pyenv install 3.12.4 3.8.19 - # shell: bash - - # # pyenv-win install list has not updated for a while - # - name: Install Pyenv Python(s) - # if: startsWith( matrix.os, 'windows') - # run: | - # pyenv install --list - # pyenv install 3.10.5 3.8.10 - # shell: bash - - # - name: Create pyenv-virtualenv envs - # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - # run: | - # eval "$(pyenv virtualenv-init -)" - # pyenv virtualenv 3.12 pyenv-virtualenv-env1 - # shell: bash - - # # region venv - # - name: Create .venv - # # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - # run: | - # python -m venv .venv - # shell: bash - - # - name: Create .venv2 - # # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') - # run: | - # python -m venv .venv2 - # shell: bash - - # # endregion venv - - # # Rust - # - name: Rust Tool Chain setup - # uses: dtolnay/rust-toolchain@stable - # with: - # toolchain: stable - # targets: ${{ matrix.target }} - - # - name: Cargo Fetch - # run: cargo fetch - # shell: bash - - # - name: Find Environments - # if: matrix.run_cli == 'yes' - # run: cargo run --release --target ${{ matrix.target }} - # shell: bash - - # - name: Run Tests - # # Run integration tests in a single thread, - # # We end up creating conda envs and running multiple tests in parallel - # # that creat conda envs simultaneously causes issues (sometimes the conda envs do not seem to get created) - # # Similar issues were identified in vscode-jupyter tests as well (something to do with conda lock files or the like) - # run: cargo test --frozen --features ci -- --nocapture --test-threads=1 - # env: - # RUST_BACKTRACE: 1 - # RUST_LOG: trace - # shell: bash + tests: + # Very generic tests, we don't verify whether the envs are discovered correctly or not. + # However we do ensure that envs that are discovered are valid. + # See other jobs for specific tests. + name: Tests + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + target: x86_64-pc-windows-msvc + run_cli: "yes" + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + run_cli: "yes" + - os: macos-latest + target: x86_64-apple-darwin + run_cli: "yes" + - os: macos-14 + target: aarch64-apple-darwin + run_cli: "yes" + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set Python to PATH + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Homebrew Python + if: startsWith( matrix.os, 'macos') + run: brew install python + shell: bash + + - name: Add Conda to PATH + if: startsWith( matrix.os, 'windows') + run: | + $path = $env:PATH + ";" + $env:CONDA + "\condabin" + echo "PATH=$path" >> $env:GITHUB_ENV + + - name: Add Conda to PATH + if: startsWith( matrix.os, 'ubuntu') + run: echo "PATH=$PATH:$CONDA/condabin" >> $GITHUB_ENV + shell: bash + + - name: Install Conda + add to PATH + if: startsWith( matrix.os, 'macos') + run: | + curl -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh + bash ~/miniconda.sh -b -p ~/miniconda + echo "PATH=$PATH:$HOME/miniconda/bin" >> $GITHUB_ENV + echo "CONDA=$HOME/miniconda" >> $GITHUB_ENV + shell: bash + + - name: Check Conda version + run: conda info --all + + - name: Create Conda Environments + run: | + conda create -n test-env1 python=3.12 -y + conda create -n test-env-no-python -y + conda create -p ./prefix-envs/.conda1 python=3.12 -y + conda create -p ./prefix-envs/.conda-nopy -y + + - name: Install pipenv + run: pip install pipenv + + - name: Check pipenv version + run: pipenv --version + + - name: Create a Pipenv Environment + run: pipenv install + + - name: Install virtualenvwrapper + # Activation of the script doesn't work on mac for some reason (didn't check why yet) + # But linux is sufficient for the tests + if: startsWith( matrix.os, 'ubuntu') + run: | + pip install virtualenvwrapper + echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV + mkdir -p $HOME/.virtualenvs + source virtualenvwrapper.sh + mkvirtualenv venv_wrapper_env1 + shell: bash + + - name: Install virtualenvwrapper-win + if: startsWith( matrix.os, 'windows') + run: | + pip install virtualenvwrapper-win + echo "WORKON_HOME=$HOME/.virtualenvs" >> $GITHUB_ENV + shell: bash + + - name: Install pyenv + if: startsWith( matrix.os, 'windows') + run: | + choco install pyenv-win -y + echo "PATH=$PATH;$HOME/.pyenv/pyenv-win/bin;$HOME/.pyenv/pyenv-win/shims" >> $GITHUB_ENV + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + shell: bash + + - name: Install pyenv and pyenv-virtualenv + if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + run: | + curl https://pyenv.run | bash + echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV + echo "PATH=$HOME/.pyenv/bin:$PATH" >> $GITHUB_ENV + shell: bash + + - name: Check Pyenv version + run: pyenv --version + shell: bash + + - name: Install Pyenv Python(s) + if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + run: | + pyenv install --list + pyenv install 3.12.4 3.8.19 + shell: bash + + # pyenv-win install list has not updated for a while + - name: Install Pyenv Python(s) + if: startsWith( matrix.os, 'windows') + run: | + pyenv install --list + pyenv install 3.10.5 3.8.10 + shell: bash + + - name: Create pyenv-virtualenv envs + if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + run: | + eval "$(pyenv virtualenv-init -)" + pyenv virtualenv 3.12 pyenv-virtualenv-env1 + shell: bash + + # region venv + - name: Create .venv + # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + run: | + python -m venv .venv + shell: bash + + - name: Create .venv2 + # if: startsWith( matrix.os, 'ubuntu') || startsWith( matrix.os, 'macos') + run: | + python -m venv .venv2 + shell: bash + + # endregion venv + + # Rust + - name: Rust Tool Chain setup + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.target }} + + - name: Cargo Fetch + run: cargo fetch + shell: bash + + - name: Find Environments + if: matrix.run_cli == 'yes' + run: cargo run --release --target ${{ matrix.target }} + shell: bash + + - name: Run Tests + # Run integration tests in a single thread, + # We end up creating conda envs and running multiple tests in parallel + # that creat conda envs simultaneously causes issues (sometimes the conda envs do not seem to get created) + # Similar issues were identified in vscode-jupyter tests as well (something to do with conda lock files or the like) + run: cargo test --frozen --features ci -- --nocapture --test-threads=1 + env: + RUST_BACKTRACE: 1 + RUST_LOG: trace + shell: bash isolated-tests: # Some of these tests are very specific and need to be run in isolation. @@ -203,24 +203,24 @@ jobs: fail-fast: false matrix: include: - # - feature: ci-poetry-global # Poetry tests with envs stored in standard location - # os: ubuntu-latest - # target: x86_64-unknown-linux-musl - # - feature: ci-poetry-project # Poetry tests, with poetry envs in project - # os: ubuntu-latest - # target: x86_64-unknown-linux-musl - # - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location - # os: ubuntu-latest - # target: x86_64-unknown-linux-musl - feature: ci-poetry-global # Poetry tests with envs stored in standard location + os: ubuntu-latest + target: x86_64-unknown-linux-musl + - feature: ci-poetry-project # Poetry tests, with poetry envs in project + os: ubuntu-latest + target: x86_64-unknown-linux-musl + - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location + os: ubuntu-latest + target: x86_64-unknown-linux-musl + - feature: ci-poetry-global # Poetry tests with envs stored in standard location + os: windows-latest + target: x86_64-pc-windows-msvc + - feature: ci-poetry-project # Poetry tests, with poetry envs in project + os: windows-latest + target: x86_64-pc-windows-msvc + - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location os: windows-latest target: x86_64-pc-windows-msvc - # - feature: ci-poetry-project # Poetry tests, with poetry envs in project - # os: windows-latest - # target: x86_64-pc-windows-msvc - # - feature: ci-poetry-custom # Poetry tests with envs stored in a custom location - # os: windows-latest - # target: x86_64-pc-windows-msvc steps: - name: Checkout uses: actions/checkout@v4 @@ -365,111 +365,111 @@ jobs: RUST_LOG: trace shell: bash - # container-tests: - # # These tests are required as its not easy/possible to use the previous jobs. - # # E.g. we need to test against the jupyter container, as we found some issues specific to that env. - # name: Tests in Containers - # container: - # image: ${{ matrix.image }} - # options: --user=root - # runs-on: ${{ matrix.os }} - # strategy: - # fail-fast: false - # matrix: - # include: - # - feature: ci-jupyter-container - # os: ubuntu-latest - # # For Tests again the container used in https://github.com/github/codespaces-jupyter - # image: mcr.microsoft.com/devcontainers/universal:2.11.1 - # target: x86_64-unknown-linux-musl - # - feature: ci-homebrew-container - # os: ubuntu-latest - # # For Homebrew in Ubuntu - # image: homebrew/brew - # target: x86_64-unknown-linux-musl - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - - # # Homebrew - # - name: Homebrew Python - # if: startsWith( matrix.image, 'homebrew') - # run: brew install python@3.12 python@3.11 - # shell: bash - - # # Rust - # - name: Rust Tool Chain setup - # uses: dtolnay/rust-toolchain@stable - # with: - # toolchain: stable - # targets: ${{ matrix.target }} - - # - name: Cargo Fetch - # run: cargo fetch - # shell: bash - - # - name: Find Environments - # run: cargo run --release --target ${{ matrix.target }} - # shell: bash - - # - name: Run Tests - # run: cargo test --frozen --features ${{ matrix.feature }} -- --nocapture - # shell: bash - - # builds: - # name: Builds - # runs-on: ${{ matrix.os }} - # strategy: - # fail-fast: false - # matrix: - # include: - # - os: windows-latest - # target: x86_64-pc-windows-msvc - # - os: windows-latest - # target: aarch64-pc-windows-msvc - # - os: ubuntu-latest - # target: x86_64-unknown-linux-musl - # run_cli: "yes" - # # - os: ubuntu-latest - # # target: aarch64-unknown-linux-gnu - # # - os: ubuntu-latest - # # target: arm-unknown-linux-gnueabihf - # - os: macos-latest - # target: x86_64-apple-darwin - # run_cli: "yes" - # - os: macos-14 - # target: aarch64-apple-darwin - # run_cli: "yes" - # # - os: ubuntu-latest - # # target: x86_64-unknown-linux-gnu - # # - os: ubuntu-latest - # # target: aarch64-unknown-linux-musl - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - - # - name: Rust Tool Chain setup - # uses: dtolnay/rust-toolchain@stable - # with: - # toolchain: stable - # targets: ${{ matrix.target }} - - # - name: Cargo Fetch - # run: cargo fetch - # shell: bash - - # - name: Run Tests - # # We do not want to run all features, CI is only for tests with Python - # # Thats a separate job. - # run: cargo test --frozen - # shell: bash - - # - name: Build - # run: cargo build --release --target ${{ matrix.target }} - # shell: bash - - # - name: Upload Artifact - # uses: actions/upload-artifact@v4 - # with: - # name: pet-${{ matrix.target }} - # path: target/${{ matrix.target }}/release/pet* + container-tests: + # These tests are required as its not easy/possible to use the previous jobs. + # E.g. we need to test against the jupyter container, as we found some issues specific to that env. + name: Tests in Containers + container: + image: ${{ matrix.image }} + options: --user=root + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - feature: ci-jupyter-container + os: ubuntu-latest + # For Tests again the container used in https://github.com/github/codespaces-jupyter + image: mcr.microsoft.com/devcontainers/universal:2.11.1 + target: x86_64-unknown-linux-musl + - feature: ci-homebrew-container + os: ubuntu-latest + # For Homebrew in Ubuntu + image: homebrew/brew + target: x86_64-unknown-linux-musl + steps: + - name: Checkout + uses: actions/checkout@v4 + + # Homebrew + - name: Homebrew Python + if: startsWith( matrix.image, 'homebrew') + run: brew install python@3.12 python@3.11 + shell: bash + + # Rust + - name: Rust Tool Chain setup + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.target }} + + - name: Cargo Fetch + run: cargo fetch + shell: bash + + - name: Find Environments + run: cargo run --release --target ${{ matrix.target }} + shell: bash + + - name: Run Tests + run: cargo test --frozen --features ${{ matrix.feature }} -- --nocapture + shell: bash + + builds: + name: Builds + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + target: x86_64-pc-windows-msvc + - os: windows-latest + target: aarch64-pc-windows-msvc + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + run_cli: "yes" + # - os: ubuntu-latest + # target: aarch64-unknown-linux-gnu + # - os: ubuntu-latest + # target: arm-unknown-linux-gnueabihf + - os: macos-latest + target: x86_64-apple-darwin + run_cli: "yes" + - os: macos-14 + target: aarch64-apple-darwin + run_cli: "yes" + # - os: ubuntu-latest + # target: x86_64-unknown-linux-gnu + # - os: ubuntu-latest + # target: aarch64-unknown-linux-musl + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Rust Tool Chain setup + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.target }} + + - name: Cargo Fetch + run: cargo fetch + shell: bash + + - name: Run Tests + # We do not want to run all features, CI is only for tests with Python + # Thats a separate job. + run: cargo test --frozen + shell: bash + + - name: Build + run: cargo build --release --target ${{ matrix.target }} + shell: bash + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: pet-${{ matrix.target }} + path: target/${{ matrix.target }}/release/pet* diff --git a/crates/pet-python-utils/src/cache.rs b/crates/pet-python-utils/src/cache.rs index 079e64cf..00b64282 100644 --- a/crates/pet-python-utils/src/cache.rs +++ b/crates/pet-python-utils/src/cache.rs @@ -120,14 +120,6 @@ impl CacheEntryImpl { // Check if any of the exes have changed since we last cached this. for symlink_info in self.symlinks.lock().unwrap().iter() { if let Ok(metadata) = symlink_info.0.metadata() { - println!( - "Mtime and ctime for {:?} is {:?} & {:?} and expected {:?} & {:?}", - metadata.modified().ok(), - metadata.created().ok(), - symlink_info.0, - symlink_info.1, - symlink_info.2 - ); if metadata.modified().ok() != Some(symlink_info.1) || metadata.created().ok() != Some(symlink_info.2) { diff --git a/crates/pet-python-utils/src/fs_cache.rs b/crates/pet-python-utils/src/fs_cache.rs index be28ab50..7de515d0 100644 --- a/crates/pet-python-utils/src/fs_cache.rs +++ b/crates/pet-python-utils/src/fs_cache.rs @@ -40,7 +40,6 @@ pub fn get_cache_from_file( let file = File::open(cache_file.clone()).ok()?; let reader = BufReader::new(file); let cache: CacheEntry = serde_json::from_reader(reader).ok()?; - println!("cache from {:?} is {:?}", cache_file, cache.environment); // Account for conflicts in the cache file // i.e. the hash generated is same for another file, remember we only take the first 16 chars. if !cache diff --git a/crates/pet-python-utils/tests/cache_test.rs b/crates/pet-python-utils/tests/cache_test.rs index 8fc5c615..64a6fb3b 100644 --- a/crates/pet-python-utils/tests/cache_test.rs +++ b/crates/pet-python-utils/tests/cache_test.rs @@ -141,12 +141,6 @@ fn verify_invalidating_cache() { // Next update the executable, so as to cause the mtime to change. // As a result of this the cache should no longer be valid. let _ = fs::write(python.clone(), format!("{:?}", SystemTime::now())); - println!( - "UPDATED EXECUTABLE: {:?}, mtime and ctime are {:?} and {:?}", - python, - python.metadata().unwrap().modified().unwrap(), - python.metadata().unwrap().created().unwrap() - ); assert!(cache.get().is_none()); assert!(!cache_file.exists()); } @@ -231,10 +225,6 @@ fn verify_invalidating_cache_due_to_hash_conflicts() { let _ = clear_cache(); // Clear in memory cache as well as the files.. let _ = fs::create_dir_all(&cache_dir).unwrap(); let _ = fs::write(&cache_file, contents.clone()); // Create the cache file with the invalid details. - println!( - "UPDATED CACHE CONTENTS: {:?} with {:?}", - cache_file, contents - ); let cache = create_cache(resolve_env.executable.clone()); let cache = cache.lock().unwrap();