refact(backend,grouping): overhaul
- Refactor the confusing/bodgy consts backend macro to use a single BackendInfo struct - Combine supports_as_dependency() and the switches_dependency into a single Option type as that is a better representation as it is an optional backend feature. - Add more types like Packages, Sections for uniformity. - Added a crate-private prelude and switches all imports to use a prelude glob import (excluding functions because it's nice to only be importing types) - Refactored Backend section name in logging by implementing Display for AnyBackend that just prints the section Implemented in #77.
This commit is contained in:
@@ -5,52 +5,37 @@ use alpm::Alpm;
|
|||||||
use alpm::PackageReason::Explicit;
|
use alpm::PackageReason::Explicit;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Arch {
|
pub struct Arch {
|
||||||
pub binary: String,
|
pub binary: String,
|
||||||
pub aur_rm_args: Vec<String>,
|
pub aur_rm_args: Vec<String>,
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
}
|
||||||
impl Arch {
|
impl Arch {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
binary: BINARY.to_string(),
|
binary: config.aur_helper.clone(),
|
||||||
aur_rm_args: vec![],
|
aur_rm_args: config.aur_rm_args.clone(),
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Arch {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BINARY: Text = "pacman";
|
|
||||||
const SECTION: Text = "arch";
|
|
||||||
|
|
||||||
const SWITCHES_INFO: Switches = &["--query", "--info"];
|
|
||||||
const SWITCHES_INSTALL: Switches = &["--sync"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &["--database", "--asdeps"];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &["--noconfirm"];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["--remove", "--recursive"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = true;
|
|
||||||
|
|
||||||
impl Backend for Arch {
|
impl Backend for Arch {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
fn get_binary(&self) -> Text {
|
binary: self.binary.clone(),
|
||||||
let r#box = self.binary.clone().into_boxed_str();
|
section: "arch",
|
||||||
Box::leak(r#box)
|
switches_info: &["--query", "--info"],
|
||||||
|
switches_install: &["--sync"],
|
||||||
|
switches_noconfirm: &["--noconfirm"],
|
||||||
|
switches_remove: &["--remove", "--recursive"],
|
||||||
|
switches_make_dependency: Some(&["--database", "--asdeps"]),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let alpm_packages = get_all_installed_packages_from_alpm()
|
let alpm_packages = get_all_installed_packages_from_alpm()
|
||||||
.context("getting all installed packages from alpm")?;
|
.context("getting all installed packages from alpm")?;
|
||||||
|
|
||||||
@@ -58,7 +43,7 @@ impl Backend for Arch {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
let alpm_packages = get_explicitly_installed_packages_from_alpm()
|
let alpm_packages = get_explicitly_installed_packages_from_alpm()
|
||||||
.context("getting all installed packages from alpm")?;
|
.context("getting all installed packages from alpm")?;
|
||||||
let result = convert_to_pacdef_packages(alpm_packages);
|
let result = convert_to_pacdef_packages(alpm_packages);
|
||||||
@@ -66,13 +51,15 @@ impl Backend for Arch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Install the specified packages.
|
/// Install the specified packages.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = Command::new(&self.binary);
|
let mut cmd = Command::new(&self.binary);
|
||||||
|
|
||||||
cmd.args(self.get_switches_install());
|
cmd.args(backend_info.switches_install);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -83,14 +70,16 @@ impl Backend for Arch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the specified packages.
|
/// Remove the specified packages.
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = Command::new(&self.binary);
|
let mut cmd = Command::new(&self.binary);
|
||||||
|
|
||||||
cmd.args(self.get_switches_remove());
|
cmd.args(backend_info.switches_remove);
|
||||||
cmd.args(&self.aur_rm_args);
|
cmd.args(&self.aur_rm_args);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -124,7 +113,7 @@ fn get_explicitly_installed_packages_from_alpm() -> Result<HashSet<String>> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_pacdef_packages(packages: HashSet<String>) -> HashSet<Package> {
|
fn convert_to_pacdef_packages(packages: HashSet<String>) -> Packages {
|
||||||
packages.into_iter().map(Package::from).collect()
|
packages.into_iter().map(Package::from).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,16 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rust_apt::cache::PackageSort;
|
use rust_apt::cache::PackageSort;
|
||||||
use rust_apt::new_cache;
|
use rust_apt::new_cache;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::backend::root::build_base_command_with_privileges;
|
use crate::backend::root::build_base_command_with_privileges;
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Debian {
|
pub struct Debian {}
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
|
||||||
impl Debian {
|
impl Debian {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {}
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Debian {
|
impl Default for Debian {
|
||||||
@@ -27,43 +19,42 @@ impl Default for Debian {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINARY: Text = "apt";
|
|
||||||
const SECTION: Text = "debian";
|
|
||||||
|
|
||||||
const SWITCHES_INFO: Switches = &["show"];
|
|
||||||
const SWITCHES_INSTALL: Switches = &["install"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[]; // not needed
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &["--yes"];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["remove"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = true;
|
|
||||||
|
|
||||||
impl Backend for Debian {
|
impl Backend for Debian {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "apt".to_string(),
|
||||||
|
section: "debian",
|
||||||
|
switches_info: &["show"],
|
||||||
|
switches_install: &["install"],
|
||||||
|
switches_noconfirm: &["--yes"],
|
||||||
|
switches_remove: &["remove"],
|
||||||
|
switches_make_dependency: Some(&[]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let cache = new_cache!()?;
|
let cache = new_cache!()?;
|
||||||
let sort = PackageSort::default().installed();
|
let sort = PackageSort::default().installed();
|
||||||
|
|
||||||
let mut result = HashSet::new();
|
let mut result = Packages::new();
|
||||||
for pkg in cache.packages(&sort)? {
|
for pkg in cache.packages(&sort)? {
|
||||||
result.insert(Package::from(pkg.name().to_string()));
|
result.insert(Package::from(pkg.name().to_string()));
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
let cache = new_cache!()?;
|
let cache = new_cache!()?;
|
||||||
let sort = PackageSort::default().installed().manually_installed();
|
let sort = PackageSort::default().installed().manually_installed();
|
||||||
|
|
||||||
let mut result = HashSet::new();
|
let mut result = Packages::new();
|
||||||
for pkg in cache.packages(&sort)? {
|
for pkg in cache.packages(&sort)? {
|
||||||
result.insert(Package::from(pkg.name().to_string()));
|
result.insert(Package::from(pkg.name().to_string()));
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, packages: &[Package]) -> Result<()> {
|
fn make_dependency(&self, packages: &Packages) -> Result<()> {
|
||||||
let mut cmd = build_base_command_with_privileges("apt-mark");
|
let mut cmd = build_base_command_with_privileges("apt-mark");
|
||||||
cmd.arg("auto");
|
cmd.arg("auto");
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -74,13 +65,15 @@ impl Backend for Debian {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Install the specified packages.
|
/// Install the specified packages.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
let mut cmd = build_base_command_with_privileges(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
cmd.args(self.get_switches_install());
|
let mut cmd = build_base_command_with_privileges(&backend_info.binary);
|
||||||
|
|
||||||
|
cmd.args(backend_info.switches_install);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -91,12 +84,14 @@ impl Backend for Debian {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the specified packages.
|
/// Remove the specified packages.
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
let mut cmd = build_base_command_with_privileges(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_remove());
|
|
||||||
|
let mut cmd = build_base_command_with_privileges(&backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_remove);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Fedora {
|
pub struct Fedora {}
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
|
||||||
impl Fedora {
|
impl Fedora {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {}
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Fedora {
|
impl Default for Fedora {
|
||||||
@@ -25,16 +18,9 @@ impl Default for Fedora {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINARY: Text = "dnf";
|
/// These repositories are ignored when storing the packages
|
||||||
const SECTION: Text = "fedora";
|
/// as these are present by default on any sane fedora system
|
||||||
|
const DEFAULT_REPOS: [&str; 5] = ["koji", "fedora", "updates", "anaconda", "@"];
|
||||||
const SWITCHES_INFO: Switches = &["info"];
|
|
||||||
const SWITCHES_INSTALL: Switches = &["install"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &["--assumeyes"];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["remove"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = false;
|
|
||||||
|
|
||||||
/// These switches are responsible for
|
/// These switches are responsible for
|
||||||
/// getting the packages explicitly installed by the user
|
/// getting the packages explicitly installed by the user
|
||||||
@@ -54,15 +40,21 @@ const SWITCHES_FETCH_GLOBAL: Switches = &[
|
|||||||
"%{from_repo}/%{name}",
|
"%{from_repo}/%{name}",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// These repositories are ignored when storing the packages
|
|
||||||
/// as these are present by default on any sane fedora system
|
|
||||||
const DEFAULT_REPOS: [&str; 5] = ["koji", "fedora", "updates", "anaconda", "@"];
|
|
||||||
|
|
||||||
impl Backend for Fedora {
|
impl Backend for Fedora {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "dnf".to_string(),
|
||||||
|
section: "fedora",
|
||||||
|
switches_info: &["info"],
|
||||||
|
switches_install: &["install"],
|
||||||
|
switches_noconfirm: &["--assumeyes"],
|
||||||
|
switches_remove: &["remove"],
|
||||||
|
switches_make_dependency: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(SWITCHES_FETCH_GLOBAL);
|
cmd.args(SWITCHES_FETCH_GLOBAL);
|
||||||
|
|
||||||
let output = String::from_utf8(cmd.output()?.stdout)?;
|
let output = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
@@ -71,8 +63,8 @@ impl Backend for Fedora {
|
|||||||
Ok(packages)
|
Ok(packages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(SWITCHES_FETCH_USER);
|
cmd.args(SWITCHES_FETCH_USER);
|
||||||
|
|
||||||
let output = String::from_utf8(cmd.output()?.stdout)?;
|
let output = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
@@ -82,13 +74,15 @@ impl Backend for Fedora {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Install the specified packages.
|
/// Install the specified packages.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = Command::new("sudo");
|
let mut cmd = Command::new("sudo");
|
||||||
cmd.arg(self.get_binary());
|
cmd.arg(backend_info.binary);
|
||||||
cmd.args(self.get_switches_install());
|
cmd.args(backend_info.switches_install);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -106,13 +100,15 @@ impl Backend for Fedora {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Show information from package manager for package.
|
/// Show information from package manager for package.
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = Command::new("sudo");
|
let mut cmd = Command::new("sudo");
|
||||||
cmd.arg(self.get_binary());
|
cmd.arg(backend_info.binary);
|
||||||
cmd.args(self.get_switches_remove());
|
cmd.args(backend_info.switches_remove);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -123,14 +119,16 @@ impl Backend for Fedora {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_package_info(&self, package: &Package) -> Result<()> {
|
fn show_package_info(&self, package: &Package) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_info());
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_info);
|
||||||
cmd.arg(&package.name);
|
cmd.arg(&package.name);
|
||||||
|
|
||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, _: &[Package]) -> Result<()> {
|
fn make_dependency(&self, _: &Packages) -> Result<()> {
|
||||||
panic!("Not supported by the package manager!")
|
panic!("Not supported by the package manager!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Flatpak {
|
pub struct Flatpak {
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
pub systemwide: bool,
|
pub systemwide: bool,
|
||||||
}
|
}
|
||||||
impl Flatpak {
|
impl Flatpak {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
packages: HashSet::new(),
|
systemwide: config.flatpak_systemwide,
|
||||||
systemwide: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,8 +24,8 @@ impl Flatpak {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_installed_packages(&self, include_implicit: bool) -> Result<HashSet<Package>> {
|
fn get_installed_packages(&self, include_implicit: bool) -> Result<Packages> {
|
||||||
let mut cmd = Command::new(BINARY);
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(["list", "--columns=application"]);
|
cmd.args(["list", "--columns=application"]);
|
||||||
if !include_implicit {
|
if !include_implicit {
|
||||||
cmd.arg("--app");
|
cmd.arg("--app");
|
||||||
@@ -40,48 +35,41 @@ impl Flatpak {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let output = String::from_utf8(cmd.output()?.stdout)?;
|
let output = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
Ok(output
|
Ok(output.lines().map(Package::from).collect::<Packages>())
|
||||||
.lines()
|
|
||||||
.map(Package::from)
|
|
||||||
.collect::<HashSet<Package>>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Flatpak {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BINARY: Text = "flatpak";
|
|
||||||
const SECTION: Text = "flatpak";
|
|
||||||
|
|
||||||
const SWITCHES_INSTALL: Switches = &["install"];
|
|
||||||
const SWITCHES_INFO: Switches = &["info"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &["--assumeyes"];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["uninstall"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = false;
|
|
||||||
|
|
||||||
impl Backend for Flatpak {
|
impl Backend for Flatpak {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "flatpak".to_string(),
|
||||||
|
section: "flatpak",
|
||||||
|
switches_info: &["info"],
|
||||||
|
switches_install: &["install"],
|
||||||
|
switches_noconfirm: &["--assumeyes"],
|
||||||
|
switches_remove: &["uninstall"],
|
||||||
|
switches_make_dependency: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
self.get_installed_packages(true)
|
self.get_installed_packages(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
self.get_installed_packages(false)
|
self.get_installed_packages(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install the specified packages.
|
/// Install the specified packages.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_install());
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_install);
|
||||||
cmd.args(self.get_switches_runtime());
|
cmd.args(self.get_switches_runtime());
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -91,18 +79,20 @@ impl Backend for Flatpak {
|
|||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, _: &[Package]) -> Result<()> {
|
fn make_dependency(&self, _: &Packages) -> Result<()> {
|
||||||
panic!("not supported by {}", BINARY)
|
panic!("not supported by {}", self.backend_info().binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the specified packages.
|
/// Remove the specified packages.
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_remove());
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_remove);
|
||||||
cmd.args(self.get_switches_runtime());
|
cmd.args(self.get_switches_runtime());
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -114,8 +104,10 @@ impl Backend for Flatpak {
|
|||||||
|
|
||||||
/// Show information from package manager for package.
|
/// Show information from package manager for package.
|
||||||
fn show_package_info(&self, package: &Package) -> Result<()> {
|
fn show_package_info(&self, package: &Package) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_info());
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_info);
|
||||||
cmd.args(self.get_switches_runtime());
|
cmd.args(self.get_switches_runtime());
|
||||||
cmd.arg(format!("{package}"));
|
cmd.arg(format!("{package}"));
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
use crate::prelude::*;
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::Package;
|
|
||||||
|
|
||||||
macro_rules! ERROR{
|
macro_rules! ERROR{
|
||||||
($bin:expr) => {
|
($bin:expr) => {
|
||||||
@@ -15,81 +12,68 @@ macro_rules! ERROR{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Python {
|
pub struct Python {
|
||||||
pub binary: String,
|
pub binary: String,
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
}
|
||||||
impl Python {
|
impl Python {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
binary: BINARY.to_string(),
|
binary: config.pip_binary.to_string(),
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_switches_runtime(&self) -> Switches {
|
fn get_switches_runtime(&self) -> Switches {
|
||||||
match self.get_binary() {
|
match self.backend_info().binary.as_str() {
|
||||||
"pip" => &["list", "--format", "json", "--not-required", "--user"],
|
"pip" => &["list", "--format", "json", "--not-required", "--user"],
|
||||||
"pipx" => &["list", "--json"],
|
"pipx" => &["list", "--json"],
|
||||||
_ => ERROR!(self.get_binary()),
|
_ => ERROR!(self.backend_info().binary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_switches_explicit(&self) -> Switches {
|
fn get_switches_explicit(&self) -> Switches {
|
||||||
match self.get_binary() {
|
match self.backend_info().binary.as_str() {
|
||||||
"pip" => &["list", "--format", "json", "--user"],
|
"pip" => &["list", "--format", "json", "--user"],
|
||||||
"pipx" => &["list", "--json"],
|
"pipx" => &["list", "--json"],
|
||||||
_ => ERROR!(self.get_binary()),
|
_ => ERROR!(self.backend_info().binary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_packages(&self, output: Value) -> Result<HashSet<Package>> {
|
fn extract_packages(&self, output: Value) -> Result<Packages> {
|
||||||
match self.get_binary() {
|
match self.backend_info().binary.as_str() {
|
||||||
"pip" => extract_pacdef_packages(output),
|
"pip" => extract_pacdef_packages(output),
|
||||||
"pipx" => extract_pacdef_packages_pipx(output),
|
"pipx" => extract_pacdef_packages_pipx(output),
|
||||||
_ => ERROR!(self.get_binary()),
|
_ => ERROR!(self.backend_info().binary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Python {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BINARY: Text = "pip";
|
|
||||||
const SECTION: Text = "python";
|
|
||||||
|
|
||||||
const SWITCHES_INFO: Switches = &["show"];
|
|
||||||
const SWITCHES_INSTALL: Switches = &["install"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[]; // not needed
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &[]; // not needed
|
|
||||||
const SWITCHES_REMOVE: Switches = &["uninstall"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = false;
|
|
||||||
|
|
||||||
impl Backend for Python {
|
impl Backend for Python {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
fn get_binary(&self) -> Text {
|
binary: self.binary.clone(),
|
||||||
let r#box = self.binary.clone().into_boxed_str();
|
section: "python",
|
||||||
Box::leak(r#box)
|
switches_info: &["show"],
|
||||||
|
switches_install: &["install"],
|
||||||
|
switches_noconfirm: &[],
|
||||||
|
switches_remove: &["uninstall"],
|
||||||
|
switches_make_dependency: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
let output = run_pip_command(&mut cmd, self.get_switches_runtime())?;
|
let output = run_pip_command(&mut cmd, self.get_switches_runtime())?;
|
||||||
self.extract_packages(output)
|
self.extract_packages(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
let output = run_pip_command(&mut cmd, self.get_switches_explicit())?;
|
let output = run_pip_command(&mut cmd, self.get_switches_explicit())?;
|
||||||
self.extract_packages(output)
|
self.extract_packages(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, _packages: &[Package]) -> Result<()> {
|
fn make_dependency(&self, _packages: &Packages) -> Result<()> {
|
||||||
panic!("not supported by {}", BINARY)
|
panic!("not supported by {}", self.binary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +84,7 @@ fn run_pip_command(cmd: &mut Command, args: &[&str]) -> Result<Value> {
|
|||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_pacdef_packages(value: Value) -> Result<HashSet<Package>> {
|
fn extract_pacdef_packages(value: Value) -> Result<Packages> {
|
||||||
let result = value
|
let result = value
|
||||||
.as_array()
|
.as_array()
|
||||||
.context("getting inner json array")?
|
.context("getting inner json array")?
|
||||||
@@ -111,7 +95,7 @@ fn extract_pacdef_packages(value: Value) -> Result<HashSet<Package>> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_pacdef_packages_pipx(value: Value) -> Result<HashSet<Package>> {
|
fn extract_pacdef_packages_pipx(value: Value) -> Result<Packages> {
|
||||||
let result = value["venvs"]
|
let result = value["venvs"]
|
||||||
.as_object()
|
.as_object()
|
||||||
.context("getting inner json object")?
|
.context("getting inner json object")?
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::io::ErrorKind::NotFound;
|
use std::io::ErrorKind::NotFound;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -6,19 +5,13 @@ use std::path::PathBuf;
|
|||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
use crate::prelude::*;
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::Package;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Rust {
|
pub struct Rust {}
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
|
||||||
impl Rust {
|
impl Rust {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {}
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Rust {
|
impl Default for Rust {
|
||||||
@@ -27,28 +20,27 @@ impl Default for Rust {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINARY: Text = "cargo";
|
|
||||||
const SECTION: Text = "rust";
|
|
||||||
|
|
||||||
const SWITCHES_INSTALL: Switches = &["install"];
|
|
||||||
const SWITCHES_INFO: Switches = &["search", "--limit", "1"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &[]; // not needed
|
|
||||||
const SWITCHES_REMOVE: Switches = &["uninstall"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = false;
|
|
||||||
|
|
||||||
impl Backend for Rust {
|
impl Backend for Rust {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "cargo".to_string(),
|
||||||
|
section: "rust",
|
||||||
|
switches_info: &["search", "--limit", "1"],
|
||||||
|
switches_install: &["install"],
|
||||||
|
switches_noconfirm: &[],
|
||||||
|
switches_remove: &["uninstall"],
|
||||||
|
switches_make_dependency: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let file = get_crates_file().context("getting path to crates file")?;
|
let file = get_crates_file().context("getting path to crates file")?;
|
||||||
|
|
||||||
let content = match read_to_string(file) {
|
let content = match read_to_string(file) {
|
||||||
Ok(string) => string,
|
Ok(string) => string,
|
||||||
Err(err) if err.kind() == NotFound => {
|
Err(err) if err.kind() == NotFound => {
|
||||||
log::warn!("no crates file found for cargo. Assuming no crates installed yet.");
|
log::warn!("no crates file found for cargo. Assuming no crates installed yet.");
|
||||||
return Ok(HashSet::new());
|
return Ok(Packages::new());
|
||||||
}
|
}
|
||||||
Err(err) => bail!(err),
|
Err(err) => bail!(err),
|
||||||
};
|
};
|
||||||
@@ -58,18 +50,18 @@ impl Backend for Rust {
|
|||||||
extract_packages(&json).context("extracting packages from crates file")
|
extract_packages(&json).context("extracting packages from crates file")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
self.get_all_installed_packages()
|
self.get_all_installed_packages()
|
||||||
.context("getting all installed packages")
|
.context("getting all installed packages")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, _: &[Package]) -> Result<()> {
|
fn make_dependency(&self, _: &Packages) -> Result<()> {
|
||||||
panic!("not supported by {}", BINARY)
|
panic!("not supported by {}", self.backend_info().binary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_packages(json: &Value) -> Result<HashSet<Package>> {
|
fn extract_packages(json: &Value) -> Result<Packages> {
|
||||||
let result: HashSet<_> = json
|
let result: Packages = json
|
||||||
.get("installs")
|
.get("installs")
|
||||||
.context("get 'installs' field from json")?
|
.context("get 'installs' field from json")?
|
||||||
.as_object()
|
.as_object()
|
||||||
@@ -83,6 +75,7 @@ fn extract_packages(json: &Value) -> Result<HashSet<Package>> {
|
|||||||
})
|
})
|
||||||
.map(|name| Package::try_from(name).expect("name is valid"))
|
.map(|name| Package::try_from(name).expect("name is valid"))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
mod helpers;
|
mod helpers;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use self::helpers::{
|
use self::helpers::{
|
||||||
@@ -14,15 +11,11 @@ use self::helpers::{
|
|||||||
};
|
};
|
||||||
use self::types::{Repotype, RustupPackage};
|
use self::types::{Repotype, RustupPackage};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Rustup {
|
pub struct Rustup {}
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
|
||||||
impl Rustup {
|
impl Rustup {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {}
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Rustup {
|
impl Default for Rustup {
|
||||||
@@ -31,38 +24,37 @@ impl Default for Rustup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINARY: Text = "rustup";
|
|
||||||
const SECTION: Text = "rustup";
|
|
||||||
|
|
||||||
const SWITCHES_INSTALL: Switches = &["component", "add"];
|
|
||||||
const SWITCHES_INFO: Switches = &["component", "list", "--installed"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &[];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &[];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["component", "remove"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = false;
|
|
||||||
|
|
||||||
impl Backend for Rustup {
|
impl Backend for Rustup {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "rustup".to_string(),
|
||||||
|
section: "rustup",
|
||||||
|
switches_install: &["component", "add"],
|
||||||
|
switches_info: &["component", "list", "--installed"],
|
||||||
|
switches_noconfirm: &[],
|
||||||
|
switches_remove: &["component", "remove"],
|
||||||
|
switches_make_dependency: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
let toolchains_vec = self
|
let toolchains_vec = self
|
||||||
.run_toolchain_command(Repotype::Toolchain.get_info_switches())
|
.run_toolchain_command(Repotype::Toolchain.get_info_switches())
|
||||||
.context("Getting installed toolchains")?;
|
.context("Getting installed toolchains")?;
|
||||||
|
|
||||||
let toolchains: HashSet<Package> = toolchains_vec
|
let toolchains: Packages = toolchains_vec
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| ["toolchain", name].join("/").into())
|
.map(|name| ["toolchain", name].join("/").into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let components: HashSet<Package> = self
|
let components: Packages = self
|
||||||
.run_component_command(Repotype::Component.get_info_switches(), &toolchains_vec)
|
.run_component_command(Repotype::Component.get_info_switches(), &toolchains_vec)
|
||||||
.context("Getting installed components")?
|
.context("Getting installed components")?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| ["component", name].join("/").into())
|
.map(|name| ["component", name].join("/").into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut packages = HashSet::new();
|
let mut packages = Packages::new();
|
||||||
|
|
||||||
packages.extend(toolchains);
|
packages.extend(toolchains);
|
||||||
packages.extend(components);
|
packages.extend(components);
|
||||||
@@ -70,16 +62,16 @@ impl Backend for Rustup {
|
|||||||
Ok(packages)
|
Ok(packages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
self.get_all_installed_packages()
|
self.get_all_installed_packages()
|
||||||
.context("Getting all installed packages")
|
.context("Getting all installed packages")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, _: &[Package]) -> Result<()> {
|
fn make_dependency(&self, _: &Packages) -> Result<()> {
|
||||||
panic!("Not supported by {}", self.get_binary())
|
panic!("Not supported by {}", self.backend_info().binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_packages(&self, packages: &[Package], _: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, _: bool) -> Result<()> {
|
||||||
let packages = RustupPackage::from_pacdef_packages(packages)?;
|
let packages = RustupPackage::from_pacdef_packages(packages)?;
|
||||||
|
|
||||||
let (toolchains, components) =
|
let (toolchains, components) =
|
||||||
@@ -91,7 +83,7 @@ impl Backend for Rustup {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_packages(&self, packages: &[Package], _: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, _: bool) -> Result<()> {
|
||||||
let rustup_packages = RustupPackage::from_pacdef_packages(packages)?;
|
let rustup_packages = RustupPackage::from_pacdef_packages(packages)?;
|
||||||
|
|
||||||
let (toolchains, components) =
|
let (toolchains, components) =
|
||||||
@@ -110,7 +102,7 @@ impl Rustup {
|
|||||||
let mut val = Vec::new();
|
let mut val = Vec::new();
|
||||||
|
|
||||||
for toolchain in toolchains {
|
for toolchain in toolchains {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(args).arg(toolchain);
|
cmd.args(args).arg(toolchain);
|
||||||
|
|
||||||
let output = String::from_utf8(cmd.output()?.stdout)?;
|
let output = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
@@ -124,7 +116,7 @@ impl Rustup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_toolchain_command(&self, args: &[&str]) -> Result<Vec<String>> {
|
fn run_toolchain_command(&self, args: &[&str]) -> Result<Vec<String>> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(args);
|
cmd.args(args);
|
||||||
|
|
||||||
let output = String::from_utf8(cmd.output()?.stdout)?;
|
let output = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
@@ -146,7 +138,7 @@ impl Rustup {
|
|||||||
if toolchains.is_empty() {
|
if toolchains.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(Repotype::Toolchain.get_install_switches());
|
cmd.args(Repotype::Toolchain.get_install_switches());
|
||||||
|
|
||||||
for toolchain in toolchains {
|
for toolchain in toolchains {
|
||||||
@@ -166,7 +158,7 @@ impl Rustup {
|
|||||||
let components_by_toolchain = group_components_by_toolchains(components);
|
let components_by_toolchain = group_components_by_toolchains(components);
|
||||||
|
|
||||||
for components_for_one_toolchain in components_by_toolchain {
|
for components_for_one_toolchain in components_by_toolchain {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(Repotype::Component.get_install_switches());
|
cmd.args(Repotype::Component.get_install_switches());
|
||||||
|
|
||||||
let the_toolchain = &components_for_one_toolchain
|
let the_toolchain = &components_for_one_toolchain
|
||||||
@@ -195,7 +187,7 @@ impl Rustup {
|
|||||||
fn remove_toolchains(&self, toolchains: Vec<RustupPackage>) -> Result<Vec<String>> {
|
fn remove_toolchains(&self, toolchains: Vec<RustupPackage>) -> Result<Vec<String>> {
|
||||||
let mut removed_toolchains = vec![];
|
let mut removed_toolchains = vec![];
|
||||||
if !toolchains.is_empty() {
|
if !toolchains.is_empty() {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(Repotype::Toolchain.get_remove_switches());
|
cmd.args(Repotype::Toolchain.get_remove_switches());
|
||||||
|
|
||||||
for toolchain_package in &toolchains {
|
for toolchain_package in &toolchains {
|
||||||
@@ -216,7 +208,7 @@ impl Rustup {
|
|||||||
removed_toolchains: Vec<String>,
|
removed_toolchains: Vec<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for component_package in components {
|
for component_package in components {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
cmd.args(Repotype::Component.get_remove_switches());
|
cmd.args(Repotype::Component.get_remove_switches());
|
||||||
|
|
||||||
if toolchain_of_component_was_already_removed(&removed_toolchains, &component_package) {
|
if toolchain_of_component_was_already_removed(&removed_toolchains, &component_package) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
use crate::{backend::backend_trait::Switches, Package};
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Repotype {
|
pub enum Repotype {
|
||||||
@@ -95,7 +95,7 @@ impl RustupPackage {
|
|||||||
(toolchains, components)
|
(toolchains, components)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_pacdef_packages(packages: &[Package]) -> Result<Vec<Self>> {
|
pub fn from_pacdef_packages(packages: &Packages) -> Result<Vec<Self>> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
||||||
for package in packages {
|
for package in packages {
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::backend::backend_trait::{Backend, Switches, Text};
|
|
||||||
use crate::backend::macros::impl_backend_constants;
|
|
||||||
use crate::backend::root::build_base_command_with_privileges;
|
use crate::backend::root::build_base_command_with_privileges;
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Void {
|
pub struct Void {}
|
||||||
pub packages: HashSet<Package>,
|
|
||||||
}
|
|
||||||
impl Void {
|
impl Void {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {}
|
||||||
packages: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Void {
|
impl Default for Void {
|
||||||
@@ -27,25 +20,25 @@ impl Default for Void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINARY: Text = "xbps-install";
|
|
||||||
const INSTALL_BINARY: Text = "xbps-install";
|
const INSTALL_BINARY: Text = "xbps-install";
|
||||||
const REMOVE_BINARY: Text = "xbps-remove";
|
const REMOVE_BINARY: Text = "xbps-remove";
|
||||||
const QUERY_BINARY: Text = "xbps-query";
|
const QUERY_BINARY: Text = "xbps-query";
|
||||||
const PKGDB_BINARY: Text = "xbps-pkgdb";
|
const PKGDB_BINARY: Text = "xbps-pkgdb";
|
||||||
const SECTION: Text = "void";
|
|
||||||
|
|
||||||
const SWITCHES_INFO: Switches = &[];
|
|
||||||
const SWITCHES_INSTALL: Switches = &["-S"];
|
|
||||||
const SWITCHES_MAKE_DEPENDENCY: Switches = &["-m", "auto"];
|
|
||||||
const SWITCHES_NOCONFIRM: Switches = &["-y"];
|
|
||||||
const SWITCHES_REMOVE: Switches = &["-R"];
|
|
||||||
|
|
||||||
const SUPPORTS_AS_DEPENDENCY: bool = true;
|
|
||||||
|
|
||||||
impl Backend for Void {
|
impl Backend for Void {
|
||||||
impl_backend_constants!();
|
fn backend_info(&self) -> BackendInfo {
|
||||||
|
BackendInfo {
|
||||||
|
binary: "xbps-install".to_string(),
|
||||||
|
section: "void",
|
||||||
|
switches_info: &[],
|
||||||
|
switches_install: &["-S"],
|
||||||
|
switches_noconfirm: &["-y"],
|
||||||
|
switches_remove: &["-R"],
|
||||||
|
switches_make_dependency: Some(&["-m", "auto"]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_all_installed_packages(&self) -> Result<Packages> {
|
||||||
// Removes the package status and description from output
|
// Removes the package status and description from output
|
||||||
let re_str_1 = r"^ii |^uu |^hr |^\?\? | .*";
|
let re_str_1 = r"^ii |^uu |^hr |^\?\? | .*";
|
||||||
// Removes the package version from output
|
// Removes the package version from output
|
||||||
@@ -67,7 +60,7 @@ impl Backend for Void {
|
|||||||
Ok(packages)
|
Ok(packages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>> {
|
fn get_explicitly_installed_packages(&self) -> Result<Packages> {
|
||||||
// Removes the package version from output
|
// Removes the package version from output
|
||||||
let re_str = r"-[^-]*$";
|
let re_str = r"-[^-]*$";
|
||||||
let re = Regex::new(re_str)?;
|
let re = Regex::new(re_str)?;
|
||||||
@@ -86,12 +79,14 @@ impl Backend for Void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Install the specified packages.
|
/// Install the specified packages.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = build_base_command_with_privileges(INSTALL_BINARY);
|
let mut cmd = build_base_command_with_privileges(INSTALL_BINARY);
|
||||||
cmd.args(self.get_switches_install());
|
cmd.args(backend_info.switches_install);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -101,12 +96,14 @@ impl Backend for Void {
|
|||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = build_base_command_with_privileges(REMOVE_BINARY);
|
let mut cmd = build_base_command_with_privileges(REMOVE_BINARY);
|
||||||
cmd.args(self.get_switches_remove());
|
cmd.args(backend_info.switches_remove);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -116,9 +113,15 @@ impl Backend for Void {
|
|||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dependency(&self, packages: &[Package]) -> Result<()> {
|
fn make_dependency(&self, packages: &Packages) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = build_base_command_with_privileges(PKGDB_BINARY);
|
let mut cmd = build_base_command_with_privileges(PKGDB_BINARY);
|
||||||
cmd.args(self.get_switches_make_dependency());
|
cmd.args(
|
||||||
|
backend_info
|
||||||
|
.switches_make_dependency
|
||||||
|
.expect("void should support make make dependency"),
|
||||||
|
);
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
cmd.arg(format!("{p}"));
|
cmd.arg(format!("{p}"));
|
||||||
@@ -129,8 +132,10 @@ impl Backend for Void {
|
|||||||
|
|
||||||
/// Show information from package manager for package.
|
/// Show information from package manager for package.
|
||||||
fn show_package_info(&self, package: &Package) -> Result<()> {
|
fn show_package_info(&self, package: &Package) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
let mut cmd = Command::new(QUERY_BINARY);
|
let mut cmd = Command::new(QUERY_BINARY);
|
||||||
cmd.args(self.get_switches_info());
|
cmd.args(backend_info.switches_info);
|
||||||
cmd.arg(format!("{package}"));
|
cmd.arg(format!("{package}"));
|
||||||
|
|
||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
|
|||||||
@@ -1,68 +1,52 @@
|
|||||||
use std::cmp::{Eq, Ord};
|
use std::collections::BTreeMap;
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::cmd::run_external_command;
|
use crate::cmd::run_external_command;
|
||||||
use crate::{Group, Groups, Package};
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub type Switches = &'static [&'static str];
|
pub type Switches = &'static [&'static str];
|
||||||
pub type Text = &'static str;
|
pub type Text = &'static str;
|
||||||
|
|
||||||
|
/// A bundle of small of bits of info associated with a backend.
|
||||||
|
pub struct BackendInfo {
|
||||||
|
/// The binary name when calling the backend.
|
||||||
|
pub binary: String,
|
||||||
|
/// The name of the section in the group files.
|
||||||
|
pub section: Text,
|
||||||
|
/// CLI switches for the package manager to show information for
|
||||||
|
/// packages.
|
||||||
|
pub switches_info: Switches,
|
||||||
|
/// CLI switches for the package manager to install packages.
|
||||||
|
pub switches_install: Switches,
|
||||||
|
/// CLI switches for the package manager to perform `sync` and `clean` without
|
||||||
|
/// confirmation.
|
||||||
|
pub switches_noconfirm: Switches,
|
||||||
|
/// CLI switches for the package manager to remove packages.
|
||||||
|
pub switches_remove: Switches,
|
||||||
|
/// CLI switches for the package manager to mark packages as
|
||||||
|
/// dependency. This is not supported by all package managers.
|
||||||
|
pub switches_make_dependency: Option<Switches>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The trait of a struct that is used as a backend.
|
/// The trait of a struct that is used as a backend.
|
||||||
#[enum_dispatch::enum_dispatch]
|
#[enum_dispatch::enum_dispatch]
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
/// Return the actual binary. Iff the backend supports different
|
/// Return the [`BackendInfo`] associated with this backend.
|
||||||
/// binaries, you will need to overwrite this implementation to return
|
fn backend_info(&self) -> BackendInfo;
|
||||||
/// the binary that was loaded at runtime. See
|
|
||||||
/// [`Backend::get_binary_default()`].
|
fn supports_as_dependency(&self) -> bool {
|
||||||
fn get_binary(&self) -> Text {
|
self.backend_info().switches_make_dependency.is_some()
|
||||||
self.get_binary_default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the default binary as defined in the constant of the module.
|
|
||||||
/// See [`Backend::get_binary()`].
|
|
||||||
fn get_binary_default(&self) -> Text;
|
|
||||||
|
|
||||||
/// Get the name of the section in the group files.
|
|
||||||
fn get_section(&self) -> Text;
|
|
||||||
|
|
||||||
/// Get CLI switches for the package manager to show information for
|
|
||||||
/// packages.
|
|
||||||
fn get_switches_info(&self) -> Switches;
|
|
||||||
|
|
||||||
/// Get CLI switches for the package manager to install packages.
|
|
||||||
fn get_switches_install(&self) -> Switches;
|
|
||||||
|
|
||||||
/// Get CLI switches for the package manager to perform `sync` and `clean` without
|
|
||||||
/// confirmation.
|
|
||||||
fn get_switches_noconfirm(&self) -> Switches;
|
|
||||||
|
|
||||||
/// Get CLI switches for the package manager to remove packages.
|
|
||||||
fn get_switches_remove(&self) -> Switches;
|
|
||||||
|
|
||||||
/// Get CLI switches for the package manager to mark packages as
|
|
||||||
/// dependency. This is not supported by all package managers. See
|
|
||||||
/// [`Backend::supports_as_dependency()`].
|
|
||||||
fn get_switches_make_dependency(&self) -> Switches;
|
|
||||||
|
|
||||||
/// Load all packages from a set of groups. The backend will visit all groups,
|
|
||||||
/// find its own section, and clone all packages into its own struct.
|
|
||||||
fn load(&mut self, groups: &Groups);
|
|
||||||
|
|
||||||
/// Get all managed packages for this backend, i.e. all packages
|
|
||||||
/// under the corresponding section in all group files.
|
|
||||||
fn get_managed_packages(&self) -> &HashSet<Package>;
|
|
||||||
|
|
||||||
/// Get all packages that are installed in the system.
|
/// Get all packages that are installed in the system.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function shall return an error if the installed packages cannot be
|
/// This function shall return an error if the installed packages cannot be
|
||||||
/// determined.
|
/// determined.
|
||||||
fn get_all_installed_packages(&self) -> Result<HashSet<Package>>;
|
fn get_all_installed_packages(&self) -> Result<Packages>;
|
||||||
|
|
||||||
/// Get all packages that were installed in the system explicitly.
|
/// Get all packages that were installed in the system explicitly.
|
||||||
///
|
///
|
||||||
@@ -70,13 +54,22 @@ pub trait Backend {
|
|||||||
///
|
///
|
||||||
/// This function shall return an error if the explicitly installed packages
|
/// This function shall return an error if the explicitly installed packages
|
||||||
/// cannot be determined.
|
/// cannot be determined.
|
||||||
fn get_explicitly_installed_packages(&self) -> Result<HashSet<Package>>;
|
fn get_explicitly_installed_packages(&self) -> Result<Packages>;
|
||||||
|
|
||||||
/// Assign each of the packages to an individual group by editing the
|
/// Assign each of the packages to an individual group by editing the
|
||||||
/// group files.
|
/// group files.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an Error if any of the groups fails to save their given packages.
|
||||||
fn assign_group(&self, to_assign: Vec<(Package, Group)>) -> Result<()> {
|
fn assign_group(&self, to_assign: Vec<(Package, Group)>) -> Result<()> {
|
||||||
let group_package_map = to_hashmap(to_assign);
|
let mut group_package_map: BTreeMap<Group, Packages> = BTreeMap::new();
|
||||||
let section_header = format!("[{}]", self.get_section());
|
|
||||||
|
for (package, group) in to_assign {
|
||||||
|
group_package_map.entry(group).or_default().insert(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
let section_header = format!("[{}]", self.backend_info().section);
|
||||||
|
|
||||||
for (group, packages) in group_package_map {
|
for (group, packages) in group_package_map {
|
||||||
group.save_packages(§ion_header, &packages)?;
|
group.save_packages(§ion_header, &packages)?;
|
||||||
@@ -92,12 +85,14 @@ pub trait Backend {
|
|||||||
///
|
///
|
||||||
/// This function will return an error if the package manager cannot be run or it
|
/// This function will return an error if the package manager cannot be run or it
|
||||||
/// returns an error.
|
/// returns an error.
|
||||||
fn install_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
fn install_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_install());
|
|
||||||
|
let mut cmd = Command::new(self.backend_info().binary);
|
||||||
|
cmd.args(backend_info.switches_install);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -113,9 +108,18 @@ pub trait Backend {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This method shall panic when the backend does not support dependent packages.
|
/// This method shall panic when the backend does not support dependent packages.
|
||||||
fn make_dependency(&self, packages: &[Package]) -> Result<()> {
|
///
|
||||||
let mut cmd = Command::new(self.get_binary());
|
/// # Errors
|
||||||
cmd.args(self.get_switches_make_dependency());
|
///
|
||||||
|
/// Returns an error if the external command fails.
|
||||||
|
fn make_dependency(&self, packages: &Packages) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
|
||||||
|
if let Some(switches_make_dependency) = backend_info.switches_make_dependency {
|
||||||
|
cmd.args(switches_make_dependency);
|
||||||
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
cmd.arg(format!("{p}"));
|
cmd.arg(format!("{p}"));
|
||||||
@@ -126,12 +130,17 @@ pub trait Backend {
|
|||||||
|
|
||||||
/// Remove the specified packages.
|
/// Remove the specified packages.
|
||||||
///
|
///
|
||||||
fn remove_packages(&self, packages: &[Package], noconfirm: bool) -> Result<()> {
|
/// # Errors
|
||||||
let mut cmd = Command::new(self.get_binary());
|
///
|
||||||
cmd.args(self.get_switches_remove());
|
/// Returns an error if the external command fails.
|
||||||
|
fn remove_packages(&self, packages: &Packages, noconfirm: bool) -> Result<()> {
|
||||||
|
let backend_info = self.backend_info();
|
||||||
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_remove);
|
||||||
|
|
||||||
if noconfirm {
|
if noconfirm {
|
||||||
cmd.args(self.get_switches_noconfirm());
|
cmd.args(backend_info.switches_noconfirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in packages {
|
for p in packages {
|
||||||
@@ -141,58 +150,18 @@ pub trait Backend {
|
|||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get missing packages, sorted alphabetically.
|
|
||||||
fn get_missing_packages_sorted(&self) -> Result<Vec<Package>> {
|
|
||||||
let installed = self
|
|
||||||
.get_all_installed_packages()
|
|
||||||
.context("could not get installed packages")?;
|
|
||||||
let managed = self.get_managed_packages();
|
|
||||||
let mut diff: Vec<_> = managed.difference(&installed).cloned().collect();
|
|
||||||
diff.sort_unstable();
|
|
||||||
Ok(diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Show information from package manager for package.
|
/// Show information from package manager for package.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the external command fails.
|
||||||
fn show_package_info(&self, package: &Package) -> Result<()> {
|
fn show_package_info(&self, package: &Package) -> Result<()> {
|
||||||
let mut cmd = Command::new(self.get_binary());
|
let backend_info = self.backend_info();
|
||||||
cmd.args(self.get_switches_info());
|
|
||||||
|
let mut cmd = Command::new(backend_info.binary);
|
||||||
|
cmd.args(backend_info.switches_info);
|
||||||
cmd.arg(format!("{package}"));
|
cmd.arg(format!("{package}"));
|
||||||
|
|
||||||
run_external_command(cmd)
|
run_external_command(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get unmanaged packages, sorted alphabetically.
|
|
||||||
fn get_unmanaged_packages_sorted(&self) -> Result<Vec<Package>> {
|
|
||||||
let installed = self
|
|
||||||
.get_explicitly_installed_packages()
|
|
||||||
.context("could not get explicitly installed packages")?;
|
|
||||||
let required = self.get_managed_packages();
|
|
||||||
let mut diff: Vec<_> = installed.difference(required).cloned().collect();
|
|
||||||
diff.sort_unstable();
|
|
||||||
Ok(diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether the underlying package manager supports dependency packages.
|
|
||||||
fn supports_as_dependency(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For a vector of tuples containing a `V` and `K`, where a `K` may occur more than
|
|
||||||
/// once and each `V` exactly once, create a `HashMap` that associates each `K` with
|
|
||||||
/// a `Vec<V>`.
|
|
||||||
fn to_hashmap<K, V>(to_assign: Vec<(V, K)>) -> HashMap<K, Vec<V>>
|
|
||||||
where
|
|
||||||
K: Hash + Eq,
|
|
||||||
V: Ord,
|
|
||||||
{
|
|
||||||
let mut map = HashMap::new();
|
|
||||||
|
|
||||||
for (value, key) in to_assign {
|
|
||||||
let inner: &mut Vec<V> = map.entry(key).or_default();
|
|
||||||
inner.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
for vecs in map.values_mut() {
|
|
||||||
vecs.sort_unstable();
|
|
||||||
}
|
|
||||||
map
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
/// Used to implement parts of the `Backend` trait that should not change between the actual
|
|
||||||
/// backends (boilerplate).
|
|
||||||
macro_rules! impl_backend_constants {
|
|
||||||
() => {
|
|
||||||
fn get_binary_default(&self) -> Text {
|
|
||||||
BINARY
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_section(&self) -> Text {
|
|
||||||
SECTION
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_switches_info(&self) -> Switches {
|
|
||||||
SWITCHES_INFO
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_switches_install(&self) -> Switches {
|
|
||||||
SWITCHES_INSTALL
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_switches_noconfirm(&self) -> Switches {
|
|
||||||
SWITCHES_NOCONFIRM
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_switches_remove(&self) -> Switches {
|
|
||||||
SWITCHES_REMOVE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_switches_make_dependency(&self) -> Switches {
|
|
||||||
SWITCHES_MAKE_DEPENDENCY
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_managed_packages(&self) -> &HashSet<Package> {
|
|
||||||
&self.packages
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load(&mut self, groups: &crate::Groups) {
|
|
||||||
let own_section_name = self.get_section();
|
|
||||||
|
|
||||||
groups
|
|
||||||
.iter()
|
|
||||||
.flat_map(|g| &g.sections)
|
|
||||||
.filter(|section| section.name == own_section_name)
|
|
||||||
.flat_map(|section| §ion.packages)
|
|
||||||
.for_each(|package| {
|
|
||||||
self.packages.insert(package.clone());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_as_dependency(&self) -> bool {
|
|
||||||
SUPPORTS_AS_DEPENDENCY
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) use impl_backend_constants;
|
|
||||||
@@ -1,23 +1,56 @@
|
|||||||
pub mod actual;
|
pub mod actual;
|
||||||
pub mod backend_trait;
|
pub mod backend_trait;
|
||||||
pub mod macros;
|
|
||||||
mod root;
|
mod root;
|
||||||
pub mod todo_per_backend;
|
pub mod todo_per_backend;
|
||||||
|
|
||||||
use crate::backend::backend_trait::Switches;
|
use std::fmt::Display;
|
||||||
use crate::backend::backend_trait::Text;
|
|
||||||
use crate::Group;
|
|
||||||
use crate::Groups;
|
|
||||||
use crate::Package;
|
|
||||||
use anyhow::Result;
|
|
||||||
use backend_trait::Backend;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use self::actual::{
|
use crate::prelude::*;
|
||||||
fedora::Fedora, flatpak::Flatpak, python::Python, rust::Rust, rustup::Rustup, void::Void,
|
use anyhow::{Context, Result};
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// A backend with its associated managed packages
|
||||||
|
pub struct ManagedBackend {
|
||||||
|
/// All managed packages for this backend, i.e. all packages
|
||||||
|
/// under the corresponding section in all group files.
|
||||||
|
pub packages: Packages,
|
||||||
|
pub any_backend: AnyBackend,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManagedBackend {
|
||||||
|
/// Get unmanaged packages
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the backend fails to get the explicitly installed packages.
|
||||||
|
pub fn get_unmanaged_packages_sorted(&self) -> Result<Packages> {
|
||||||
|
let installed = self
|
||||||
|
.any_backend
|
||||||
|
.get_explicitly_installed_packages()
|
||||||
|
.context("could not get explicitly installed packages")?;
|
||||||
|
|
||||||
|
let diff = installed.difference(&self.packages).cloned().collect();
|
||||||
|
|
||||||
|
Ok(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get missing packages
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the backend fails to get the installed packages.
|
||||||
|
pub fn get_missing_packages_sorted(&self) -> Result<Packages> {
|
||||||
|
let installed = self
|
||||||
|
.any_backend
|
||||||
|
.get_all_installed_packages()
|
||||||
|
.context("could not get installed packages")?;
|
||||||
|
|
||||||
|
let diff = self.packages.difference(&installed).cloned().collect();
|
||||||
|
|
||||||
|
Ok(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[enum_dispatch::enum_dispatch(Backend)]
|
#[enum_dispatch::enum_dispatch(Backend)]
|
||||||
pub enum AnyBackend {
|
pub enum AnyBackend {
|
||||||
#[cfg(feature = "arch")]
|
#[cfg(feature = "arch")]
|
||||||
@@ -31,22 +64,44 @@ pub enum AnyBackend {
|
|||||||
Rustup(Rustup),
|
Rustup(Rustup),
|
||||||
Void(Void),
|
Void(Void),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyBackend {
|
impl AnyBackend {
|
||||||
/// Returns an iterator of every variant of backend.
|
/// Returns an iterator of every variant of backend.
|
||||||
pub fn iter() -> impl Iterator<Item = Self> {
|
pub fn all(config: &Config) -> impl Iterator<Item = Self> {
|
||||||
vec![
|
vec![
|
||||||
#[cfg(feature = "arch")]
|
#[cfg(feature = "arch")]
|
||||||
Self::Arch(actual::arch::Arch::new()),
|
Self::Arch(actual::arch::Arch::new(config)),
|
||||||
#[cfg(feature = "debian")]
|
#[cfg(feature = "debian")]
|
||||||
Self::Debian(actual::debian::Debian::new()),
|
Self::Debian(actual::debian::Debian::new()),
|
||||||
Self::Flatpak(Flatpak::new()),
|
Self::Flatpak(Flatpak::new(config)),
|
||||||
Self::Fedora(Fedora::new()),
|
Self::Fedora(Fedora::new()),
|
||||||
Self::Python(Python::new()),
|
Self::Python(Python::new(config)),
|
||||||
Self::Rust(Rust::new()),
|
Self::Rust(Rust::new()),
|
||||||
Self::Rustup(Rustup::new()),
|
Self::Rustup(Rustup::new()),
|
||||||
Self::Void(Void::new()),
|
Self::Void(Void::new()),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_section(section: &str, config: &Config) -> Result<Self> {
|
||||||
|
match section {
|
||||||
|
#[cfg(feature = "arch")]
|
||||||
|
"arch" => Ok(Self::Arch(actual::arch::Arch::new(config))),
|
||||||
|
#[cfg(feature = "debian")]
|
||||||
|
"debian" => Ok(Self::Debian(actual::debian::Debian::new())),
|
||||||
|
"flatpak" => Ok(Self::Flatpak(Flatpak::new(config))),
|
||||||
|
"fedora" => Ok(Self::Fedora(Fedora::new())),
|
||||||
|
"python" => Ok(Self::Python(Python::new(config))),
|
||||||
|
"rust" => Ok(Self::Rust(Rust::new())),
|
||||||
|
"rustup" => Ok(Self::Rustup(Rustup::new())),
|
||||||
|
"void" => Ok(Self::Void(Void::new())),
|
||||||
|
_ => Err(anyhow::anyhow!(
|
||||||
|
"no matching backend for the section: {section}"
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for AnyBackend {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.backend_info().section)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ use std::fmt::Write;
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use super::{AnyBackend, Backend};
|
use crate::prelude::*;
|
||||||
use crate::Package;
|
|
||||||
|
|
||||||
/// A vector of tuples containing a Backends and a vector of unmanaged packages
|
/// A vector of tuples containing a Backends and a vector of unmanaged packages
|
||||||
/// for that backend.
|
/// for that backend.
|
||||||
@@ -11,17 +10,17 @@ use crate::Package;
|
|||||||
/// This struct is used to store a list of unmanaged packages or missing packages
|
/// This struct is used to store a list of unmanaged packages or missing packages
|
||||||
/// for all backends.
|
/// for all backends.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ToDoPerBackend(Vec<(AnyBackend, Vec<Package>)>);
|
pub struct ToDoPerBackend(Vec<(AnyBackend, Packages)>);
|
||||||
impl ToDoPerBackend {
|
impl ToDoPerBackend {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(vec![])
|
Self(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, item: (AnyBackend, Vec<Package>)) {
|
pub fn push(&mut self, item: (AnyBackend, Packages)) {
|
||||||
self.0.push(item);
|
self.0.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &(AnyBackend, Vec<Package>)> {
|
pub fn iter(&self) -> impl Iterator<Item = &(AnyBackend, Packages)> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ impl ToDoPerBackend {
|
|||||||
|
|
||||||
backend
|
backend
|
||||||
.install_packages(packages, noconfirm)
|
.install_packages(packages, noconfirm)
|
||||||
.with_context(|| format!("installing packages for {}", backend.get_section()))?;
|
.with_context(|| format!("installing packages for {backend}"))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -50,7 +49,7 @@ impl ToDoPerBackend {
|
|||||||
|
|
||||||
backend
|
backend
|
||||||
.remove_packages(packages, noconfirm)
|
.remove_packages(packages, noconfirm)
|
||||||
.with_context(|| format!("removing packages for {}", backend.get_section()))?;
|
.with_context(|| format!("removing packages for {backend}"))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -65,7 +64,7 @@ impl ToDoPerBackend {
|
|||||||
|
|
||||||
let mut segment = String::new();
|
let mut segment = String::new();
|
||||||
|
|
||||||
segment.write_str(&format!("[{}]", backend.get_section()))?;
|
segment.write_str(&format!("[{backend}]"))?;
|
||||||
for package in packages {
|
for package in packages {
|
||||||
segment.write_str(&format!("\n{package}"))?;
|
segment.write_str(&format!("\n{package}"))?;
|
||||||
}
|
}
|
||||||
@@ -95,7 +94,7 @@ impl Default for ToDoPerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for ToDoPerBackend {
|
impl IntoIterator for ToDoPerBackend {
|
||||||
type Item = (AnyBackend, Vec<Package>);
|
type Item = (AnyBackend, Packages);
|
||||||
|
|
||||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ use std::path::Path;
|
|||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
// Update the master README if fields change.
|
// Update the master README if fields change.
|
||||||
/// Config for the program, as listed in `$XDG_CONFIG_HOME/pacdef/pacdef.toml`.
|
/// Config for the program, as listed in `$XDG_CONFIG_HOME/pacdef/pacdef.toml`.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@@ -55,7 +57,7 @@ impl Config {
|
|||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.kind() == ErrorKind::NotFound {
|
if e.kind() == ErrorKind::NotFound {
|
||||||
bail!(crate::Error::ConfigFileNotFound)
|
bail!(Error::ConfigFileNotFound)
|
||||||
}
|
}
|
||||||
bail!("unexpected error occurred: {e:?}");
|
bail!("unexpected error occurred: {e:?}");
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-65
@@ -8,23 +8,14 @@ use std::process::Command;
|
|||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
use const_format::formatcp;
|
use const_format::formatcp;
|
||||||
|
|
||||||
use crate::backend::backend_trait::Backend;
|
|
||||||
use crate::backend::todo_per_backend::ToDoPerBackend;
|
|
||||||
use crate::backend::AnyBackend;
|
|
||||||
use crate::cli::{
|
|
||||||
CleanPackageAction, EditGroupAction, ExportGroupAction, GroupAction, GroupArguments,
|
|
||||||
ImportGroupAction, ListGroupAction, MainArguments, MainSubcommand, NewGroupAction,
|
|
||||||
PackageAction, PackageArguments, RemoveGroupAction, ReviewPackageAction, SearchPackageAction,
|
|
||||||
ShowGroupAction, SyncPackageAction, UnmanagedPackageAction, VersionArguments,
|
|
||||||
};
|
|
||||||
use crate::cmd::{run_edit_command, run_external_command};
|
use crate::cmd::{run_edit_command, run_external_command};
|
||||||
use crate::env::{get_editor, should_print_debug_info};
|
use crate::env::{get_editor, should_print_debug_info};
|
||||||
|
use crate::grouping::group::groups_to_backend_packages;
|
||||||
use crate::path::{binary_in_path, get_absolutized_file_paths, get_group_dir};
|
use crate::path::{binary_in_path, get_absolutized_file_paths, get_group_dir};
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::review::review;
|
use crate::review::review;
|
||||||
use crate::search::search_packages;
|
use crate::search::search_packages;
|
||||||
use crate::ui::get_user_confirmation;
|
use crate::ui::get_user_confirmation;
|
||||||
use crate::Group;
|
|
||||||
use crate::{Config, Error, Groups};
|
|
||||||
|
|
||||||
impl MainArguments {
|
impl MainArguments {
|
||||||
/// Run the action that was provided by the user as first argument.
|
/// Run the action that was provided by the user as first argument.
|
||||||
@@ -39,7 +30,7 @@ impl MainArguments {
|
|||||||
match self.subcommand {
|
match self.subcommand {
|
||||||
MainSubcommand::Group(group) => group.run(groups),
|
MainSubcommand::Group(group) => group.run(groups),
|
||||||
MainSubcommand::Package(package) => package.run(groups, config),
|
MainSubcommand::Package(package) => package.run(groups, config),
|
||||||
MainSubcommand::Version(version) => version.run(),
|
MainSubcommand::Version(version) => version.run(config),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,8 +38,8 @@ impl MainArguments {
|
|||||||
impl VersionArguments {
|
impl VersionArguments {
|
||||||
/// If the crate was compiled from git, return `pacdef, <version> (<hash>)`.
|
/// If the crate was compiled from git, return `pacdef, <version> (<hash>)`.
|
||||||
/// Otherwise return `pacdef, <version>`.
|
/// Otherwise return `pacdef, <version>`.
|
||||||
fn run(self) -> Result<()> {
|
fn run(self, config: &Config) -> Result<()> {
|
||||||
let backends = get_included_backends();
|
let backends = get_included_backends(config);
|
||||||
let mut result = format!("pacdef, version: {}\n", get_version_string());
|
let mut result = format!("pacdef, version: {}\n", get_version_string());
|
||||||
result.push_str("supported backends:");
|
result.push_str("supported backends:");
|
||||||
for b in backends {
|
for b in backends {
|
||||||
@@ -221,7 +212,7 @@ impl NewGroupAction {
|
|||||||
for new_group in &self.new_groups {
|
for new_group in &self.new_groups {
|
||||||
ensure!(
|
ensure!(
|
||||||
new_group != "." && new_group != "..",
|
new_group != "." && new_group != "..",
|
||||||
crate::Error::InvalidGroupName(new_group.clone())
|
Error::InvalidGroupName(new_group.clone())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,10 +227,7 @@ impl NewGroupAction {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for file in &paths {
|
for file in &paths {
|
||||||
ensure!(
|
ensure!(!file.exists(), Error::GroupAlreadyExists(file.clone()));
|
||||||
!file.exists(),
|
|
||||||
crate::Error::GroupAlreadyExists(file.clone())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for file in &paths {
|
for file in &paths {
|
||||||
@@ -284,10 +272,7 @@ impl ShowGroupAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return an error if any arg was not found
|
// return an error if any arg was not found
|
||||||
ensure!(
|
ensure!(errors.is_empty(), Error::MultipleGroupsNotFound(errors));
|
||||||
errors.is_empty(),
|
|
||||||
crate::Error::MultipleGroupsNotFound(errors)
|
|
||||||
);
|
|
||||||
|
|
||||||
let show_more_than_one_group = self.show_groups.len() > 1;
|
let show_more_than_one_group = self.show_groups.len() > 1;
|
||||||
|
|
||||||
@@ -398,50 +383,38 @@ impl UnmanagedPackageAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_missing_packages(groups: &Groups, config: &Config) -> Result<ToDoPerBackend> {
|
fn get_missing_packages(groups: &Groups, config: &Config) -> Result<ToDoPerBackend> {
|
||||||
|
let backend_packages = groups_to_backend_packages(groups, config)?;
|
||||||
|
|
||||||
let mut to_install = ToDoPerBackend::new();
|
let mut to_install = ToDoPerBackend::new();
|
||||||
|
|
||||||
for mut backend in AnyBackend::iter() {
|
for (any_backend, packages) in &backend_packages {
|
||||||
|
let backend_info = any_backend.backend_info();
|
||||||
|
|
||||||
if config
|
if config
|
||||||
.disabled_backends
|
.disabled_backends
|
||||||
.contains(&backend.get_section().to_string())
|
.contains(&backend_info.section.to_string())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !binary_in_path(backend.get_binary())? {
|
if !binary_in_path(&backend_info.binary)? {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
overwrite_values_from_config(&mut backend, config);
|
let managed_backend = ManagedBackend {
|
||||||
backend.load(groups);
|
packages: packages.clone(),
|
||||||
|
any_backend: any_backend.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
match backend.get_missing_packages_sorted() {
|
match managed_backend.get_missing_packages_sorted() {
|
||||||
Ok(diff) => to_install.push((backend, diff)),
|
Ok(diff) => to_install.push((any_backend.clone(), diff)),
|
||||||
Err(error) => show_backend_query_error(&error, &backend),
|
Err(error) => show_backend_query_error(&error, any_backend),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(to_install)
|
Ok(to_install)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overwrite_values_from_config(backend: &mut AnyBackend, config: &Config) {
|
|
||||||
#[cfg(feature = "arch")]
|
|
||||||
{
|
|
||||||
if let AnyBackend::Arch(arch) = backend {
|
|
||||||
arch.binary.clone_from(&config.aur_helper);
|
|
||||||
arch.aur_rm_args.clone_from(&config.aur_rm_args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let AnyBackend::Flatpak(flatpak) = backend {
|
|
||||||
flatpak.systemwide = config.flatpak_systemwide;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let AnyBackend::Python(python) = backend {
|
|
||||||
python.binary.clone_from(&config.pip_binary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a list of unmanaged packages per backend.
|
/// Get a list of unmanaged packages per backend.
|
||||||
///
|
///
|
||||||
/// This method loops through all enabled `Backend`s whose binary is in `PATH`.
|
/// This method loops through all enabled `Backend`s whose binary is in `PATH`.
|
||||||
@@ -450,29 +423,35 @@ fn overwrite_values_from_config(backend: &mut AnyBackend, config: &Config) {
|
|||||||
///
|
///
|
||||||
/// This function will propagate errors from the individual backends.
|
/// This function will propagate errors from the individual backends.
|
||||||
fn get_unmanaged_packages(groups: &Groups, config: &Config) -> Result<ToDoPerBackend> {
|
fn get_unmanaged_packages(groups: &Groups, config: &Config) -> Result<ToDoPerBackend> {
|
||||||
let mut result = ToDoPerBackend::new();
|
let backend_packages = groups_to_backend_packages(groups, config)?;
|
||||||
|
|
||||||
for mut backend in AnyBackend::iter() {
|
let mut todo_unmanaged = ToDoPerBackend::new();
|
||||||
|
|
||||||
|
for (any_backend, packages) in &backend_packages {
|
||||||
|
let backend_info = any_backend.backend_info();
|
||||||
if config
|
if config
|
||||||
.disabled_backends
|
.disabled_backends
|
||||||
.contains(&backend.get_section().to_string())
|
.contains(&backend_info.section.to_string())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !binary_in_path(backend.get_binary())? {
|
if !binary_in_path(&backend_info.binary)? {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
overwrite_values_from_config(&mut backend, config);
|
let managed_backend = ManagedBackend {
|
||||||
backend.load(groups);
|
packages: packages.clone(),
|
||||||
|
any_backend: any_backend.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
match backend.get_unmanaged_packages_sorted() {
|
match managed_backend.get_unmanaged_packages_sorted() {
|
||||||
Ok(unmanaged) => result.push((backend, unmanaged)),
|
Ok(unmanaged) => todo_unmanaged.push((any_backend.clone(), unmanaged)),
|
||||||
Err(error) => show_backend_query_error(&error, &backend),
|
Err(error) => show_backend_query_error(&error, any_backend),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(result)
|
|
||||||
|
Ok(todo_unmanaged)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the parent directory of the `path` if that directory does not exist.
|
/// Create the parent directory of the `path` if that directory does not exist.
|
||||||
@@ -553,14 +532,13 @@ fn find_groups_by_name<'a>(names: &[String], groups: &'a Groups) -> Result<Vec<&
|
|||||||
/// Show the error chain for an error that has occurred when a backend was queried
|
/// Show the error chain for an error that has occurred when a backend was queried
|
||||||
/// if the `RUST_BACKTRACE` env variable is set to `1` or `full`.
|
/// if the `RUST_BACKTRACE` env variable is set to `1` or `full`.
|
||||||
fn show_backend_query_error(error: &anyhow::Error, backend: &AnyBackend) {
|
fn show_backend_query_error(error: &anyhow::Error, backend: &AnyBackend) {
|
||||||
let section = backend.get_section();
|
|
||||||
if should_print_debug_info() {
|
if should_print_debug_info() {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"skipping backend '{section}': {}",
|
"skipping backend '{backend}': {}",
|
||||||
error.chain().map(|x| x.to_string()).collect::<String>()
|
error.chain().map(|x| x.to_string()).collect::<String>()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("skipping backend '{section}': {error}");
|
log::warn!("skipping backend '{backend}': {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,10 +556,10 @@ pub const fn get_version_string() -> &'static str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a vector with the names of all backends, sorted alphabetically.
|
/// Get a vector with the names of all backends, sorted alphabetically.
|
||||||
fn get_included_backends() -> Vec<&'static str> {
|
fn get_included_backends(config: &Config) -> Vec<&'static str> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
for backend in AnyBackend::iter() {
|
for backend in AnyBackend::all(config) {
|
||||||
result.push(backend.get_section());
|
result.push(backend.backend_info().section);
|
||||||
}
|
}
|
||||||
result.sort_unstable();
|
result.sort_unstable();
|
||||||
result
|
result
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::{BTreeSet, HashSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::fs::{create_dir, read_to_string, File};
|
use std::fs::{create_dir, read_to_string, File};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@@ -11,11 +11,27 @@ use walkdir::WalkDir;
|
|||||||
|
|
||||||
use crate::path::get_relative_path;
|
use crate::path::get_relative_path;
|
||||||
|
|
||||||
use super::{Package, Section};
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// A set of groups
|
/// A set of groups
|
||||||
pub type Groups = BTreeSet<Group>;
|
pub type Groups = BTreeSet<Group>;
|
||||||
|
|
||||||
|
pub type BackendPackages = BTreeMap<AnyBackend, Packages>;
|
||||||
|
pub fn groups_to_backend_packages(groups: &Groups, config: &Config) -> Result<BackendPackages> {
|
||||||
|
let mut backend_packages = BackendPackages::new();
|
||||||
|
|
||||||
|
for group in groups {
|
||||||
|
for section in &group.sections {
|
||||||
|
backend_packages
|
||||||
|
.entry(AnyBackend::from_section(§ion.name, config)?)
|
||||||
|
.or_default()
|
||||||
|
.extend(section.packages.iter().cloned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(backend_packages)
|
||||||
|
}
|
||||||
|
|
||||||
/// Representation of a group file.
|
/// Representation of a group file.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Group {
|
pub struct Group {
|
||||||
@@ -23,7 +39,7 @@ pub struct Group {
|
|||||||
/// base dir).
|
/// base dir).
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The sections in the file which in turn hold the packages.
|
/// The sections in the file which in turn hold the packages.
|
||||||
pub sections: HashSet<Section>,
|
pub sections: Sections,
|
||||||
/// The absolute path of the original file.
|
/// The absolute path of the original file.
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
/// Whether the main program should warn this group being loaded from a symlink.
|
/// Whether the main program should warn this group being loaded from a symlink.
|
||||||
@@ -143,7 +159,7 @@ impl Group {
|
|||||||
let name = extract_group_name(path, group_dir.as_ref());
|
let name = extract_group_name(path, group_dir.as_ref());
|
||||||
|
|
||||||
let mut lines = content.lines().peekable();
|
let mut lines = content.lines().peekable();
|
||||||
let mut sections = HashSet::new();
|
let mut sections = Sections::new();
|
||||||
|
|
||||||
while lines.peek().is_some() {
|
while lines.peek().is_some() {
|
||||||
let result = Section::try_from_lines(&mut lines).context("reading section");
|
let result = Section::try_from_lines(&mut lines).context("reading section");
|
||||||
@@ -180,7 +196,7 @@ impl Group {
|
|||||||
///
|
///
|
||||||
/// This function returns an error if the group file cannot be read, or if the
|
/// This function returns an error if the group file cannot be read, or if the
|
||||||
/// file cannot be written to.
|
/// file cannot be written to.
|
||||||
pub fn save_packages(&self, section_header: &str, packages: &[Package]) -> Result<()> {
|
pub fn save_packages(&self, section_header: &str, packages: &Packages) -> Result<()> {
|
||||||
let mut content = read_to_string(&self.path)
|
let mut content = read_to_string(&self.path)
|
||||||
.with_context(|| format!("reading existing file contents from {:?}", &self.path))?;
|
.with_context(|| format!("reading existing file contents from {:?}", &self.path))?;
|
||||||
|
|
||||||
@@ -248,7 +264,7 @@ impl Display for Group {
|
|||||||
fn write_packages_to_existing_section(
|
fn write_packages_to_existing_section(
|
||||||
group_file_content: &mut String,
|
group_file_content: &mut String,
|
||||||
section_header: &str,
|
section_header: &str,
|
||||||
packages: &[Package],
|
packages: &Packages,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let idx_of_first_package_line_in_section =
|
let idx_of_first_package_line_in_section =
|
||||||
find_first_package_line_in_section(group_file_content, section_header)?;
|
find_first_package_line_in_section(group_file_content, section_header)?;
|
||||||
@@ -290,7 +306,7 @@ fn find_first_package_line_in_section(
|
|||||||
fn add_new_section_with_packages(
|
fn add_new_section_with_packages(
|
||||||
group_file_content: &mut String,
|
group_file_content: &mut String,
|
||||||
section_header: &str,
|
section_header: &str,
|
||||||
packages: &[Package],
|
packages: &Packages,
|
||||||
) {
|
) {
|
||||||
group_file_content.push('\n');
|
group_file_content.push('\n');
|
||||||
group_file_content.push_str(section_header);
|
group_file_content.push_str(section_header);
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ all groups using [`Group::load`], which in turn will get all packages from all
|
|||||||
sections.
|
sections.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mod group;
|
pub mod group;
|
||||||
mod package;
|
pub mod package;
|
||||||
mod section;
|
pub mod section;
|
||||||
|
|
||||||
pub use group::Group;
|
|
||||||
pub use group::Groups;
|
|
||||||
pub use package::Package;
|
|
||||||
pub use section::Section;
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::{Display, Write};
|
use std::fmt::{Display, Write};
|
||||||
use std::hash::Hash;
|
|
||||||
|
pub type Packages = BTreeSet<Package>;
|
||||||
|
|
||||||
/// A struct to represent a single package, consisting of a `name`, and
|
/// A struct to represent a single package, consisting of a `name`, and
|
||||||
/// optionally a `repo`.
|
/// optionally a `repo`.
|
||||||
#[derive(Debug, Eq, PartialOrd, Ord, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Package {
|
pub struct Package {
|
||||||
/// The name of the package
|
/// The name of the package
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -51,7 +54,7 @@ impl Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to parse a string (from a line in a group file) and return a package.
|
/// 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.
|
/// From the string, any possible comment is removed and whitespace is trimmed.package
|
||||||
/// Returns `None` if there is nothing left after trimming.
|
/// Returns `None` if there is nothing left after trimming.
|
||||||
pub fn try_from<S>(s: S) -> Option<Self>
|
pub fn try_from<S>(s: S) -> Option<Self>
|
||||||
where
|
where
|
||||||
@@ -69,22 +72,25 @@ impl Package {
|
|||||||
|
|
||||||
impl PartialEq for Package {
|
impl PartialEq for Package {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
let self_repo = self.repo.as_ref();
|
self.cmp(other).is_eq()
|
||||||
let other_repo = other.repo.as_ref();
|
|
||||||
|
|
||||||
// iff both packages have repos, they must be identical, otherwise we don't care
|
|
||||||
let repos_are_identical =
|
|
||||||
self_repo.map_or(true, |sr| other_repo.map_or(true, |or| sr == or));
|
|
||||||
|
|
||||||
let names_are_identical = self.name == other.name;
|
|
||||||
|
|
||||||
names_are_identical && repos_are_identical
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Eq for Package {}
|
||||||
impl Hash for Package {
|
impl PartialOrd for Package {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.name.hash(state);
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for Package {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.name
|
||||||
|
.cmp(&other.name)
|
||||||
|
.then(self.repo.as_ref().map_or(Ordering::Equal, |self_repo| {
|
||||||
|
other
|
||||||
|
.repo
|
||||||
|
.as_ref()
|
||||||
|
.map_or(Ordering::Equal, |other_repo| self_repo.cmp(other_repo))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::{Display, Write};
|
use std::fmt::{Display, Write};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use anyhow::{ensure, Context, Result};
|
use anyhow::{ensure, Context, Result};
|
||||||
|
|
||||||
use super::Package;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type Sections = BTreeSet<Section>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Section {
|
pub struct Section {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub packages: HashSet<Package>,
|
pub packages: Packages,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Section {
|
impl Section {
|
||||||
pub fn new(name: String, packages: HashSet<Package>) -> Self {
|
pub fn new(name: String, packages: Packages) -> Self {
|
||||||
Self { name, packages }
|
Self { name, packages }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_from_lines<'a>(iter: &mut Peekable<impl Iterator<Item = &'a str>>) -> Result<Self> {
|
pub fn try_from_lines<'a>(iter: &mut Peekable<impl Iterator<Item = &'a str>>) -> Result<Self> {
|
||||||
let name = find_next_section_name(iter)?;
|
let name = find_next_section_name(iter)?;
|
||||||
|
|
||||||
let mut packages = HashSet::new();
|
let mut packages = Packages::new();
|
||||||
|
|
||||||
while next_line_might_be_package(iter) {
|
while next_line_might_be_package(iter) {
|
||||||
if let Some(package) = Package::try_from(iter.next().expect("we checked this is some"))
|
if let Some(package) = Package::try_from(iter.next().expect("we checked this is some"))
|
||||||
@@ -36,7 +38,7 @@ impl Section {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_package(package: Package, packages: &mut HashSet<Package>) {
|
fn insert_package(package: Package, packages: &mut Packages) {
|
||||||
let package_name = package.name.clone();
|
let package_name = package.name.clone();
|
||||||
let newly_inserted = packages.insert(package);
|
let newly_inserted = packages.insert(package);
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,9 @@ mod review;
|
|||||||
mod search;
|
mod search;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
mod prelude;
|
||||||
|
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
|
||||||
pub use crate::config::Config;
|
pub use prelude::{Config, Error, Group};
|
||||||
pub use crate::errors::Error;
|
|
||||||
pub use crate::grouping::Group;
|
|
||||||
pub use crate::grouping::Groups;
|
|
||||||
pub use crate::grouping::Package;
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#[cfg(feature = "arch")]
|
||||||
|
pub use crate::backend::actual::arch::Arch;
|
||||||
|
#[cfg(feature = "debian")]
|
||||||
|
pub use crate::backend::actual::debian::Debian;
|
||||||
|
pub use crate::backend::actual::{
|
||||||
|
fedora::Fedora, flatpak::Flatpak, python::Python, rust::Rust, rustup::Rustup, void::Void,
|
||||||
|
};
|
||||||
|
pub use crate::backend::backend_trait::{Backend, BackendInfo, Switches, Text};
|
||||||
|
pub use crate::backend::todo_per_backend::ToDoPerBackend;
|
||||||
|
pub use crate::backend::AnyBackend;
|
||||||
|
pub use crate::backend::ManagedBackend;
|
||||||
|
pub use crate::cli::CleanPackageAction;
|
||||||
|
pub use crate::cli::EditGroupAction;
|
||||||
|
pub use crate::cli::ExportGroupAction;
|
||||||
|
pub use crate::cli::GroupAction;
|
||||||
|
pub use crate::cli::GroupArguments;
|
||||||
|
pub use crate::cli::ImportGroupAction;
|
||||||
|
pub use crate::cli::ListGroupAction;
|
||||||
|
pub use crate::cli::MainArguments;
|
||||||
|
pub use crate::cli::MainSubcommand;
|
||||||
|
pub use crate::cli::NewGroupAction;
|
||||||
|
pub use crate::cli::PackageAction;
|
||||||
|
pub use crate::cli::PackageArguments;
|
||||||
|
pub use crate::cli::RemoveGroupAction;
|
||||||
|
pub use crate::cli::ReviewPackageAction;
|
||||||
|
pub use crate::cli::SearchPackageAction;
|
||||||
|
pub use crate::cli::ShowGroupAction;
|
||||||
|
pub use crate::cli::SyncPackageAction;
|
||||||
|
pub use crate::cli::UnmanagedPackageAction;
|
||||||
|
pub use crate::cli::VersionArguments;
|
||||||
|
pub use crate::config::Config;
|
||||||
|
pub use crate::errors::Error;
|
||||||
|
pub use crate::grouping::{
|
||||||
|
group::{Group, Groups},
|
||||||
|
package::{Package, Packages},
|
||||||
|
section::{Section, Sections},
|
||||||
|
};
|
||||||
|
pub use crate::path::binary_in_path;
|
||||||
|
pub use crate::path::get_absolutized_file_paths;
|
||||||
|
pub use crate::path::get_cargo_home;
|
||||||
|
pub use crate::path::get_config_path;
|
||||||
|
pub use crate::path::get_config_path_old_version;
|
||||||
|
pub use crate::path::get_group_dir;
|
||||||
|
pub use crate::path::get_home_dir;
|
||||||
|
pub use crate::path::get_pacdef_base_dir;
|
||||||
|
pub use crate::path::get_relative_path;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{backend::AnyBackend, Group, Package};
|
use crate::prelude::*;
|
||||||
|
|
||||||
use super::strategy::Strategy;
|
use super::strategy::Strategy;
|
||||||
|
|
||||||
@@ -48,9 +48,9 @@ impl ReviewsPerBackend {
|
|||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
||||||
for (backend, actions) in self {
|
for (backend, actions) in self {
|
||||||
let mut to_delete = vec![];
|
let mut to_delete = Packages::new();
|
||||||
let mut assign_group = vec![];
|
let mut assign_group = vec![];
|
||||||
let mut as_dependency = vec![];
|
let mut as_dependency = Packages::new();
|
||||||
|
|
||||||
extract_actions(
|
extract_actions(
|
||||||
actions,
|
actions,
|
||||||
@@ -91,15 +91,19 @@ pub enum ContinueWithReview {
|
|||||||
|
|
||||||
fn extract_actions(
|
fn extract_actions(
|
||||||
actions: Vec<ReviewAction>,
|
actions: Vec<ReviewAction>,
|
||||||
to_delete: &mut Vec<Package>,
|
to_delete: &mut Packages,
|
||||||
assign_group: &mut Vec<(Package, Group)>,
|
assign_group: &mut Vec<(Package, Group)>,
|
||||||
as_dependency: &mut Vec<Package>,
|
as_dependency: &mut Packages,
|
||||||
) {
|
) {
|
||||||
for action in actions {
|
for action in actions {
|
||||||
match action {
|
match action {
|
||||||
ReviewAction::Delete(package) => to_delete.push(package),
|
ReviewAction::Delete(package) => {
|
||||||
|
to_delete.insert(package);
|
||||||
|
}
|
||||||
ReviewAction::AssignGroup(package, group) => assign_group.push((package, group)),
|
ReviewAction::AssignGroup(package, group) => assign_group.push((package, group)),
|
||||||
ReviewAction::AsDependency(package) => as_dependency.push(package),
|
ReviewAction::AsDependency(package) => {
|
||||||
|
as_dependency.insert(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ use std::io::{stdin, stdout, Write};
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::backend::backend_trait::Backend;
|
use crate::prelude::*;
|
||||||
use crate::backend::todo_per_backend::ToDoPerBackend;
|
|
||||||
use crate::ui::{get_user_confirmation, read_single_char_from_terminal};
|
use crate::ui::{get_user_confirmation, read_single_char_from_terminal};
|
||||||
use crate::{Group, Groups, Package};
|
|
||||||
|
|
||||||
use self::datastructures::{ContinueWithReview, ReviewAction, ReviewIntention, ReviewsPerBackend};
|
use self::datastructures::{ContinueWithReview, ReviewAction, ReviewIntention, ReviewsPerBackend};
|
||||||
use self::strategy::Strategy;
|
use self::strategy::Strategy;
|
||||||
@@ -24,7 +22,7 @@ pub fn review(todo_per_backend: ToDoPerBackend, groups: &Groups) -> Result<()> {
|
|||||||
'outer: for (backend, packages) in todo_per_backend {
|
'outer: for (backend, packages) in todo_per_backend {
|
||||||
let mut actions = vec![];
|
let mut actions = vec![];
|
||||||
for package in packages {
|
for package in packages {
|
||||||
println!("{}: {package}", backend.get_section());
|
println!("{}: {package}", backend.backend_info().section);
|
||||||
match get_action_for_package(package, groups, &mut actions, &backend)? {
|
match get_action_for_package(package, groups, &mut actions, &backend)? {
|
||||||
ContinueWithReview::Yes => continue,
|
ContinueWithReview::Yes => continue,
|
||||||
ContinueWithReview::No => return Ok(()),
|
ContinueWithReview::No => return Ok(()),
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
backend::{backend_trait::Backend, AnyBackend},
|
|
||||||
Group, Package,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Strategy {
|
pub struct Strategy {
|
||||||
backend: AnyBackend,
|
backend: AnyBackend,
|
||||||
delete: Vec<Package>,
|
delete: Packages,
|
||||||
as_dependency: Vec<Package>,
|
as_dependency: Packages,
|
||||||
assign_group: Vec<(Package, Group)>,
|
assign_group: Vec<(Package, Group)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strategy {
|
impl Strategy {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
backend: AnyBackend,
|
backend: AnyBackend,
|
||||||
delete: Vec<Package>,
|
delete: Packages,
|
||||||
as_dependency: Vec<Package>,
|
as_dependency: Packages,
|
||||||
assign_group: Vec<(Package, Group)>,
|
assign_group: Vec<(Package, Group)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -49,7 +46,7 @@ impl Strategy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("[{}]", self.backend.get_section());
|
println!("[{}]", self.backend.backend_info().section);
|
||||||
|
|
||||||
if !self.delete.is_empty() {
|
if !self.delete.is_empty() {
|
||||||
println!("delete:");
|
println!("delete:");
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
grouping::{Group, Package, Section},
|
|
||||||
Groups,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Find all packages in all groups whose name match the regex from the
|
/// Find all packages in all groups whose name match the regex from the
|
||||||
/// command-line arguments. Print the name of the packages per group and
|
/// command-line arguments. Print the name of the packages per group and
|
||||||
/// section.
|
/// section.
|
||||||
|
|||||||
Reference in New Issue
Block a user