blob: 037b9b0041ae76c846feb0c5c33fa9527eb98986 [file] [log] [blame]
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A command-line tool for managing repositories of 3rd party crates
//! such as external/rust/android-crates-io.
use std::env::current_dir;
use std::fs::{create_dir_all, remove_dir_all};
use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::{anyhow, Context, Result};
use success_or_error::RunAndExpectSuccess;
use thiserror::Error;
mod android_bp;
mod crate_collection;
mod crate_type;
mod managed_crate;
mod managed_repo;
mod patch;
mod pseudo_crate;
mod upgradable;
pub use self::android_bp::maybe_build_cargo_embargo;
pub use self::managed_repo::ManagedRepo;
pub use self::upgradable::SemverCompatibilityRule;
/// Error types for the 'crate_tool' crate. For the most part,
/// we use `anyhow`, but sometimes type information is useful.
#[derive(Error, Debug)]
pub enum CrateError {
/// Virtual crate, usually a workspace.
#[error("Virtual crate: {0}")]
VirtualCrate(PathBuf),
}
/// Returns the absolute path to the root of the current Android source
/// repo, based on the current working directory.
pub fn default_repo_root() -> Result<PathBuf> {
let cwd = current_dir().context("Could not get current working directory")?;
for cur in cwd.ancestors() {
for e in cur.read_dir()? {
if e?.file_name() == ".repo" {
return Ok(cur.to_path_buf());
}
}
}
Err(anyhow!(".repo directory not found in any ancestor of {}", cwd.display()))
}
fn ensure_exists_and_empty(dir: impl AsRef<Path>) -> Result<()> {
let dir = dir.as_ref();
if dir.exists() {
remove_dir_all(dir).context(format!("Failed to remove {}", dir.display()))?;
}
create_dir_all(dir).context(format!("Failed to create {}", dir.display()))
}
// The copy_dir crate doesn't handle symlinks.
fn copy_dir(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
Command::new("cp")
.arg("--archive")
.arg(src.as_ref())
.arg(dst.as_ref())
.run_quiet_and_expect_success()?;
Ok(())
}