diff --git a/.cargo/config.toml b/.cargo/config.toml index dc506023f3..eb46e005f7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -12,8 +12,12 @@ rustflags = [ "link-arg=/STACK:8000000", ] -# Required for `dist` to work with linux arm targets: https://github.com/axodotdev/cargo-dist/issues/74#issuecomment-2053680080 [env] +PIXI_CONFIG_DIR = "pixi" +PIXI_DEFAULT_CHANNELS = "conda-forge" +PIXI_DIR = ".pixi" +PIXI_PROJECT_LOCK_FILE = "pixi.lock" +# Required for `dist` to work with linux arm targets: https://github.com/axodotdev/cargo-dist/issues/74#issuecomment-2053680080 CC_aarch64_unknown_linux_musl = "aarch64-linux-gnu-gcc" [target.aarch64-unknown-linux-musl] diff --git a/Cargo.toml b/Cargo.toml index 9c8b379f0d..2808e5bc96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -335,7 +335,7 @@ strip = false async-trait = { workspace = true } fake = "3.0.1" http = { workspace = true } -insta = { workspace = true, features = ["yaml", "glob"] } +insta = { workspace = true, features = ["yaml", "glob", "filters"] } rstest = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = ["rt"] } diff --git a/crates/pixi_config/src/lib.rs b/crates/pixi_config/src/lib.rs index e5e61e90dd..e8f3d766bd 100644 --- a/crates/pixi_config/src/lib.rs +++ b/crates/pixi_config/src/lib.rs @@ -84,8 +84,7 @@ pub fn get_cache_dir() -> miette::Result { .map(PathBuf::from) .or_else(|| std::env::var("RATTLER_CACHE_DIR").map(PathBuf::from).ok()) .or_else(|| { - let pixi_cache_dir = dirs::cache_dir().map(|d| d.join("pixi")); - + let pixi_cache_dir = dirs::cache_dir().map(|d| d.join(consts::PIXI_DIR)); // Only use the xdg cache pixi directory when it exists pixi_cache_dir.and_then(|d| d.exists().then_some(d)) }) @@ -964,7 +963,13 @@ impl Config { if self.default_channels.is_empty() { consts::DEFAULT_CHANNELS .iter() - .map(|s| NamedChannelOrUrl::Name(s.to_string())) + .map(|s| { + if s.starts_with("http://") || s.starts_with("https://") { + NamedChannelOrUrl::Url(Url::parse(s).unwrap()) + } else { + NamedChannelOrUrl::Name(s.to_string()) + } + }) .collect() } else { self.default_channels.clone() @@ -1256,13 +1261,13 @@ pub fn config_path_system() -> PathBuf { #[cfg(not(target_os = "windows"))] let base_path = PathBuf::from("/etc"); - base_path.join("pixi").join(consts::CONFIG_FILE) + base_path.join(consts::CONFIG_DIR).join(consts::CONFIG_FILE) } /// Returns the path(s) to the global pixi config file. pub fn config_path_global() -> Vec { vec![ - dirs::config_dir().map(|d| d.join("pixi").join(consts::CONFIG_FILE)), + dirs::config_dir().map(|d| d.join(consts::CONFIG_DIR).join(consts::CONFIG_FILE)), pixi_home().map(|d| d.join(consts::CONFIG_FILE)), ] .into_iter() diff --git a/crates/pixi_consts/src/consts.rs b/crates/pixi_consts/src/consts.rs index ca07ceaa7b..f3f2afb6ce 100644 --- a/crates/pixi_consts/src/consts.rs +++ b/crates/pixi_consts/src/consts.rs @@ -1,6 +1,10 @@ use console::Style; use lazy_static::lazy_static; -use std::fmt::{Display, Formatter}; +use std::{ + ffi::OsStr, + fmt::{Display, Formatter}, + path::Path, +}; use url::Url; pub const DEFAULT_ENVIRONMENT_NAME: &str = "default"; @@ -9,9 +13,7 @@ pub const PYPROJECT_PIXI_PREFIX: &str = "tool.pixi"; pub const PROJECT_MANIFEST: &str = "pixi.toml"; pub const PYPROJECT_MANIFEST: &str = "pyproject.toml"; -pub const PROJECT_LOCK_FILE: &str = "pixi.lock"; pub const CONFIG_FILE: &str = "config.toml"; -pub const PIXI_DIR: &str = ".pixi"; pub const PIXI_VERSION: &str = match option_env!("PIXI_VERSION") { Some(v) => v, None => "0.39.4", @@ -36,13 +38,41 @@ pub const _CACHED_BUILD_ENVS_DIR: &str = "cached-build-envs-v0"; pub const CACHED_BUILD_TOOL_ENVS_DIR: &str = "cached-build-tool-envs-v0"; pub const CACHED_GIT_DIR: &str = "git-cache-v0"; +pub const MOJOPROJECT_MANIFEST: &str = "mojoproject.toml"; + +pub const CONFIG_DIR: &str = match option_env!("PIXI_CONFIG_DIR") { + Some(dir) => dir, + None => "pixi", +}; +pub const PROJECT_LOCK_FILE: &str = match option_env!("PIXI_PROJECT_LOCK_FILE") { + Some(file) => file, + None => "pixi.lock", +}; +pub const PIXI_DIR: &str = match option_env!("PIXI_DIR") { + Some(dir) => dir, + None => ".pixi", +}; + +lazy_static! { + /// The default channels to use for a new project. + pub static ref DEFAULT_CHANNELS: Vec = match option_env!("PIXI_DEFAULT_CHANNELS") { + Some(channels) => channels.split(',').map(|s| s.to_string()).collect(), + None => vec!["conda-forge".to_string()], + }; + + /// The name of the binary. + pub static ref PIXI_BIN_NAME: String = std::env::args().next() + .as_ref() + .map(Path::new) + .and_then(Path::file_name) + .and_then(OsStr::to_str) + .map(String::from).unwrap_or("pixi".to_string()); +} + pub const CONDA_INSTALLER: &str = "conda"; pub const ONE_TIME_MESSAGES_DIR: &str = "one-time-messages"; -/// The default channels to use for a new project. -pub const DEFAULT_CHANNELS: &[&str] = &["conda-forge"]; - pub const ENVIRONMENT_FILE_NAME: &str = "pixi"; lazy_static! { diff --git a/crates/pixi_manifest/src/manifests/manifest.rs b/crates/pixi_manifest/src/manifests/manifest.rs index fbf3c64225..e5fe88d006 100644 --- a/crates/pixi_manifest/src/manifests/manifest.rs +++ b/crates/pixi_manifest/src/manifests/manifest.rs @@ -41,6 +41,7 @@ impl ManifestKind { match path.file_name().and_then(OsStr::to_str)? { consts::PROJECT_MANIFEST => Some(Self::Pixi), consts::PYPROJECT_MANIFEST => Some(Self::Pyproject), + consts::MOJOPROJECT_MANIFEST => Some(Self::Pixi), _ => None, } } @@ -94,6 +95,7 @@ impl Manifest { match self.source { ManifestSource::PixiToml(_) => consts::PROJECT_MANIFEST, ManifestSource::PyProjectToml(_) => consts::PYPROJECT_MANIFEST, + ManifestSource::MojoProjectToml(_) => consts::MOJOPROJECT_MANIFEST, } } @@ -378,7 +380,10 @@ impl Manifest { ) -> miette::Result { // Determine the name of the package to add let (Some(name), spec) = spec.clone().into_nameless() else { - miette::bail!("pixi does not support wildcard dependencies") + miette::bail!(format!( + "{} does not support wildcard dependencies", + consts::PIXI_BIN_NAME.as_str() + )); }; let spec = PixiSpec::from_nameless_matchspec(spec, channel_config); let mut any_added = false; diff --git a/crates/pixi_manifest/src/manifests/source.rs b/crates/pixi_manifest/src/manifests/source.rs index d92d83720a..0188e99eee 100644 --- a/crates/pixi_manifest/src/manifests/source.rs +++ b/crates/pixi_manifest/src/manifests/source.rs @@ -14,6 +14,7 @@ use crate::{ /// Discriminates between a 'pixi.toml' and a 'pyproject.toml' manifest. #[derive(Debug, Clone)] pub enum ManifestSource { + MojoProjectToml(TomlDocument), PyProjectToml(TomlDocument), PixiToml(TomlDocument), } @@ -21,6 +22,7 @@ pub enum ManifestSource { impl fmt::Display for ManifestSource { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + ManifestSource::MojoProjectToml(document) => write!(f, "{}", document), ManifestSource::PyProjectToml(document) => write!(f, "{}", document), ManifestSource::PixiToml(document) => write!(f, "{}", document), } @@ -44,6 +46,7 @@ impl ManifestSource { #[cfg(test)] fn file_name(&self) -> &'static str { match self { + ManifestSource::MojoProjectToml(_) => "mojoproject.toml", ManifestSource::PyProjectToml(_) => "pyproject.toml", ManifestSource::PixiToml(_) => "pixi.toml", } @@ -51,6 +54,7 @@ impl ManifestSource { fn table_prefix(&self) -> Option<&'static str> { match self { + ManifestSource::MojoProjectToml(_) => None, ManifestSource::PyProjectToml(_) => Some(PYPROJECT_PIXI_PREFIX), ManifestSource::PixiToml(_) => None, } @@ -58,6 +62,7 @@ impl ManifestSource { fn manifest_mut(&mut self) -> &mut TomlDocument { match self { + ManifestSource::MojoProjectToml(document) => document, ManifestSource::PyProjectToml(document) => document, ManifestSource::PixiToml(document) => document, } @@ -66,6 +71,7 @@ impl ManifestSource { /// Returns the inner TOML document pub fn manifest(&self) -> &TomlDocument { match self { + ManifestSource::MojoProjectToml(document) => document, ManifestSource::PyProjectToml(document) => document, ManifestSource::PixiToml(document) => document, } @@ -99,6 +105,7 @@ impl ManifestSource { fn as_table_mut(&mut self) -> &mut Table { match self { + ManifestSource::MojoProjectToml(document) => document.as_table_mut(), ManifestSource::PyProjectToml(document) => document.as_table_mut(), ManifestSource::PixiToml(document) => document.as_table_mut(), } @@ -244,6 +251,7 @@ impl ManifestSource { // - When a specific platform is requested, as markers are not supported (https://github.com/prefix-dev/pixi/issues/2149) // - When an editable install is requested if matches!(self, ManifestSource::PixiToml(_)) + || matches!(self, ManifestSource::MojoProjectToml(_)) || matches!(location, Some(PypiDependencyLocation::PixiPypiDependencies)) || platform.is_some() || editable.is_some_and(|e| e) diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 806ed7e5d2..75fececb85 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -58,7 +58,7 @@ impl Generator for Shell { } /// Generate completions for the pixi cli, and print those to the stdout -pub(crate) fn execute(args: Args) -> miette::Result<()> { +pub fn execute(args: Args) -> miette::Result<()> { // Generate the original completion script. let script = get_completion_script(args.shell); @@ -82,7 +82,8 @@ pub(crate) fn execute(args: Args) -> miette::Result<()> { /// Generate the completion script using clap_complete for a specified shell. fn get_completion_script(shell: Shell) -> String { let mut buf = vec![]; - clap_complete::generate(shell, &mut CommandArgs::command(), "pixi", &mut buf); + let bin_name: &str = pixi_consts::consts::PIXI_BIN_NAME.as_str(); + clap_complete::generate(shell, &mut CommandArgs::command(), bin_name, &mut buf); String::from_utf8(buf).expect("clap_complete did not generate a valid UTF8 script") } @@ -90,21 +91,29 @@ fn get_completion_script(shell: Shell) -> String { fn replace_bash_completion(script: &str) -> Cow { // Adds tab completion to the pixi run command. // NOTE THIS IS FORMATTED BY HAND - let pattern = r#"(?s)pixi__run\).*?opts="(.*?)".*?(if.*?fi)"#; - let replacement = r#"pixi__run) + // Replace the '-' with '__' since that's what clap's generator does as well for Bash Shell completion. + let bin_name: &str = pixi_consts::consts::PIXI_BIN_NAME.as_str(); + let clap_name = bin_name.replace("-", "__"); + let pattern = format!(r#"(?s){}__run\).*?opts="(.*?)".*?(if.*?fi)"#, &clap_name); + let replacement = r#"CLAP_NAME__run) opts="$1" if [[ $${cur} == -* ]] ; then COMPREPLY=( $$(compgen -W "$${opts}" -- "$${cur}") ) return 0 elif [[ $${COMP_CWORD} -eq 2 ]]; then - local tasks=$$(pixi task list --machine-readable 2> /dev/null) + local tasks=$$(BIN_NAME task list --machine-readable 2> /dev/null) if [[ $$? -eq 0 ]]; then COMPREPLY=( $$(compgen -W "$${tasks}" -- "$${cur}") ) return 0 fi fi"#; - let re = Regex::new(pattern).unwrap(); - re.replace(script, replacement) + let re = Regex::new(pattern.as_str()).unwrap(); + re.replace( + script, + replacement + .replace("BIN_NAME", bin_name) + .replace("CLAP_NAME", &clap_name), + ) } /// Replace the parts of the zsh completion script that need different functionality. @@ -112,9 +121,10 @@ fn replace_zsh_completion(script: &str) -> Cow { // Adds tab completion to the pixi run command. // NOTE THIS IS FORMATTED BY HAND let pattern = r"(?ms)(\(run\))(?:.*?)(_arguments.*?)(\*::task)"; + let bin_name: &str = pixi_consts::consts::PIXI_BIN_NAME.as_str(); let replacement = r#"$1 local tasks -tasks=("$${(@s/ /)$$(pixi task list --machine-readable 2> /dev/null)}") +tasks=("$${(@s/ /)$$(BIN_NAME task list --machine-readable 2> /dev/null)}") if [[ -n "$$tasks" ]]; then _values 'task' "$${tasks[@]}" @@ -124,12 +134,13 @@ fi $2::task"#; let re = Regex::new(pattern).unwrap(); - re.replace(script, replacement) + re.replace(script, replacement.replace("BIN_NAME", bin_name)) } fn replace_fish_completion(script: &str) -> Cow { // Adds tab completion to the pixi run command. - let addition = "complete -c pixi -n \"__fish_seen_subcommand_from run\" -f -a \"(string split ' ' (pixi task list --machine-readable 2> /dev/null))\""; + let bin_name = pixi_consts::consts::PIXI_BIN_NAME.as_str(); + let addition = format!("complete -c {} -n \"__fish_seen_subcommand_from run\" -f -a \"(string split ' ' ({} task list --machine-readable 2> /dev/null))\"", bin_name, bin_name); let new_script = format!("{}{}\n", script, addition); let pattern = r#"-n "__fish_seen_subcommand_from run""#; let replacement = r#"-n "__fish_seen_subcommand_from run; or __fish_seen_subcommand_from r""#; @@ -142,20 +153,24 @@ fn replace_fish_completion(script: &str) -> Cow { fn replace_nushell_completion(script: &str) -> Cow { // Adds tab completion to the pixi run command. // NOTE THIS IS FORMATTED BY HAND - let pattern = r#"(#.*\n export extern "pixi run".*\n.*...task: string)([^\]]*--environment\(-e\): string)"#; + let bin_name = pixi_consts::consts::PIXI_BIN_NAME.as_str(); + let pattern = format!( + r#"(#.*\n export extern "{} run".*\n.*...task: string)([^\]]*--environment\(-e\): string)"#, + bin_name + ); let replacement = r#" - def "nu-complete pixi run" [] { - ^pixi info --json | from json | get environments_info | get tasks | flatten | uniq + def "nu-complete BIN_NAME run" [] { + ^BIN_NAME info --json | from json | get environments_info | get tasks | flatten | uniq } - def "nu-complete pixi run environment" [] { - ^pixi info --json | from json | get environments_info | get name + def "nu-complete BIN_NAME run environment" [] { + ^BIN_NAME info --json | from json | get environments_info | get name } - ${1}@"nu-complete pixi run"${2}@"nu-complete pixi run environment""#; + ${1}@"nu-complete BIN_NAME run"${2}@"nu-complete BIN_NAME run environment""#; - let re = Regex::new(pattern).unwrap(); - re.replace(script, replacement) + let re = Regex::new(pattern.as_str()).unwrap(); + re.replace(script, replacement.replace("BIN_NAME", bin_name)) } #[cfg(test)] @@ -201,7 +216,12 @@ _arguments "${_arguments_options[@]}" \ "#; let result = replace_zsh_completion(script); - insta::assert_snapshot!(result); + let replacement = format!("{} task list", pixi_consts::consts::PIXI_BIN_NAME.as_str()); + insta::with_settings!({filters => vec![ + (replacement.as_str(), "pixi task list"), + ]}, { + insta::assert_snapshot!(result); + }); } #[test] @@ -215,9 +235,15 @@ _arguments "${_arguments_options[@]}" \ ;; pixi__run) opts="-v -q -h --manifest-path --locked --frozen --verbose --quiet --color --help [TASK]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 + elif [[ ${COMP_CWORD} -eq 2 ]]; then + local tasks=$(pixi task list --machine-readable 2> /dev/null) + if [[ $? -eq 0 ]]; then + COMPREPLY=( $(compgen -W "${tasks}" -- "${cur}") ) + return 0 + fi fi case "${prev}" in --manifest-path) @@ -247,7 +273,20 @@ _arguments "${_arguments_options[@]}" \ ;; "#; let result = replace_bash_completion(script); - insta::assert_snapshot!(result); + let replacement = format!("{} task list", pixi_consts::consts::PIXI_BIN_NAME.as_str()); + let zsh_arg_name = format!( + "{}__", + pixi_consts::consts::PIXI_BIN_NAME + .as_str() + .replace("-", "__") + ); + println!("{}", result); + insta::with_settings!({filters => vec![ + (replacement.as_str(), "pixi task list"), + (zsh_arg_name.as_str(), "[PIXI COMMAND]"), + ]}, { + insta::assert_snapshot!(result); + }); } #[test] @@ -260,7 +299,7 @@ _arguments "${_arguments_options[@]}" \ --manifest-path: string # The path to `pixi.toml` or `pyproject.toml` --frozen # Install the environment as defined in the lockfile, doesn't update lockfile if it isn't up-to-date with the manifest file --locked # Check if lockfile is up-to-date before installing the environment, aborts when lockfile isn't up-to-date with the manifest file - --environment(-e): string # The environment to run the task in + --environment(-e): string@"nu-complete pixi run" # The environment to run the task in --tls-no-verify # Do not verify the TLS certificate of the server --auth-file: string # Path to the file containing the authentication token --pypi-keyring-provider: string@"nu-complete pixi run pypi_keyring_provider" # Specifies if we want to use uv keyring provider @@ -272,7 +311,18 @@ _arguments "${_arguments_options[@]}" \ --help(-h) # Print help (see more with '--help') ]"#; let result = replace_nushell_completion(script); - insta::assert_snapshot!(result); + let replacement = format!("{} run", pixi_consts::consts::PIXI_BIN_NAME.as_str()); + let nu_complete_run = format!( + "nu-complete {} run", + pixi_consts::consts::PIXI_BIN_NAME.as_str() + ); + println!("{}", result); + insta::with_settings!({filters => vec![ + (replacement.as_str(), "[PIXI RUN]"), + (nu_complete_run.as_str(), "[nu_complete_run PIXI COMMAND]"), + ]}, { + insta::assert_snapshot!(result); + }); } #[test] diff --git a/src/cli/init.rs b/src/cli/init.rs index 900bafb931..863745fdb1 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -26,6 +26,7 @@ use crate::Project; pub enum ManifestFormat { Pixi, Pyproject, + Mojoproject, } /// Creates a new project @@ -48,7 +49,7 @@ pub struct Args { pub env_file: Option, /// The manifest format to create. - #[arg(long, conflicts_with_all = ["env_file", "pyproject_toml"], ignore_case = true)] + #[arg(long, conflicts_with_all = ["env_file", "pyproject_toml", "mojoproject_toml"], ignore_case = true)] pub format: Option, /// Create a pyproject.toml manifest instead of a pixi.toml manifest @@ -59,9 +60,14 @@ pub struct Args { /// Source Control Management used for this project #[arg(short = 's', long = "scm", ignore_case = true)] pub scm: Option, + + /// Create a mojoproject.toml manifest instead of a pixi.toml manifest + // BREAK (Magic alpha): Remove this option from the cli in favor of the `format` option. + #[arg(long, conflicts_with_all = ["env_file", "format"], alias = "mojoproject", hide = true)] + pub mojoproject_toml: bool, } -/// The pixi.toml template +/// The pixi.toml/mojoproject.toml template /// /// This uses a template just to simplify the flexibility of emitting it. const PROJECT_TEMPLATE: &str = r#"[project] @@ -184,6 +190,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { let dir = get_dir(args.path).into_diagnostic()?; let pixi_manifest_path = dir.join(consts::PROJECT_MANIFEST); let pyproject_manifest_path = dir.join(consts::PYPROJECT_MANIFEST); + let mojoproject_manifest_path = dir.join(consts::MOJOPROJECT_MANIFEST); let gitignore_path = dir.join(".gitignore"); let gitattributes_path = dir.join(".gitattributes"); let config = Config::load_global(); @@ -413,9 +420,15 @@ pub async fn execute(args: Args) -> miette::Result<()> { // Create a 'pixi.toml' manifest } else { - // Check if the 'pixi.toml' file doesn't already exist. We don't want to - // overwrite it. - if pixi_manifest_path.is_file() { + let path = if args.mojoproject_toml || args.format == Some(ManifestFormat::Mojoproject) + { + mojoproject_manifest_path + } else { + pixi_manifest_path + }; + + // Check if the manifest file doesn't already exist. We don't want to overwrite it. + if path.is_file() { miette::bail!("{} already exists", consts::PROJECT_MANIFEST); } let rv = render_project( @@ -428,7 +441,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { index_url.as_ref(), &extra_index_urls, ); - save_manifest_file(&pixi_manifest_path, rv)?; + save_manifest_file(&path, rv)?; }; } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index fdd85f24fc..3cd1a395ca 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -17,7 +17,7 @@ pub mod clean; pub mod cli_config; pub mod completion; pub mod config; -mod exec; +pub mod exec; pub mod global; pub mod has_specs; pub mod info; diff --git a/src/cli/snapshots/pixi__cli__completion__tests__bash_completion.snap b/src/cli/snapshots/pixi__cli__completion__tests__bash_completion.snap index a1fda1609c..6638926b27 100644 --- a/src/cli/snapshots/pixi__cli__completion__tests__bash_completion.snap +++ b/src/cli/snapshots/pixi__cli__completion__tests__bash_completion.snap @@ -2,7 +2,6 @@ source: src/cli/completion.rs expression: result --- - pixi__project__help__help) opts="" COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -11,8 +10,8 @@ expression: result pixi__run) opts="-v -q -h --manifest-path --locked --frozen --verbose --quiet --color --help [TASK]..." if [[ ${cur} == -* ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 elif [[ ${COMP_CWORD} -eq 2 ]]; then local tasks=$(pixi task list --machine-readable 2> /dev/null) if [[ $? -eq 0 ]]; then @@ -46,4 +45,3 @@ expression: result COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) ;; - diff --git a/src/cli/snapshots/pixi__cli__completion__tests__nushell_completion.snap b/src/cli/snapshots/pixi__cli__completion__tests__nushell_completion.snap index 8117489f62..8c19070b22 100644 --- a/src/cli/snapshots/pixi__cli__completion__tests__nushell_completion.snap +++ b/src/cli/snapshots/pixi__cli__completion__tests__nushell_completion.snap @@ -2,22 +2,13 @@ source: src/cli/completion.rs expression: result --- - - def "nu-complete pixi run" [] { - ^pixi info --json | from json | get environments_info | get tasks | flatten | uniq - } - - def "nu-complete pixi run environment" [] { - ^pixi info --json | from json | get environments_info | get name - } - # Runs task in project export extern "pixi run" [ - ...task: string@"nu-complete pixi run" # The pixi task or a task shell command you want to run in the project's environment, which can be an executable in the environment's PATH + ...task: string # The pixi task or a task shell command you want to run in the project's environment, which can be an executable in the environment's PATH --manifest-path: string # The path to `pixi.toml` or `pyproject.toml` --frozen # Install the environment as defined in the lockfile, doesn't update lockfile if it isn't up-to-date with the manifest file --locked # Check if lockfile is up-to-date before installing the environment, aborts when lockfile isn't up-to-date with the manifest file - --environment(-e): string@"nu-complete pixi run environment" # The environment to run the task in + --environment(-e): string@"nu-complete pixi run" # The environment to run the task in --tls-no-verify # Do not verify the TLS certificate of the server --auth-file: string # Path to the file containing the authentication token --pypi-keyring-provider: string@"nu-complete pixi run pypi_keyring_provider" # Specifies if we want to use uv keyring provider diff --git a/src/global/project/manifest.rs b/src/global/project/manifest.rs index fb2b55adff..052feb3ad1 100644 --- a/src/global/project/manifest.rs +++ b/src/global/project/manifest.rs @@ -824,7 +824,7 @@ mod tests { Some( DEFAULT_CHANNELS .iter() - .map(|&name| NamedChannelOrUrl::Name(name.to_string())) + .map(|name| NamedChannelOrUrl::Name(name.to_string())) .collect(), ), ) diff --git a/src/lock_file/records_by_name.rs b/src/lock_file/records_by_name.rs index 2aae0fe853..f9c50ec4ae 100644 --- a/src/lock_file/records_by_name.rs +++ b/src/lock_file/records_by_name.rs @@ -35,6 +35,7 @@ impl HasNameVersion for PypiRecord { &self.0.version } } +#[allow(refining_impl_trait)] impl HasNameVersion for RepoDataRecord { type N = rattler_conda_types::PackageName; type V = VersionWithSource; diff --git a/src/project/environment.rs b/src/project/environment.rs index a55d54d828..e9876e0472 100644 --- a/src/project/environment.rs +++ b/src/project/environment.rs @@ -75,7 +75,7 @@ impl<'p> Environment<'p> { } /// Returns the name of this environment. - pub(crate) fn name(&self) -> &EnvironmentName { + pub fn name(&self) -> &EnvironmentName { &self.environment.name } diff --git a/src/project/mod.rs b/src/project/mod.rs index a27ef18c0f..df33c4f408 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -226,9 +226,11 @@ impl Project { } miette::bail!( - "could not find {} or {} which is configured to use pixi", + "could not find {}, {}, or {} which is configured to use {}", consts::PROJECT_MANIFEST, - consts::PYPROJECT_MANIFEST + consts::PYPROJECT_MANIFEST, + consts::MOJOPROJECT_MANIFEST, + consts::PIXI_BIN_NAME.as_str() ); } @@ -423,7 +425,7 @@ impl Project { /// Returns an environment in this project based on a name or an environment /// variable. - pub(crate) fn environment_from_name_or_env_var( + pub fn environment_from_name_or_env_var( &self, name: Option, ) -> miette::Result { @@ -1029,9 +1031,14 @@ impl<'source> HasManifestRef<'source> for &'source Project { /// Iterates over the current directory and all its parent directories and /// returns the manifest path in the first directory path that contains the -/// [`consts::PROJECT_MANIFEST`] or [`consts::PYPROJECT_MANIFEST`]. +/// [`consts::PROJECT_MANIFEST`], [`consts::PYPROJECT_MANIFEST`], +/// or [`consts::MOJOPROJECT_MANIFEST`] file. pub(crate) fn find_project_manifest(current_dir: PathBuf) -> Option { - let manifests = [consts::PROJECT_MANIFEST, consts::PYPROJECT_MANIFEST]; + let manifests = [ + consts::PROJECT_MANIFEST, + consts::MOJOPROJECT_MANIFEST, + consts::PYPROJECT_MANIFEST, + ]; for dir in current_dir.ancestors() { for manifest in &manifests { @@ -1041,6 +1048,7 @@ pub(crate) fn find_project_manifest(current_dir: PathBuf) -> Option { } match *manifest { + consts::MOJOPROJECT_MANIFEST => return Some(path), consts::PROJECT_MANIFEST => return Some(path), consts::PYPROJECT_MANIFEST => { if let Ok(content) = fs_err::read_to_string(&path) { diff --git a/tests/integration_rust/common/mod.rs b/tests/integration_rust/common/mod.rs index a580431a5d..101a899de6 100644 --- a/tests/integration_rust/common/mod.rs +++ b/tests/integration_rust/common/mod.rs @@ -264,15 +264,15 @@ impl PixiControl { pub fn manifest_path(&self) -> PathBuf { // Either pixi.toml or pyproject.toml if self.project_path().join(consts::PROJECT_MANIFEST).exists() { - return self.project_path().join(consts::PROJECT_MANIFEST); + self.project_path().join(consts::PROJECT_MANIFEST) } else if self .project_path() .join(consts::PYPROJECT_MANIFEST) .exists() { - return self.project_path().join(consts::PYPROJECT_MANIFEST); + self.project_path().join(consts::PYPROJECT_MANIFEST) } else { - return self.project_path().join(consts::PROJECT_MANIFEST); + self.project_path().join(consts::PROJECT_MANIFEST) } } @@ -297,6 +297,7 @@ impl PixiControl { format: None, pyproject_toml: false, scm: Some(GitAttributes::Github), + mojoproject_toml: false, }, } } @@ -315,6 +316,7 @@ impl PixiControl { format: None, pyproject_toml: false, scm: Some(GitAttributes::Github), + mojoproject_toml: false, }, } }