add missing docs
This commit is contained in:
@@ -67,6 +67,7 @@ fn get_arg_parser() -> Command {
|
|||||||
.subcommand(Command::new(VERSION).about("show version info"))
|
.subcommand(Command::new(VERSION).about("show version info"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get and parse the CLI arguments.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get() -> clap::ArgMatches {
|
pub fn get() -> clap::ArgMatches {
|
||||||
get_arg_parser().get_matches()
|
get_arg_parser().get_matches()
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/// Used to implement parts of the `Backend` trait that should not change between the actual
|
||||||
|
/// backends (boilerplate).
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_backend_constants {
|
macro_rules! impl_backend_constants {
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@@ -1,30 +1,34 @@
|
|||||||
use std::fs::{read_to_string, File};
|
use std::fs::{read_to_string, File};
|
||||||
use std::io::{ErrorKind, Write};
|
use std::io::{ErrorKind, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::path::get_pacdef_base_dir;
|
/// Config for the program, as listed in `$XDG_CONFIG_HOME/pacdef/pacdef.yaml`.
|
||||||
|
|
||||||
const CONFIG_FILE_NAME: &str = "pacdef.yaml";
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// The AUR helper to use for Arch Linux.
|
||||||
pub aur_helper: String,
|
pub aur_helper: String,
|
||||||
|
/// Additional arguments to pass to `aur_helper` when removing a package.
|
||||||
pub aur_rm_args: Option<Vec<String>>,
|
pub aur_rm_args: Option<Vec<String>>,
|
||||||
|
/// Warn the user when a group is not a symlink.
|
||||||
pub warn_not_symlinks: bool,
|
pub warn_not_symlinks: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Result<Self> {
|
/// Load the config from the associated file. If the config does not exist, create a default
|
||||||
let file = get_config_file()?;
|
/// config.
|
||||||
let from_file = read_to_string(&file);
|
pub fn load(config_file: &Path) -> Result<Self> {
|
||||||
|
let from_file = read_to_string(config_file);
|
||||||
|
|
||||||
if let Err(e) = from_file {
|
if let Err(e) = from_file {
|
||||||
if e.kind() == ErrorKind::NotFound {
|
if e.kind() == ErrorKind::NotFound {
|
||||||
println!("creating default config under {}", file.to_string_lossy());
|
println!(
|
||||||
return Self::use_default_and_save_to(file);
|
"creating default config under {}",
|
||||||
|
config_file.to_string_lossy()
|
||||||
|
);
|
||||||
|
return Self::use_default_and_save_to(config_file);
|
||||||
}
|
}
|
||||||
bail!("unexpected error occured: {e:?}");
|
bail!("unexpected error occured: {e:?}");
|
||||||
}
|
}
|
||||||
@@ -34,7 +38,7 @@ impl Config {
|
|||||||
serde_yaml::from_str(&content).context("parsing yaml config")
|
serde_yaml::from_str(&content).context("parsing yaml config")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_default_and_save_to(file: PathBuf) -> Result<Self> {
|
fn use_default_and_save_to(file: &Path) -> Result<Self> {
|
||||||
let result = Self::default();
|
let result = Self::default();
|
||||||
|
|
||||||
let content = serde_yaml::to_string(&result).context("converting Config to yaml")?;
|
let content = serde_yaml::to_string(&result).context("converting Config to yaml")?;
|
||||||
@@ -45,12 +49,6 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_file() -> Result<PathBuf> {
|
|
||||||
let mut file = get_pacdef_base_dir().context("getting pacdef base dir for config file")?;
|
|
||||||
file.push(CONFIG_FILE_NAME);
|
|
||||||
Ok(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use crate::ui::get_user_confirmation;
|
|||||||
use crate::Config;
|
use crate::Config;
|
||||||
use crate::Group;
|
use crate::Group;
|
||||||
|
|
||||||
|
/// Most data that is required during runtime of the program.
|
||||||
pub struct Pacdef {
|
pub struct Pacdef {
|
||||||
args: ArgMatches,
|
args: ArgMatches,
|
||||||
config: Config,
|
config: Config,
|
||||||
@@ -25,6 +26,8 @@ pub struct Pacdef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pacdef {
|
impl Pacdef {
|
||||||
|
/// Creates a new [`Pacdef`]. `config` should be passed from [`Config::load`], and `args` from
|
||||||
|
/// [`args::get`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(args: ArgMatches, config: Config, groups: HashSet<Group>) -> Self {
|
pub const fn new(args: ArgMatches, config: Config, groups: HashSet<Group>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -34,6 +37,18 @@ impl Pacdef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run the action that was provided by the user as first argument.
|
||||||
|
///
|
||||||
|
/// For convenience sake, all called functions take a `&self` argument, even if these are not
|
||||||
|
/// strictly required.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the user passed an unexpected action. This means all fields from `crate::action::Action` must be matched in this function.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will return an error if any of the underlying functions return an error.
|
||||||
#[allow(clippy::unit_arg)]
|
#[allow(clippy::unit_arg)]
|
||||||
pub fn run_action_from_arg(mut self) -> Result<()> {
|
pub fn run_action_from_arg(mut self) -> Result<()> {
|
||||||
match self.args.subcommand() {
|
match self.args.subcommand() {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use anyhow::{Context, Result};
|
|||||||
|
|
||||||
use super::{Package, Section};
|
use super::{Package, Section};
|
||||||
|
|
||||||
use crate::Config;
|
/// Representation of a group file, composed of a name (file name from which it was read), the
|
||||||
|
/// sections in the file, and the absolute path of the original file.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Group {
|
pub struct Group {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
@@ -18,15 +18,21 @@ pub struct Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Group {
|
impl Group {
|
||||||
pub fn load(config: &Config) -> Result<HashSet<Self>> {
|
/// Load all group files from the pacdef group dir. If a group file is not a symlink and
|
||||||
|
/// `warn_not_symlinks` is true, a warning is printed.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will return an error if any of the files under `group_dir` cannot be
|
||||||
|
/// accessed.
|
||||||
|
pub fn load(group_dir: &Path, warn_not_symlinks: bool) -> Result<HashSet<Self>> {
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
|
|
||||||
let path = crate::path::get_pacdef_group_dir().context("getting pacdef group dir")?;
|
for entry in group_dir.read_dir().context("reading group dir")? {
|
||||||
for entry in path.read_dir().context("reading group dir")? {
|
|
||||||
let file = entry.context("getting group file")?;
|
let file = entry.context("getting group file")?;
|
||||||
let path = file.path();
|
let path = file.path();
|
||||||
|
|
||||||
if config.warn_not_symlinks && !path.is_symlink() {
|
if warn_not_symlinks && !path.is_symlink() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"WARNING: group file {} is not a symlink",
|
"WARNING: group file {} is not a symlink",
|
||||||
path.to_string_lossy()
|
path.to_string_lossy()
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
clippy::unwrap_used,
|
clippy::unwrap_used,
|
||||||
clippy::use_debug,
|
clippy::use_debug,
|
||||||
clippy::use_self,
|
clippy::use_self,
|
||||||
clippy::wildcard_dependencies
|
clippy::wildcard_dependencies,
|
||||||
|
missing_docs
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod action;
|
mod action;
|
||||||
pub mod args;
|
mod args;
|
||||||
mod backend;
|
mod backend;
|
||||||
mod cmd;
|
mod cmd;
|
||||||
mod config;
|
mod config;
|
||||||
@@ -22,10 +23,12 @@ mod review;
|
|||||||
mod search;
|
mod search;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
pub use crate::args::get as get_args;
|
||||||
pub use crate::config::Config;
|
pub use crate::config::Config;
|
||||||
pub use crate::core::Pacdef;
|
pub use crate::core::Pacdef;
|
||||||
pub use crate::grouping::Group;
|
pub use crate::grouping::Group;
|
||||||
pub(crate) use crate::grouping::Package;
|
pub(crate) use crate::grouping::Package;
|
||||||
|
pub use crate::path::{get_config_path, get_pacdef_group_dir};
|
||||||
pub use crate::search::NO_PACKAGES_FOUND;
|
pub use crate::search::NO_PACKAGES_FOUND;
|
||||||
|
|
||||||
extern crate pacdef_macros;
|
extern crate pacdef_macros;
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ use std::{env, path::PathBuf};
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
const CONFIG_FILE_NAME: &str = "pacdef.yaml";
|
||||||
|
|
||||||
|
/// Get the group directory where all group files are located. This is
|
||||||
|
/// `$XDG_CONFIG_HOME/pacdef/groups`, which defaults to `$HOME/.config/pacdef/groups`.
|
||||||
pub fn get_pacdef_group_dir() -> Result<PathBuf> {
|
pub fn get_pacdef_group_dir() -> Result<PathBuf> {
|
||||||
let mut result = get_pacdef_base_dir().context("getting pacdef base dir")?;
|
let mut result = get_pacdef_base_dir().context("getting pacdef base dir")?;
|
||||||
result.push("groups");
|
result.push("groups");
|
||||||
@@ -27,3 +31,11 @@ fn get_xdg_config_home() -> Result<PathBuf> {
|
|||||||
pub fn get_home_dir() -> Result<PathBuf> {
|
pub fn get_home_dir() -> Result<PathBuf> {
|
||||||
Ok(env::var("HOME").context("getting $HOME variable")?.into())
|
Ok(env::var("HOME").context("getting $HOME variable")?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the group directory where all group files are located. This is
|
||||||
|
/// `$XDG_CONFIG_HOME/pacdef/pacdef.yaml`.
|
||||||
|
pub fn get_config_path() -> Result<PathBuf> {
|
||||||
|
let mut file = get_pacdef_base_dir().context("getting pacdef base dir for config file")?;
|
||||||
|
file.push(CONFIG_FILE_NAME);
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use regex::Regex;
|
|||||||
|
|
||||||
use crate::grouping::{Group, Package, Section};
|
use crate::grouping::{Group, Package, Section};
|
||||||
|
|
||||||
|
/// Error message provided when a package search yields no results.
|
||||||
pub const NO_PACKAGES_FOUND: &str = "no packages matching query";
|
pub const NO_PACKAGES_FOUND: &str = "no packages matching query";
|
||||||
|
|
||||||
pub fn search_packages(args: &ArgMatches, groups: &HashSet<Group>) -> Result<()> {
|
pub fn search_packages(args: &ArgMatches, groups: &HashSet<Group>) -> Result<()> {
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
|
#![warn(
|
||||||
|
clippy::as_conversions,
|
||||||
|
clippy::option_if_let_else,
|
||||||
|
clippy::redundant_pub_crate,
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::unwrap_used,
|
||||||
|
clippy::use_debug,
|
||||||
|
clippy::use_self,
|
||||||
|
clippy::wildcard_dependencies,
|
||||||
|
missing_docs
|
||||||
|
)]
|
||||||
|
|
||||||
mod action;
|
mod action;
|
||||||
mod register;
|
mod register;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
/// Derive (1) an iterator over the variants, (2) imports for the individual backends, and (3)
|
||||||
|
/// instatiation code for each backend.
|
||||||
#[proc_macro_derive(Register)]
|
#[proc_macro_derive(Register)]
|
||||||
pub fn register(input: TokenStream) -> TokenStream {
|
pub fn register(input: TokenStream) -> TokenStream {
|
||||||
register::register(input)
|
register::register(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive public constants from each variant of the enum, such that the name of the constant is
|
||||||
|
/// the name of the variant in all caps, and the value is the name of the variant in lowercase.
|
||||||
#[proc_macro_derive(Action)]
|
#[proc_macro_derive(Action)]
|
||||||
pub fn action(input: TokenStream) -> TokenStream {
|
pub fn action(input: TokenStream) -> TokenStream {
|
||||||
action::action(input)
|
action::action(input)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::process::{ExitCode, Termination};
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use pacdef_core as core;
|
use pacdef_core as core;
|
||||||
use pacdef_core::{args, Config, Group, Pacdef};
|
use pacdef_core::{get_args, get_config_path, get_pacdef_group_dir, Config, Group, Pacdef};
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
handle_final_result(main_inner())
|
handle_final_result(main_inner())
|
||||||
@@ -27,9 +27,14 @@ fn handle_final_result(result: Result<()>) -> ExitCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main_inner() -> Result<()> {
|
fn main_inner() -> Result<()> {
|
||||||
let args = args::get();
|
let args = get_args();
|
||||||
let config = Config::load().context("loading config file")?;
|
|
||||||
let groups = Group::load(&config).context("loading groups").unwrap();
|
let config_file = get_config_path().context("getting config file")?;
|
||||||
|
let config = Config::load(&config_file).context("loading config file")?;
|
||||||
|
|
||||||
|
let group_dir = get_pacdef_group_dir().context("resolving group dir")?;
|
||||||
|
let groups = Group::load(&group_dir, config.warn_not_symlinks).context("loading groups")?;
|
||||||
|
|
||||||
let pacdef = Pacdef::new(args, config, groups);
|
let pacdef = Pacdef::new(args, config, groups);
|
||||||
pacdef.run_action_from_arg().context("running action")
|
pacdef.run_action_from_arg().context("running action")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user