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

tamada / sibling / 21247312507

22 Jan 2026 11:49AM UTC coverage: 61.989% (+2.2%) from 59.751%
21247312507

push

github

web-flow
Merge pull request #40 from tamada/release/v2.0.3

- Comprehensive documentation added with new README files for both the library and CLI
- Error type renamed from SiblingError to Error for better naming consistency
- Extensive logging support integrated using the log crate for debugging and monitoring
- API refinements to the Nexter trait with new next() and next_with() method structure

105 of 171 new or added lines in 4 files covered. (61.4%)

16 existing lines in 2 files now uncovered.

349 of 563 relevant lines covered (61.99%)

4.43 hits per line

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

63.21
/cli/src/main.rs
1
use std::vec;
2

3
use crate::cli::{CliOpts, PrintingOpts};
4
use clap::Parser;
5
use sibling::{Dirs, Error, Nexter, Result};
6

7
mod cli;
8
mod gencomp;
9
mod init;
10
mod printer;
11

12
#[derive(clap::ValueEnum, Clone, Debug)]
13
pub enum LogLevel {
14
    Error,
15
    Warn,
16
    Info,
17
    Debug,
18
    Trace,
19
}
20

NEW
21
fn init_log(level: &LogLevel) {
×
22
    use LogLevel::*;
NEW
23
    if std::env::var_os("RUST_LOG").is_none() {
×
NEW
24
        match level {
×
NEW
25
            Error => std::env::set_var("RUST_LOG", "error"),
×
NEW
26
            Warn => std::env::set_var("RUST_LOG", "warn"),
×
NEW
27
            Info => std::env::set_var("RUST_LOG", "info"),
×
NEW
28
            Debug => std::env::set_var("RUST_LOG", "debug"),
×
NEW
29
            Trace => std::env::set_var("RUST_LOG", "trace"),
×
30
        };
NEW
31
    }
×
NEW
32
    env_logger::init();
×
NEW
33
    log::info!("Log level set to {level:?}");
×
NEW
34
}
×
35

36
fn perform_impl(
1✔
37
    dirs: Dirs,
1✔
38
    nexter: &dyn Nexter,
1✔
39
    step: usize,
1✔
40
    opts: &PrintingOpts,
1✔
41
) -> Result<String> {
1✔
42
    let next = dirs.next_with(nexter, step);
1✔
43
    printer::result_string(&dirs, next, opts)
1✔
44
}
1✔
45

46
fn perform_from_file(opts: CliOpts) -> Vec<Result<String>> {
1✔
47
    let nexter = sibling::NexterFactory::build(opts.nexter);
1✔
48
    let r = match opts.input {
1✔
NEW
49
        None => Err(Error::Fatal("input is not specified".into())),
×
50
        Some(file) => match Dirs::new_from_file(file) {
1✔
51
            Err(e) => Err(e),
1✔
52
            Ok(dirs) => perform_impl(dirs, nexter.as_ref(), opts.step, &opts.p_opts),
×
53
        },
54
    };
55
    vec![r]
1✔
56
}
1✔
57

58
fn perform_each(
1✔
59
    dir: std::path::PathBuf,
1✔
60
    nexter: &dyn Nexter,
1✔
61
    step: usize,
1✔
62
    opts: &PrintingOpts,
1✔
63
) -> Result<String> {
1✔
64
    match Dirs::new(dir) {
1✔
65
        Err(e) => Err(e),
×
66
        Ok(dirs) => perform_impl(dirs, nexter, step, opts),
1✔
67
    }
68
}
1✔
69

70
fn perform_sibling(opts: CliOpts) -> Vec<Result<String>> {
1✔
71
    let nexter = sibling::NexterFactory::build(opts.nexter);
1✔
72
    let target_dirs = if opts.dirs.is_empty() {
1✔
73
        vec![std::env::current_dir().unwrap()]
×
74
    } else {
75
        opts.dirs
1✔
76
    };
77
    let mut result = vec![];
1✔
78
    for dir in target_dirs {
2✔
79
        let dir = if dir == std::path::Path::new(".") {
1✔
80
            std::env::current_dir().unwrap()
1✔
81
        } else {
82
            dir
×
83
        };
84
        let r = perform_each(dir, nexter.as_ref(), opts.step, &opts.p_opts);
1✔
85
        result.push(r);
1✔
86
    }
87
    result
1✔
88
}
1✔
89

90
fn perform(opts: CliOpts) -> Vec<Result<String>> {
2✔
91
    if let Some(shell) = opts.init {
2✔
92
        vec![init::generate_init_script(shell)]
×
93
    } else if opts.input.is_some() {
2✔
94
        perform_from_file(opts)
1✔
95
    } else {
96
        perform_sibling(opts)
1✔
97
    }
98
}
2✔
99

UNCOV
100
fn main() {
×
UNCOV
101
    let mut args = std::env::args();
×
102
    let args = if args.len() == 1 {
×
103
        vec![args.next().unwrap(), ".".into()]
×
104
    } else {
105
        args.collect()
×
106
    };
107
    let opts = cli::CliOpts::parse_from(args);
×
NEW
108
    init_log(&opts.log);
×
UNCOV
109
    if cfg!(debug_assertions) {
×
110
        #[cfg(debug_assertions)]
111
        if opts.compopts.completion {
×
112
            return gencomp::generate(opts.compopts.dest);
×
113
        }
×
114
    }
×
115
    for item in perform(opts) {
×
116
        match item {
×
117
            Ok(result) => println!("{result}"),
×
NEW
118
            Err(e) => eprintln!("{e}"),
×
119
        }
120
    }
121
}
×
122

123
#[cfg(test)]
124
mod tests {
125
    use super::*;
126

127
    #[test]
128
    fn test_nexter_example() {
1✔
129
        let opts_r = cli::CliOpts::try_parse_from(vec!["sibling", "."]);
1✔
130

131
        if let Err(e) = &opts_r {
1✔
132
            eprintln!("{e}");
×
133
        }
1✔
134
        assert!(opts_r.is_ok());
1✔
135
        let r = perform(opts_r.unwrap());
1✔
136
        assert_eq!(r.len(), 1);
1✔
137
        match r.first().unwrap() {
1✔
NEW
138
            Err(e) => eprintln!("{e}"),
×
139
            Ok(result) => println!("{result}"),
1✔
140
        }
141
    }
1✔
142

143
    #[test]
144
    fn test_from_file() {
1✔
145
        let opts_r = cli::CliOpts::try_parse_from(vec![
1✔
146
            "sibling",
147
            "--input",
1✔
148
            "testdata/basic/dirlist.txt",
1✔
149
            "--type",
1✔
150
            "previous",
1✔
151
        ]);
152

153
        if let Err(e) = &opts_r {
1✔
154
            eprintln!("{e}");
×
155
        }
1✔
156
        assert!(opts_r.is_ok());
1✔
157
        let r = perform(opts_r.unwrap());
1✔
158
        assert_eq!(r.len(), 1);
1✔
159
        match r.first().unwrap() {
1✔
160
            Err(e) => eprintln!("{e}"),
1✔
NEW
161
            Ok(result) => assert_eq!(result, "testdata/basic/a"),
×
162
        }
163
    }
1✔
164
}
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