diff --git a/crates/pacdef_core/src/backend/backend_trait.rs b/crates/pacdef_core/src/backend/backend_trait.rs index 98cfddb..1336f3e 100644 --- a/crates/pacdef_core/src/backend/backend_trait.rs +++ b/crates/pacdef_core/src/backend/backend_trait.rs @@ -58,9 +58,19 @@ pub trait Backend: Debug { fn get_managed_packages(&self) -> &HashSet; /// Get all packages that are installed in the system. + /// + /// # Errors + /// + /// This function shall return an error if the installed packages cannot be + /// determined. fn get_all_installed_packages(&self) -> Result>; /// Get all packages that were installed in the system explicitly. + /// + /// # Errors + /// + /// This function shall return an error if the explicitly installed packages + /// cannot be determined. fn get_explicitly_installed_packages(&self) -> Result>; /// Assign each of the packages to an individual group by editing the @@ -76,7 +86,13 @@ pub trait Backend: Debug { Ok(()) } - /// Install the specified packages. + /// Install the specified packages. If `noconfirm` is `true`, pass the corresponding + /// switch to the package manager. Return the [`ExitStatus`] from the package manager. + /// + /// # Errors + /// + /// This function will return an error if the package manager cannot be run or it + /// returns an error. fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result { let mut cmd = Command::new(self.get_binary()); cmd.args(self.get_switches_install()); diff --git a/crates/pacdef_core/src/grouping/group.rs b/crates/pacdef_core/src/grouping/group.rs index ecf72d5..5c39fcf 100644 --- a/crates/pacdef_core/src/grouping/group.rs +++ b/crates/pacdef_core/src/grouping/group.rs @@ -23,7 +23,7 @@ pub struct Group { } impl Group { - /// Load all group files from the pacdef group dir by recursing through the group dir. + /// Load all group files from the pacdef group dir by traversing through the group dir. /// /// This method will print a warning if /// - there are no files under `group_dir`, or @@ -105,6 +105,17 @@ impl Eq for Group { } impl Group { + /// Load the group from `path`. Determine the name from the path relative to the + /// `group_dir`. + /// + /// # Warnings + /// + /// This function will print a warning if any section in the group file cannot + /// be processed, or the file contains no sections. + /// + /// # Errors + /// + /// This function will return an error if the group file cannot be read. fn try_from

(path: P, group_dir: P) -> Result where P: AsRef, @@ -146,6 +157,11 @@ impl Group { /// Add the new `packages` to the group file under the section `section_header`. If /// the section header does not yet exist, it is created. The packages are written /// in the provided order immediately after the header. + /// + /// # Errors + /// + /// This function returns an error if the group file cannot be read, or if the + /// file cannot be written to. pub(crate) fn save_packages(&self, section_header: &str, packages: &[Package]) -> Result<()> { let mut content = read_to_string(&self.path) .with_context(|| format!("reading existing file contents from {:?}", &self.path))?; @@ -205,6 +221,12 @@ impl Display for Group { } } +/// Add some packages to an existing section in the content of a group file. +/// +/// # Errors +/// +/// This function will return an error if the header cannot be found in +/// the file content. fn write_packages_to_existing_section( group_file_content: &mut String, section_header: &str, @@ -223,6 +245,14 @@ fn write_packages_to_existing_section( Ok(()) } +/// Find the index to the first line in `group_file_content` after the +/// given `section_header`. +/// +/// # Errors +/// +/// This function will return an error if the `section_header` does not +/// exist in `group_file_content`, or if the line containing the +/// `section_header` is not newline-terminated. fn find_first_package_line_in_section( group_file_content: &str, section_header: &str, @@ -238,6 +268,7 @@ fn find_first_package_line_in_section( Ok(section_start + distance_to_next_newline + 1) // + 1 to be after the newline } +/// Append a new section with some packages to the content of a group file. fn add_new_section_with_packages( group_file_content: &mut String, section_header: &str, diff --git a/crates/pacdef_core/src/grouping/package.rs b/crates/pacdef_core/src/grouping/package.rs index 19a0a73..f10b756 100644 --- a/crates/pacdef_core/src/grouping/package.rs +++ b/crates/pacdef_core/src/grouping/package.rs @@ -1,13 +1,15 @@ use std::fmt::{Display, Write}; use std::hash::Hash; +/// A struct to represent a single package, consiting of a `name`, and +/// optionally a `repo`. #[derive(Debug, Eq, PartialOrd, Ord, Clone)] pub struct Package { pub(crate) name: String, repo: Option, } -fn remove_all_but_package_name(s: &str) -> &str { +fn remove_comment_and_trim_whitespace(s: &str) -> &str { s.split('#') // remove comment .next() .expect("line contains something") @@ -16,7 +18,7 @@ fn remove_all_but_package_name(s: &str) -> &str { impl From for Package { fn from(value: String) -> Self { - let trimmed = remove_all_but_package_name(&value); + let trimmed = remove_comment_and_trim_whitespace(&value); debug_assert!(!trimmed.is_empty(), "empty package names are not allowed"); let (name, repo) = Self::split_into_name_and_repo(trimmed); @@ -31,18 +33,28 @@ impl From<&str> for Package { } impl Package { - fn split_into_name_and_repo(s: &str) -> (String, Option) { - let mut iter = s.split('/').rev(); + /// From a string that contains a package name, optionally prefixed by a + /// repository, return the package name as well as the repository if it + /// exists. + /// + /// # Panics + /// + /// Panics if `string` is empty. + fn split_into_name_and_repo(string: &str) -> (String, Option) { + let mut iter = string.split('/').rev(); let name = iter.next().expect("we checked that earlier").to_string(); let repo = iter.next().map(|s| s.to_string()); (name, repo) } + /// Try to parse a string (from a line in a group file) and return a package. + /// From the string, any possible comment is removed and whitespace is trimmed. + /// Returns `None` if there is nothing left after trimming. pub(crate) fn try_from(s: S) -> Option where S: AsRef, { - let trimmed = remove_all_but_package_name(s.as_ref()); + let trimmed = remove_comment_and_trim_whitespace(s.as_ref()); if trimmed.is_empty() { return None; }