• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tamada / sibling / 16365780383

18 Jul 2025 08:18AM UTC coverage: 59.751% (-10.5%) from 70.292%
16365780383

push

github

web-flow
Merge pull request #38 from tamada/release/v2.0.1

Release/v2.0.1

246 of 414 new or added lines in 5 files covered. (59.42%)

288 of 482 relevant lines covered (59.75%)

3.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.62
/cli/src/main.rs
1
use std::path::PathBuf;
2
use std::vec;
3

4
use crate::cli::{CliOpts, PrintingOpts};
5
use clap::Parser;
6
use sibling::Nexter;
7
use sibling::{Result, SiblingError};
8

9
mod cli;
10
mod gencomp;
11
mod init;
12
mod printer;
13

14
fn perform_impl(
1✔
15
    dirs: sibling::Dirs,
1✔
16
    nexter: &dyn Nexter,
1✔
17
    step: usize,
1✔
18
    opts: &PrintingOpts,
1✔
19
) -> Result<String> {
1✔
20
    let next = dirs.next_with(nexter, step);
1✔
21
    printer::result_string(&dirs, next, opts)
1✔
22
}
1✔
23

24
fn perform_from_file(opts: CliOpts) -> Vec<Result<String>> {
1✔
25
    let nexter = sibling::NexterFactory::build(opts.nexter);
1✔
26
    let r = match opts.input {
1✔
27
        None => Err(SiblingError::Fatal("input is not specified".into())),
×
28
        Some(file) => match sibling::Dirs::new_from_file(file) {
1✔
29
            Err(e) => Err(e),
1✔
NEW
30
            Ok(dirs) => perform_impl(dirs, nexter.as_ref(), opts.step, &opts.p_opts),
×
31
        },
32
    };
33
    vec![r]
1✔
34
}
1✔
35

36
fn perform_each(
1✔
37
    dir: std::path::PathBuf,
1✔
38
    nexter: &dyn Nexter,
1✔
39
    step: usize,
1✔
40
    opts: &PrintingOpts,
1✔
41
) -> Result<String> {
1✔
42
    match sibling::Dirs::new(dir) {
1✔
43
        Err(e) => Err(e),
×
44
        Ok(dirs) => perform_impl(dirs, nexter, step, opts),
1✔
45
    }
46
}
1✔
47

48
fn perform_sibling(opts: CliOpts) -> Vec<Result<String>> {
1✔
49
    let nexter = sibling::NexterFactory::build(opts.nexter);
1✔
50
    let target_dirs = if opts.dirs.is_empty() {
1✔
51
        vec![std::env::current_dir().unwrap()]
×
52
    } else {
53
        opts.dirs
1✔
54
    };
55
    let mut result = vec![];
1✔
56
    for dir in target_dirs {
2✔
57
        let dir = if dir == PathBuf::from(".") {
1✔
58
            std::env::current_dir().unwrap()
1✔
59
        } else {
NEW
60
            dir
×
61
        };
62
        let r = perform_each(dir, nexter.as_ref(), opts.step, &opts.p_opts);
1✔
63
        result.push(r);
1✔
64
    }
65
    result
1✔
66
}
1✔
67

68
fn perform(opts: CliOpts) -> Vec<Result<String>> {
2✔
69
    if let Some(shell) = opts.init {
2✔
70
        vec![init::generate_init_script(shell)]
×
71
    } else if opts.input.is_some() {
2✔
72
        perform_from_file(opts)
1✔
73
    } else {
74
        perform_sibling(opts)
1✔
75
    }
76
}
2✔
77

78
fn print_error(e: &SiblingError) {
1✔
79
    match e {
1✔
NEW
80
        SiblingError::Io(e) => eprintln!("I/O error: {e}"),
×
NEW
81
        SiblingError::NotDir(path) => eprintln!("{path:?}: Not a directory"),
×
NEW
82
        SiblingError::NoParent(path) => eprintln!("{path:?}: no parent directory"),
×
83
        SiblingError::Array(array) => {
×
84
            array.iter().for_each(print_error);
×
NEW
85
        }
×
NEW
86
        SiblingError::NotFile(path) => eprintln!("{path:?}: not a file"),
×
87
        SiblingError::NotFound(path) => eprintln!("{path:?}: not found"),
1✔
NEW
88
        SiblingError::Fatal(message) => eprintln!("fatal error: {message}"),
×
89
    }
90
}
1✔
91

92
fn main() {
×
93
    let mut args = std::env::args();
×
94
    let args = if args.len() == 1 {
×
95
        vec![args.next().unwrap(), ".".into()]
×
96
    } else {
97
        args.collect()
×
98
    };
99
    let opts = cli::CliOpts::parse_from(args);
×
NEW
100
    if cfg!(debug_assertions) {
×
101
        #[cfg(debug_assertions)]
NEW
102
        if opts.compopts.completion {
×
NEW
103
            return gencomp::generate(opts.compopts.dest);
×
NEW
104
        }
×
NEW
105
    }
×
106
    for item in perform(opts) {
×
107
        match item {
×
NEW
108
            Ok(result) => println!("{result}"),
×
109
            Err(e) => print_error(&e),
×
110
        }
111
    }
112
}
×
113

114
#[cfg(test)]
115
mod tests {
116
    use super::*;
117

118
    #[test]
119
    fn test_nexter_example() {
1✔
120
        let opts_r = cli::CliOpts::try_parse_from(vec!["sibling", "."]);
1✔
121

122
        if let Err(e) = &opts_r {
1✔
NEW
123
            eprintln!("{e}");
×
124
        }
1✔
125
        assert!(opts_r.is_ok());
1✔
126
        let r = perform(opts_r.unwrap());
1✔
127
        assert_eq!(r.len(), 1);
1✔
128
        match r.first().unwrap() {
1✔
NEW
129
            Err(e) => print_error(e),
×
130
            Ok(result) => println!("{result}"),
1✔
131
        }
132
    }
1✔
133

134
    #[test]
135
    fn test_from_file() {
1✔
136
        let opts_r = cli::CliOpts::try_parse_from(vec![
1✔
137
            "sibling",
138
            "--input",
1✔
139
            "testdata/dirlist.txt",
1✔
140
            "--type",
1✔
141
            "previous",
1✔
142
        ]);
143

144
        if let Err(e) = &opts_r {
1✔
NEW
145
            eprintln!("{e}");
×
146
        }
1✔
147
        assert!(opts_r.is_ok());
1✔
148
        let r = perform(opts_r.unwrap());
1✔
149
        assert_eq!(r.len(), 1);
1✔
150
        match r.first().unwrap() {
1✔
151
            Err(e) => print_error(e),
1✔
NEW
152
            Ok(result) => assert_eq!(result, "testdata/a"),
×
153
        }
154
    }
1✔
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc