cli/cli_commands/
list_steps.rs

1//! # list_steps
2//!
3//! Lists all known tasks in multiple formats.
4//! Or can list tasks based on a category
5//!
6
7#[cfg(test)]
8#[path = "list_steps_test.rs"]
9mod list_steps_test;
10
11use crate::error::CargoMakeError;
12use crate::execution_plan;
13use crate::io;
14use crate::types::{Config, DeprecationInfo};
15use std::collections::{BTreeMap, BTreeSet};
16
17pub fn run(
18    config: &Config,
19    output_format: &str,
20    output_file: &Option<String>,
21    category: &Option<String>,
22    hide_uninteresting: bool,
23) -> Result<(), CargoMakeError> {
24    let output = create_list(&config, output_format, category, hide_uninteresting)?;
25
26    match output_file {
27        Some(file) => {
28            io::write_text_file(&file, &output);
29            ()
30        }
31        None => print!("{}", output),
32    };
33    Ok(())
34}
35
36pub(crate) fn create_list(
37    config: &Config,
38    output_format: &str,
39    category_filter: &Option<String>,
40    hide_uninteresting: bool,
41) -> Result<String, CargoMakeError> {
42    // category -> actual_task -> description
43    let mut categories: BTreeMap<String, BTreeMap<String, String>> = BTreeMap::new();
44    // actual_task -> aliases
45    let mut aliases: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
46
47    // iterate over all tasks to build categories and aliases
48    for key in config.tasks.keys() {
49        let actual_task_name = execution_plan::get_actual_task_name(&config, &key)?;
50
51        let task = execution_plan::get_normalized_task(&config, &actual_task_name, true)?;
52
53        let is_private = match task.private {
54            Some(private) => private,
55            None => false,
56        };
57
58        let skip_task = if is_private {
59            true
60        } else if hide_uninteresting {
61            key.contains("pre-")
62                || key.contains("post-")
63                || key == "init"
64                || key == "end"
65                || key == "empty"
66        } else {
67            false
68        };
69
70        if !skip_task {
71            let category = match task.category {
72                Some(value) => value,
73                None => "No Category".to_string(),
74            };
75
76            if category_filter
77                .as_ref()
78                .map_or(false, |value| value != &category)
79            {
80                continue;
81            }
82
83            if &actual_task_name != key {
84                aliases
85                    .entry(actual_task_name)
86                    .or_default()
87                    .insert(key.clone());
88                continue;
89            }
90
91            let description = match task.description {
92                Some(value) => value,
93                None => "No Description.".to_string(),
94            };
95
96            let deprecated_message = match task.deprecated {
97                Some(deprecated) => match deprecated {
98                    DeprecationInfo::Boolean(value) => {
99                        if value {
100                            " (deprecated)".to_string()
101                        } else {
102                            "".to_string()
103                        }
104                    }
105                    DeprecationInfo::Message(ref message) => {
106                        let mut buffer = " (deprecated - ".to_string();
107                        buffer.push_str(message);
108                        buffer.push_str(")");
109
110                        buffer
111                    }
112                },
113                None => "".to_string(),
114            };
115
116            let mut text = String::from(description);
117            text.push_str(&deprecated_message);
118
119            categories
120                .entry(category)
121                .or_default()
122                .insert(key.clone(), text);
123        }
124    }
125
126    // build the task list output string
127    let single_page_markdown = output_format == "markdown-single-page";
128    let markdown = single_page_markdown
129        || output_format == "markdown"
130        || output_format == "markdown-sub-section";
131    let just_task_name = output_format == "autocomplete";
132
133    let mut buffer = String::new();
134    if single_page_markdown {
135        buffer.push_str(&format!("# Task List\n\n"));
136    }
137
138    let post_key = if markdown { "**" } else { "" };
139    for (category, tasks) in &categories {
140        if category_filter
141            .as_ref()
142            .map_or(false, |value| value != category)
143        {
144            continue;
145        }
146
147        if !just_task_name {
148            if single_page_markdown {
149                buffer.push_str(&format!("## {}\n\n", category));
150            } else if markdown {
151                buffer.push_str(&format!("#### {}\n\n", category));
152            } else {
153                buffer.push_str(&format!("{}\n----------\n", category));
154            }
155        }
156
157        for (key, description) in tasks {
158            if markdown {
159                buffer.push_str(&format!("* **"));
160            }
161
162            let aliases = if let Some(aliases) = aliases.remove(key) {
163                if just_task_name {
164                    aliases.into_iter().collect::<Vec<String>>().join(" ")
165                } else {
166                    format!(
167                        " [aliases: {}]",
168                        aliases.into_iter().collect::<Vec<String>>().join(", ")
169                    )
170                }
171            } else {
172                "".to_string()
173            };
174
175            if just_task_name {
176                buffer.push_str(&format!("{} {} ", &key, aliases));
177            } else {
178                buffer.push_str(&format!(
179                    "{}{} - {}{}\n",
180                    &key, &post_key, &description, aliases
181                ));
182            }
183        }
184
185        if !just_task_name {
186            buffer.push('\n');
187        }
188    }
189
190    Ok(buffer)
191}