xs/nu/commands/
cas_command.rs1use std::io::Read;
2
3use nu_engine::CallExt;
4use nu_protocol::engine::{Call, Command, EngineState, Stack};
5use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
6
7use crate::store::Store;
8
9#[derive(Clone)]
10pub struct CasCommand {
11 store: Store,
12}
13
14impl CasCommand {
15 pub fn new(store: Store) -> Self {
16 Self { store }
17 }
18}
19
20impl Command for CasCommand {
21 fn name(&self) -> &str {
22 ".cas"
23 }
24
25 fn signature(&self) -> Signature {
26 Signature::build(".cas")
27 .input_output_types(vec![(Type::Nothing, Type::String)])
28 .required(
29 "hash",
30 SyntaxShape::String,
31 "hash of the content to retrieve",
32 )
33 .category(Category::Experimental)
34 }
35
36 fn description(&self) -> &str {
37 "Retrieve content from the CAS for the given hash"
38 }
39
40 fn run(
41 &self,
42 engine_state: &EngineState,
43 stack: &mut Stack,
44 call: &Call,
45 _input: PipelineData,
46 ) -> Result<PipelineData, ShellError> {
47 let span = call.head;
48 let hash: String = call.req(engine_state, stack, 0)?;
49 let hash: ssri::Integrity = hash.parse().map_err(|e| ShellError::GenericError {
50 error: "I/O Error".into(),
51 msg: format!("Malformed ssri::Integrity:: {e}"),
52 span: Some(span),
53 help: None,
54 inner: vec![],
55 })?;
56
57 let mut reader =
58 self.store
59 .cas_reader_sync(hash)
60 .map_err(|e| ShellError::GenericError {
61 error: "I/O Error".into(),
62 msg: e.to_string(),
63 span: Some(span),
64 help: None,
65 inner: vec![],
66 })?;
67
68 let mut contents = Vec::new();
69 reader
70 .read_to_end(&mut contents)
71 .map_err(|e| ShellError::GenericError {
72 error: "I/O Error".into(),
73 msg: e.to_string(),
74 span: Some(span),
75 help: None,
76 inner: vec![],
77 })?;
78
79 let value = match String::from_utf8(contents.clone()) {
81 Ok(string) => Value::string(string, span),
82 Err(_) => Value::binary(contents, span),
83 };
84
85 Ok(PipelineData::Value(value, None))
86 }
87}