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

tamada / sibling / 21246419634

22 Jan 2026 11:16AM UTC coverage: 62.21% (+2.5%) from 59.751%
21246419634

Pull #40

github

tamada
feat: add .nodata files for directories with spaces and multibyte characters
Pull Request #40: Release/v2.0.3

105 of 169 new or added lines in 4 files covered. (62.13%)

16 existing lines in 2 files now uncovered.

349 of 561 relevant lines covered (62.21%)

4.45 hits per line

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

64.42
/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
    match level {
×
NEW
24
        Error => std::env::set_var("RUST_LOG", "error"),
×
NEW
25
        Warn => std::env::set_var("RUST_LOG", "warn"),
×
NEW
26
        Info => std::env::set_var("RUST_LOG", "info"),
×
NEW
27
        Debug => std::env::set_var("RUST_LOG", "debug"),
×
NEW
28
        Trace => std::env::set_var("RUST_LOG", "trace"),
×
29
    };
NEW
30
    env_logger::init();
×
NEW
31
    log::info!("Log level set to {level:?}");
×
NEW
32
}
×
33

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

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

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

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

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

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

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

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

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

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

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