• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2025 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! TOML file to store per-repo configuration.
16 
17 use std::{collections::BTreeSet, fs::read_to_string, io, path::Path};
18 
19 use serde::Deserialize;
20 
21 /// A parsed android_repo_config.toml file
22 #[derive(Deserialize, Debug, Default, Clone)]
23 pub struct RepoConfig {
24     #[serde(default, skip_serializing_if = "Vec::is_empty")]
25     crate_denylist: BTreeSet<String>,
26 }
27 
28 /// Error types for the 'repo_config' crate.
29 #[derive(thiserror::Error, Debug)]
30 pub enum Error {
31     /// Error parsing TOML.
32     #[error(transparent)]
33     TomlParseError(#[from] toml::de::Error),
34     /// Error reading TOML file.
35     #[error(transparent)]
36     IoError(#[from] io::Error),
37 }
38 
39 /// The repo config file name.
40 pub static CONFIG_FILE_NAME: &str = "android_repo_config.toml";
41 
42 impl RepoConfig {
43     /// Read the android_repo_config.toml file in the specified directory. If not present,
44     /// a default version is returned.
read(managed_repo_dir: impl AsRef<Path>) -> Result<RepoConfig, Error>45     pub fn read(managed_repo_dir: impl AsRef<Path>) -> Result<RepoConfig, Error> {
46         let config_file = managed_repo_dir.as_ref().join(CONFIG_FILE_NAME);
47         if !config_file.exists() {
48             return Ok(RepoConfig::default());
49         }
50         let toml: RepoConfig = toml::from_str(read_to_string(config_file)?.as_str())?;
51         Ok(toml)
52     }
53     /// Returns true if the crate is on the crate denylist.
is_allowed(&self, crate_name: impl AsRef<str>) -> bool54     pub fn is_allowed(&self, crate_name: impl AsRef<str>) -> bool {
55         !self.crate_denylist.contains(crate_name.as_ref())
56     }
57 }
58 
59 #[cfg(test)]
60 mod tests {
61     use std::fs::write;
62 
63     use super::*;
64 
65     #[test]
basic()66     fn basic() {
67         let dir = tempfile::tempdir().expect("Failed to create tempdir");
68         write(dir.path().join(CONFIG_FILE_NAME), r#"crate_denylist = ["foo"]"#)
69             .expect("Failed to write to tempdir");
70         let config = RepoConfig::read(dir.path()).expect("Failed to read config file");
71         assert!(!config.is_allowed("foo"));
72         assert!(config.is_allowed("bar"));
73     }
74 
75     #[test]
default()76     fn default() {
77         let dir = tempfile::tempdir().expect("Failed to create tempdir");
78         let config = RepoConfig::read(dir.path()).expect("Failed to get default config");
79         assert!(config.is_allowed("foo"));
80     }
81 
82     #[test]
parse_error()83     fn parse_error() {
84         let dir = tempfile::tempdir().expect("Failed to create tempdir");
85         write(dir.path().join(CONFIG_FILE_NAME), r#"blah"#).expect("Failed to write to tempdir");
86         assert!(matches!(RepoConfig::read(dir.path()), Err(Error::TomlParseError(_))));
87     }
88 }
89