microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1ce32569373cda4d4b485f6e6f09f15e1e4dd569

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/cli/var_db.rs

206lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::exec_snippet::FloweyPipelineStaticDb;
5use super::exec_snippet::VarDbBackendKind;
6use anyhow::Context;
7use flowey_core::node::RuntimeVarDb;
8use std::fmt::Write as _;
9use std::io::Read;
10use std::io::Write;
11use std::path::PathBuf;
12
13pub fn construct_var_db_cli(
14 flowey_bin: &str,
15 job_idx: usize,
16 var: &str,
17 is_secret: bool,
18 update_from_stdin: bool,
19 update_from_file: Option<&str>,
20 is_raw_string: bool,
21 write_to_gh_env: Option<&str>,
22 condvar: Option<&str>,
23) -> String {
24 let mut base = format!(r#"{flowey_bin} v {job_idx} '{var}'"#);
25
26 if update_from_stdin {
27 if is_secret {
28 base += " --is-secret"
29 }
30
31 base += " --update-from-stdin"
32 } else if let Some(file) = update_from_file {
33 if is_secret {
34 base += " --is-secret"
35 }
36
37 write!(base, " --update-from-file {file}").unwrap();
38 } else if let Some(gh_var) = write_to_gh_env {
39 if is_secret {
40 base += " --is-secret"
41 }
42
43 write!(base, " --write-to-gh-env {gh_var}").unwrap();
44 }
45
46 if is_raw_string {
47 base += " --is-raw-string"
48 }
49
50 if let Some(condvar) = condvar {
51 write!(base, " --condvar {condvar}").unwrap();
52 }
53
54 base
55}
56
57/// (internal) interact with the runtime variable database
58#[derive(clap::Args)]
59pub struct VarDb {
60 /// job idx corresponding to the var db to access
61 pub(crate) job_idx: usize,
62
63 /// Runtime variable to access
64 var_name: String,
65
66 /// Set the variable by reading from stdin
67 #[clap(long, group = "update")]
68 update_from_stdin: bool,
69
70 /// Set the variable by reading from a file
71 #[clap(long, group = "update")]
72 update_from_file: Option<PathBuf>,
73
74 /// Variable is a raw string, and should be read/written as a plain string.
75 #[clap(long)]
76 is_raw_string: bool,
77
78 /// Whether or not the variable being set if a secret
79 #[clap(long, requires = "update")]
80 is_secret: bool,
81
82 /// Set the variable as a github environment variable with the given name
83 /// rather than printing to stdout.
84 #[clap(long, requires = "var_name", group = "update")]
85 write_to_gh_env: Option<String>,
86
87 /// Only run if the given variable is true.
88 #[clap(long)]
89 condvar: Option<String>,
90}
91
92impl VarDb {
93 pub fn run(self) -> anyhow::Result<()> {
94 let Self {
95 job_idx,
96 var_name,
97 update_from_stdin,
98 update_from_file,
99 is_secret,
100 is_raw_string,
101 write_to_gh_env,
102 condvar,
103 } = self;
104
105 let mut runtime_var_db = open_var_db(job_idx)?;
106
107 if let Some(condvar) = condvar {
108 let condvar_data = runtime_var_db.get_var(&condvar);
109 let set: bool = serde_json::from_slice(&condvar_data).unwrap();
110 if !set {
111 return Ok(());
112 }
113 }
114
115 if update_from_stdin {
116 let mut data = Vec::new();
117 std::io::stdin().read_to_end(&mut data).unwrap();
118
119 // HACK: only one kind of db, so we know what routine to use
120 if is_raw_string {
121 // account for bash HEREDOCs including a trailing newline
122 // TODO: probably want this to be configurable.
123 if matches!(data.last(), Some(b'\n')) {
124 data.pop();
125 }
126
127 let s = String::from_utf8(data).unwrap();
128 data = serde_json::to_vec(&s).unwrap();
129 }
130
131 runtime_var_db.set_var(&var_name, is_secret, data);
132 } else if let Some(file) = update_from_file {
133 let mut data = fs_err::read(file)?;
134
135 // HACK: only one kind of db, so we know what routine to use
136 if is_raw_string {
137 let s: String = String::from_utf8(data).unwrap();
138 data = serde_json::to_vec(&s).unwrap();
139 }
140
141 let var_name = var_name.trim_matches('\'');
142 runtime_var_db.set_var(var_name, is_secret, data);
143 } else {
144 let mut data = runtime_var_db.get_var(&var_name);
145
146 // HACK: only one kind of db, so we know what routine to use
147 if is_raw_string {
148 let s: String = serde_json::from_slice(&data).unwrap();
149 data = s.into();
150 }
151
152 if let Some(write_to_gh_env) = write_to_gh_env {
153 let data_string = String::from_utf8(data)?;
154 if is_secret {
155 data_string.lines().for_each(|line| {
156 println!("::add-mask::{}", line);
157 });
158 }
159 let gh_env_file_path = std::env::var("GITHUB_ENV")?;
160 let mut gh_env_file = fs_err::OpenOptions::new()
161 .append(true)
162 .open(gh_env_file_path)?;
163 let gh_env_var_assignment = format!(
164 r#"{}<<EOF
165{}
166EOF
167"#,
168 write_to_gh_env, data_string
169 );
170 gh_env_file.write_all(gh_env_var_assignment.as_bytes())?;
171 } else {
172 std::io::stdout().write_all(&data).unwrap()
173 }
174 }
175
176 Ok(())
177 }
178}
179
180/// Obtain a handle to a runtime var db
181///
182/// CONTRACT: Requires a pipeline-specific `pipeline.json` file to be in the
183/// same dir as the flowey exe
184///
185/// CONTRACT: Requires a var-backend specific var db file called
186/// `job{job_idx}.<ext>` to be in the same dir as the flowey exe
187pub(crate) fn open_var_db(job_idx: usize) -> anyhow::Result<Box<dyn RuntimeVarDb>> {
188 let current_exe =
189 std::env::current_exe().context("failed to get path to current flowey executable")?;
190
191 let FloweyPipelineStaticDb {
192 var_db_backend_kind,
193 ..
194 } = {
195 let pipeline_static_db = fs_err::File::open(current_exe.with_file_name("pipeline.json"))?;
196 serde_json::from_reader(pipeline_static_db)?
197 };
198
199 Ok(match var_db_backend_kind {
200 VarDbBackendKind::Json => {
201 Box::new(crate::var_db::single_json_file::SingleJsonFileVarDb::new(
202 current_exe.with_file_name(format!("job{job_idx}.json")),
203 )?)
204 }
205 })
206}
207