flowey_lib_common/
download_azcopy.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Download a copy of `azcopy`
5
6use crate::cache::CacheHit;
7use flowey::node::prelude::*;
8
9flowey_request! {
10    pub enum Request {
11        /// Version of `azcopy` to install (e.g: "v10")
12        Version(String),
13        /// Get a path to `azcopy`
14        GetAzCopy(WriteVar<PathBuf>),
15    }
16}
17
18new_flow_node!(struct Node);
19
20impl FlowNode for Node {
21    type Request = Request;
22
23    fn imports(ctx: &mut ImportCtx<'_>) {
24        ctx.import::<crate::install_dist_pkg::Node>();
25        ctx.import::<crate::cache::Node>();
26    }
27
28    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
29        let mut version = None;
30        let mut get_azcopy = Vec::new();
31
32        for req in requests {
33            match req {
34                Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
35                Request::GetAzCopy(v) => get_azcopy.push(v),
36            }
37        }
38
39        let version_with_date =
40            version.ok_or(anyhow::anyhow!("Missing essential request: Version"))?;
41        let version_without_date = version_with_date.split_once('-').unwrap().0.to_owned();
42        let get_azcopy = get_azcopy;
43
44        // -- end of req processing -- //
45
46        if get_azcopy.is_empty() {
47            return Ok(());
48        }
49
50        let azcopy_bin = ctx.platform().binary("azcopy");
51
52        let cache_dir = ctx.emit_rust_stepv("create azcopy cache dir", |_| {
53            |_| Ok(std::env::current_dir()?.absolute()?)
54        });
55
56        let cache_key = ReadVar::from_static(format!("azcopy-{version_with_date}"));
57        let hitvar = ctx.reqv(|hitvar| crate::cache::Request {
58            label: "azcopy".into(),
59            dir: cache_dir.clone(),
60            key: cache_key,
61            restore_keys: None,
62            hitvar,
63        });
64
65        // in case we need to unzip the thing we downloaded
66        let platform = ctx.platform();
67        let bsdtar_installed = ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
68            package_names: match platform {
69                FlowPlatform::Linux(linux_distribution) => match linux_distribution {
70                    FlowPlatformLinuxDistro::Fedora => vec!["bsdtar".into()],
71                    FlowPlatformLinuxDistro::Ubuntu => vec!["libarchive-tools".into()],
72                    FlowPlatformLinuxDistro::Arch => vec!["libarchive".into()],
73                    FlowPlatformLinuxDistro::Unknown => vec![],
74                },
75                _ => {
76                    vec![]
77                }
78            },
79            done: v,
80        });
81
82        ctx.emit_rust_step("installing azcopy", |ctx| {
83            bsdtar_installed.claim(ctx);
84            let cache_dir = cache_dir.claim(ctx);
85            let hitvar = hitvar.claim(ctx);
86            let get_azcopy = get_azcopy.claim(ctx);
87            move |rt| {
88                let cache_dir = rt.read(cache_dir);
89
90                let cached = if matches!(rt.read(hitvar), CacheHit::Hit) {
91                    let cached_bin = cache_dir.join(&azcopy_bin);
92                    assert!(cached_bin.exists());
93                    Some(cached_bin)
94                } else {
95                    None
96                };
97
98
99                let path_to_azcopy = if let Some(cached) = cached {
100                    cached
101                } else {
102                    let sh = xshell::Shell::new()?;
103                    let arch = match rt.arch() {
104                        FlowArch::X86_64 => "amd64",
105                        FlowArch::Aarch64 => "arm64",
106                        arch => anyhow::bail!("unhandled arch {arch}"),
107                    };
108                    match rt.platform().kind() {
109                        FlowPlatformKind::Windows => {
110                            xshell::cmd!(sh, "curl --fail -L https://azcopyvnext-awgzd8g7aagqhzhe.b02.azurefd.net/releases/release-{version_with_date}/azcopy_windows_{arch}_{version_without_date}.zip -o azcopy.zip").run()?;
111
112                            let bsdtar = crate::_util::bsdtar_name(rt);
113                            xshell::cmd!(sh, "{bsdtar} -xf azcopy.zip --strip-components=1").run()?;
114                        }
115                        FlowPlatformKind::Unix => {
116                            let os = match rt.platform() {
117                                FlowPlatform::Linux(_) => "linux",
118                                FlowPlatform::MacOs => "darwin",
119                                platform => anyhow::bail!("unhandled platform {platform}"),
120                            };
121                            xshell::cmd!(sh, "curl --fail -L https://azcopyvnext-awgzd8g7aagqhzhe.b02.azurefd.net/releases/release-{version_with_date}/azcopy_{os}_{arch}_{version_without_date}.tar.gz -o azcopy.tar.gz").run()?;
122                            xshell::cmd!(sh, "tar -xf azcopy.tar.gz --strip-components=1").run()?;
123                        }
124                    };
125
126                    // move the unzipped bin into the cache dir
127                    let final_bin = cache_dir.join(&azcopy_bin);
128                    fs_err::rename(&azcopy_bin, &final_bin)?;
129
130                    final_bin.absolute()?
131                };
132
133                for var in get_azcopy {
134                    rt.write(var, &path_to_azcopy)
135                }
136
137                Ok(())
138            }
139        });
140
141        Ok(())
142    }
143}