• 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-crate configuration.
16 
17 use std::{fs::read_to_string, io, path::Path};
18 
19 use serde::Deserialize;
20 
21 /// A parsed android_config.toml file
22 #[derive(Deserialize, Debug, Default, Clone)]
23 pub struct CrateConfig {
24     #[serde(default, skip_serializing_if = "Vec::is_empty")]
25     deletions: Vec<String>,
26 
27     #[serde(default, skip_serializing_if = "Vec::is_empty")]
28     update_with: Vec<String>,
29 }
30 
31 /// Error types for the 'crate_config' crate.
32 #[derive(thiserror::Error, Debug)]
33 pub enum Error {
34     /// Error parsing TOML.
35     #[error(transparent)]
36     TomlParseError(#[from] toml::de::Error),
37     /// Error reading TOML file.
38     #[error(transparent)]
39     IoError(#[from] io::Error),
40 }
41 
42 /// The crate config file name.
43 pub static CONFIG_FILE_NAME: &str = "android_config.toml";
44 
45 impl CrateConfig {
46     /// Read the android_config.toml file in the specified directory. If not present,
47     /// a default version is returned.
read(crate_dir: impl AsRef<Path>) -> Result<CrateConfig, Error>48     pub fn read(crate_dir: impl AsRef<Path>) -> Result<CrateConfig, Error> {
49         let config_file = crate_dir.as_ref().join(CONFIG_FILE_NAME);
50         if !config_file.exists() {
51             return Ok(CrateConfig::default());
52         }
53         let toml: CrateConfig = toml::from_str(read_to_string(config_file)?.as_str())?;
54         Ok(toml)
55     }
56     /// Get an iterator over directories and files to delete.
deletions(&self) -> impl Iterator<Item = &str>57     pub fn deletions(&self) -> impl Iterator<Item = &str> {
58         self.deletions.iter().map(|d| d.as_str())
59     }
60     /// Get an iterator of crates that also need to be updated at the same time as this crate.
update_with(&self) -> impl Iterator<Item = &str>61     pub fn update_with(&self) -> impl Iterator<Item = &str> {
62         self.update_with.iter().map(|d| d.as_str())
63     }
64 }
65 
66 #[cfg(test)]
67 mod tests {
68     use std::fs::write;
69 
70     use super::*;
71 
72     #[test]
basic()73     fn basic() {
74         let dir = tempfile::tempdir().expect("Failed to create tempdir");
75         write(dir.path().join(CONFIG_FILE_NAME), r#"deletions = ["foo"]"#)
76             .expect("Failed to write to tempdir");
77         let config = CrateConfig::read(dir.path()).expect("Failed to read config file");
78         assert_eq!(config.deletions, ["foo"]);
79     }
80 
81     #[test]
default()82     fn default() {
83         let dir = tempfile::tempdir().expect("Failed to create tempdir");
84         let config = CrateConfig::read(dir.path()).expect("Failed to get default config");
85         assert!(config.deletions.is_empty());
86     }
87 
88     #[test]
parse_error()89     fn parse_error() {
90         let dir = tempfile::tempdir().expect("Failed to create tempdir");
91         write(dir.path().join(CONFIG_FILE_NAME), r#"blah"#).expect("Failed to write to tempdir");
92         assert!(matches!(CrateConfig::read(dir.path()), Err(Error::TomlParseError(_))));
93     }
94 }
95