Skip to content
Open
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
75 changes: 74 additions & 1 deletion crates/pixi_cli/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,12 @@ pub async fn execute(args: Args) -> miette::Result<()> {
let version = "0.1.0";
let author = get_default_author();
let platforms = if args.platforms.is_empty() {
vec![Platform::current().to_string()]
let config_platforms = config.default_platforms();
if config_platforms.is_empty() {
vec![Platform::current().to_string()]
} else {
config_platforms
}
} else {
args.platforms.clone()
};
Expand Down Expand Up @@ -744,4 +749,72 @@ mod tests {
);
}
}

#[tokio::test]
async fn test_default_platforms_usage() {
use pixi_config::Config;
use tempfile::tempdir;

let temp_dir = tempdir().unwrap();
let config_dir = temp_dir.path().join(".pixi");
fs_err::create_dir_all(&config_dir).unwrap();
let config_file = config_dir.join("config.toml");

// Create a config with default platforms
let config_content = r#"default-platforms = ["win-64", "linux-64", "osx-64"]"#;
fs_err::write(&config_file, config_content).unwrap();

// Parse the config
let (config, _) = Config::from_toml(config_content, Some(&config_file)).unwrap();

// Test that default_platforms() returns the expected values
assert_eq!(
config.default_platforms(),
vec!["win-64", "linux-64", "osx-64"]
);

// Test init args with empty platforms should use config defaults
let args = Args {
path: temp_dir.path().to_path_buf(),
channels: None,
platforms: vec![], // Empty platforms
env_file: None,
format: None,
pyproject_toml: false,
scm: None,
};

// Test the platform selection logic matches what's in execute()
let platforms = if args.platforms.is_empty() {
let config_platforms = config.default_platforms();
if config_platforms.is_empty() {
vec![Platform::current().to_string()]
} else {
config_platforms
}
} else {
args.platforms.clone()
};

assert_eq!(platforms, vec!["win-64", "linux-64", "osx-64"]);

// Test with explicit platforms should override config
let args_with_platforms = Args {
platforms: vec!["linux-aarch64".to_string()],
..args
};

let platforms_override = if args_with_platforms.platforms.is_empty() {
let config_platforms = config.default_platforms();
if config_platforms.is_empty() {
vec![Platform::current().to_string()]
} else {
config_platforms
}
} else {
args_with_platforms.platforms.clone()
};

assert_eq!(platforms_override, vec!["linux-aarch64"]);
}
}
91 changes: 91 additions & 0 deletions crates/pixi_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,11 @@ pub struct Config {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub default_channels: Vec<NamedChannelOrUrl>,

#[serde(default)]
#[serde(alias = "default_platforms")] // BREAK: remove to stop supporting snake_case alias
#[serde(skip_serializing_if = "Vec::is_empty")]
pub default_platforms: Vec<String>,

/// Path to the file containing the authentication token.
#[serde(default)]
#[serde(alias = "authentication_override_file")] // BREAK: remove to stop supporting snake_case alias
Expand Down Expand Up @@ -736,6 +741,7 @@ impl Default for Config {
fn default() -> Self {
Self {
default_channels: Vec::new(),
default_platforms: Vec::new(),
authentication_override_file: None,
tls_no_verify: None,
mirrors: HashMap::new(),
Expand Down Expand Up @@ -1339,6 +1345,11 @@ impl Config {
} else {
other.default_channels
},
default_platforms: if other.default_platforms.is_empty() {
self.default_platforms
} else {
other.default_platforms
},
tls_no_verify: other.tls_no_verify.or(self.tls_no_verify),
authentication_override_file: other
.authentication_override_file
Expand Down Expand Up @@ -1384,6 +1395,11 @@ impl Config {
}
}

/// Retrieve the value for the default_platforms field (defaults to empty).
pub fn default_platforms(&self) -> Vec<String> {
self.default_platforms.clone()
}

/// Retrieve the value for the tls_no_verify field (defaults to false).
pub fn tls_no_verify(&self) -> bool {
self.tls_no_verify.unwrap_or(false)
Expand Down Expand Up @@ -2102,6 +2118,7 @@ UNUSED = "unused"
let mut config = Config::default();
let other = Config {
default_channels: vec![NamedChannelOrUrl::from_str("conda-forge").unwrap()],
default_platforms: vec!["linux-64".to_string()],
channel_config: ChannelConfig::default_with_root_dir(PathBuf::from("/root/dir")),
tls_no_verify: Some(true),
detached_environments: Some(DetachedEnvironments::Path(PathBuf::from("/path/to/envs"))),
Expand Down Expand Up @@ -2854,4 +2871,78 @@ UNUSED = "unused"
}
);
}

#[test]
fn test_config_parse_default_platforms() {
// Test parsing default_platforms from TOML
let toml = r#"default-platforms = ["win-64", "linux-64", "osx-64"]"#;
let (config, _) = Config::from_toml(toml, None).unwrap();
assert_eq!(
config.default_platforms,
vec!["win-64", "linux-64", "osx-64"]
);
assert_eq!(
config.default_platforms(),
vec!["win-64", "linux-64", "osx-64"]
);

// Test empty default_platforms (should return empty vec)
let toml = r#"default-platforms = []"#;
let (config, _) = Config::from_toml(toml, None).unwrap();
assert_eq!(config.default_platforms, Vec::<String>::new());
assert_eq!(config.default_platforms(), Vec::<String>::new());

// Test missing default_platforms (should default to empty)
let toml = r#"tls-no-verify = true"#;
let (config, _) = Config::from_toml(toml, None).unwrap();
assert_eq!(config.default_platforms, Vec::<String>::new());
assert_eq!(config.default_platforms(), Vec::<String>::new());
}

#[test]
fn test_config_merge_default_platforms() {
// Test that higher priority config overrides lower priority for default_platforms
let base_config = Config {
default_platforms: vec!["linux-64".to_string()],
..Config::default()
};

let override_config = Config {
default_platforms: vec!["win-64".to_string(), "osx-64".to_string()],
..Config::default()
};

let merged = base_config.merge_config(override_config);
assert_eq!(merged.default_platforms, vec!["win-64", "osx-64"]);

// Test that empty override doesn't change base
let base_config = Config {
default_platforms: vec!["linux-64".to_string()],
..Config::default()
};

let empty_override = Config::default();

let merged = base_config.merge_config(empty_override);
assert_eq!(merged.default_platforms, vec!["linux-64"]);
}

#[test]
fn test_config_parse_combined_defaults() {
// Test that both default_channels and default_platforms work together
let toml = r#"
default-channels = ["conda-forge", "bioconda"]
default-platforms = ["win-64", "linux-64"]
"#;
let (config, _) = Config::from_toml(toml, None).unwrap();

assert_eq!(
config.default_channels,
vec![
NamedChannelOrUrl::from_str("conda-forge").unwrap(),
NamedChannelOrUrl::from_str("bioconda").unwrap()
]
);
assert_eq!(config.default_platforms, vec!["win-64", "linux-64"]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Config {
"defaults",
),
],
default_platforms: [],
authentication_override_file: None,
tls_no_verify: Some(
false,
Expand Down
13 changes: 13 additions & 0 deletions docs/reference/pixi_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ For backwards compatibility, the following configuration options can still be wr
in `snake_case`:

- `default_channels`
- `default_platforms`
- `change_ps1`
- `tls_no_verify`
- `authentication_override_file`
Expand All @@ -77,6 +78,18 @@ This defaults to only conda-forge.
The `default-channels` are only used when initializing a new project. Once initialized the `channels` are used from the
project manifest.

### `default-platforms`

The default platforms to select when running `pixi init`.
This defaults to the current platform if not specified.

```toml title="config.toml"
default-platforms = ["win-64", "linux-64", "osx-64"]
```

!!! note
The `default-platforms` are only used when initializing a new project. You can override this by explicitly providing platforms with the `--platform` flag.

### `shell`

- `change-ps1`: When set to `false`, the `(pixi)` prefix in the shell prompt is removed.
Expand Down
Loading