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::Unknown => vec![],
73                },
74                _ => {
75                    vec![]
76                }
77            },
78            done: v,
79        });
80
81        ctx.emit_rust_step("installing azcopy", |ctx| {
82            bsdtar_installed.claim(ctx);
83            let cache_dir = cache_dir.claim(ctx);
84            let hitvar = hitvar.claim(ctx);
85            let get_azcopy = get_azcopy.claim(ctx);
86            move |rt| {
87                let cache_dir = rt.read(cache_dir);
88
89                let cached = if matches!(rt.read(hitvar), CacheHit::Hit) {
90                    let cached_bin = cache_dir.join(&azcopy_bin);
91                    assert!(cached_bin.exists());
92                    Some(cached_bin)
93                } else {
94                    None
95                };
96
97
98                let path_to_azcopy = if let Some(cached) = cached {
99                    cached
100                } else {
101                    let sh = xshell::Shell::new()?;
102                    let arch = match rt.arch() {
103                        FlowArch::X86_64 => "amd64",
104                        FlowArch::Aarch64 => "arm64",
105                        arch => anyhow::bail!("unhandled arch {arch}"),
106                    };
107                    match rt.platform().kind() {
108                        FlowPlatformKind::Windows => {
109                            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()?;
110
111                            let bsdtar = crate::_util::bsdtar_name(rt);
112                            xshell::cmd!(sh, "{bsdtar} -xf azcopy.zip --strip-components=1").run()?;
113                        }
114                        FlowPlatformKind::Unix => {
115                            let os = match rt.platform() {
116                                FlowPlatform::Linux(_) => "linux",
117                                FlowPlatform::MacOs => "darwin",
118                                platform => anyhow::bail!("unhandled platform {platform}"),
119                            };
120                            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()?;
121                            xshell::cmd!(sh, "tar -xf azcopy.tar.gz --strip-components=1").run()?;
122                        }
123                    };
124
125                    // move the unzipped bin into the cache dir
126                    let final_bin = cache_dir.join(&azcopy_bin);
127                    fs_err::rename(&azcopy_bin, &final_bin)?;
128
129                    final_bin.absolute()?
130                };
131
132                for var in get_azcopy {
133                    rt.write(var, &path_to_azcopy)
134                }
135
136                Ok(())
137            }
138        });
139
140        Ok(())
141    }
142}