Skip to content

Commit

Permalink
Group parsing (#4)
Browse files Browse the repository at this point in the history
* strum to iterate through backend enums

Signed-off-by: innocentzero <[email protected]>

* add toml parsing for group files

Adds TOML parsing for group files. Some of the
backend trait types for various backends need to
be modified for TOML compatibility.

Signed-off-by: innocentzero <[email protected]>

* optional dependency install option for arch

Signed-off-by: innocentzero <[email protected]>

* implement cargo install features

Signed-off-by: innocentzero <[email protected]>

* refactor group file loading

Signed-off-by: innocentzero <[email protected]>

---------

Signed-off-by: innocentzero <[email protected]>
  • Loading branch information
InnocentZero authored Sep 1, 2024
1 parent a67cbb2 commit e217f5b
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 75 deletions.
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dirs = "5.0.1"
home = "0.5.9"
pretty_env_logger = "0.5.0"
dialoguer = "0.11.0"
strum = { version = "0.26.3", features = ["derive"] }

[profile.release]
lto = "off"
Expand Down
Empty file added rustfmt.toml
Empty file.
6 changes: 4 additions & 2 deletions src/backend/apt.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use std::collections::BTreeMap;

use anyhow::Result;
use serde::{Deserialize, Serialize};

use crate::cmd::{command_found, run_args, run_args_for_stdout};
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Apt;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AptQueryInfo {
pub explicit: bool,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AptMakeImplicit;

impl Backend for Apt {
Expand Down
22 changes: 20 additions & 2 deletions src/backend/arch.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

use crate::cmd::{command_found, run_args, run_args_for_stdout};
use crate::prelude::*;

#[derive(Debug, Clone, Copy, derive_more::Display)]
#[derive(Debug, Clone, Copy, Default, derive_more::Display)]
pub struct Arch;

#[derive(Debug, Clone)]
Expand All @@ -14,10 +16,26 @@ pub struct ArchQueryInfo {

pub struct ArchMakeImplicit;

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ArchOptionalDeps(Vec<String>);

impl Deref for ArchOptionalDeps {
type Target = Vec<String>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for ArchOptionalDeps {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl Backend for Arch {
type PackageId = String;
type RemoveOptions = ();
type InstallOptions = ();
type InstallOptions = ArchOptionalDeps;
type QueryInfo = ArchQueryInfo;
type Modification = ArchMakeImplicit;

Expand Down
128 changes: 113 additions & 15 deletions src/backend/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@ use std::collections::BTreeMap;
use std::io::ErrorKind::NotFound;

use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::cmd::{command_found, run_args};
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Cargo;

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CargoInstallOptions {
git: Option<String>,
all_features: bool,
no_default_features: bool,
}

impl Backend for Cargo {
type PackageId = String;
type RemoveOptions = ();
type InstallOptions = ();
type QueryInfo = ();
type InstallOptions = CargoInstallOptions;
type QueryInfo = CargoInstallOptions;
type Modification = ();

fn query_installed_packages(_: &Config) -> Result<BTreeMap<Self::PackageId, Self::QueryInfo>> {
Expand Down Expand Up @@ -44,10 +52,78 @@ impl Backend for Cargo {
_: &Config,
) -> Result<()> {
run_args(
["cargo", "install"]
.into_iter()
.chain(packages.keys().map(String::as_str)),
)
["cargo", "install"].into_iter().chain(
packages
.iter()
.filter(|(_, opts)| {
opts.git.is_none() && !opts.all_features && !opts.no_default_features
})
.map(|(name, _)| name)
.map(String::as_str),
),
)?;
for (package, options) in packages {
match options {
CargoInstallOptions {
git: _,
all_features: true,
no_default_features: true,
} => {
bail!("Invalid config parameters for {package}");
}

CargoInstallOptions {
git: None,
all_features: false,
no_default_features: false,
} => {} // cannot be matched

CargoInstallOptions {
git: Some(remote),
all_features: false,
no_default_features: false,
} => run_args(["cargo", "install", "--git", remote, package])?,

CargoInstallOptions {
git: Some(remote),
all_features: true,
no_default_features: false,
} => run_args([
"cargo",
"install",
"--all-features",
"--git",
remote,
package,
])?,

CargoInstallOptions {
git: Some(remote),
all_features: false,
no_default_features: true,
} => run_args([
"cargo",
"install",
"--no-default-features",
"--git",
remote,
package,
])?,

CargoInstallOptions {
git: None,
all_features: true,
no_default_features: false,
} => run_args(["cargo", "install", "--all-features", package])?,

CargoInstallOptions {
git: None,
all_features: false,
no_default_features: true,
} => run_args(["cargo", "install", "--no-default-features", package])?,
}
}
Ok(())
}

fn modify_packages(
Expand All @@ -70,22 +146,44 @@ impl Backend for Cargo {
}
}

fn extract_packages(contents: &str) -> Result<BTreeMap<String, ()>> {
fn extract_packages(contents: &str) -> Result<BTreeMap<String, CargoInstallOptions>> {
let json: Value = serde_json::from_str(contents).context("parsing JSON from crates file")?;

let result: BTreeMap<String, ()> = json
let result: BTreeMap<String, CargoInstallOptions> = json
.get("installs")
.context("get 'installs' field from json")?
.as_object()
.context("getting object")?
.into_iter()
.map(|(name, _)| name)
.map(|name| {
name.split_whitespace()
.next()
.expect("identifier is whitespace-delimited")
.map(|(name, value)| {
let (name, git_repo) = name
.split_once('+')
.expect("Resolve git status and name separately");

let all_features = value
.as_object()
.expect("Won't fail")
.get("all_features")
.expect("Won't fail")
.as_bool()
.expect("Won't fail");

let no_default_features = value
.as_object()
.expect("Won't fail")
.get("no_default_features")
.expect("Won't fail")
.as_bool()
.expect("Won't fail");
(
name.to_string(),
CargoInstallOptions {
git: git_repo.split_once('#').map(|(repo, _)| repo.to_string()),
all_features,
no_default_features,
},
)
})
.map(|name| (name.to_string(), ()))
.collect();

Ok(result)
Expand Down
7 changes: 4 additions & 3 deletions src/backend/dnf.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use std::collections::BTreeMap;

use anyhow::Result;
use serde::{Deserialize, Serialize};

use crate::cmd::{command_found, run_args, run_args_for_stdout};
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Dnf;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DnfQueryInfo {
pub user: bool,
}

#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DnfInstallOptions {
repo: Option<String>,
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/flatpak.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use anyhow::Result;
use crate::cmd::{command_found, run_args, run_args_for_stdout};
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Flatpak;

#[derive(Debug, Clone)]
Expand Down
33 changes: 3 additions & 30 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,17 @@ pub mod xbps;

use std::{collections::BTreeMap, str::FromStr};

pub use crate::packages::AnyBackend;
use crate::prelude::*;
use anyhow::{Context, Result};

#[derive(Debug, Copy, Clone, derive_more::Display)]
pub enum AnyBackend {
Apt(Apt),
Arch(Arch),
Cargo(Cargo),
Dnf(Dnf),
Flatpak(Flatpak),
Pip(Pip),
Pipx(Pipx),
Rustup(Rustup),
Xbps(Xbps),
}

impl AnyBackend {
pub const ALL: [Self; 9] = [
Self::Apt(Apt),
Self::Arch(Arch),
Self::Cargo(Cargo),
Self::Dnf(Dnf),
Self::Flatpak(Flatpak),
Self::Pip(Pip),
Self::Pipx(Pipx),
Self::Rustup(Rustup),
Self::Xbps(Xbps),
];
}
use strum::IntoEnumIterator;

impl FromStr for AnyBackend {
type Err = anyhow::Error;

fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
Self::ALL
.iter()
Self::iter()
.find(|x| x.to_string().to_lowercase() == s)
.copied()
.with_context(|| anyhow::anyhow!("unable to parse backend from string: {s}"))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/pip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::cmd::run_args;
use crate::cmd::run_args_for_stdout;
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Pip;

#[derive(Debug, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion src/backend/pipx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::cmd::run_args;
use crate::cmd::run_args_for_stdout;
use crate::prelude::*;

#[derive(Debug, Copy, Clone, derive_more::Display)]
#[derive(Debug, Copy, Clone, Default, derive_more::Display)]
pub struct Pipx;

impl Backend for Pipx {
Expand Down
Loading

0 comments on commit e217f5b

Please sign in to comment.