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: Update task list console output #1443

Merged
merged 11 commits into from
May 28, 2024
2 changes: 1 addition & 1 deletion docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ List all tasks in the project.
##### Options

- `--environment`(`-e`): the environment's tasks list, if non is provided the default tasks will be listed.
- `--summary`(`-s`): the output gets formatted to be machine parsable. (Used in the autocompletion of `pixi run`).
- `--summary`(`-s`): list the tasks per environment.

```shell
pixi task list
Expand Down
4 changes: 2 additions & 2 deletions src/cli/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn replace_bash_completion(script: &str) -> Cow<str> {
COMPREPLY=( $$(compgen -W "$${opts}" -- "$${cur}") )
return 0
elif [[ $${COMP_CWORD} -eq 2 ]]; then
local tasks=$$(pixi task list --summary 2> /dev/null)
local tasks=$$(pixi task list --machine-readable 2> /dev/null)
if [[ $$? -eq 0 ]]; then
COMPREPLY=( $$(compgen -W "$${tasks}" -- "$${cur}") )
return 0
Expand All @@ -73,7 +73,7 @@ fn replace_zsh_completion(script: &str) -> Cow<str> {
// NOTE THIS IS FORMATTED BY HAND
let zsh_replacement = r#"$1
local tasks
tasks=("$${(@s/ /)$$(pixi task list --summary 2> /dev/null)}")
tasks=("$${(@s/ /)$$(pixi task list --machine-readable 2> /dev/null)}")

if [[ -n "$$tasks" ]]; then
_values 'task' "$${tasks[@]}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ expression: result
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
elif [[ ${COMP_CWORD} -eq 2 ]]; then
local tasks=$(pixi task list --summary 2> /dev/null)
local tasks=$(pixi task list --machine-readable 2> /dev/null)
if [[ $? -eq 0 ]]; then
COMPREPLY=( $(compgen -W "${tasks}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -46,4 +46,4 @@ expression: result
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )

;;

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ _arguments "${_arguments_options[@]}" \
;;
(run)
local tasks
tasks=("${(@s/ /)$(pixi task list --summary 2> /dev/null)}")
tasks=("${(@s/ /)$(pixi task list --machine-readable 2> /dev/null)}")

if [[ -n "$tasks" ]]; then
_values 'task' "${tasks[@]}"
Expand Down Expand Up @@ -45,4 +45,4 @@ _arguments "${_arguments_options[@]}" \
&& ret=0
;;


85 changes: 71 additions & 14 deletions src/cli/task.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::project::manifest::EnvironmentName;
use crate::project::manifest::FeatureName;
use crate::project::virtual_packages::verify_current_platform_has_required_virtual_packages;
use crate::project::Environment;
use crate::task::{quote, Alias, CmdArgs, Execute, Task, TaskName};
use crate::Project;
use clap::Parser;
Expand All @@ -9,6 +10,9 @@ use itertools::Itertools;
use rattler_conda_types::Platform;
use std::collections::HashSet;
use std::error::Error;
use std::fmt::Write as _;
vigneshmanick marked this conversation as resolved.
Show resolved Hide resolved
use std::io;
use std::io::{stdout, Write};
use std::path::PathBuf;
use std::str::FromStr;
use toml_edit::{Array, Item, Table, Value};
Expand All @@ -28,7 +32,7 @@ pub enum Operation {
#[clap(alias = "@")]
Alias(AliasArgs),

/// List all tasks
/// List all tasks in the project
#[clap(visible_alias = "ls", alias = "l")]
List(ListArgs),
}
Expand Down Expand Up @@ -107,10 +111,17 @@ pub struct AliasArgs {

#[derive(Parser, Debug, Clone)]
pub struct ListArgs {
/// Tasks available for this machine per environment
#[arg(long, short)]
pub summary: bool,

/// The environment the list should be generated for
/// Output the list of tasks from all environments in
/// machine readable format (space delimited)
/// this output is used for autocomplete by `pixi run`
#[arg(long, hide(true))]
pub machine_readable: bool,

/// The environment the list should be generated for.
/// If not specified, the default environment is used.
#[arg(long, short)]
pub environment: Option<String>,
Expand Down Expand Up @@ -182,6 +193,42 @@ pub struct Args {
pub manifest_path: Option<PathBuf>,
}

fn print_heading(value: &str) -> io::Result<()> {
let bold = console::Style::new().bold();
let mut writer = tabwriter::TabWriter::new(stdout());
writeln!(
writer,
"{}\n{:-<2$}",
bold.apply_to(value),
"",
value.len() + 4
)?;
writer.flush()?;
Ok(())
}
vigneshmanick marked this conversation as resolved.
Show resolved Hide resolved

fn print_tasks_per_env(envs: Vec<Environment>) -> io::Result<()> {
let mut writer = tabwriter::TabWriter::new(stdout());
for env in envs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have been for env in envs.sorted() or something along those lines? In pixi 0.28.1 (the latest release) I see that the tasks are indeed sorted for pixi task list -s, but the order in which the environments are shown varies randomly.

let formatted: String =
env.get_filtered_tasks()
.iter()
.sorted()
.fold(String::new(), |mut output, name| {
let _ = write!(output, "{}, ", name.fancy_display());
vigneshmanick marked this conversation as resolved.
Show resolved Hide resolved
output
});
writeln!(
writer,
"{}\t: {}",
env.name().fancy_display().bold(),
formatted
)?;
}
writer.flush()?;
Ok(())
}

pub fn execute(args: Args) -> miette::Result<()> {
let mut project = Project::load_or_else_discover(args.manifest_path.as_deref())?;
match args.operation {
Expand Down Expand Up @@ -309,19 +356,29 @@ pub fn execute(args: Args) -> miette::Result<()> {

if available_tasks.is_empty() {
eprintln!("No tasks found",);
} else if args.summary {
vigneshmanick marked this conversation as resolved.
Show resolved Hide resolved
print_heading("Tasks per environment:").expect("io error when printing heading");
print_tasks_per_env(project.environments()).expect("io error when printing tasks");
} else if args.machine_readable {
let unformatted: String =
available_tasks
.iter()
.sorted()
.fold(String::new(), |mut output, name| {
let _ = write!(output, "{} ", name.as_str());
output
});
println!("{}", unformatted);
} else {
let formatted: String = available_tasks
.iter()
.sorted()
.map(|name| {
if args.summary {
format!("{} ", name.as_str(),)
} else {
format!("* {}\n", name.fancy_display().bold(),)
}
})
.collect();

let formatted: String =
available_tasks
.iter()
.sorted()
.fold(String::new(), |mut output, name| {
let _ = write!(output, "{}, ", name.fancy_display());
output
});
print_heading("Tasks that can run on this machine:").expect("an io error occurred");
println!("{}", formatted);
}
}
Expand Down
Loading