Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 92 additions & 44 deletions src/cmd/pkg_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use crate::errors::*;

use crate::args::Install;
use crate::api::Client;
use crate::args;
use crate::config::Config;
use crate::args::Install;
use crate::cmd::{Cmd, LiteCmd};
use crate::config::Config;
use crate::engine::{Library, Module};
use crate::keyring::KeyRing;
use crate::registry::{self, InstallTask, UpdateTask, Updater};
use crate::shell::Shell;
use crate::update::AutoUpdater;
use crate::worker;
use colored::{Color, Colorize};
use sn0int_common::ModuleID;
use sn0int_common::metadata::Stealth;
use sn0int_common::ModuleID;
use std::collections::HashSet;
use std::fmt::Write;
use std::sync::Arc;
use structopt::StructOpt;
use structopt::clap::AppSettings;

use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(global_settings = &[AppSettings::ColoredHelp])]
Expand All @@ -37,22 +37,22 @@ pub struct ArgsInteractive {
#[derive(Debug, StructOpt)]
pub enum SubCommand {
/// List installed modules
#[structopt(name="list")]
#[structopt(name = "list")]
List(List),
/// Install module from registry
#[structopt(name="install")]
#[structopt(name = "install")]
Install(args::Install),
/// Search modules in registry
#[structopt(name="search")]
#[structopt(name = "search")]
Search(args::Search),
/// Update modules
#[structopt(name="update")]
#[structopt(name = "update")]
Update(Update),
/// Uninstall a module
#[structopt(name="uninstall")]
#[structopt(name = "uninstall")]
Uninstall(Uninstall),
/// Install all featured modules
#[structopt(name="quickstart")]
#[structopt(name = "quickstart")]
Quickstart,
}

Expand All @@ -61,33 +61,31 @@ pub enum SubCommandInteractive {
#[structopt(flatten)]
Base(SubCommand),
/// Reload modules
#[structopt(name="reload")]
#[structopt(name = "reload")]
Reload(Reload),
}

#[derive(Debug, StructOpt)]
pub struct List {
/// Only show modules with a specific input source
#[structopt(long="source")]
#[structopt(long = "source")]
pub source: Option<String>,
/// List outdated modules
#[structopt(long="outdated")]
#[structopt(long = "outdated")]
pub outdated_only: bool,
/// Only show modules with equal or better stealth level
#[structopt(long="stealth", possible_values=Stealth::variants())]
pub stealth: Option<Stealth>,
/// Filter by pattern
#[structopt(default_value="*")]
#[structopt(default_value = "*")]
pub pattern: String,
}

#[derive(Debug, StructOpt)]
pub struct Reload {
}
pub struct Reload {}

#[derive(Debug, StructOpt)]
pub struct Update {
}
pub struct Update {}

#[derive(Debug, StructOpt)]
pub struct Uninstall {
Expand All @@ -108,9 +106,39 @@ fn write_tag(out: &mut String, color: Color, txt: &str) -> Result<()> {

fn print_module(module: &Module, is_outdated: bool) -> Result<()> {
let mut out = String::new();
write!(&mut out, "{}/{} {}", module.author().purple(),
module.name(),
module.version().blue())?;
write!(
&mut out,
"{}/{} {}",
module.author().purple(),
module.name(),
module.version().blue()
)?;

let key_ring = KeyRing::load(&KeyRing::path().unwrap());

if !module.keyring_access().is_empty() {
let mut keys = String::new();
for key in module.keyring_access() {
match &key_ring {
Ok(kr) => {
if kr.get_all_for(key).is_empty() {
write!(
keys,
"{}, ",
&format!("{}(missing)", &key).color(Color::Red)
)?;
} else {
write!(keys, "{}, ", &key.color(Color::Green))?;
}
}
Err(_) => {
write!(keys, "{}, ", &key)?;
}
}
}
let keys = keys.strip_suffix(", ").unwrap();
write_tag(&mut out, Color::Cyan, &format!("Keyring: {}", keys))?;
}

match module.stealth() {
Stealth::Loud => write_tag(&mut out, Color::Yellow, "LOUD")?,
Expand All @@ -128,7 +156,11 @@ fn print_module(module: &Module, is_outdated: bool) -> Result<()> {
Ok(())
}

fn run_subcommand(subcommand: SubCommand, library: &Library, config: &Config) -> Result<ModuleReload> {
fn run_subcommand(
subcommand: SubCommand,
library: &Library,
config: &Config,
) -> Result<ModuleReload> {
match subcommand {
SubCommand::List(list) => {
let autoupdate = AutoUpdater::load()?;
Expand Down Expand Up @@ -161,21 +193,22 @@ fn run_subcommand(subcommand: SubCommand, library: &Library, config: &Config) ->
print_module(module, is_outdated)?;
}
Ok(ModuleReload::No)
},
}
SubCommand::Install(install) => {
registry::run_install(install, config)?;
// trigger reload
Ok(ModuleReload::Yes)
},
}
SubCommand::Search(search) => {
registry::run_search(library, &search, config)?;
Ok(ModuleReload::No)
},
}
SubCommand::Update(_) => {
let mut autoupdate = AutoUpdater::load()?;
let updater = Arc::new(Updater::new(config)?);

let modules = library.list()
let modules = library
.list()
.into_iter()
.filter_map(|module| {
let canonical = module.canonical();
Expand All @@ -189,32 +222,38 @@ fn run_subcommand(subcommand: SubCommand, library: &Library, config: &Config) ->
})
.collect::<Vec<_>>();

worker::spawn_multi(modules, |name| {
autoupdate.updated(&name);
}, 3)?;
worker::spawn_multi(
modules,
|name| {
autoupdate.updated(&name);
},
3,
)?;

autoupdate.save()?;

// trigger reload
Ok(ModuleReload::Yes)
},
}
SubCommand::Uninstall(uninstall) => {
let updater = Updater::new(config)?;
updater.uninstall(&uninstall.module)?;
// trigger reload
Ok(ModuleReload::Yes)
},
}
SubCommand::Quickstart => {
let client = Client::new(config)?;
let updater = Arc::new(Updater::new(config)?);
let mut autoupdate = AutoUpdater::load()?;

let installed = library.list()
let installed = library
.list()
.into_iter()
.map(|module| module.id())
.collect::<HashSet<_>>();

let modules = client.quickstart()?
let modules = client
.quickstart()?
.into_iter()
.filter_map(|module| {
let id = ModuleID {
Expand All @@ -224,27 +263,34 @@ fn run_subcommand(subcommand: SubCommand, library: &Library, config: &Config) ->

if !installed.contains(&id) {
info!("Queueing for install: {}", id);
Some(InstallTask::new(Install {
module: id,
version: None,
force: false,
}, updater.clone()))
Some(InstallTask::new(
Install {
module: id,
version: None,
force: false,
},
updater.clone(),
))
} else {
info!("Skipping already installed module: {}", id);
None
}
})
.collect::<Vec<_>>();

worker::spawn_multi(modules, |name| {
autoupdate.updated(&name);
}, 3)?;
worker::spawn_multi(
modules,
|name| {
autoupdate.updated(&name);
},
3,
)?;

autoupdate.save()?;

// trigger reload
Ok(ModuleReload::Yes)
},
}
}
}

Expand All @@ -259,7 +305,9 @@ impl LiteCmd for Args {
impl Cmd for ArgsInteractive {
fn run(self, rl: &mut Shell) -> Result<()> {
let action = match self.subcommand {
SubCommandInteractive::Base(subcommand) => run_subcommand(subcommand, rl.library(), rl.config())?,
SubCommandInteractive::Base(subcommand) => {
run_subcommand(subcommand, rl.library(), rl.config())?
}
SubCommandInteractive::Reload(_) => ModuleReload::Yes,
};
if action == ModuleReload::Yes {
Expand Down