libaki_resort/lib.rs
1/*!
2sort lines of text. You can use regex to specify the KEY.
3
4# Features
5
6- sort lines of text. You can use regex to specify the KEY.
7- minimum support rustc 1.65.0 (897e37553 2022-11-02)
8
9# Command help
10
11```text
12aki-resort --help
13```
14
15```text
16Usage:
17 aki-resort [options]
18
19sort lines of text.
20
21Ordering options:
22 -r, --reverse reverse the result of comparisons
23 --according-to <word> sort according to <word>
24 -h, --head <num> unsort the first <num> lines.
25 -t, --tail <num> unsort the last <num> lines.
26
27Other options:
28 --color <when> use markers to highlight the matching strings
29 -e, --exp <exp> regular expression. sort by the entires match
30 -u, --unique output only the first line of an equal
31 --max-buffer <size> max buffer size
32
33 -H, --help display this help and exit
34 -V, --version display version information and exit
35
36Option Parameters:
37 <word> 'month', 'numeric', 'string', 'time', 'version'
38 <when> 'always', 'never', or 'auto'
39 <exp> regular expression, sort by the entires match.
40 <size> if a reading size is more than <size>, then it is not output,
41 quit and display error message.
42
43Environments:
44 AKI_RESORT_COLOR_SEQ_ST color start sequence specified by ansi
45 AKI_RESORT_COLOR_SEQ_ED color end sequence specified by ansi
46
47Examples:
48 This sort via utf-8 code:
49 cat file1.txt | aki-resort
50 This sort via 1st chunk of numeric character according to numeric:
51 cat file1.txt | aki-resort -e "[0-9]+" --according-to numeric
52 This sort via 1st chunk of numeric character according to month:
53 cat file1.txt | aki-resort -e ":([^:]+)$" --according-to month
54 This sort via 1st chunk of numeric version character according to version:
55 cat file1.txt | aki-resort -e "[^:]+:[^:]+:([0-9.]+):" --according-to version
56 This sort via 1st chunk of numeric time character according to time:
57 cat file1.txt | aki-resort -e "([0-9]+:([0-9]+:)?[0-9]+(.[0-9]+)?)" --according-to time
58```
59
60# Quick install
61
621. you can install this into cargo bin path:
63
64```text
65cargo install aki-resort
66```
67
682. you can build debian package:
69
70```text
71cargo deb
72```
73
74and install **.deb** into your local repository of debian package.
75
76# Examples
77
78The input data used in this example looks like this:
79
80```text
81cat fixtures/fruit.txt
82```
83
84result output:
85```text
86Apple:33:3.3:good:Mar
87Orange:222:1.1.2:good:Jan
88Cherry:4:4:good:Oct
89Kiwi:1111:1.1.11:good:Jun
90```
91
92## Example 1: simple sort
93
94This sort via utf-8 code.
95
96command line:
97```text
98cat fixtures/fruit.txt | aki-resort
99```
100
101result output:
102```text
103Apple:33:3.3:good:Mar
104Cherry:4:4:good:Oct
105Kiwi:1111:1.1.11:good:Jun
106Orange:222:1.1.2:good:Jan
107```
108
109## Example 2: numeric sort
110
111This sort via 1st chunk of numeric character according to numeric.
112
113command line:
114```text
115cat fixtures/fruit.txt | aki-resort -e "[0-9]+" --according-to numeric
116```
117
118result output:
119```text
120Cherry:4:4:good:Oct
121Apple:33:3.3:good:Mar
122Orange:222:1.1.2:good:Jan
123Kiwi:1111:1.1.11:good:Jun
124```
125
126## Example 3: version sort
127
128This sort via 1st capture of version character according to version.
129
130command line:
131```text
132cat fixtures/fruit.txt | aki-resort -e "^[^:]+:[^:]+:([^:]+)" --according-to version
133```
134
135result output:
136```text
137Orange:222:1.1.2:good:Jan
138Kiwi:1111:1.1.11:good:Jun
139Apple:33:3.3:good:Mar
140Cherry:4:4:good:Oct
141```
142
143## Example 4: month sort
144
145This sort via 1st capture of month character according to month.
146
147command line:
148```text
149cat fixtures/fruit.txt | aki-resort -e ":([^:]+)$" --according-to month
150```
151
152result output:
153```text
154Orange:222:1.1.2:good:Jan
155Apple:33:3.3:good:Mar
156Kiwi:1111:1.1.11:good:Jun
157Cherry:4:4:good:Oct
158```
159
160## Example 5: time sort
161
162This sort via 1st capture of numeric time character according to time.
163
164command line:
165```text
166cat fixtures/fruit.txt | aki-resort -e "([0-9]+:([0-9]+:)?[0-9]+(.[0-9]+)?)" --according-to time
167```
168
169result output:
170```text
171Cherry:4:4:good:Oct
172Apple:33:3.3:good:Mar
173Orange:222:1.1.2:good:Jan
174Kiwi:1111:1.1.11:good:Jun
175```
176
177## Example 6: numeric sort with the header
178
179This sort via 1st chunk of numeric character according to numeric.
180And the 1st line is the fixed header.
181
182command line:
183```text
184cat fixtures/fruit_header.txt | aki-resort -e "[0-9]+" --according-to numeric -h 1
185```
186
187result output:
188```text
189name:number:version:nice:month
190Cherry:4:4:good:Oct
191Apple:33:3.3:good:Mar
192Orange:222:1.1.2:good:Jan
193Kiwi:1111:1.1.11:good:Jun
194```
195
196# Library example
197
198See [`fn execute()`] for this library examples.
199
200[`fn execute()`]: crate::execute
201*/
202#[macro_use]
203extern crate lazy_static;
204#[macro_use]
205extern crate anyhow;
206
207pub mod conf;
208mod run;
209mod sort;
210
211#[macro_use]
212mod util;
213
214use flood_tide::HelpVersion;
215use runnel::RunnelIoe;
216
217const TRY_HELP_MSG: &str = "Try --help for help.";
218
219/// execute resort
220///
221/// params:
222/// - sioe: stream in/out/err
223/// - program: program name. etc. "resort"
224/// - args: parameter arguments.
225///
226/// return:
227/// - ok: ()
228/// - err: anyhow
229///
230/// # Examples
231///
232/// ## Example 1: simple sort
233///
234/// This sort via utf-8 code.
235///
236/// ```rust
237/// use runnel::RunnelIoeBuilder;
238///
239/// let r = libaki_resort::execute(&RunnelIoeBuilder::new().build(),
240/// "resort", &[] as &[&str]);
241/// ```
242///
243/// ## Example 2: numeric sort
244///
245/// This sort via 1st chunk of numeric character according to numeric.
246///
247/// ```rust
248/// use runnel::RunnelIoeBuilder;
249///
250/// let r = libaki_resort::execute(&RunnelIoeBuilder::new().build(),
251/// "resort", ["-e", r"[0-9]+", "--according-to", "numeric"]);
252/// ```
253///
254pub fn execute<I, S>(sioe: &RunnelIoe, prog_name: &str, args: I) -> anyhow::Result<()>
255where
256 I: IntoIterator<Item = S>,
257 S: AsRef<std::ffi::OsStr>,
258{
259 execute_with_env(sioe, prog_name, args, vec![("", "")])
260}
261
262/// execute resort with environments
263///
264/// params:
265/// - sioe: stream in/out/err
266/// - program: program name. etc. "resort"
267/// - env: environments array.
268///
269/// return:
270/// - ok: ()
271/// - err: anyhow
272///
273/// # Examples
274///
275/// ## Example 1: simple sort
276///
277/// This sort via utf-8 code.
278///
279/// ```rust
280/// use runnel::RunnelIoeBuilder;
281///
282/// let r = libaki_resort::execute_with_env(&RunnelIoeBuilder::new().build(),
283/// "resort",
284/// ["--color", "always"],
285/// vec![
286/// ("AKI_RESORT_COLOR_SEQ_ST", "<S>"),
287/// ("AKI_RESORT_COLOR_SEQ_ED", "<E>"),
288/// ]
289/// );
290/// ```
291///
292/// ## Example 2: numeric sort
293///
294/// This sort via 1st chunk of numeric character according to numeric.
295///
296/// ```rust
297/// use runnel::RunnelIoeBuilder;
298///
299/// let r = libaki_resort::execute_with_env(&RunnelIoeBuilder::new().build(),
300/// "resort",
301/// [
302/// "-e", r"[0-9]+",
303/// "--according-to", "numeric",
304/// "--color", "always"
305/// ],
306/// vec![
307/// ("AKI_RESORT_COLOR_SEQ_ST", "<S>"),
308/// ("AKI_RESORT_COLOR_SEQ_ED", "<E>"),
309/// ]
310/// );
311/// ```
312///
313pub fn execute_with_env<I, S, IKV, K, V>(
314 sioe: &RunnelIoe,
315 prog_name: &str,
316 args: I,
317 env: IKV,
318) -> anyhow::Result<()>
319where
320 I: IntoIterator<Item = S>,
321 S: AsRef<std::ffi::OsStr>,
322 IKV: IntoIterator<Item = (K, V)>,
323 K: AsRef<std::ffi::OsStr>,
324 V: AsRef<std::ffi::OsStr>,
325{
326 let args: Vec<String> = args
327 .into_iter()
328 .map(|s| s.as_ref().to_string_lossy().into_owned())
329 .collect();
330 let args_str: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
331 let env_cnf: conf::EnvConf = env.into();
332 //
333 match conf::parse_cmdopts(prog_name, &args_str) {
334 Ok(conf) => run::run(sioe, &conf, &env_cnf),
335 Err(errs) => {
336 if let Some(err) = errs.iter().find(|e| e.is_help() || e.is_version()) {
337 sioe.pg_out().write_line(err.to_string())?;
338 Ok(())
339 } else {
340 Err(anyhow!("{errs}\n{TRY_HELP_MSG}"))
341 }
342 }
343 }
344}