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