microsoft/openvmm

Public

mirrored from https://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
b8910f97c258ca39c8f2e535fbc241ea1e1be3ff

Branches

Tags

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

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/cli/var_db.rs

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