1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::env;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
11*bb4ee6a4SAndroid Build Coastguard Worker use named_lock::NamedLock;
12*bb4ee6a4SAndroid Build Coastguard Worker
13*bb4ee6a4SAndroid Build Coastguard Worker mod sys;
14*bb4ee6a4SAndroid Build Coastguard Worker
15*bb4ee6a4SAndroid Build Coastguard Worker static BASE_URL: &str = "https://storage.googleapis.com/chromeos-localmirror/distfiles/prebuilts/";
16*bb4ee6a4SAndroid Build Coastguard Worker static DOWNLOAD_RETRIES: usize = 3;
17*bb4ee6a4SAndroid Build Coastguard Worker
18*bb4ee6a4SAndroid Build Coastguard Worker // Returns `deps` directory for the current build.
get_deps_directory() -> Result<PathBuf>19*bb4ee6a4SAndroid Build Coastguard Worker fn get_deps_directory() -> Result<PathBuf> {
20*bb4ee6a4SAndroid Build Coastguard Worker let out_dir = env::var("OUT_DIR")
21*bb4ee6a4SAndroid Build Coastguard Worker .ok()
22*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("OUT_DIR is not set"))?;
23*bb4ee6a4SAndroid Build Coastguard Worker
24*bb4ee6a4SAndroid Build Coastguard Worker let dest = PathBuf::from(&out_dir)
25*bb4ee6a4SAndroid Build Coastguard Worker .parent()
26*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("../ not found for {:?}", out_dir))?
27*bb4ee6a4SAndroid Build Coastguard Worker .parent()
28*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("../../ not found for {:?}", out_dir))?
29*bb4ee6a4SAndroid Build Coastguard Worker .parent()
30*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(|| anyhow!("../../../ not found for {:?}", out_dir))?
31*bb4ee6a4SAndroid Build Coastguard Worker .join("deps");
32*bb4ee6a4SAndroid Build Coastguard Worker if dest.is_dir() {
33*bb4ee6a4SAndroid Build Coastguard Worker Ok(dest)
34*bb4ee6a4SAndroid Build Coastguard Worker } else {
35*bb4ee6a4SAndroid Build Coastguard Worker Err(anyhow!(
36*bb4ee6a4SAndroid Build Coastguard Worker "deps({:?}) directory not found OUT_DIR: {:?}",
37*bb4ee6a4SAndroid Build Coastguard Worker dest,
38*bb4ee6a4SAndroid Build Coastguard Worker out_dir
39*bb4ee6a4SAndroid Build Coastguard Worker ))
40*bb4ee6a4SAndroid Build Coastguard Worker }
41*bb4ee6a4SAndroid Build Coastguard Worker }
42*bb4ee6a4SAndroid Build Coastguard Worker
43*bb4ee6a4SAndroid Build Coastguard Worker // We download the prebuilt into deps directory and create a symlink to the downloaded prebuilt in
44*bb4ee6a4SAndroid Build Coastguard Worker // deps parent directory.
45*bb4ee6a4SAndroid Build Coastguard Worker // The symlink will help windows find the dll when an executable is manually run.
46*bb4ee6a4SAndroid Build Coastguard Worker // For example, `file` is downloaded in
47*bb4ee6a4SAndroid Build Coastguard Worker // `target/x86_64-pc-windows-gnu/release/deps/` and a `link` will be crated in
48*bb4ee6a4SAndroid Build Coastguard Worker // `target/x86_64-pc-windows-gnu/release/`.
49*bb4ee6a4SAndroid Build Coastguard Worker // Any executable in those two directories will be able to find the dlls they depend as in the same
50*bb4ee6a4SAndroid Build Coastguard Worker // directory.
51*bb4ee6a4SAndroid Build Coastguard Worker struct PrebuiltPath {
52*bb4ee6a4SAndroid Build Coastguard Worker file: PathBuf,
53*bb4ee6a4SAndroid Build Coastguard Worker link: PathBuf,
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker
get_dest_path(filename: &str) -> Result<PrebuiltPath>56*bb4ee6a4SAndroid Build Coastguard Worker fn get_dest_path(filename: &str) -> Result<PrebuiltPath> {
57*bb4ee6a4SAndroid Build Coastguard Worker let deps = get_deps_directory()?;
58*bb4ee6a4SAndroid Build Coastguard Worker
59*bb4ee6a4SAndroid Build Coastguard Worker Ok(PrebuiltPath {
60*bb4ee6a4SAndroid Build Coastguard Worker file: deps.join(filename),
61*bb4ee6a4SAndroid Build Coastguard Worker link: deps.parent().unwrap().join(filename),
62*bb4ee6a4SAndroid Build Coastguard Worker })
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker
get_url(library: &str, filename: &str, version: u32) -> String65*bb4ee6a4SAndroid Build Coastguard Worker fn get_url(library: &str, filename: &str, version: u32) -> String {
66*bb4ee6a4SAndroid Build Coastguard Worker let build_type = if env::var("DEBUG").is_ok() {
67*bb4ee6a4SAndroid Build Coastguard Worker "debug"
68*bb4ee6a4SAndroid Build Coastguard Worker } else {
69*bb4ee6a4SAndroid Build Coastguard Worker "release"
70*bb4ee6a4SAndroid Build Coastguard Worker };
71*bb4ee6a4SAndroid Build Coastguard Worker let platform = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
72*bb4ee6a4SAndroid Build Coastguard Worker let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
73*bb4ee6a4SAndroid Build Coastguard Worker let toolchain = env::var("CARGO_CFG_TARGET_ENV").unwrap();
74*bb4ee6a4SAndroid Build Coastguard Worker
75*bb4ee6a4SAndroid Build Coastguard Worker format!("{BASE_URL}{platform}/{arch}/{toolchain}/{library}/{build_type}/{version}/{filename}",)
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker
download_file(url: &str, destination: &Path) -> Result<()>78*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_file(url: &str, destination: &Path) -> Result<()> {
79*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create("crosvm_prebuilts_download")?;
80*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock()?;
81*bb4ee6a4SAndroid Build Coastguard Worker
82*bb4ee6a4SAndroid Build Coastguard Worker // Another process may have already downloaded this since we last checked.
83*bb4ee6a4SAndroid Build Coastguard Worker if destination.exists() {
84*bb4ee6a4SAndroid Build Coastguard Worker println!("Prebuilt {destination:?} has already been downloaded by another process.");
85*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
86*bb4ee6a4SAndroid Build Coastguard Worker }
87*bb4ee6a4SAndroid Build Coastguard Worker
88*bb4ee6a4SAndroid Build Coastguard Worker println!("Downloading prebuilt {url} to {destination:?}");
89*bb4ee6a4SAndroid Build Coastguard Worker let mut attempts_left = DOWNLOAD_RETRIES + 1;
90*bb4ee6a4SAndroid Build Coastguard Worker loop {
91*bb4ee6a4SAndroid Build Coastguard Worker attempts_left -= 1;
92*bb4ee6a4SAndroid Build Coastguard Worker let mut cmd = sys::download_command(url, destination);
93*bb4ee6a4SAndroid Build Coastguard Worker match cmd.status() {
94*bb4ee6a4SAndroid Build Coastguard Worker Ok(exit_code) => {
95*bb4ee6a4SAndroid Build Coastguard Worker if !exit_code.success() {
96*bb4ee6a4SAndroid Build Coastguard Worker if attempts_left == 0 {
97*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("Cannot download {}", url));
98*bb4ee6a4SAndroid Build Coastguard Worker } else {
99*bb4ee6a4SAndroid Build Coastguard Worker println!("Failed to download {url}. Retrying.");
100*bb4ee6a4SAndroid Build Coastguard Worker }
101*bb4ee6a4SAndroid Build Coastguard Worker } else {
102*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
103*bb4ee6a4SAndroid Build Coastguard Worker }
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker Err(error) => {
106*bb4ee6a4SAndroid Build Coastguard Worker if attempts_left == 0 {
107*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!(error));
108*bb4ee6a4SAndroid Build Coastguard Worker } else {
109*bb4ee6a4SAndroid Build Coastguard Worker println!("Failed to download {url}: {error:?}");
110*bb4ee6a4SAndroid Build Coastguard Worker }
111*bb4ee6a4SAndroid Build Coastguard Worker }
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker
116*bb4ee6a4SAndroid Build Coastguard Worker /// Downloads a prebuilt file, with name `filename` of `version` from the `library` into target's
117*bb4ee6a4SAndroid Build Coastguard Worker /// `deps` directory.
download_prebuilt(library: &str, version: u32, filename: &str) -> Result<PathBuf>118*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_prebuilt(library: &str, version: u32, filename: &str) -> Result<PathBuf> {
119*bb4ee6a4SAndroid Build Coastguard Worker let dest_path = get_dest_path(filename)?;
120*bb4ee6a4SAndroid Build Coastguard Worker let url = get_url(library, filename, version);
121*bb4ee6a4SAndroid Build Coastguard Worker
122*bb4ee6a4SAndroid Build Coastguard Worker println!("downloading prebuilt:{} to:{:?}", url, dest_path.file);
123*bb4ee6a4SAndroid Build Coastguard Worker download_file(&url, Path::new(&dest_path.file))?;
124*bb4ee6a4SAndroid Build Coastguard Worker println!(
125*bb4ee6a4SAndroid Build Coastguard Worker "creating symlink:{:?} linking to:{:?}",
126*bb4ee6a4SAndroid Build Coastguard Worker dest_path.link, dest_path.file
127*bb4ee6a4SAndroid Build Coastguard Worker );
128*bb4ee6a4SAndroid Build Coastguard Worker let _ = std::fs::remove_file(&dest_path.link);
129*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
130*bb4ee6a4SAndroid Build Coastguard Worker std::os::unix::fs::symlink(&dest_path.file, &dest_path.link)?;
131*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
132*bb4ee6a4SAndroid Build Coastguard Worker let _ = std::fs::copy(&dest_path.file, &dest_path.link)?;
133*bb4ee6a4SAndroid Build Coastguard Worker Ok(dest_path.file)
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard Worker /// Downloads a list of prebuilt file, with names in `filenames` of `version` from the `library`
137*bb4ee6a4SAndroid Build Coastguard Worker /// into target's `deps` directory.
download_prebuilts(library: &str, version: u32, filenames: &[&str]) -> Result<Vec<PathBuf>>138*bb4ee6a4SAndroid Build Coastguard Worker pub fn download_prebuilts(library: &str, version: u32, filenames: &[&str]) -> Result<Vec<PathBuf>> {
139*bb4ee6a4SAndroid Build Coastguard Worker let mut paths = vec![];
140*bb4ee6a4SAndroid Build Coastguard Worker for filename in filenames {
141*bb4ee6a4SAndroid Build Coastguard Worker paths.push(download_prebuilt(library, version, filename)?);
142*bb4ee6a4SAndroid Build Coastguard Worker }
143*bb4ee6a4SAndroid Build Coastguard Worker Ok(paths)
144*bb4ee6a4SAndroid Build Coastguard Worker }
145