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}