microsoft/openvmm

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
15e07a8246fa7bad80ef06f167641da58f4e021b

Branches

Tags

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

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/cli/var_db.rs

186lines · modecode

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