Brian Silverman | 0aa1373 | 2022-05-19 23:14:08 -0700 | [diff] [blame] | 1 | //! 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. |
| 7 | use std::{ |
| 8 | env, fs, |
| 9 | io::{self, ErrorKind}, |
| 10 | path::Path, |
| 11 | }; |
| 12 | |
| 13 | use anyhow::Context; |
| 14 | use toml::Value; |
| 15 | |
| 16 | fn 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 | |
| 23 | fn 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 | } |