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 use spdx::Licensee; 16 use std::{ 17 collections::BTreeSet, 18 fs::read_to_string, 19 path::{Path, PathBuf}, 20 sync::OnceLock, 21 }; 22 23 use crate::{Error, LICENSE_DATA}; 24 25 #[derive(Debug)] 26 pub(crate) struct Classifier { 27 file_path: PathBuf, 28 contents: String, 29 by_content: OnceLock<BTreeSet<Licensee>>, 30 by_content_fuzzy: OnceLock<Option<Licensee>>, 31 } 32 33 impl Classifier { new<FP: Into<PathBuf>>(file_path: FP, contents: String) -> Classifier34 pub fn new<FP: Into<PathBuf>>(file_path: FP, contents: String) -> Classifier { 35 Classifier { 36 file_path: file_path.into(), 37 contents, 38 by_content: OnceLock::new(), 39 by_content_fuzzy: OnceLock::new(), 40 } 41 } new_vec<CP: Into<PathBuf>>( crate_path: CP, possible_license_files: BTreeSet<PathBuf>, ) -> Result<Vec<Classifier>, Error>42 pub fn new_vec<CP: Into<PathBuf>>( 43 crate_path: CP, 44 possible_license_files: BTreeSet<PathBuf>, 45 ) -> Result<Vec<Classifier>, Error> { 46 let crate_path = crate_path.into(); 47 let mut classifiers = Vec::new(); 48 for file_path in possible_license_files { 49 let full_path = crate_path.join(&file_path); 50 let contents = 51 read_to_string(&full_path).map_err(|e| Error::FileReadError(full_path, e))?; 52 classifiers.push(Classifier::new(file_path, contents)); 53 } 54 Ok(classifiers) 55 } file_path(&self) -> &Path56 pub fn file_path(&self) -> &Path { 57 self.file_path.as_path() 58 } by_name(&self) -> Option<&Licensee>59 pub fn by_name(&self) -> Option<&Licensee> { 60 LICENSE_DATA.classify_file_name(self.file_path()) 61 } by_content(&self) -> &BTreeSet<Licensee>62 pub fn by_content(&self) -> &BTreeSet<Licensee> { 63 self.by_content.get_or_init(|| LICENSE_DATA.classify_file_contents(&self.contents)) 64 } by_content_fuzzy(&self) -> Option<&Licensee>65 pub fn by_content_fuzzy(&self) -> Option<&Licensee> { 66 self.by_content_fuzzy 67 .get_or_init(|| LICENSE_DATA.classify_file_contents_fuzzy(&self.contents)) 68 .as_ref() 69 } 70 } 71