Skip to main content

xs/nu/commands/
cas_command.rs

1use 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        // Try to convert to string if valid UTF-8, otherwise return as binary
68        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}