1use anyhow::{Context, Result};
3use fs_extra::dir::{copy, CopyOptions};
4use std::{
5 fs,
6 path::{Path, PathBuf},
7 process::Command,
8};
9
10fn get_rustc_sysroot() -> Result<PathBuf> {
13 let rustc = Command::new("rustc")
14 .arg("--print")
15 .arg("sysroot")
16 .output()?;
17 let sysroot = PathBuf::from(
18 std::str::from_utf8(&rustc.stdout)
19 .context("Failed to convert sysroot path to utf-8")?
20 .trim(),
21 );
22 Ok(sysroot)
23}
24
25fn get_rustc_target_libdir(target: Option<&Path>) -> Result<PathBuf> {
27 let mut rustc = Command::new("rustc");
28 rustc.arg("--print").arg("target-libdir");
29 if let Some(target) = target {
30 rustc.arg("--target").arg(target);
31 }
32 let rustc = rustc.output()?;
33 let sysroot = PathBuf::from(
34 std::str::from_utf8(&rustc.stdout)
35 .context("Failed to convert sysroot path to utf-8")?
36 .trim(),
37 );
38 Ok(sysroot)
39}
40
41pub fn get_rust_src() -> Result<PathBuf> {
47 let root = get_rustc_sysroot()?;
48 let sys = root
49 .join("lib")
50 .join("rustlib")
51 .join("src")
52 .join("rust")
53 .join("library");
54 Ok(sys)
55}
56
57#[allow(clippy::blocks_in_if_conditions)]
60pub fn copy_host_tools(local_sysroot: &Path) -> Result<()> {
61 let root = get_rustc_target_libdir(None)?;
62 let host = root
63 .parent()
64 .and_then(|f| f.file_stem())
65 .and_then(|f| f.to_str())
66 .context("Error parsing host target triple")?;
67 let local_sysroot = local_sysroot.join("lib").join("rustlib").join(&host);
68 let src = root;
69
70 let src_meta = fs::metadata(&src)
71 .with_context(|| format!("Couldn't get metadata for {}", src.display()))?;
72 let to_meta = fs::metadata(&local_sysroot)
73 .with_context(|| format!("Couldn't get metadata for {}", local_sysroot.display()));
74
75 if let Ok(to_meta) = to_meta {
77 if to_meta.modified().with_context(|| {
81 format!(
82 "Couldn't get modification time for {}",
83 local_sysroot.display()
84 )
85 })? > src_meta.modified().with_context(|| {
86 format!(
87 "Couldn't get modification time for {}",
88 local_sysroot.display()
89 )
90 })? {
91 return Ok(());
92 }
93 }
94 let mut options = CopyOptions::new();
95 options.overwrite = true;
96 let local_sysroot = local_sysroot
97 .parent()
98 .context("Error getting local sysroot parent directory")?;
99 copy(&src, &local_sysroot, &options).with_context(|| {
100 format!(
101 "Couldn't copy from `{}` to `{}`",
102 src.display(),
103 local_sysroot.display()
104 )
105 })?;
106 Ok(())
107}