Skip to main content

quasar_cli/
deploy.rs

1use {
2    crate::{config::QuasarConfig, error::CliResult, style, utils},
3    std::{
4        path::PathBuf,
5        process::{Command, Stdio},
6    },
7};
8
9pub fn run(
10    program_keypair: Option<PathBuf>,
11    upgrade_authority: Option<PathBuf>,
12    keypair: Option<PathBuf>,
13    url: Option<String>,
14    skip_build: bool,
15) -> CliResult {
16    let config = QuasarConfig::load()?;
17    let name = &config.project.name;
18
19    // Build unless skipped
20    if !skip_build {
21        crate::build::run(false, false, None)?;
22    }
23
24    // Find the .so binary
25    let so_path = utils::find_so(&config, false).unwrap_or_else(|| {
26        eprintln!(
27            "\n  {}",
28            style::fail(&format!("no compiled binary found for \"{name}\""))
29        );
30        eprintln!();
31        eprintln!("  Run {} first.", style::bold("quasar build"));
32        eprintln!();
33        std::process::exit(1);
34    });
35
36    // Find the program keypair
37    let keypair_path = program_keypair.unwrap_or_else(|| {
38        let default = PathBuf::from("target")
39            .join("deploy")
40            .join(format!("{}-keypair.json", name));
41        if !default.exists() {
42            // Try module name (underscores)
43            let module = config.module_name();
44            let alt = PathBuf::from("target")
45                .join("deploy")
46                .join(format!("{module}-keypair.json"));
47            if alt.exists() {
48                return alt;
49            }
50        }
51        default
52    });
53
54    if !keypair_path.exists() {
55        eprintln!(
56            "\n  {}",
57            style::fail(&format!(
58                "program keypair not found: {}",
59                keypair_path.display()
60            ))
61        );
62        eprintln!();
63        eprintln!(
64            "  Run {} to generate one, or pass {} explicitly.",
65            style::bold("quasar build"),
66            style::bold("--program-keypair")
67        );
68        eprintln!();
69        std::process::exit(1);
70    }
71
72    let sp = style::spinner("Deploying...");
73
74    let mut cmd = Command::new("solana");
75    cmd.args([
76        "program",
77        "deploy",
78        so_path.to_str().unwrap_or_default(),
79        "--program-id",
80        keypair_path.to_str().unwrap_or_default(),
81    ]);
82
83    if let Some(authority) = &upgrade_authority {
84        cmd.args([
85            "--upgrade-authority",
86            authority.to_str().unwrap_or_default(),
87        ]);
88    }
89
90    if let Some(payer) = &keypair {
91        cmd.args(["--keypair", payer.to_str().unwrap_or_default()]);
92    }
93
94    if let Some(cluster) = &url {
95        cmd.args(["--url", cluster]);
96    }
97
98    let output = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).output();
99
100    sp.finish_and_clear();
101
102    match output {
103        Ok(o) if o.status.success() => {
104            let stdout = String::from_utf8_lossy(&o.stdout);
105
106            // Extract program ID from solana CLI output
107            let program_id = stdout
108                .lines()
109                .find(|l| l.contains("Program Id:"))
110                .and_then(|l| l.split(':').nth(1))
111                .map(|s| s.trim())
112                .unwrap_or("(unknown)");
113
114            println!(
115                "\n  {}",
116                style::success(&format!("Deployed to {}", style::bold(program_id)))
117            );
118            println!();
119            Ok(())
120        }
121        Ok(o) => {
122            let stderr = String::from_utf8_lossy(&o.stderr);
123            let stdout = String::from_utf8_lossy(&o.stdout);
124            if !stderr.is_empty() {
125                eprintln!();
126                for line in stderr.lines() {
127                    eprintln!("  {line}");
128                }
129            }
130            if !stdout.is_empty() {
131                for line in stdout.lines() {
132                    eprintln!("  {line}");
133                }
134            }
135            eprintln!();
136            eprintln!("  {}", style::fail("deploy failed"));
137            std::process::exit(o.status.code().unwrap_or(1));
138        }
139        Err(e) => {
140            eprintln!(
141                "\n  {}",
142                style::fail(&format!("failed to run solana program deploy: {e}"))
143            );
144            eprintln!();
145            eprintln!(
146                "  Make sure the {} CLI is installed and configured.",
147                style::bold("solana")
148            );
149            eprintln!();
150            std::process::exit(1);
151        }
152    }
153}