Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Add a config file for managed crate repos.
Browse files Browse the repository at this point in the history
Currently supports one parameter: a crate import denylist.

For both crate and repo config crates, put the config file name inside the crate.

Add unit tests.

Test: cargo test, ./crate_tool import instant 1.2.3
Change-Id: Ieb8f165d98af054f434dfc487f0e2ae99b8d4aae
  • Loading branch information
jfgoog committed Jan 28, 2025
1 parent b5086b5 commit f58ed2d
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 43 deletions.
1 change: 1 addition & 0 deletions tools/external_crates/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"license_checker",
"name_and_version",
"name_and_version_proc_macros",
"repo_config",
"rooted_path",
"test_mapping",
]
Expand Down
3 changes: 3 additions & 0 deletions tools/external_crates/cargo_embargo.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
},
"name_and_version_proc_macros": {
"device_supported": false
},
"repo_config": {
"device_supported": false
}
},
"tests": true,
Expand Down
20 changes: 20 additions & 0 deletions tools/external_crates/crate_config/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ package {
default_applicable_licenses: ["Android-Apache-2.0"],
}

rust_test_host {
name: "crate_config_test_src_lib",
crate_name: "crate_config",
cargo_env_compat: true,
cargo_pkg_version: "0.1.0",
crate_root: "src/lib.rs",
test_suites: ["general-tests"],
auto_gen_config: true,
test_options: {
unit_test: true,
},
edition: "2021",
rustlibs: [
"libserde",
"libtempfile",
"libthiserror",
"libtoml",
],
}

rust_library_host {
name: "libcrate_config",
crate_name: "crate_config",
Expand Down
5 changes: 4 additions & 1 deletion tools/external_crates/crate_config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ edition = "2021"
[dependencies]
serde = { version = "=1.0.210", features = ["derive"] }
toml = "0.8"
thiserror = "1.0"
thiserror = "1.0"

[dev-dependencies]
tempfile = "3"
42 changes: 38 additions & 4 deletions tools/external_crates/crate_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::{fs::read_to_string, io, path::Path};

use serde::Deserialize;

/// A parsed android_config.json file
/// A parsed android_config.toml file
#[derive(Deserialize, Debug, Default, Clone)]
pub struct CrateConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
Expand All @@ -34,10 +34,14 @@ pub enum Error {
IoError(#[from] io::Error),
}

/// The crate config file name.
pub static CONFIG_FILE_NAME: &str = "android_config.toml";

impl CrateConfig {
/// Read the android_config.toml file in the specified directory.
pub fn read(config_file: impl AsRef<Path>) -> Result<CrateConfig, Error> {
let config_file = config_file.as_ref();
/// Read the android_config.toml file in the specified directory. If not present,
/// a default version is returned.
pub fn read(crate_dir: impl AsRef<Path>) -> Result<CrateConfig, Error> {
let config_file = crate_dir.as_ref().join(CONFIG_FILE_NAME);
if !config_file.exists() {
return Ok(CrateConfig::default());
}
Expand All @@ -49,3 +53,33 @@ impl CrateConfig {
self.deletions.iter().map(|d| d.as_str())
}
}

#[cfg(test)]
mod tests {
use std::fs::write;

use super::*;

#[test]
fn basic() {
let dir = tempfile::tempdir().expect("Failed to create tempdir");
write(dir.path().join(CONFIG_FILE_NAME), r#"deletions = ["foo"]"#)
.expect("Failed to write to tempdir");
let config = CrateConfig::read(dir.path()).expect("Failed to read config file");
assert_eq!(config.deletions, ["foo"]);
}

#[test]
fn default() {
let dir = tempfile::tempdir().expect("Failed to create tempdir");
let config = CrateConfig::read(dir.path()).expect("Failed to get default config");
assert!(config.deletions.is_empty());
}

#[test]
fn parse_error() {
let dir = tempfile::tempdir().expect("Failed to create tempdir");
write(dir.path().join(CONFIG_FILE_NAME), r#"blah"#).expect("Failed to write to tempdir");
assert!(matches!(CrateConfig::read(dir.path()), Err(Error::TomlParseError(_))));
}
}
1 change: 1 addition & 0 deletions tools/external_crates/crate_tool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ google_metadata = { path = "../google_metadata"}
license_checker = { path = "../license_checker", features = ["fuzzy_content_match"] }
name_and_version = { path = "../name_and_version" }
name_and_version_proc_macros = { path = "../name_and_version_proc_macros" }
repo_config = { path = "../repo_config" }
rooted_path = { path = "../rooted_path" }
test_mapping = { path = "../test_mapping" }

Expand Down
11 changes: 8 additions & 3 deletions tools/external_crates/crate_tool/src/managed_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,14 @@ impl<State: ManagedCrateState> ManagedCrate<State> {
}
pub fn config(&self) -> &CrateConfig {
self.config.get_or_init(|| {
let config_file = self.android_crate_path().join("android_config.toml").unwrap();
CrateConfig::read(&config_file)
.unwrap_or_else(|e| panic!("Failed to read {config_file}/android_config.toml: {e}"))
CrateConfig::read(self.android_crate_path().abs()).unwrap_or_else(|e| {
panic!(
"Failed to read crate config {}/{}: {}",
self.android_crate_path(),
crate_config::CONFIG_FILE_NAME,
e
)
})
})
}
pub fn android_bp(&self) -> RootedPath {
Expand Down
54 changes: 19 additions & 35 deletions tools/external_crates/crate_tool/src/managed_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
// limitations under the License.

use std::{
cell::OnceCell,
collections::{BTreeMap, BTreeSet},
env,
fs::{create_dir, create_dir_all, read_dir, remove_file, write},
os::unix::fs::symlink,
path::Path,
process::Command,
str::from_utf8,
sync::LazyLock,
};

use anyhow::{anyhow, bail, Context, Result};
Expand All @@ -30,6 +30,7 @@ use google_metadata::GoogleMetadata;
use itertools::Itertools;
use license_checker::find_licenses;
use name_and_version::{NameAndVersionMap, NameAndVersionRef, NamedAndVersioned};
use repo_config::RepoConfig;
use rooted_path::RootedPath;
use semver::Version;
use serde::Serialize;
Expand All @@ -48,37 +49,6 @@ use crate::{
SuccessOrError,
};

// TODO: Store this as a data file in the monorepo.
static IMPORT_DENYLIST: LazyLock<BTreeSet<&str>> = LazyLock::new(|| {
BTreeSet::from([
"instant", // Not maintained.
"bumpalo", // Unsound
"allocator-api2", // Unsound
// Uniffi crates.
// Per mmaurer: "considered too difficult to verify and stopped being used for the original use case".
"oneshot-uniffi",
"uniffi",
"uniffi_checksum_derive",
"uniffi_core",
"uniffi_macros",
"uniffi_meta",
// From go/android-restricted-rust-crates
"ctor", // Runs before main, can cause linking errors
"inventory", // Depends on ctor
"ouroboros", // Sketchy unsafe, code smell
"sled", // There is too much unsafe.
"proc-macro-error", // Unmaintained and depends on syn 1
"derive-getters", // Unmaintained and depends on syn 1
"android_system_properties", // Duplicates internal functionality
"x509-parser", // Duplicates x509-cert and BoringSSL
"der-parser", // Duplicates der
"oid-registry",
"asn1-rs",
"android-tzdata", // Relies on unsupported API
"rustls", // Duplicates BoringSSL
])
});

#[derive(Serialize, Default, Debug)]
struct UpdateSuggestions {
updates: Vec<UpdateSuggestion>,
Expand All @@ -94,16 +64,30 @@ struct UpdateSuggestion {

pub struct ManagedRepo {
path: RootedPath,
config: OnceCell<RepoConfig>,
crates_io: CratesIoIndex,
}

impl ManagedRepo {
pub fn new(path: RootedPath, offline: bool) -> Result<ManagedRepo> {
Ok(ManagedRepo {
path,
config: OnceCell::new(),
crates_io: if offline { CratesIoIndex::new_offline()? } else { CratesIoIndex::new()? },
})
}
pub fn config(&self) -> &RepoConfig {
self.config.get_or_init(|| {
RepoConfig::read(self.path.abs()).unwrap_or_else(|e| {
panic!(
"Failed to read crate config {}/{}: {}",
self.path,
repo_config::CONFIG_FILE_NAME,
e
)
})
})
}
fn pseudo_crate(&self) -> PseudoCrate<CargoVendorDirty> {
PseudoCrate::new(self.path.join("pseudo_crate").unwrap())
}
Expand Down Expand Up @@ -428,7 +412,7 @@ impl ManagedRepo {
return Ok(());
}

if IMPORT_DENYLIST.contains(crate_name) {
if !self.config().is_allowed(crate_name) {
println!("Crate {crate_name} is on the import denylist");
return Ok(());
}
Expand Down Expand Up @@ -456,7 +440,7 @@ impl ManagedRepo {
dep.crate_name(),
dep.requirement()
);
if IMPORT_DENYLIST.contains(dep.crate_name()) {
if !self.config().is_allowed(dep.crate_name()) {
println!(" And {} is on the import denylist", dep.crate_name());
}
// This is a no-op because our dependency code only considers normal deps anyway.
Expand Down Expand Up @@ -516,7 +500,7 @@ impl ManagedRepo {
if legacy_dir.abs().exists() {
bail!("Legacy crate already imported at {}", legacy_dir);
}
if IMPORT_DENYLIST.contains(crate_name) {
if !self.config().is_allowed(crate_name) {
bail!("Crate {crate_name} is on the import denylist");
}

Expand Down
1 change: 1 addition & 0 deletions tools/external_crates/repo_config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
43 changes: 43 additions & 0 deletions tools/external_crates/repo_config/Android.bp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// This file is generated by cargo_embargo.
// Do not modify this file after the first "rust_*" or "genrule" module
// because the changes will be overridden on upgrade.
// Content before the first "rust_*" or "genrule" module is preserved.

package {
default_team: "trendy_team_android_rust",
default_applicable_licenses: ["Android-Apache-2.0"],
}

rust_library_host {
name: "librepo_config",
crate_name: "repo_config",
cargo_env_compat: true,
cargo_pkg_version: "0.1.0",
crate_root: "src/lib.rs",
edition: "2021",
rustlibs: [
"libserde",
"libthiserror",
"libtoml",
],
}

rust_test_host {
name: "repo_config_test_src_lib",
crate_name: "repo_config",
cargo_env_compat: true,
cargo_pkg_version: "0.1.0",
crate_root: "src/lib.rs",
test_suites: ["general-tests"],
auto_gen_config: true,
test_options: {
unit_test: true,
},
edition: "2021",
rustlibs: [
"libserde",
"libtempfile",
"libthiserror",
"libtoml",
],
}
12 changes: 12 additions & 0 deletions tools/external_crates/repo_config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "repo_config"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "=1.0.210", features = ["derive"] }
toml = "0.8"
thiserror = "1.0"

[dev-dependencies]
tempfile = "3"
Loading

0 comments on commit f58ed2d

Please sign in to comment.