1use super::family::Family;
8
9pub fn clap_version(family: &Family) -> &'static str {
12 Box::leak(format!("({}) {}", family.crate_name, family.version).into_boxed_str())
14}
15
16pub fn line(family: &Family, tool: &str) -> String {
18 format!("{tool} ({}) {}", family.crate_name, family.version)
19}
20
21#[derive(Debug, PartialEq, Eq)]
23pub struct Identity {
24 pub tool: String,
25 pub crate_name: String,
26 pub version: String,
27}
28
29pub fn parse(output: &str) -> Option<Identity> {
33 let first = output.lines().next()?.trim();
34 let (tool, rest) = first.split_once(" (")?;
35 let (crate_name, version) = rest.split_once(") ")?;
36 let well_formed = !tool.is_empty()
37 && !tool.contains(char::is_whitespace)
38 && !crate_name.is_empty()
39 && !crate_name.contains(char::is_whitespace)
40 && version.split('.').count() >= 3
41 && !version.contains(char::is_whitespace);
42 well_formed.then(|| Identity {
43 tool: tool.to_string(),
44 crate_name: crate_name.to_string(),
45 version: version.to_string(),
46 })
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 fn identity(tool: &str, crate_name: &str, version: &str) -> Option<Identity> {
54 Some(Identity {
55 tool: tool.into(),
56 crate_name: crate_name.into(),
57 version: version.into(),
58 })
59 }
60
61 #[test]
62 fn our_shape_is_read() {
63 assert_eq!(
64 parse("mkfs.ext4 (am-fs-ext4) 0.6.0\n"),
65 identity("mkfs.ext4", "am-fs-ext4", "0.6.0")
66 );
67 assert_eq!(
68 parse("img.qcow2 (am-img-qcow2) 0.4.5\ntrailing lines are ignored\n"),
69 identity("img.qcow2", "am-img-qcow2", "0.4.5")
70 );
71 }
72
73 #[test]
74 fn another_package_in_our_shape_is_read_and_names_itself() {
75 assert_eq!(
78 parse("mkfs.erofs (erofs-utils) 1.9.1\n"),
79 identity("mkfs.erofs", "erofs-utils", "1.9.1")
80 );
81 }
82
83 #[test]
84 fn other_banners_and_usage_messages_are_nobodys() {
85 for foreign in [
86 "mke2fs 1.47.0 (5-Feb-2023)",
87 "Usage: mkfs.ext4 [-c|-l filename] device",
88 "mkntfs v2022.10.3 (libntfs-3g)",
89 "Usage: mkntfs [options] device [number-of-sectors]",
90 "mkfs.erofs 1.8.10",
91 "Usage: mkfs.erofs [OPTIONS] FILE SOURCE",
92 "unsquashfs version 4.6.1 (2023/03/25)",
93 "btrfs-progs v6.6.3",
94 "xfs_db version 6.1.0",
95 "",
96 "fs.x () 1.2.3",
98 " (am-fs-x) 1.2.3",
99 "two words (am-fs-x) 1.2.3",
100 "fs.x (am fs x) 1.2.3",
101 "fs.x (am-fs-x) 1.2",
102 "fs.x (am-fs-x) 1.2.3 beta",
103 ] {
104 assert_eq!(parse(foreign), None, "{foreign:?}");
105 }
106 }
107
108 #[test]
109 fn the_line_clap_prints_is_the_line_parse_reads() {
110 let family = super::super::Family {
111 repo: "rust-fs-x",
112 crate_name: "am-fs-x",
113 version: "1.2.3",
114 about: "",
115 install_hints: &[],
116 tools: &[],
117 };
118 assert_eq!(clap_version(&family), "(am-fs-x) 1.2.3");
119 assert_eq!(line(&family, "fs.x"), "fs.x (am-fs-x) 1.2.3");
120 assert_eq!(
121 parse(&line(&family, "fs.x")),
122 identity("fs.x", "am-fs-x", "1.2.3")
123 );
124 }
125}