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 flowey::node::prelude::*;
7
8flowey_request! {
9    pub enum Request {
10        /// Version of `azcopy` to install (e.g: "v10.31.0")
11        Version(String),
12        /// Get a path to `azcopy`
13        GetAzCopy(WriteVar<PathBuf>),
14    }
15}
16
17new_flow_node!(struct Node);
18
19impl FlowNode for Node {
20    type Request = Request;
21
22    fn imports(ctx: &mut ImportCtx<'_>) {
23        ctx.import::<crate::install_dist_pkg::Node>();
24        ctx.import::<crate::download_gh_release::Node>();
25    }
26
27    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
28        let mut version = None;
29        let mut get_azcopy = Vec::new();
30
31        for req in requests {
32            match req {
33                Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
34                Request::GetAzCopy(v) => get_azcopy.push(v),
35            }
36        }
37
38        let version = version.ok_or(anyhow::anyhow!("Missing essential request: Version"))?;
39        let get_azcopy = get_azcopy;
40
41        // -- end of req processing -- //
42
43        if get_azcopy.is_empty() {
44            return Ok(());
45        }
46
47        let azcopy_bin = ctx.platform().binary("azcopy");
48
49        // in case we need to unzip the thing we downloaded
50        let platform = ctx.platform();
51        let bsdtar_installed = ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
52            package_names: match platform {
53                FlowPlatform::Linux(linux_distribution) => match linux_distribution {
54                    FlowPlatformLinuxDistro::Fedora => vec!["bsdtar".into()],
55                    FlowPlatformLinuxDistro::Ubuntu => vec!["libarchive-tools".into()],
56                    FlowPlatformLinuxDistro::Arch => vec!["libarchive".into()],
57                    FlowPlatformLinuxDistro::Unknown => vec![],
58                },
59                _ => {
60                    vec![]
61                }
62            },
63            done: v,
64        });
65
66        // Determine file name at emit time based on platform/arch
67        let (file_name, is_tar) = {
68            let arch = match ctx.arch() {
69                FlowArch::X86_64 => "amd64",
70                FlowArch::Aarch64 => "arm64",
71                _ => unreachable!("unsupported arch"),
72            };
73            match ctx.platform() {
74                FlowPlatform::Windows => (format!("azcopy_windows_{arch}_{version}.zip"), false),
75                FlowPlatform::Linux(_) => (format!("azcopy_linux_{arch}_{version}.tar.gz"), true),
76                FlowPlatform::MacOs => (format!("azcopy_darwin_{arch}_{version}.zip"), false),
77                _ => unreachable!("unsupported platform"),
78            }
79        };
80
81        let azcopy_archive = ctx.reqv(|v| crate::download_gh_release::Request {
82            repo_owner: "Azure".to_string(),
83            repo_name: "azure-storage-azcopy".to_string(),
84            needs_auth: false,
85            tag: format!("v{version}"),
86            file_name,
87            path: v,
88        });
89
90        ctx.emit_rust_step("extract azcopy from archive", |ctx| {
91            bsdtar_installed.claim(ctx);
92            let get_azcopy = get_azcopy.claim(ctx);
93            let azcopy_archive = azcopy_archive.claim(ctx);
94            let azcopy_bin = azcopy_bin.clone();
95            move |rt| {
96                let azcopy_archive = rt.read(azcopy_archive);
97
98                let sh = xshell::Shell::new()?;
99                sh.change_dir(azcopy_archive.parent().unwrap());
100
101                if is_tar {
102                    xshell::cmd!(sh, "tar -xf {azcopy_archive} --strip-components=1").run()?;
103                } else {
104                    let bsdtar = crate::_util::bsdtar_name(rt);
105                    xshell::cmd!(sh, "{bsdtar} -xf {azcopy_archive} --strip-components=1").run()?;
106                }
107
108                let path_to_azcopy = azcopy_archive
109                    .parent()
110                    .unwrap()
111                    .join(&azcopy_bin)
112                    .absolute()?;
113
114                for var in get_azcopy {
115                    rt.write(var, &path_to_azcopy)
116                }
117
118                Ok(())
119            }
120        });
121
122        Ok(())
123    }
124}