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 if !skip_build {
21 crate::build::run(false, false, None)?;
22 }
23
24 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 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 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 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}