1use std::collections::HashMap;
8
9#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
10pub struct ChangelogBehaviour {
12 #[serde(rename = "update")]
13 pub update_changelog: bool,
15
16 pub explanation: String,
18}
19
20#[derive(Debug, serde::Serialize)]
21struct Failure {
22 pub result_code: String,
23 pub versions: HashMap<String, String>,
24 pub description: String,
25 pub transient: Option<bool>,
26}
27
28impl std::fmt::Display for Failure {
29 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30 write!(f, "{}: {}", self.result_code, self.description)
31 }
32}
33
34impl std::error::Error for Failure {}
35
36impl std::fmt::Display for Success {
37 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
38 write!(f, "Success")
39 }
40}
41
42#[derive(Debug, serde::Serialize)]
43struct DebianContext {
44 pub changelog: Option<ChangelogBehaviour>,
45}
46
47#[derive(Debug, serde::Serialize)]
48struct Success {
49 pub versions: HashMap<String, String>,
50 pub value: Option<i32>,
51 pub context: Option<serde_json::Value>,
52 pub debian: Option<DebianContext>,
53 #[serde(rename = "target-branch-url")]
54 pub target_branch_url: Option<url::Url>,
55 #[serde(rename = "commit-message")]
56 pub commit_message: Option<String>,
57}
58
59fn write_svp_success(data: &Success) -> std::io::Result<()> {
61 if enabled() {
62 let f = std::fs::File::create(std::env::var("SVP_RESULT").unwrap()).unwrap();
63
64 Ok(serde_json::to_writer(f, data)?)
65 } else {
66 Ok(())
67 }
68}
69
70fn write_svp_failure(data: &Failure) -> std::io::Result<()> {
72 if enabled() {
73 let f = std::fs::File::create(std::env::var("SVP_RESULT").unwrap()).unwrap();
74
75 Ok(serde_json::to_writer(f, data)?)
76 } else {
77 Ok(())
78 }
79}
80
81pub fn report_success<T>(versions: HashMap<String, String>, value: Option<i32>, context: Option<T>)
83where
84 T: serde::Serialize,
85{
86 write_svp_success(&Success {
87 versions,
88 value,
89 context: context.map(|x| serde_json::to_value(x).unwrap()),
90 debian: None,
91 target_branch_url: None,
92 commit_message: None,
93 })
94 .unwrap();
95}
96
97pub fn report_success_debian<T>(
99 versions: HashMap<String, String>,
100 value: Option<i32>,
101 context: Option<T>,
102 changelog: Option<ChangelogBehaviour>,
103) where
104 T: serde::Serialize,
105{
106 write_svp_success(&Success {
107 versions,
108 value,
109 context: context.map(|x| serde_json::to_value(x).unwrap()),
110 debian: Some(DebianContext { changelog }),
111 target_branch_url: None,
112 commit_message: None,
113 })
114 .unwrap();
115}
116
117pub fn report_nothing_to_do(
119 versions: HashMap<String, String>,
120 description: Option<&str>,
121 hint: Option<&str>,
122) -> ! {
123 let description = description.unwrap_or("Nothing to do");
124 write_svp_failure(&Failure {
125 result_code: "nothing-to-do".to_string(),
126 versions,
127 description: description.to_string(),
128 transient: None,
129 })
130 .unwrap();
131 log::error!("{}", description);
132 if let Some(hint) = hint {
133 log::info!("{}", hint);
134 }
135
136 std::process::exit(0);
137}
138
139pub fn report_fatal(
141 versions: HashMap<String, String>,
142 code: &str,
143 description: &str,
144 hint: Option<&str>,
145 transient: Option<bool>,
146) -> ! {
147 write_svp_failure(&Failure {
148 result_code: code.to_string(),
149 versions,
150 description: description.to_string(),
151 transient,
152 })
153 .unwrap();
154 log::error!("{}", description);
155 if let Some(hint) = hint {
156 log::info!("{}", hint);
157 }
158 std::process::exit(1);
159}
160
161pub fn load_resume<T: serde::de::DeserializeOwned>() -> Option<T> {
163 if enabled() {
164 if let Ok(resume_path) = std::env::var("SVP_RESUME") {
165 let f = std::fs::File::open(resume_path).unwrap();
166 let resume: T = serde_json::from_reader(f).unwrap();
167 Some(resume)
168 } else {
169 None
170 }
171 } else {
172 None
173 }
174}
175
176pub fn enabled() -> bool {
178 std::env::var("SVP_API").ok().as_deref() == Some("1")
179}
180
181pub struct Reporter {
183 versions: HashMap<String, String>,
184 target_branch_url: Option<url::Url>,
185 commit_message: Option<String>,
186}
187
188impl Reporter {
189 pub fn new(versions: HashMap<String, String>) -> Self {
191 Self {
192 versions,
193 target_branch_url: None,
194 commit_message: None,
195 }
196 }
197
198 pub fn enabled(&self) -> bool {
200 enabled()
201 }
202
203 pub fn load_resume<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
205 load_resume()
206 }
207
208 pub fn set_target_branch_url(&mut self, url: url::Url) {
210 self.target_branch_url = Some(url);
211 }
212
213 pub fn set_commit_message(&mut self, message: String) {
215 self.commit_message = Some(message);
216 }
217
218 pub fn report_success<T>(self, value: Option<i32>, context: Option<T>)
220 where
221 T: serde::Serialize,
222 {
223 write_svp_success(&Success {
224 versions: self.versions,
225 value,
226 context: context.map(|x| serde_json::to_value(x).unwrap()),
227 debian: None,
228 target_branch_url: self.target_branch_url,
229 commit_message: self.commit_message,
230 })
231 .unwrap();
232 }
233
234 pub fn report_success_debian<T>(
236 self,
237 value: Option<i32>,
238 context: Option<T>,
239 changelog: Option<ChangelogBehaviour>,
240 ) where
241 T: serde::Serialize,
242 {
243 write_svp_success(&Success {
244 versions: self.versions,
245 value,
246 context: context.map(|x| serde_json::to_value(x).unwrap()),
247 debian: Some(DebianContext { changelog }),
248 target_branch_url: self.target_branch_url,
249 commit_message: self.commit_message,
250 })
251 .unwrap();
252 }
253
254 pub fn report_nothing_to_do(self, description: Option<&str>, hint: Option<&str>) -> ! {
256 report_nothing_to_do(self.versions, description, hint);
257 }
258
259 pub fn report_fatal(
261 self,
262 code: &str,
263 description: &str,
264 hint: Option<&str>,
265 transient: Option<bool>,
266 ) -> ! {
267 report_fatal(self.versions, code, description, hint, transient);
268 }
269}