Skip to content

Commit

Permalink
add raw packages for better duplicate package detection for nicer err…
Browse files Browse the repository at this point in the history
…or messages
  • Loading branch information
ripytide committed Oct 8, 2024
1 parent 22b8ef4 commit 883d2f3
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 84 deletions.
67 changes: 48 additions & 19 deletions src/backends/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ macro_rules! is_empty {
macro_rules! to_package_ids {
($($backend:ident),*) => {
pub fn to_package_ids(&self) -> PackageIds {
PackageIds {
inner: BTreeMap::from([
PackageIds (
BTreeMap::from([
$( (AnyBackend::$backend, self.$backend.keys().cloned().collect()), )*
])
}
)
}
};
}
Expand All @@ -44,38 +44,43 @@ macro_rules! any {
}
apply_public_backends!(any);

#[derive(Debug, Clone, Default, Serialize)]
#[derive(Debug, Clone, Default, Serialize, derive_more::Deref, derive_more::DerefMut)]
#[serde(transparent)]
pub struct PackageIds {
inner: BTreeMap<AnyBackend, BTreeSet<String>>,
pub struct RawPackageIds(BTreeMap<AnyBackend, Vec<String>>);
impl RawPackageIds {
pub fn contains(&self, backend: AnyBackend, package: &String) -> bool {
self.get(&backend).is_some_and(|x| x.contains(package))
}
}

#[derive(Debug, Clone, Default, Serialize, derive_more::Deref, derive_more::DerefMut)]
#[serde(transparent)]
pub struct PackageIds(BTreeMap<AnyBackend, BTreeSet<String>>);
impl PackageIds {
pub fn simplified(mut self) -> Self {
self.inner.retain(|_, x| !x.is_empty());
self.retain(|_, x| !x.is_empty());
self
}

pub fn append(&mut self, other: &mut Self) {
for (backend, packages) in other.inner.iter_mut() {
self.inner.entry(*backend).or_default().append(packages);
for (backend, packages) in other.iter_mut() {
self.entry(*backend).or_default().append(packages);
}
}

pub fn is_empty(&self) -> bool {
self.inner.values().all(|x| x.is_empty())
self.values().all(|x| x.is_empty())
}

pub fn contains(&self, backend: AnyBackend, package: &String) -> bool {
self.inner
.get(&backend)
.is_some_and(|x| x.contains(package))
self.get(&backend).is_some_and(|x| x.contains(package))
}

pub fn difference(&self, other: &Self) -> Self {
let mut output = Self::default();
for (backend, packages) in self.inner.iter() {
if let Some(other_packages) = other.inner.get(backend) {
output.inner.insert(
for (backend, packages) in self.iter() {
if let Some(other_packages) = other.get(backend) {
output.insert(
*backend,
packages.difference(other_packages).cloned().collect(),
);
Expand All @@ -86,7 +91,7 @@ impl PackageIds {
}
impl std::fmt::Display for PackageIds {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (backend, packages) in self.inner.iter() {
for (backend, packages) in self.iter() {
if !packages.is_empty() {
writeln!(f, "[{backend}]")?;
writeln!(
Expand All @@ -107,7 +112,7 @@ macro_rules! package_ids {
pub fn to_install_options(self) -> InstallOptions {
InstallOptions {
$(
$backend: if let Some(packages) = self.inner.get(&AnyBackend::$backend) {
$backend: if let Some(packages) = self.get(&AnyBackend::$backend) {
packages.iter().map(|x| (x.clone(), <$backend as Backend>::InstallOptions::default())).collect()
} else {
Default::default()
Expand All @@ -118,7 +123,7 @@ macro_rules! package_ids {
pub fn to_remove_options(self) -> RemoveOptions {
RemoveOptions{
$(
$backend: if let Some(packages) = self.inner.get(&AnyBackend::$backend) {
$backend: if let Some(packages) = self.get(&AnyBackend::$backend) {
packages.iter().map(|x| (x.clone(), <$backend as Backend>::RemoveOptions::default())).collect()
} else {
Default::default()
Expand Down Expand Up @@ -162,6 +167,30 @@ macro_rules! query_infos {
}
apply_public_backends!(query_infos);

macro_rules! raw_install_options {
($($backend:ident),*) => {
#[derive(Debug, Clone, Default)]
#[allow(non_snake_case)]
pub struct RawInstallOptions {
$(
pub $backend: Vec<(String, <$backend as Backend>::InstallOptions)>,
)*
}
impl RawInstallOptions {
append!($($backend),*);

pub fn to_raw_package_ids(&self) -> RawPackageIds {
RawPackageIds(
BTreeMap::from([
$( (AnyBackend::$backend, self.$backend.iter().map(|(x, _)| x).cloned().collect()), )*
])
)
}
}
}
}
apply_public_backends!(raw_install_options);

macro_rules! install_options {
($($backend:ident),*) => {
#[derive(Debug, Clone, Default)]
Expand Down
20 changes: 10 additions & 10 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ pub struct MainArguments {

#[derive(Subcommand)]
pub enum MainSubcommand {
Clean(CleanPackage),
Add(AddPackage),
Review(ReviewPackage),
Sync(SyncPackage),
Unmanaged(UnmanagedPackage),
Clean(CleanCommand),
Add(AddCommand),
Review(ReviewCommand),
Sync(SyncCommand),
Unmanaged(UnmanagedCommand),
}

#[derive(Args)]
#[command(visible_alias("c"))]
/// remove unmanaged packages
pub struct CleanPackage {
pub struct CleanCommand {
#[arg(short, long)]
/// do not ask for any confirmation
pub no_confirm: bool,
Expand All @@ -46,7 +46,7 @@ pub struct CleanPackage {
/// add a package for the given backend and group file
///
/// if the group file does not exist a new one will be created
pub struct AddPackage {
pub struct AddCommand {
#[arg(short, long)]
/// the backend for the package
pub backend: AnyBackend,
Expand All @@ -61,12 +61,12 @@ pub struct AddPackage {
#[derive(Args)]
#[command(visible_alias("r"))]
/// review unmanaged packages
pub struct ReviewPackage {}
pub struct ReviewCommand {}

#[derive(Args)]
#[command(visible_alias("s"))]
/// install packages from groups
pub struct SyncPackage {
pub struct SyncCommand {
#[arg(short, long)]
/// do not ask for any confirmation
pub no_confirm: bool,
Expand All @@ -75,4 +75,4 @@ pub struct SyncPackage {
#[derive(Args)]
#[command(visible_alias("u"))]
/// show explicitly installed packages not managed by pacdef
pub struct UnmanagedPackage {}
pub struct UnmanagedCommand {}
48 changes: 23 additions & 25 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,24 @@ impl MainArguments {
let group_dir = config_dir.join("groups/");

let config = Config::load(&config_dir).wrap_err("loading config file")?;
let groups =
Groups::load(&group_dir, &hostname, &config).wrap_err("failed to load groups")?;
let groups = Groups::load(&group_dir, &hostname, &config)
.wrap_err("failed to load package install options from groups")?;

if groups.is_empty() {
log::warn!("no group files found");
}
let install_options = groups.to_install_options();

match self.subcommand {
MainSubcommand::Clean(clean) => clean.run(&groups, &config),
MainSubcommand::Clean(clean) => clean.run(&install_options, &config),
MainSubcommand::Add(add) => add.run(&group_dir, &groups),
MainSubcommand::Review(review) => review.run(&groups, &config),
MainSubcommand::Sync(sync) => sync.run(&groups, &config),
MainSubcommand::Unmanaged(unmanaged) => unmanaged.run(&groups, &config),
MainSubcommand::Review(review) => review.run(&install_options, &config),
MainSubcommand::Sync(sync) => sync.run(&install_options, &config),
MainSubcommand::Unmanaged(unmanaged) => unmanaged.run(&install_options, &config),
}
}
}

impl CleanPackage {
fn run(self, groups: &Groups, config: &Config) -> Result<()> {
let unmanaged = unmanaged(groups, config)?;
impl CleanCommand {
fn run(self, install_options: &InstallOptions, config: &Config) -> Result<()> {
let unmanaged = unmanaged(install_options, config)?;

if unmanaged.is_empty() {
log::info!("nothing to do since there are no unmanaged packages");
Expand All @@ -76,7 +74,7 @@ impl CleanPackage {
}
}

impl AddPackage {
impl AddCommand {
fn run(self, group_dir: &Path, groups: &Groups) -> Result<()> {
let containing_group_files = groups.contains(self.backend, &self.package);
if !containing_group_files.is_empty() {
Expand Down Expand Up @@ -119,15 +117,15 @@ impl AddPackage {
}
}

impl ReviewPackage {
fn run(self, _: &Groups, _: &Config) -> Result<()> {
impl ReviewCommand {
fn run(self, _: &InstallOptions, _: &Config) -> Result<()> {
review()
}
}

impl SyncPackage {
fn run(self, groups: &Groups, config: &Config) -> Result<()> {
let missing = missing(groups, config)?;
impl SyncCommand {
fn run(self, install_options: &InstallOptions, config: &Config) -> Result<()> {
let missing = missing(install_options, config)?;

if missing.is_empty() {
log::info!("nothing to do as there are no missing packages");
Expand All @@ -154,9 +152,9 @@ impl SyncPackage {
}
}

impl UnmanagedPackage {
fn run(self, groups: &Groups, config: &Config) -> Result<()> {
let unmanaged = unmanaged(groups, config)?.simplified();
impl UnmanagedCommand {
fn run(self, install_options: &InstallOptions, config: &Config) -> Result<()> {
let unmanaged = unmanaged(install_options, config)?.simplified();

if unmanaged.is_empty() {
eprintln!("no unmanaged packages");
Expand All @@ -168,13 +166,13 @@ impl UnmanagedPackage {
}
}

fn unmanaged(groups: &Groups, config: &Config) -> Result<PackageIds> {
fn unmanaged(install_options: &InstallOptions, config: &Config) -> Result<PackageIds> {
Ok(QueryInfos::query_installed_packages(config)?
.to_package_ids()
.difference(&groups.to_package_ids()))
.difference(&install_options.to_package_ids()))
}
fn missing(groups: &Groups, config: &Config) -> Result<PackageIds> {
Ok(groups
fn missing(install_options: &InstallOptions, config: &Config) -> Result<PackageIds> {
Ok(install_options
.to_package_ids()
.difference(&QueryInfos::query_installed_packages(config)?.to_package_ids()))
}
Loading

0 comments on commit 883d2f3

Please sign in to comment.