]> git.proxmox.com Git - rustc.git/blame - src/tools/cargo/benches/benchsuite/src/lib.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / src / tools / cargo / benches / benchsuite / src / lib.rs
CommitLineData
4b012472
FG
1#![allow(clippy::disallowed_methods)]
2
0a29b90c
FG
3use cargo::Config;
4use std::fs;
5use std::path::{Path, PathBuf};
6use std::process::Command;
7use url::Url;
8
9#[macro_export]
10macro_rules! fixtures {
11 () => {
12 $crate::Fixtures::new(env!("CARGO_TARGET_TMPDIR"))
13 };
14}
15
16// This is an arbitrary commit that existed when I started. This helps
17// ensure consistent results. It can be updated if needed, but that can
18// make it harder to compare results with older versions of cargo.
19const CRATES_IO_COMMIT: &str = "85f7bfd61ea4fee08ec68c468762e886b2aebec6";
20
21pub struct Fixtures {
22 cargo_target_tmpdir: PathBuf,
23}
24
25impl Fixtures {
26 pub fn new(cargo_target_tmpdir: &str) -> Self {
27 let bench = Self {
28 cargo_target_tmpdir: PathBuf::from(cargo_target_tmpdir),
29 };
30 bench.create_home();
31 bench.create_target_dir();
32 bench.clone_index();
33 bench.unpack_workspaces();
34 bench
35 }
36
37 fn root(&self) -> PathBuf {
38 self.cargo_target_tmpdir.join("bench")
39 }
40
41 fn target_dir(&self) -> PathBuf {
42 let mut p = self.root();
43 p.push("target");
44 p
45 }
46
47 fn cargo_home(&self) -> PathBuf {
48 let mut p = self.root();
49 p.push("chome");
50 p
51 }
52
53 fn index(&self) -> PathBuf {
54 let mut p = self.root();
55 p.push("index");
56 p
57 }
58
59 fn workspaces_path(&self) -> PathBuf {
60 let mut p = self.root();
61 p.push("workspaces");
62 p
63 }
64
65 fn registry_url(&self) -> Url {
66 Url::from_file_path(self.index()).unwrap()
67 }
68
69 fn create_home(&self) {
70 let home = self.cargo_home();
71 if !home.exists() {
72 fs::create_dir_all(&home).unwrap();
73 }
74 fs::write(
75 home.join("config.toml"),
76 format!(
77 r#"
78 [source.crates-io]
79 replace-with = 'local-snapshot'
80
81 [source.local-snapshot]
82 registry = '{}'
83 "#,
84 self.registry_url()
85 ),
86 )
87 .unwrap();
88 }
89
90 fn create_target_dir(&self) {
91 // This is necessary to ensure the .rustc_info.json file is written.
92 // Otherwise it won't be written, and it is very expensive to create.
93 if !self.target_dir().exists() {
94 fs::create_dir_all(self.target_dir()).unwrap();
95 }
96 }
97
98 /// This clones crates.io at a specific point in time into tmp/index.
99 fn clone_index(&self) {
100 let index = self.index();
101 let maybe_git = |command: &str| {
102 let status = Command::new("git")
103 .current_dir(&index)
104 .args(command.split_whitespace().collect::<Vec<_>>())
105 .status()
106 .expect("git should be installed");
107 status.success()
108 };
109 let git = |command: &str| {
110 if !maybe_git(command) {
111 panic!("failed to run git command: {}", command);
112 }
113 };
114 if index.exists() {
115 if maybe_git(&format!(
116 "rev-parse -q --verify {}^{{commit}}",
117 CRATES_IO_COMMIT
118 )) {
119 // Already fetched.
120 return;
121 }
122 } else {
123 fs::create_dir_all(&index).unwrap();
124 git("init --bare");
125 git("remote add origin https://github.com/rust-lang/crates.io-index-archive");
126 }
127 git(&format!("fetch origin {}", CRATES_IO_COMMIT));
128 git("branch -f master FETCH_HEAD");
129 }
130
131 /// This unpacks the compressed workspace skeletons into tmp/workspaces.
132 fn unpack_workspaces(&self) {
133 let ws_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
134 .parent()
135 .unwrap()
136 .join("workspaces");
137 let archives = fs::read_dir(ws_dir)
138 .unwrap()
139 .map(|e| e.unwrap().path())
140 .filter(|p| p.extension() == Some(std::ffi::OsStr::new("tgz")));
141 for archive in archives {
142 let name = archive.file_stem().unwrap();
143 let f = fs::File::open(&archive).unwrap();
144 let f = flate2::read::GzDecoder::new(f);
145 let dest = self.workspaces_path().join(&name);
146 if dest.exists() {
147 fs::remove_dir_all(&dest).unwrap();
148 }
149 let mut archive = tar::Archive::new(f);
150 archive.unpack(self.workspaces_path()).unwrap();
151 }
152 }
153
154 /// Vec of `(ws_name, ws_root)`.
155 pub fn workspaces(&self) -> Vec<(String, PathBuf)> {
156 // CARGO_BENCH_WORKSPACES can be used to override, otherwise it just uses
157 // the workspaces in the workspaces directory.
158 let mut ps: Vec<_> = match std::env::var_os("CARGO_BENCH_WORKSPACES") {
159 Some(s) => std::env::split_paths(&s).collect(),
160 None => fs::read_dir(self.workspaces_path())
161 .unwrap()
162 .map(|e| e.unwrap().path())
163 // These currently fail in most cases on Windows due to long
164 // filenames in the git checkouts.
165 .filter(|p| {
166 !(cfg!(windows)
167 && matches!(p.file_name().unwrap().to_str().unwrap(), "servo" | "tikv"))
168 })
169 .collect(),
170 };
171 // Sort so it is consistent.
172 ps.sort();
173 ps.into_iter()
174 .map(|p| (p.file_name().unwrap().to_str().unwrap().to_owned(), p))
175 .collect()
176 }
177
178 /// Creates a new Config.
179 pub fn make_config(&self, ws_root: &Path) -> Config {
180 let shell = cargo::core::Shell::new();
181 let mut config = Config::new(shell, ws_root.to_path_buf(), self.cargo_home());
182 // Configure is needed to set the target_dir which is needed to write
183 // the .rustc_info.json file which is very expensive.
184 config
185 .configure(
186 0,
187 false,
188 None,
189 false,
190 false,
191 false,
192 &Some(self.target_dir()),
193 &[],
194 &[],
195 )
196 .unwrap();
197 config
198 }
199}