Skip to content

Commit

Permalink
get can create directories recursevly. (#168)
Browse files Browse the repository at this point in the history
* state.total

* fmt

* coverage

* c.json

* clippy

* parse JSON

* map_err

* coverage

* to recursive dir

* cov

* 0.0.4
  • Loading branch information
sergey-shandar authored Mar 14, 2024
1 parent 4b2069e commit 7ce783a
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `blockset get` can create directories recursively. PR [#168](https://github.com/datablockset/blockset/pull/168)
- `blockset add` works with directories. PR [#165](https://github.com/datablockset/blockset/pull/165).

## 0.4.2
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ io-trait = "0.10.0"
io-impl = "0.10.0"
io-test = "0.10.1"
wasm-bindgen-test = "0.3.42"
nanvm-lib = "0.0.3"
nanvm-lib = "0.0.4"
18 changes: 9 additions & 9 deletions blockset-lib/src/app/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ fn dir_to_json<M: Manager>(

fn calculate_len(files: &[(String, u64)], state: &mut State) {
// JSON size:
if files.is_empty() {
state.total = if files.is_empty() {
// `{}`
state.total = 2;
return;
}
// `{` +
// `"` + path + `":"` + 45 + `",` = path.len() + 51
state.total = files.iter().fold(1, |total, (path, len)| {
total + len + (path.len() as u64) + 51
});
2
} else {
// `{` +
// `"` + path + `":"` + 45 + `",` = path.len() + 51
files.iter().fold(1, |total, (path, len)| {
total + len + (path.len() as u64) + 51
})
};
}

fn normalize_path(path: &str) -> &str {
Expand Down
51 changes: 51 additions & 0 deletions blockset-lib/src/app/get.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::io::{self, Write};

use io_trait::Io;
use nanvm_lib::{
js::any::Any,
mem::manager::Manager,
parser::{parse_with_tokens, Context, ParseError, ParseResult},
tokenizer::tokenize,
};

use crate::{
cdt::node_type::NodeType,
forest::{file::FileForest, node_id::ForestNodeId, Forest},
uint::u224::U224,
};

use super::invalid_input;

pub fn restore(io: &impl Io, hash: &U224, w: &mut impl Write) -> io::Result<()> {
FileForest(io).restore(&ForestNodeId::new(NodeType::Root, hash), w, io)
}

fn tokenize_and_parse<M: Manager>(
io: &impl Io,
manager: M,
s: String,
) -> Result<ParseResult<M>, ParseError> {
parse_with_tokens(
&Context::new(manager, io, String::default()),
tokenize(s).into_iter(),
)
}

pub fn parse_json<M: Manager>(io: &impl Io, manager: M, v: Vec<u8>) -> io::Result<Any<M::Dealloc>> {
let s = String::from_utf8(v).map_err(|_| invalid_input("Invalid UTF-8"))?;
let result = tokenize_and_parse(io, manager, s).map_err(|_| invalid_input("Invalid JSON"))?;
Ok(result.any)
}

fn dir(path: &str) -> Option<&str> {
path.rsplit_once('/').map(|(d, _)| d)
}

fn create_file_path_recursively<T: Io>(io: &T, path: &str) -> io::Result<()> {
dir(path).map_or(Ok(()), |d| io.create_dir_recursively(d))
}

pub fn create_file_recursively<T: Io>(io: &T, path: &str) -> io::Result<T::File> {
create_file_path_recursively(io, path)?;
io.create(path)
}
84 changes: 75 additions & 9 deletions blockset-lib/src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
mod add;
mod add_entry;
mod get;

use std::io::{self, ErrorKind, Read, Write};
use std::io::{self, Cursor, ErrorKind, Read, Write};

use add_entry::add_entry;

use io_trait::Io;
use nanvm_lib::{
js::{any::Any, any_cast::AnyCast, js_object::JsObjectRef, js_string::JsStringRef},
mem::{global::GLOBAL, manager::Dealloc},
};

use crate::{
cdt::{main_tree::MainTreeAdd, node_type::NodeType, tree_add::TreeAdd},
cdt::{main_tree::MainTreeAdd, tree_add::TreeAdd},
common::{
base32::{StrEx, ToBase32},
eol::ToPosixEol,
print::Print,
progress::{self, Progress, State},
status_line::{mb, StatusLine},
},
forest::{file::FileForest, node_id::ForestNodeId, tree_add::ForestTreeAdd, Forest},
forest::{file::FileForest, tree_add::ForestTreeAdd},
info::calculate_total,
uint::u224::U224,
};

use self::add::posix_path;
use self::{
add::posix_path,
get::{create_file_recursively, parse_json, restore},
};

fn set_progress(
state: &mut StatusLine<'_, impl Io>,
Expand Down Expand Up @@ -131,6 +139,15 @@ fn validate(a: &mut impl Iterator<Item = String>, stdout: &mut impl Write) -> io
stdout.println(["valid: ", d.as_str()])
}

fn js_string_to_string(s: &JsStringRef<impl Dealloc>) -> io::Result<String> {
String::from_utf16(s.items())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-16"))
}

fn try_move<D: Dealloc, T: AnyCast<D>>(o: Any<D>) -> io::Result<T> {
o.try_move().map_err(|_| invalid_input("invalid JSON"))
}

pub fn run(io: &impl Io) -> io::Result<()> {
let stdout = &mut io.stdout();
let mut a = io.args();
Expand All @@ -143,8 +160,22 @@ pub fn run(io: &impl Io) -> io::Result<()> {
"get" => {
let d = get_hash(&mut a)?;
let path = posix_path(a.next().ok_or(invalid_input("missing file name"))?.as_str());
let w = &mut io.create(&path)?;
FileForest(io).restore(&ForestNodeId::new(NodeType::Root, &d), w, io)
if path.ends_with('/') {
let mut buffer = Vec::default();
let mut w = Cursor::new(&mut buffer);
restore(io, &d, &mut w)?;
let json: JsObjectRef<_> = try_move(parse_json(io, GLOBAL, buffer)?)?;
for (k, v) in json.items() {
stdout.println([
js_string_to_string(k)?.as_str(),
": ",
js_string_to_string(&try_move(v.clone())?)?.as_str(),
])?;
}
Ok(())
} else {
restore(io, &d, &mut create_file_recursively(io, &path)?)
}
}
"info" => stdout.println(["size: ", calculate_total(io)?.to_string().as_str(), " B."]),
_ => Err(invalid_input("unknown command")),
Expand Down Expand Up @@ -396,11 +427,46 @@ mod test {
let mut a = io.args();
a.next().unwrap();
run(&mut io).unwrap();
io.stdout.to_stdout()
let x = io.stdout.to_stdout()[..45].to_owned();
(io, x)
};
let a = f("a");
let b = f("a/");
let (mut io, a) = f("a");
let (_, b) = f("a/");
assert_eq!(a, b);
f("b");
// as a file
{
io.args = ["blockset", "get", &a, "c.json"]
.iter()
.map(|s| s.to_string())
.collect();
run(&mut io).unwrap();
io.read("c.json").unwrap();
}
// as a file to a new folder
{
io.args = ["blockset", "get", &a, "d/c.json"]
.iter()
.map(|s| s.to_string())
.collect();
run(&mut io).unwrap();
io.read("c.json").unwrap();
}
// invalid directory
{
io.args = ["blockset", "get", &a, "?/v.json"]
.iter()
.map(|s| s.to_string())
.collect();
run(&mut io).unwrap_err();
}
// as a directory
{
io.args = ["blockset", "get", &a, "c/"]
.iter()
.map(|s| s.to_string())
.collect();
run(&mut io).unwrap();
}
}
}

0 comments on commit 7ce783a

Please sign in to comment.