Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/cli/global/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ pub async fn execute(args: Args) -> miette::Result<()> {
// Prune environments that are not listed
let state_change = project.prune_old_environments().await?;

// Prune broken completions
project.completions_dir.prune_old_completions()?;
#[cfg(unix)]
{
// Prune broken completions
let completions_dir = crate::global::completions::CompletionsDir::from_env().await?;
completions_dir.prune_old_completions()?;
}

if state_change.has_changed() {
has_changed = true;
Expand Down
6 changes: 5 additions & 1 deletion src/cli/global/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ pub async fn execute(args: Args) -> miette::Result<()> {
// prune old environments and completions
let state_changes = project_original.prune_old_environments().await?;
state_changes.report();
project_original.completions_dir.prune_old_completions()?;
#[cfg(unix)]
{
let completions_dir = global::completions::CompletionsDir::from_env().await?;
completions_dir.prune_old_completions()?;
}
project_original.environments().keys().cloned().collect()
}
};
Expand Down
1 change: 1 addition & 0 deletions src/global/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ pub(crate) enum StateChange {
UninstalledShortcut(String),
#[allow(dead_code)] // This variant is not used on Windows
AddedCompletion(String),
#[allow(dead_code)] // This variant is not used on Windows
RemovedCompletion(String),
}

Expand Down
15 changes: 0 additions & 15 deletions src/global/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ impl CompletionsDir {
#[derive(Debug, Clone)]
pub struct Completion {
name: String,
#[allow(dead_code)] // This member variable is not used on Windows
source: PathBuf,
destination: PathBuf,
}
Expand All @@ -85,12 +84,7 @@ impl Completion {
}
}

pub fn name(&self) -> &str {
&self.name
}

/// Install the shell completion
#[cfg(unix)]
pub async fn install(&self) -> miette::Result<Option<StateChange>> {
tracing::debug!("Requested to install completion {}.", self.source.display());

Expand All @@ -107,15 +101,6 @@ impl Completion {
Ok(Some(StateChange::AddedCompletion(self.name.clone())))
}

#[cfg(not(unix))]
pub async fn install(&self) -> miette::Result<Option<StateChange>> {
tracing::info!(
"Symlinks are only supported on unix-like platforms. Skipping completion installation for {}.",
self.name
);
Ok(None)
}

/// Remove the shell completion
pub async fn remove(&self) -> miette::Result<StateChange> {
tokio_fs::remove_file(&self.destination)
Expand Down
1 change: 1 addition & 0 deletions src/global/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub(crate) mod common;
#[cfg(unix)] // Completions are only supported on unix-like systems
pub(crate) mod completions;
pub(crate) mod install;
pub(crate) mod list;
Expand Down
125 changes: 40 additions & 85 deletions src/global/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::{
common::{
channel_url_to_prioritized_channel, expose_scripts_sync_status, find_package_records,
},
completions::{completions_sync_status, CompletionsDir},
find_executables, find_executables_for_many_records,
install::{create_executable_trampolines, script_exec_mapping},
project::environment::environment_specs_in_sync,
Expand All @@ -20,6 +19,7 @@ use crate::{
repodata::Repodata,
rlimit::try_increase_rlimit_to_sensible,
};

use std::{
ffi::OsStr,
fmt::{Debug, Formatter},
Expand Down Expand Up @@ -86,8 +86,6 @@ pub struct Project {
pub(crate) env_root: EnvRoot,
/// Binary directory
pub(crate) bin_dir: BinDir,
/// Directory where shell completions are located
pub(crate) completions_dir: CompletionsDir,
/// Reqwest client shared for this project.
/// This is wrapped in a `OnceCell` to allow for lazy initialization.
// TODO: once https://github.com/rust-lang/rust/issues/109737 is stabilized, switch to OnceLock
Expand Down Expand Up @@ -256,12 +254,7 @@ async fn package_from_conda_meta(

impl Project {
/// Constructs a new instance from an internal manifest representation
pub(crate) fn from_manifest(
manifest: Manifest,
env_root: EnvRoot,
bin_dir: BinDir,
completions_dir: CompletionsDir,
) -> Self {
pub(crate) fn from_manifest(manifest: Manifest, env_root: EnvRoot, bin_dir: BinDir) -> Self {
let root = manifest
.path
.parent()
Expand All @@ -278,7 +271,6 @@ impl Project {
config,
env_root,
bin_dir,
completions_dir,
client,
repodata_gateway,
concurrent_downloads_semaphore: OnceCell::new(),
Expand All @@ -291,15 +283,9 @@ impl Project {
content: &str,
env_root: EnvRoot,
bin_dir: BinDir,
completions_dir: CompletionsDir,
) -> miette::Result<Self> {
let manifest = Manifest::from_str(manifest_path, content)?;
Ok(Self::from_manifest(
manifest,
env_root,
bin_dir,
completions_dir,
))
Ok(Self::from_manifest(manifest, env_root, bin_dir))
}

/// Discovers the project manifest file in path at
Expand All @@ -313,7 +299,6 @@ impl Project {

let bin_dir = BinDir::from_env().await?;
let env_root = EnvRoot::from_env().await?;
let completions_dir = CompletionsDir::from_env().await?;

if !manifest_path.exists() {
tracing::debug!(
Expand All @@ -328,14 +313,11 @@ impl Project {
tracing::debug!(
"Existing installation found. Creating global manifest from that information."
);
return Self::try_from_existing_installation(
&manifest_path,
env_root,
bin_dir,
completions_dir,
)
.await
.wrap_err_with(|| "Failed to create global manifest from existing installation");
return Self::try_from_existing_installation(&manifest_path, env_root, bin_dir)
.await
.wrap_err_with(|| {
"Failed to create global manifest from existing installation"
});
} else {
tracing::debug!("Create an empty global manifest.");
tokio_fs::File::create(&manifest_path)
Expand All @@ -344,14 +326,13 @@ impl Project {
}
}

Self::from_path(&manifest_path, env_root, bin_dir, completions_dir)
Self::from_path(&manifest_path, env_root, bin_dir)
}

async fn try_from_existing_installation(
manifest_path: &Path,
env_root: EnvRoot,
bin_dir: BinDir,
completions_dir: CompletionsDir,
) -> miette::Result<Self> {
let config = Config::load(env_root.path());

Expand Down Expand Up @@ -406,7 +387,7 @@ impl Project {
tokio_fs::write(&manifest_path, &toml)
.await
.into_diagnostic()?;
Self::from_str(manifest_path, &toml, env_root, bin_dir, completions_dir)
Self::from_str(manifest_path, &toml, env_root, bin_dir)
}

/// Get default dir for the pixi global manifest
Expand Down Expand Up @@ -445,15 +426,9 @@ impl Project {
manifest_path: &Path,
env_root: EnvRoot,
bin_dir: BinDir,
completions_dir: CompletionsDir,
) -> miette::Result<Self> {
let manifest = Manifest::from_path(manifest_path)?;
Ok(Project::from_manifest(
manifest,
env_root,
bin_dir,
completions_dir,
))
Ok(Project::from_manifest(manifest, env_root, bin_dir))
}

/// Merge config with existing config project
Expand Down Expand Up @@ -672,8 +647,12 @@ impl Project {
);
}

// Prune old completions
self.completions_dir.prune_old_completions()?;
#[cfg(unix)] // Completions are only supported on unix-like systems
{
// Prune old completions
let completions_dir = super::completions::CompletionsDir::from_env().await?;
completions_dir.prune_old_completions()?;
}

state_changes.insert_change(env_name, StateChange::RemovedEnvironment);

Expand Down Expand Up @@ -907,30 +886,6 @@ impl Project {
return Ok(false);
}

tracing::debug!("Verify that the completions are in sync with the environment");
let execs_all = self
.executables_of_all_dependencies(env_name)
.await?
.into_iter()
.map(|exec| exec.name)
.collect();
let (completions_to_remove, completions_to_add) = completions_sync_status(
environment.exposed.clone(),
execs_all,
prefix.root(),
&self.completions_dir,
)
.await?;
if !completions_to_remove.is_empty() || !completions_to_add.is_empty() {
tracing::debug!(
"Environment {} completions are not in sync: to_remove: {}, to_add: {}",
env_name.fancy_display(),
completions_to_remove.iter().map(|c| c.name()).join(", "),
completions_to_add.iter().map(|c| c.name()).join(", ")
);
return Ok(false);
}

tracing::debug!("Verify that the shortcuts are in sync with the environment");
let shortcuts = environment.shortcuts.clone().unwrap_or_default();
let (shortcuts_to_remove, shortcuts_to_add) =
Expand Down Expand Up @@ -1252,6 +1207,7 @@ impl Project {
Ok(state_changes)
}

#[cfg(unix)] // Completions are only supported on unix like systems
pub async fn sync_completions(
&self,
env_name: &EnvironmentName,
Expand All @@ -1270,13 +1226,15 @@ impl Project {
.map(|exec| exec.name)
.collect();

let (completions_to_remove, completions_to_add) = completions_sync_status(
environment.exposed.clone(),
execs_all,
prefix.root(),
&self.completions_dir,
)
.await?;
let completions_dir = crate::global::completions::CompletionsDir::from_env().await?;
let (completions_to_remove, completions_to_add) =
super::completions::completions_sync_status(
environment.exposed.clone(),
execs_all,
prefix.root(),
&completions_dir,
)
.await?;

for completion_to_remove in completions_to_remove {
let state_change = completion_to_remove.remove().await?;
Expand All @@ -1294,6 +1252,15 @@ impl Project {
Ok(state_changes)
}

#[cfg(not(unix))]
pub async fn sync_completions(
&self,
_env_name: &EnvironmentName,
) -> miette::Result<StateChanges> {
let state_changes = StateChanges::default();
Ok(state_changes)
}

/// Returns a semaphore than can be used to limit the number of concurrent
/// according to the user configuration.
fn concurrent_downloads_semaphore(&self) -> Arc<Semaphore> {
Expand Down Expand Up @@ -1351,16 +1318,9 @@ mod tests {
let manifest_path: PathBuf = FilePath().fake();
let env_root = EnvRoot::from_env().await.unwrap();
let bin_dir = BinDir::from_env().await.unwrap();
let completions_dir = CompletionsDir::from_env().await.unwrap();

let project = Project::from_str(
&manifest_path,
SIMPLE_MANIFEST,
env_root,
bin_dir,
completions_dir,
)
.unwrap();
let project =
Project::from_str(&manifest_path, SIMPLE_MANIFEST, env_root, bin_dir).unwrap();
assert_eq!(project.root, manifest_path.parent().unwrap());
}

Expand All @@ -1371,13 +1331,11 @@ mod tests {

let env_root = EnvRoot::from_env().await.unwrap();
let bin_dir = BinDir::from_env().await.unwrap();
let completions_dir = CompletionsDir::from_env().await.unwrap();

// Create and write global manifest
let mut file = fs::File::create(&manifest_path).unwrap();
file.write_all(SIMPLE_MANIFEST.as_bytes()).unwrap();
let project =
Project::from_path(&manifest_path, env_root, bin_dir, completions_dir).unwrap();
let project = Project::from_path(&manifest_path, env_root, bin_dir).unwrap();

// Canonicalize both paths
let canonical_root = project.root.canonicalize().unwrap();
Expand All @@ -1392,10 +1350,9 @@ mod tests {

let env_root = EnvRoot::from_env().await.unwrap();
let bin_dir = BinDir::from_env().await.unwrap();
let completions_dir = CompletionsDir::from_env().await.unwrap();

let manifest = Manifest::from_str(&manifest_path, SIMPLE_MANIFEST).unwrap();
let project = Project::from_manifest(manifest, env_root, bin_dir, completions_dir);
let project = Project::from_manifest(manifest, env_root, bin_dir);
assert_eq!(project.root, manifest_path.parent().unwrap());
}

Expand All @@ -1419,7 +1376,6 @@ mod tests {
"#,
EnvRoot::new(tempdir.path().to_path_buf()).unwrap(),
BinDir::new(tempdir.path().to_path_buf()).unwrap(),
CompletionsDir::from_env().await.unwrap(),
)
.unwrap();

Expand Down Expand Up @@ -1541,7 +1497,6 @@ mod tests {
manifest,
env_root.clone(),
BinDir::new(env_root.path().parent().unwrap().to_path_buf()).unwrap(),
CompletionsDir::from_env().await.unwrap(),
);

// Call the prune method with a list of environments to keep (env1 and env3) but
Expand Down
Loading