sp1_cli/commands/
new.rs

1use anyhow::Result;
2use clap::{Args, Parser};
3use std::{
4    fs,
5    path::Path,
6    process::{Command, Stdio},
7};
8use yansi::Paint;
9
10#[derive(Args)]
11#[group(required = true, multiple = false)]
12struct TemplateType {
13    /// Use the `bare` template which includes just a program and script.
14    #[arg(long)]
15    bare: bool,
16
17    /// Use the `evm` template which includes Solidity smart contracts for onchain integration.
18    #[arg(long)]
19    evm: bool,
20}
21
22#[derive(Parser)]
23#[command(name = "new", about = "Setup a new project that runs inside the SP1.")]
24pub struct NewCmd {
25    /// The name of the project.
26    name: String,
27
28    /// The template to use for the project.
29    #[command(flatten)]
30    template: TemplateType,
31
32    /// Version of sp1-project-template to use (branch or tag).
33    #[arg(long, default_value = "main")]
34    version: String,
35}
36
37const TEMPLATE_REPOSITORY_URL: &str = "https://github.com/succinctlabs/sp1-project-template";
38
39impl NewCmd {
40    pub fn run(&self) -> Result<()> {
41        let root = Path::new(&self.name);
42
43        // Create the root directory if it doesn't exist.
44        if !root.exists() {
45            fs::create_dir(&self.name)?;
46        }
47
48        println!("     \x1b[1m{}\x1b[0m {}", Paint::green("Cloning"), TEMPLATE_REPOSITORY_URL);
49
50        // Clone the repository with the specified version.
51        let mut command = Command::new("git");
52
53        command
54            .arg("clone")
55            .arg("--branch")
56            .arg(&self.version)
57            .arg(TEMPLATE_REPOSITORY_URL)
58            .arg(root.as_os_str())
59            .arg("--depth=1");
60
61        // Stream output to stdout.
62        command.stdout(Stdio::inherit()).stderr(Stdio::piped());
63
64        let output = command.output().expect("failed to execute command");
65        if !output.status.success() {
66            let stderr = String::from_utf8_lossy(&output.stderr);
67            return Err(anyhow::anyhow!("Failed to clone repository: {}", stderr));
68        }
69
70        // Remove the .git directory.
71        fs::remove_dir_all(root.join(".git"))?;
72
73        if self.template.evm {
74            // Check if the user has `foundry` installed.
75            if Command::new("forge").arg("--version").output().is_err() {
76                println!(
77                    "    \x1b[1m{}\x1b[0m Make sure to install Foundry and run `forge install` in the \"contracts\" folder to use contracts: https://book.getfoundry.sh/getting-started/installation",
78                    Paint::yellow("Warning:"),
79                );
80            } else {
81                println!(
82                        "       \x1b[1m{}\x1b[0m Please run `forge install` in the \"contracts\" folder to setup contracts development",
83                        Paint::blue("Info:"),
84                    );
85            }
86        } else {
87            // Remove the `contracts` directory.
88            fs::remove_dir_all(root.join("contracts"))?;
89
90            // Remove the `.gitmodules` file.
91            fs::remove_file(root.join(".gitmodules"))?;
92        }
93
94        println!(
95            " \x1b[1m{}\x1b[0m {} ({})",
96            Paint::green("Initialized"),
97            self.name,
98            std::fs::canonicalize(root).expect("failed to canonicalize").to_str().unwrap()
99        );
100
101        Ok(())
102    }
103}