microsoft/openvmm

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/apply-async-process-wait-functionality

Branches

Tags

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

Clone

HTTPS

Download ZIP

flowey/flowey_lib_common/src/_util/extract.rs

265lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use flowey::node::prelude::*;
5
6const FLOWEY_INFO_DIR: &str = ".flowey_info";
7const FLOWEY_EXTRACT_DIR: &str = "extracted";
8
9#[derive(Clone)]
10#[non_exhaustive]
11pub struct ExtractZipDeps<C = VarNotClaimed> {
12 persistent_dir: Option<ReadVar<PathBuf, C>>,
13 bsdtar_installed: ReadVar<SideEffect, C>,
14}
15
16impl ClaimVar for ExtractZipDeps {
17 type Claimed = ExtractZipDeps<VarClaimed>;
18
19 fn claim(self, ctx: &mut StepCtx<'_>) -> Self::Claimed {
20 let Self {
21 persistent_dir,
22 bsdtar_installed,
23 } = self;
24 ExtractZipDeps {
25 persistent_dir: persistent_dir.claim(ctx),
26 bsdtar_installed: bsdtar_installed.claim(ctx),
27 }
28 }
29}
30
31#[track_caller]
32pub fn extract_zip_if_new_deps(ctx: &mut NodeCtx<'_>) -> ExtractZipDeps {
33 let platform = ctx.platform();
34 ExtractZipDeps {
35 persistent_dir: ctx.persistent_dir(),
36 bsdtar_installed: ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
37 package_names: match platform {
38 FlowPlatform::Linux(linux_distribution) => match linux_distribution {
39 FlowPlatformLinuxDistro::Fedora => {
40 vec!["bsdtar".into()]
41 }
42 FlowPlatformLinuxDistro::Ubuntu => vec!["libarchive-tools".into()],
43 FlowPlatformLinuxDistro::AzureLinux | FlowPlatformLinuxDistro::Arch => {
44 vec!["libarchive".into()]
45 }
46 FlowPlatformLinuxDistro::Nix => vec![],
47 FlowPlatformLinuxDistro::Unknown => vec![],
48 },
49 _ => {
50 vec![]
51 }
52 },
53 done: v,
54 }),
55 }
56}
57
58/// Extracts the given `file` into `persistent_dir` (or into
59/// [`std::env::current_dir()`], if no persistent dir is available).
60///
61/// To avoid redundant unzips between pipeline runs, callers must provide a
62/// `file_version` string that identifies the current file. If the
63/// previous run already unzipped a zip with the given `file_version`, this
64/// function will return nearly instantaneously.
65pub fn extract_zip_if_new(
66 rt: &mut RustRuntimeServices<'_>,
67 deps: ExtractZipDeps<VarClaimed>,
68 file: &Path,
69 file_version: &str,
70) -> anyhow::Result<PathBuf> {
71 let ExtractZipDeps {
72 persistent_dir,
73 bsdtar_installed: _,
74 } = deps;
75
76 let root_dir = match persistent_dir {
77 Some(dir) => rt.read(dir),
78 None => rt.sh.current_dir(),
79 };
80
81 let filename = file.file_name().expect("zip file was not a file");
82 let extract_dir = root_dir.join(FLOWEY_EXTRACT_DIR).join(filename);
83 fs_err::create_dir_all(&extract_dir)?;
84
85 let pkg_info_dir = root_dir.join(FLOWEY_INFO_DIR);
86 fs_err::create_dir_all(&pkg_info_dir)?;
87 let pkg_info_file = pkg_info_dir.join(filename);
88
89 let mut already_extracted = false;
90 if let Ok(info) = fs_err::read_to_string(&pkg_info_file) {
91 if info == file_version {
92 already_extracted = true;
93 }
94 }
95
96 if !already_extracted {
97 // clear out any old version that was present
98 //
99 // FUTURE: maybe reconsider this approach, and keep
100 // old versions lying around, to make branch
101 // switching easier?
102 fs_err::remove_dir_all(&extract_dir)?;
103 fs_err::create_dir(&extract_dir)?;
104
105 rt.sh.change_dir(&extract_dir);
106
107 let bsdtar = crate::_util::bsdtar_name(rt);
108 flowey::shell_cmd!(rt, "{bsdtar} -xf {file}").run()?;
109 fs_err::write(pkg_info_file, file_version)?;
110 } else {
111 log::info!("already extracted!");
112 }
113
114 Ok(extract_dir)
115}
116
117/// Extracts the given `.tar.gz` `file` into `persistent_dir` (or into
118/// [`std::env::current_dir()`], if no persistent dir is available).
119///
120/// Unlike `.tar.bz2`, `.tar.gz` is handled natively by every platform's `tar`,
121/// so this helper has no install-package dependency to track. The caller
122/// resolves the persistent dir itself and passes it (already read) as
123/// `persistent_dir` — no `Deps` struct needed.
124///
125/// To avoid redundant extracts between pipeline runs, callers must provide a
126/// `file_version` string that identifies the current file. If the previous
127/// run already extracted an archive with the given `file_version`, this
128/// function will return nearly instantaneously.
129pub fn extract_tar_gz_if_new(
130 rt: &mut RustRuntimeServices<'_>,
131 persistent_dir: Option<&Path>,
132 file: &Path,
133 file_version: &str,
134) -> anyhow::Result<PathBuf> {
135 let root_dir = match persistent_dir {
136 Some(dir) => dir.to_path_buf(),
137 None => rt.sh.current_dir(),
138 };
139
140 let filename = file.file_name().expect("tar.gz file was not a file");
141 let extract_dir = root_dir.join(FLOWEY_EXTRACT_DIR).join(filename);
142 fs_err::create_dir_all(&extract_dir)?;
143
144 let pkg_info_dir = root_dir.join(FLOWEY_INFO_DIR);
145 fs_err::create_dir_all(&pkg_info_dir)?;
146 let pkg_info_file = pkg_info_dir.join(filename);
147
148 let mut already_extracted = false;
149 if let Ok(info) = fs_err::read_to_string(&pkg_info_file) {
150 if info == file_version {
151 already_extracted = true;
152 }
153 }
154
155 if !already_extracted {
156 // clear out any old version that was present
157 fs_err::remove_dir_all(&extract_dir)?;
158 fs_err::create_dir(&extract_dir)?;
159
160 rt.sh.change_dir(&extract_dir);
161
162 // windows builds past Windows 10 build 17063 come with tar installed,
163 // and `tar -xf` auto-detects gzip compression on all platforms
164 flowey::shell_cmd!(rt, "tar -xf {file}").run()?;
165
166 fs_err::write(pkg_info_file, file_version)?;
167 } else {
168 log::info!("already extracted!");
169 }
170
171 Ok(extract_dir)
172}
173
174#[derive(Clone)]
175#[non_exhaustive]
176pub struct ExtractTarBz2Deps<C = VarNotClaimed> {
177 persistent_dir: Option<ReadVar<PathBuf, C>>,
178 bzip2_installed: ReadVar<SideEffect, C>,
179}
180
181impl ClaimVar for ExtractTarBz2Deps {
182 type Claimed = ExtractTarBz2Deps<VarClaimed>;
183
184 fn claim(self, ctx: &mut StepCtx<'_>) -> Self::Claimed {
185 let Self {
186 persistent_dir,
187 bzip2_installed,
188 } = self;
189 ExtractTarBz2Deps {
190 persistent_dir: persistent_dir.claim(ctx),
191 bzip2_installed: bzip2_installed.claim(ctx),
192 }
193 }
194}
195
196#[track_caller]
197pub fn extract_tar_bz2_if_new_deps(ctx: &mut NodeCtx<'_>) -> ExtractTarBz2Deps {
198 ExtractTarBz2Deps {
199 persistent_dir: ctx.persistent_dir(),
200 bzip2_installed: ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
201 package_names: vec!["bzip2".into()],
202 done: v,
203 }),
204 }
205}
206
207/// Extracts the given `file` into `persistent_dir` (or into
208/// [`std::env::current_dir()`], if no persistent dir is available).
209///
210/// To avoid redundant unzips between pipeline runs, callers must provide a
211/// `file_version` string that identifies the current file. If the previous run
212/// already unzipped a zip with the given `file_version`, this function will
213/// return nearly instantaneously.
214pub fn extract_tar_bz2_if_new(
215 rt: &mut RustRuntimeServices<'_>,
216 deps: ExtractTarBz2Deps<VarClaimed>,
217 file: &Path,
218 file_version: &str,
219) -> anyhow::Result<PathBuf> {
220 let ExtractTarBz2Deps {
221 persistent_dir,
222 bzip2_installed: _,
223 } = deps;
224
225 let root_dir = match persistent_dir {
226 Some(dir) => rt.read(dir),
227 None => rt.sh.current_dir(),
228 };
229
230 let filename = file.file_name().expect("tar.bz2 file was not a file");
231 let extract_dir = root_dir.join(FLOWEY_EXTRACT_DIR).join(filename);
232 fs_err::create_dir_all(&extract_dir)?;
233
234 let pkg_info_dir = root_dir.join(FLOWEY_INFO_DIR);
235 fs_err::create_dir_all(&pkg_info_dir)?;
236 let pkg_info_file = pkg_info_dir.join(filename);
237
238 let mut already_extracted = false;
239 if let Ok(info) = fs_err::read_to_string(&pkg_info_file) {
240 if info == file_version {
241 already_extracted = true;
242 }
243 }
244
245 if !already_extracted {
246 rt.sh.change_dir(&extract_dir);
247
248 // clear out any old version that was present
249 //
250 // FUTURE: maybe reconsider this approach, and keep
251 // old versions lying around, to make branch
252 // switching easier?
253 fs_err::remove_dir_all(&extract_dir)?;
254 fs_err::create_dir(&extract_dir)?;
255
256 // windows builds past Windows 10 build 17063 come with tar installed
257 flowey::shell_cmd!(rt, "tar -xf {file}").run()?;
258
259 fs_err::write(pkg_info_file, file_version)?;
260 } else {
261 log::info!("already extracted!");
262 }
263
264 Ok(extract_dir)
265}