wash_cli/
generate.rs

1use std::{collections::HashMap, path::PathBuf};
2
3use anyhow::{Context, Result};
4use clap::{Args, Subcommand};
5use serde_json::json;
6use wash_lib::{
7    cli::CommandOutput,
8    generate::{generate_project, Project, ProjectKind},
9};
10
11/// Create a new project from template
12#[derive(Debug, Clone, Subcommand)]
13pub enum NewCliCommand {
14    /// Generate a wasmCloud component project
15    #[clap(name = "component")]
16    Component(NewProjectArgs),
17
18    /// Generate a new capability provider project
19    #[clap(name = "provider")]
20    Provider(NewProjectArgs),
21}
22
23#[derive(Args, Debug, Default, Clone)]
24pub struct NewProjectArgs {
25    /// Project name
26    #[clap(help = "Project name")]
27    pub project_name: Option<String>,
28
29    /// GitHub repository url. Requires 'git' to be installed in PATH.
30    #[clap(long)]
31    pub git: Option<String>,
32
33    /// Optional subfolder of the git repository
34    #[clap(long, alias = "subdir")]
35    pub subfolder: Option<String>,
36
37    /// Optional github branch. Defaults to "main"
38    #[clap(long)]
39    pub branch: Option<String>,
40
41    /// Optional path for template project (alternative to --git)
42    #[clap(short, long)]
43    pub path: Option<PathBuf>,
44
45    /// Optional path to file containing placeholder values
46    #[clap(short, long)]
47    pub values: Option<PathBuf>,
48
49    /// Silent - do not prompt user. Placeholder values in the templates
50    /// will be resolved from a '--values' file and placeholder defaults.
51    #[clap(long)]
52    pub silent: bool,
53
54    /// Favorites file - to use for project selection
55    #[clap(long)]
56    pub favorites: Option<PathBuf>,
57
58    /// Template name - name of template to use
59    #[clap(short, long)]
60    pub template_name: Option<String>,
61
62    /// Don't run 'git init' on the new folder
63    #[clap(long)]
64    pub no_git_init: bool,
65}
66
67impl From<NewCliCommand> for Project {
68    fn from(cmd: NewCliCommand) -> Project {
69        let (args, kind) = match cmd {
70            NewCliCommand::Component(args) => (args, ProjectKind::Component),
71            NewCliCommand::Provider(args) => (args, ProjectKind::Provider),
72        };
73
74        Project {
75            kind,
76            project_name: args.project_name,
77            values: args.values,
78            silent: args.silent,
79            favorites: args.favorites,
80            template_name: args.template_name,
81            no_git_init: args.no_git_init,
82            path: args.path,
83            git: args.git,
84            subfolder: args.subfolder,
85            branch: args.branch,
86        }
87    }
88}
89
90pub async fn handle_command(cmd: NewCliCommand) -> Result<CommandOutput> {
91    generate_project(cmd.into())
92        .await
93        .map(|path| CommandOutput {
94            map: HashMap::from([(
95                "project_path".to_string(),
96                json!(path.to_string_lossy().to_string()),
97            )]),
98            text: format!(
99                "Project generated and is located at: {}",
100                path.to_string_lossy()
101            ),
102        })
103        .context("Failed to generate project")
104}