Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new commands for pixi project {version|channel|platform|description} #579

Merged
merged 30 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2067851
add description get and set
hadim Dec 18, 2023
40eaeed
add channel list and remove
hadim Dec 18, 2023
05aa46b
platform list/add/remove
hadim Dec 18, 2023
91393d4
wrap up platform remove
hadim Dec 18, 2023
604078b
version set/get
hadim Dec 18, 2023
5b41533
draft of version bump cli
hadim Dec 18, 2023
ccc9f4f
fix version get
hadim Dec 18, 2023
24ac697
cleanup
hadim Dec 18, 2023
a7dbb94
cleanup again
hadim Dec 18, 2023
5941f42
add test for description set
hadim Dec 18, 2023
4283762
Refactor environment directory path
hadim Dec 19, 2023
d1ea1d4
Remove bump command for now
hadim Dec 19, 2023
1d84c56
Remove all the empty `Args` and refactor the docstring into `Command`…
hadim Dec 19, 2023
b9c8e23
Prefer print instead of eprint for user facing outputs
hadim Dec 19, 2023
91ad729
docstring
hadim Dec 19, 2023
16eafcd
Update src/cli/project/channel/remove.rs
hadim Dec 19, 2023
d9acfed
Update src/cli/project/channel/remove.rs
hadim Dec 19, 2023
85691dd
Update src/cli/project/channel/remove.rs
hadim Dec 19, 2023
6ae2a0f
Update src/cli/project/platform/remove.rs
hadim Dec 19, 2023
0f4fa7d
Update src/cli/project/platform/remove.rs
hadim Dec 19, 2023
31a0ce9
docstring
hadim Dec 19, 2023
f71bfd8
Update src/cli/project/platform/remove.rs
hadim Dec 19, 2023
938c77a
Update src/cli/project/platform/remove.rs
hadim Dec 19, 2023
16366db
docstring again
hadim Dec 19, 2023
edde656
test_set_version
hadim Dec 19, 2023
29c90e9
tests for set_description, set_version, {add|remove}_platforms and {a…
hadim Dec 19, 2023
f64a915
remove test
hadim Dec 20, 2023
773cbfe
use pixi_dir in environment_dir
hadim Dec 20, 2023
f9ce6e5
Update directory name from environment_dir to pixi_dir
hadim Dec 20, 2023
848f9b3
fmt
hadim Dec 20, 2023
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
28 changes: 28 additions & 0 deletions src/cli/project/channel/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::Project;
use clap::Parser;

/// List the channels in the project file.
#[derive(Parser, Debug, Default)]
pub struct Args {
/// Whether to display the channel's names or urls
hadim marked this conversation as resolved.
Show resolved Hide resolved
#[clap(long)]
pub urls: bool,
}

pub async fn execute(project: Project, args: Args) -> miette::Result<()> {
project.channels().iter().for_each(|channel| {
if args.urls {
// Print the channel's url
eprintln!("{}", channel.base_url());
hadim marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Print the channel's name and fallback to the url if it doesn't have one
let name = channel
.name
.as_deref()
.unwrap_or(channel.base_url().as_str());
eprintln!("{}", name);
}
});

Ok(())
}
6 changes: 6 additions & 0 deletions src/cli/project/channel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod add;
pub mod list;
pub mod remove;

use crate::Project;
use clap::Parser;
Expand All @@ -19,12 +21,16 @@ pub struct Args {
#[derive(Parser, Debug)]
pub enum Command {
Add(add::Args),
List(list::Args),
Remove(remove::Args),
}

pub async fn execute(args: Args) -> miette::Result<()> {
let project = Project::load_or_else_discover(args.manifest_path.as_deref())?;

match args.command {
Command::Add(args) => add::execute(project, args).await,
Command::List(args) => list::execute(project, args).await,
Command::Remove(args) => remove::execute(project, args).await,
}
}
87 changes: 87 additions & 0 deletions src/cli/project/channel/remove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::environment::update_prefix;
use crate::lock_file::{load_lock_file, update_lock_file};
use crate::prefix::Prefix;
use crate::Project;
use clap::Parser;
use itertools::Itertools;
use miette::IntoDiagnostic;
use rattler_conda_types::{Channel, ChannelConfig, Platform};

/// Remove a channel(s) to the project file and updates the lockfile.
hadim marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Parser, Debug, Default)]
pub struct Args {
/// The channel name(s) or URL
#[clap(required = true, num_args=1..)]
pub channel: Vec<String>,

/// Don't update the environment, only remove the channel(s) to the lock-file.
hadim marked this conversation as resolved.
Show resolved Hide resolved
#[clap(long)]
pub no_install: bool,
}

pub async fn execute(mut project: Project, args: Args) -> miette::Result<()> {
// Determine which channels are missing
hadim marked this conversation as resolved.
Show resolved Hide resolved
let channel_config = ChannelConfig::default();
let channels = args
.channel
.into_iter()
.map(|channel_str| {
Channel::from_str(&channel_str, &channel_config).map(|channel| (channel_str, channel))
})
.collect::<Result<Vec<_>, _>>()
.into_diagnostic()?;

let channels_to_remove = channels
.into_iter()
.filter(|(_name, channel)| project.channels().contains(channel))
.collect_vec();

if channels_to_remove.is_empty() {
eprintln!(
hadim marked this conversation as resolved.
Show resolved Hide resolved
"{}The channel(s) are not present.",
console::style(console::Emoji("✔ ", "")).green(),
);
return Ok(());
}

// Load the existing lock-file
let lock_file = load_lock_file(&project).await?;

// Add the channels to the lock-file
hadim marked this conversation as resolved.
Show resolved Hide resolved
project
.manifest
.remove_channels(channels_to_remove.iter().map(|(name, _channel)| name))?;

// Try to update the lock-file with the new channels
hadim marked this conversation as resolved.
Show resolved Hide resolved
let lock_file = update_lock_file(&project, lock_file, None).await?;
project.save()?;

// Update the installation if needed
if !args.no_install {
// Get the currently installed packages
let prefix = Prefix::new(project.root().join(".pixi/env"))?;
let installed_packages = prefix.find_installed_packages(None).await?;

// Update the prefix
update_prefix(
project.pypi_package_db()?,
&prefix,
installed_packages,
&lock_file,
Platform::current(),
)
.await?;
}

// Report back to the user
for (name, channel) in channels_to_remove {
eprintln!(
"{}Removed {} ({})",
console::style(console::Emoji("✔ ", "")).green(),
name,
channel.base_url()
);
}

Ok(())
}
14 changes: 14 additions & 0 deletions src/cli/project/description/get.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::Project;
use clap::Parser;

/// Get the project description.
#[derive(Parser, Debug, Default)]
pub struct Args {}

pub async fn execute(project: Project, _args: Args) -> miette::Result<()> {
// Print the description if it exists
if let Some(description) = project.description() {
eprintln!("{}", description);
}
Ok(())
}
35 changes: 35 additions & 0 deletions src/cli/project/description/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
pub mod get;
pub mod set;

use crate::Project;
use clap::Parser;
use std::path::PathBuf;

/// Commands to manage project description.
#[derive(Parser, Debug)]
pub struct Args {
/// The path to 'pixi.toml'
#[clap(long, global = true)]
pub manifest_path: Option<PathBuf>,

/// The subcommand to execute
#[clap(subcommand)]
pub command: Command,
}

#[derive(Parser, Debug)]
pub enum Command {
Get(get::Args),
hadim marked this conversation as resolved.
Show resolved Hide resolved
Set(set::Args),
}

pub async fn execute(args: Args) -> miette::Result<()> {
let project = Project::load_or_else_discover(args.manifest_path.as_deref())?;

match args.command {
Command::Get(args) => get::execute(project, args).await?,
Command::Set(args) => set::execute(project, args).await?,
}

Ok(())
}
33 changes: 33 additions & 0 deletions src/cli/project/description/set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::Project;
use clap::Parser;

/// Set the project description.
#[derive(Parser, Debug, Default)]
pub struct Args {
/// The project description
#[clap(required = true, num_args = 1)]
pub description: String,
}

pub async fn execute(mut project: Project, args: Args) -> miette::Result<()> {
// Set the description
project.manifest.set_description(&args.description)?;

// Save the manifest on disk
project.save()?;

// Report back to the user
eprintln!(
"{}Updated project description to '{}'.",
console::style(console::Emoji("✔ ", "")).green(),
project
.manifest
.parsed
.project
.description
.as_ref()
.unwrap()
);

Ok(())
}
9 changes: 9 additions & 0 deletions src/cli/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ use clap::Parser;
use std::path::PathBuf;

pub mod channel;
pub mod description;
pub mod platform;
pub mod version;

#[derive(Debug, Parser)]
pub enum Command {
Channel(channel::Args),
Description(description::Args),
Platform(platform::Args),
Version(version::Args),
}

/// Modify the project configuration file through the command line.
Expand All @@ -21,6 +27,9 @@ pub struct Args {
pub async fn execute(cmd: Args) -> miette::Result<()> {
match cmd.command {
Command::Channel(args) => channel::execute(args).await?,
Command::Description(args) => description::execute(args).await?,
Command::Platform(args) => platform::execute(args).await?,
Command::Version(args) => version::execute(args).await?,
};
Ok(())
}
83 changes: 83 additions & 0 deletions src/cli/project/platform/add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use std::str::FromStr;

use crate::environment::update_prefix;
use crate::lock_file::{load_lock_file, update_lock_file};
use crate::prefix::Prefix;
use crate::Project;
use clap::Parser;
use itertools::Itertools;
use miette::IntoDiagnostic;
use rattler_conda_types::Platform;

/// Adds a platform(s) to the project file and updates the lockfile.
#[derive(Parser, Debug, Default)]
pub struct Args {
/// The platform name(s) to add.
#[clap(required = true, num_args=1..)]
pub platform: Vec<String>,

/// Don't update the environment, only add changed packages to the lock-file.
#[clap(long)]
pub no_install: bool,
}

pub async fn execute(mut project: Project, args: Args) -> miette::Result<()> {
// Determine which platforms are missing
let platforms = args
.platform
.into_iter()
.map(|platform_str| Platform::from_str(&platform_str))
.collect::<Result<Vec<_>, _>>()
.into_diagnostic()?;

let missing_platforms = platforms
.into_iter()
.filter(|x| !project.platforms().contains(x))
.collect_vec();

if missing_platforms.is_empty() {
eprintln!(
"{}All platform(s) have already been added.",
console::style(console::Emoji("✔ ", "")).green(),
);
return Ok(());
}

// Load the existing lock-file
let lock_file = load_lock_file(&project).await?;

// Add the platforms to the lock-file
project.manifest.add_platforms(missing_platforms.iter())?;

// Try to update the lock-file with the new channels
let lock_file = update_lock_file(&project, lock_file, None).await?;
project.save()?;

// Update the installation if needed
if !args.no_install {
// Get the currently installed packages
let prefix = Prefix::new(project.root().join(".pixi/env"))?;
hadim marked this conversation as resolved.
Show resolved Hide resolved
let installed_packages = prefix.find_installed_packages(None).await?;

// Update the prefix
update_prefix(
project.pypi_package_db()?,
&prefix,
installed_packages,
&lock_file,
Platform::current(),
)
.await?;
}

// Report back to the user
for platform in missing_platforms {
eprintln!(
"{}Added {}",
console::style(console::Emoji("✔ ", "")).green(),
platform
);
}

Ok(())
}
14 changes: 14 additions & 0 deletions src/cli/project/platform/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::Project;
use clap::Parser;

/// List the platforms in the project file.
#[derive(Parser, Debug, Default)]
pub struct Args {}

pub async fn execute(project: Project, _args: Args) -> miette::Result<()> {
project.platforms().iter().for_each(|platform| {
eprintln!("{}", platform.as_str());
});

Ok(())
}
36 changes: 36 additions & 0 deletions src/cli/project/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pub mod add;
pub mod list;
pub mod remove;

use crate::Project;
use clap::Parser;
use std::path::PathBuf;

/// Commands to manage project channels.
#[derive(Parser, Debug)]
pub struct Args {
/// The path to 'pixi.toml'
#[clap(long, global = true)]
pub manifest_path: Option<PathBuf>,

/// The subcommand to execute
#[clap(subcommand)]
pub command: Command,
}

#[derive(Parser, Debug)]
pub enum Command {
Add(add::Args),
List(list::Args),
Remove(remove::Args),
}

pub async fn execute(args: Args) -> miette::Result<()> {
let project = Project::load_or_else_discover(args.manifest_path.as_deref())?;

match args.command {
Command::Add(args) => add::execute(project, args).await,
Command::List(args) => list::execute(project, args).await,
Command::Remove(args) => remove::execute(project, args).await,
}
}
Loading