1 use anyhow::{anyhow, Result}; 2 use std::env; 3 use std::fs; 4 use std::fs::File; 5 use std::io::Write; 6 use std::path::{Path, PathBuf}; 7 8 use convert_finalized_flags::read_files_to_map_using_path; 9 use convert_finalized_flags::FinalizedFlagMap; 10 11 // This fn makes assumptions about the working directory which we should not rely 12 // on for actual (Soong) builds. It is reasonable to assume that this is being 13 // called from the aconfig directory as cargo is used for local development and 14 // the cargo workspace for our project is build/make/tools/aconfig. 15 // This is meant to get the list of finalized flag 16 // files provided by the filegroup + "locations" in soong. 17 // Cargo-only usage is asserted via implementation of 18 // read_files_to_map_using_env, the only public cargo-only fn. read_files_to_map_using_env() -> Result<FinalizedFlagMap>19fn read_files_to_map_using_env() -> Result<FinalizedFlagMap> { 20 let mut current_dir = std::env::current_dir()?; 21 22 // Path of aconfig from the top of tree. 23 let aconfig_path = PathBuf::from("build/make/tools/aconfig"); 24 25 // Path of SDK files from the top of tree. 26 let sdk_dir_path = PathBuf::from("prebuilts/sdk"); 27 28 // Iterate up the directory structure until we have the base aconfig dir. 29 while !current_dir.canonicalize()?.ends_with(&aconfig_path) { 30 if let Some(parent) = current_dir.parent() { 31 current_dir = parent.to_path_buf(); 32 } else { 33 return Err(anyhow!("Cannot execute outside of aconfig.")); 34 } 35 } 36 37 // Remove the aconfig path, leaving the top of the tree. 38 for _ in 0..aconfig_path.components().count() { 39 current_dir.pop(); 40 } 41 42 // Get the absolute path of the sdk files. 43 current_dir.push(sdk_dir_path); 44 45 let mut flag_files = Vec::new(); 46 47 // Search all sub-dirs in prebuilts/sdk for finalized-flags.txt files. 48 // The files are in prebuilts/sdk/<api level>/finalized-flags.txt. 49 let api_level_dirs = fs::read_dir(current_dir)?; 50 for api_level_dir in api_level_dirs { 51 if api_level_dir.is_err() { 52 eprintln!("Error opening directory: {}", api_level_dir.err().unwrap()); 53 continue; 54 } 55 56 // Skip non-directories. 57 let api_level_dir_path = api_level_dir.unwrap().path(); 58 if !api_level_dir_path.is_dir() { 59 continue; 60 } 61 62 // Some directories were created before trunk stable and don't have 63 // flags, or aren't api level directories at all. 64 let flag_file_path = api_level_dir_path.join("finalized-flags.txt"); 65 if !flag_file_path.exists() { 66 continue; 67 } 68 69 if let Some(path) = flag_file_path.to_str() { 70 flag_files.push(path.to_string()); 71 } else { 72 eprintln!("Error converting path to string: {:?}", flag_file_path); 73 } 74 } 75 76 read_files_to_map_using_path(flag_files) 77 } 78 main()79fn main() { 80 let out_dir = env::var_os("OUT_DIR").unwrap(); 81 let dest_path = Path::new(&out_dir).join("finalized_flags_record.json"); 82 83 let finalized_flags_map: Result<FinalizedFlagMap> = read_files_to_map_using_env(); 84 if finalized_flags_map.is_err() { 85 return; 86 } 87 let json_str = serde_json::to_string(&finalized_flags_map.unwrap()).unwrap(); 88 89 let mut f = File::create(&dest_path).unwrap(); 90 f.write_all(json_str.as_bytes()).unwrap(); 91 92 //println!("cargo:rerun-if-changed=input.txt"); 93 } 94