1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
use std::path::PathBuf; use crate::prelude::*; use nu_engine::WholeStreamCommand; use nu_errors::ShellError; use nu_path::canonicalize; use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_source::Tagged; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; pub struct SubCommand; #[derive(Deserialize)] pub struct Arguments { #[serde(rename = "load")] pub load_path: Option<Tagged<PathBuf>>, } impl WholeStreamCommand for SubCommand { fn name(&self) -> &str { "nu plugin" } fn signature(&self) -> Signature { Signature::build("nu plugin").named( "load", SyntaxShape::FilePath, "a path to load the plugins from", Some('l'), ) } fn usage(&self) -> &str { "Nu Plugin" } fn examples(&self) -> Vec<Example> { vec![Example { description: "Load all plugins in the current directory", example: "nu plugin --load .", result: None, }] } fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> { let scope = args.scope().clone(); let shell_manager = args.shell_manager(); let load_path: Option<Tagged<PathBuf>> = args.get_flag("load")?; if let Some(Tagged { item: load_path, tag, }) = load_path { let path = canonicalize(shell_manager.path(), load_path).map_err(|_| { ShellError::labeled_error( "Cannot load plugins from directory", "directory not found", &tag, ) })?; if !path.is_dir() { return Err(ShellError::labeled_error( "Cannot load plugins from directory", "is not a directory", &tag, )); } #[cfg(unix)] { let has_exec = path .metadata() .map(|m| umask::Mode::from(m.permissions().mode()).has(umask::USER_READ)) .map_err(|e| { ShellError::labeled_error( "Cannot load plugins from directory", format!("cannot stat ({})", e), &tag, ) })?; if !has_exec { return Err(ShellError::labeled_error( "Cannot load plugins from directory", "permission denied", &tag, )); } } return Ok(vec![ReturnSuccess::action(CommandAction::AddPlugins( path.to_string_lossy().to_string(), ))] .into()); } Ok(ActionStream::one(ReturnSuccess::value( UntaggedValue::string(get_full_help(&SubCommand, &scope)).into_value(Tag::unknown()), ))) } } #[cfg(test)] mod tests { use super::ShellError; use super::SubCommand; #[test] fn examples_work_as_expected() -> Result<(), ShellError> { use crate::examples::test as test_examples; test_examples(SubCommand {}) } }