1 //! A Cargo build script binary used in unit tests for the Bazel `cargo_build_script` rule
2
3 use std::collections::HashSet;
4 use std::path::PathBuf;
5
main()6 fn main() {
7 // The cargo_build_script macro appends an underscore to the given name.
8 //
9 // This file would be the only expected source file within the CARGO_MANIFEST_DIR without
10 // any exec root symlink functionality.
11 let build_script = PathBuf::from(
12 std::env::args()
13 .next()
14 .expect("Unable to get the build script executable"),
15 );
16
17 let build_script_name = build_script
18 .file_name()
19 .expect("Unable to get the build script name")
20 .to_str()
21 .expect("Unable to convert the build script name to a string");
22
23 let mut root_files = std::fs::read_dir(".")
24 .expect("Unable to read the current directory")
25 .map(|entry| {
26 entry
27 .expect("Failed to get entry")
28 .file_name()
29 .into_string()
30 .expect("Failed to convert file name to string")
31 })
32 .collect::<HashSet<_>>();
33
34 assert!(
35 root_files.take(build_script_name).is_some(),
36 "Build script must be in the current directory"
37 );
38
39 let cargo_manifest_dir_file = root_files.take("cargo_manifest_dir_file.txt");
40 assert!(
41 cargo_manifest_dir_file.is_some(),
42 "'cargo_manifest_dir_file.txt' must be in the current directory"
43 );
44 assert_eq!(
45 std::fs::read_to_string(cargo_manifest_dir_file.unwrap()).unwrap(),
46 "This is a file to be found alongside the build script."
47 );
48
49 if symlink_feature_enabled() {
50 assert!(
51 root_files.take("bazel-out").is_some(),
52 "'bazel-out' must be in the current directory when the symlink feature is enabled"
53 );
54 assert!(
55 root_files.take("external").is_some(),
56 "'external' must be in the current directory when the symlink feature is enabled"
57 );
58 }
59
60 let remaining_files = root_files
61 .iter()
62 // An __action_home_<hash> directory is created in some remote execution builds.
63 .filter(|file| !file.starts_with("__action_home"))
64 .collect::<HashSet<_>>();
65
66 // If we're in a sandbox then there should be no other files in the current directory.
67 let is_in_sandbox = is_in_sandbox(&root_files);
68 assert_eq!(
69 remaining_files.is_empty(),
70 is_in_sandbox,
71 "There should not be any other files in the current directory, found {:?}",
72 root_files
73 );
74 }
75
76 /// Check if the symlink feature is enabled.
symlink_feature_enabled() -> bool77 fn symlink_feature_enabled() -> bool {
78 std::env::var("RULES_RUST_SYMLINK_EXEC_ROOT")
79 .map(|v| v == "1")
80 .unwrap_or(false)
81 }
82
83 /// Check if the current directory is in a sandbox.
84 ///
85 /// This is done by checking if the current directory contains a directory prefixed with
86 /// `local-spawn-runner`. If it does, then it is assumed to not be in a sandbox.
87 ///
88 /// Non-sandboxed builds contain one or more directories in the exec root with the following
89 /// structure:
90 /// local-spawn-runner.6722268259075335658/
91 /// `-- work/
92 /// local-spawn-runner.3585764808440126801/
93 /// `-- work/
is_in_sandbox(cwd_files: &HashSet<String>) -> bool94 fn is_in_sandbox(cwd_files: &HashSet<String>) -> bool {
95 for file in cwd_files {
96 if file.starts_with("local-spawn-runner.") {
97 return false;
98 }
99 }
100
101 true
102 }
103