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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
use anyhow::bail;
use anyhow::Result;
use clap::Args;
use itertools::Itertools;
use std::io;
use std::fs::File;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::BufRead;
use zip::read::ZipArchive;
pub const DEFAULT_PATH_TEMP: &str = "temp";
#[derive(Args)]
pub struct ExtractStreamCMD {
#[arg(short = 'i', value_parser)] /// can take a file. note that we use a string to ensure comparability with later paths
pub path_in: Option<String>,
}
impl ExtractStreamCMD {
/// Run the commandline option.
/// This is an interactive terminal to navigate Bascet-ZIP content; could generalize to any container later
pub fn try_execute(&mut self) -> Result<()> {
//Tell version info etc. Final line is "ready" or "error"
println!("version_major:1");
println!("version_minor:0");
let mut stream = ExtractStream {
curfile: None
};
//Open file provided as argument, if given
if let Some(path_in) = &self.path_in {
let res = stream.open(path_in);
if res.is_err() {
println!("error could not open file provided as argument");
bail!("");
} else {
println!("ready");
}
} else {
println!("ready");
}
//Start the terminal loop
stream.run()
}
}
pub struct ExtractStream {
curfile: Option<(String, ZipArchive<BufReader<File>>)>
}
impl ExtractStream {
/// Set which file is currently open
pub fn open(&mut self, path_in: &String) -> Result<()> {
let file = File::open(path_in);
if let Ok(file) = file {
let bufreader_shard = BufReader::new(file);
self.curfile = Some((
path_in.clone(),
ZipArchive::new(bufreader_shard).expect("error could not open zip archive"))
);
anyhow::Ok(())
} else {
bail!("error no such file {}", path_in);
}
}
/// Run the terminal
pub fn run(&mut self) -> Result<()> {
loop {
let mut buffer = String::new();
let stdin = io::stdin();
stdin.read_line(&mut buffer)?;
let buffer = buffer.trim();
if buffer=="help" {
/////////////////////////////// help
println!("Available commands: exit ls showtext extract_to");
println!("Note that this system is optimized for streaming data to Zorn, and not for being user friendly to terminal users!");
} else if buffer=="ls" {
/////////////////////////////// ls
if let Some((_, zip_shard)) = &self.curfile {
let list_files = zip_shard.file_names().collect_vec();
println!("{}", list_files.len());
for f in list_files {
println!("{}", f);
}
} else {
println!("error no file open");
}
} else if buffer.starts_with("open") {
/////////////////////////////// open ///////////////////////////////
let mut splitter=buffer.split_whitespace();
splitter.next();
let path_in = splitter.next().expect("Did not get file name");
//Only open file if it is different from the currently open file
if let Some((f,_)) = &self.curfile {
if f==path_in {
println!("ok");
continue;
}
}
//If a file is open, close it
self.curfile = None;
//Attempt to open new file
let res = self.open(&path_in.to_string());
if res.is_err() {
println!("error could not open file provided as argument");
} else {
println!("ok");
}
} else if buffer.starts_with("showtext") {
/////////////////////////////// showtext ///////////////////////////////
if let Some((_, zip_shard)) = &mut self.curfile {
let mut splitter=buffer.split_whitespace();
splitter.next();
let zip_entry_name = splitter.next().expect("Did not get zip entry name");
let entry = zip_shard.by_name(&zip_entry_name);
if let Ok(entry) = entry {
if entry.is_file() {
//Figure out how many lines there are in this file
let reader = io::BufReader::new(entry);
let mut lines: Vec<String> = Vec::new();
for line in reader.lines().map_while(Result::ok) {
lines.push(line);
}
//Print each line of the file
println!("{}", lines.len());
for line in lines {
println!("{}", line);
}
} else {
println!("error not a file");
}
} else {
println!("error missing -{}-", zip_entry_name);
}
} else {
println!("error no file open");
}
} else if buffer.starts_with("extract_to") {
/////////////////////////////// extract_to ///////////////////////////////
if let Some((_, zip_shard)) = &mut self.curfile {
let mut splitter=buffer.split_whitespace();
splitter.next();
let zip_entry_name = splitter.next().expect("Did not get zip entry name");
let path_outfile = splitter.next().expect("Did not get out file name");
//let fname=&buffer[b"showtext ".len()..];
let mut entry = zip_shard.by_name(&zip_entry_name);
if let Ok(entry) = &mut entry {
if entry.is_file() {
let file_out = File::create(&path_outfile).unwrap();
let mut bufwriter_out = BufWriter::new(&file_out);
let mut bufreader_found = BufReader::new(entry);
std::io::copy(&mut bufreader_found, &mut bufwriter_out).unwrap();
println!("ok");
} else {
println!("error not a file");
}
} else {
println!("error missing -{}-", zip_entry_name);
}
} else {
println!("error no file open");
}
} else if buffer=="exit" {
/////////////////////////////// exit ///////////////////////////////
break;
} else {
/////////////////////////////// anything else ///////////////////////////////
println!("error unknown command -{}-", buffer);
}
}
println!("exiting");
Ok(())
}
}