blob: 88a9d0a143408bb8a7e8f6a5597dce4e821f507d [file] [log] [blame]
Brian Silverman0aa13732022-05-19 23:14:08 -07001//! A tool that postprocesses cargo-raze output to do what we want.
2//!
3//! Currently this is limited to removing extraneous BUILD files which cargo-raze places in all the
4//! third_party packages we feed to it, which we don't want to use. We're hand-writing BUILD files
5//! for these dependencies, without intending them to be used as separate Bazel workspaces, so it's
6//! easiest for them to all reference the top-level //third_party/cargo package.
7use std::{
8 env, fs,
9 io::{self, ErrorKind},
10 path::Path,
11};
12
13use anyhow::Context;
14use toml::Value;
15
16fn filter_not_found(result: io::Result<()>) -> io::Result<()> {
17 match result {
18 Err(e) if matches!(e.kind(), ErrorKind::NotFound) => Ok(()),
19 r => r,
20 }
21}
22
23fn main() -> anyhow::Result<()> {
24 let argv: Vec<_> = env::args().collect();
25 let workspace_path = Path::new(&argv[1]);
26 let cargo_toml_path = workspace_path.join("Cargo.toml");
27 eprintln!("Loading Cargo.toml from {:?}", cargo_toml_path);
28 let cargo_toml_contents = fs::read(&cargo_toml_path)
29 .with_context(|| format!("Failed to read Cargo.toml: {:?}", cargo_toml_path))?;
30 let cargo_toml_contents = std::str::from_utf8(&cargo_toml_contents).with_context(|| {
31 format!(
32 "Failed to interpret Cargo.toml contents as UTF-8: {:?}",
33 cargo_toml_path
34 )
35 })?;
36 let cargo_toml: Value = cargo_toml_contents
37 .parse()
38 .with_context(|| format!("Failed to parse Cargo.toml contents: {:?}", cargo_toml_path))?;
39
40 let package_aliases_dir = cargo_toml["workspace"]["metadata"]["raze"]["package_aliases_dir"]
41 .as_str()
42 .with_context(|| {
43 format!(
44 "Found non-string package_aliases_dir in Cargo.toml: {:?}",
45 cargo_toml_path
46 )
47 })?;
48
49 let workspace_members = cargo_toml["workspace"]["members"]
50 .as_array()
51 .with_context(|| {
52 format!(
53 "Did not find workspace members in Cargo.toml: {:?}",
54 cargo_toml_path
55 )
56 })?;
57 for member in workspace_members.iter() {
58 let member = member.as_str().with_context(|| {
59 format!(
60 "Found non-string workspace member in Cargo.toml: {:?}",
61 cargo_toml_path
62 )
63 })?;
64
65 // First delete the BUILD file.
66 let member_build = workspace_path
67 .join(member)
68 .join(package_aliases_dir)
69 .join("BUILD.bazel");
70 filter_not_found(fs::remove_file(&member_build)).with_context(|| {
71 format!(
72 "Failed to remove workspace member BUILD.bazel: {:?}",
73 member_build
74 )
75 })?;
76
77 // Then go and delete each folder in reverse order, but only if it's now empty to avoid
78 // overeager deletion. The file we're deleting should be the only thing in these folders,
79 // but if somebody wrote something else for some reason then we don't want to silently
80 // delete it.
81 let mut folder_path = workspace_path.join(member);
82 for d in Path::new(package_aliases_dir)
83 .components()
84 .scan(&mut folder_path, |a, b| {
85 **a = a.join(b);
86 Some(a.clone())
87 })
88 .collect::<Vec<_>>()
89 .iter()
90 .rev()
91 {
92 filter_not_found(fs::remove_dir(d)).with_context(|| {
93 format!(
94 "Failed to remove workspace member package_aliases directory: {:?}",
95 d
96 )
97 })?;
98 }
99 }
100 eprintln!("All done");
101 Ok(())
102}