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
use clap::Parser;
use flate2::read::GzDecoder;
use glob::glob;
use json::ndjson::{parse_json_iterable, parse_ndjson_bufreader, FileStats};
use jsonpath::Selector;
use std::error;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::PathBuf;
pub mod json;
type Result<T> = ::std::result::Result<T, Box<dyn error::Error>>;
#[derive(Parser, Default)]
#[clap(author, version, about, long_about = None, arg_required_else_help(true))]
pub struct Cli {
#[clap(parse(from_os_str))]
file_path: Option<std::path::PathBuf>,
#[clap(short, long)]
glob: Option<String>,
#[clap(short = 'n', long)]
lines: Option<usize>,
#[clap(long)]
jsonpath: Option<String>,
#[clap(long)]
explode_arrays: bool,
}
impl Cli {
fn jsonpath_selector(&self) -> Result<Option<Selector>> {
let jsonpath_selector = if let Some(jsonpath) = &self.jsonpath {
let selector = Selector::new(jsonpath)?;
Some(selector)
} else {
None
};
Ok(jsonpath_selector)
}
}
fn get_bufreader(_args: &Cli, file_path: &std::path::PathBuf) -> Result<Box<dyn BufRead + Send>> {
let extension = file_path.extension().and_then(OsStr::to_str);
let file = File::open(file_path)?;
if extension == Some("gz") {
let file = GzDecoder::new(file);
Ok(Box::new(io::BufReader::new(file)))
} else {
Ok(Box::new(io::BufReader::new(file)))
}
}
fn parse_ndjson_file_path(args: &Cli, file_path: &PathBuf) -> Result<FileStats> {
let buf_reader = get_bufreader(args, file_path)?;
parse_ndjson_bufreader(args, buf_reader)
}
pub fn run(args: Cli) -> Result<()> {
if let Some(file_path) = &args.file_path {
let file_stats = parse_ndjson_file_path(&args, file_path)?;
println!("{}", file_stats);
return Ok(());
}
if let Some(pattern) = &args.glob {
println!("Glob '{}':", pattern);
for entry in glob(pattern)? {
let path = entry?;
println!("File '{}':", path.display());
let file_stats = parse_ndjson_file_path(&args, &path)?;
println!("{}", file_stats);
}
return Ok(());
}
let stdin = io::stdin().lock();
let stdin_file_stats = parse_json_iterable(&args, stdin.lines())?;
if stdin_file_stats != FileStats::default() {
println!("{}", stdin_file_stats);
return Ok(());
}
Ok(())
}