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

tamada / sibling / 21895149576

11 Feb 2026 06:32AM UTC coverage: 64.642% (+0.3%) from 64.338%
21895149576

push

github

tamada
refactor: reorganize code structure and update dependencies for improved functionality

76 of 118 new or added lines in 4 files covered. (64.41%)

1 existing line in 1 file now uncovered.

415 of 642 relevant lines covered (64.64%)

4.1 hits per line

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

62.96
/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
pub(crate) mod minisib;
12

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

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

39
fn perform_impl(
1✔
40
    dirs: &Dirs,
1✔
41
    nexter: &dyn Nexter,
1✔
42
    step: i32,
1✔
43
    opts: &PrintingOpts,
1✔
44
) -> String {
1✔
45
    let next = dirs.next_with(nexter, step);
1✔
46
    printer::result_string(dirs, next, opts)
1✔
47
}
1✔
48

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

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

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

93
fn perform(opts: CliOpts) -> Vec<Result<String>> {
2✔
94
    if let Some(shell) = opts.init {
2✔
95
        vec![init::generate_init_script(&shell)]
×
96
    } else if opts.nexter_opts.input.is_some() {
2✔
97
        perform_from_file(opts)
1✔
98
    } else if let Some(minisib) = opts.minisib {
1✔
NEW
99
        vec![minisib.perform()]
×
100
    } else {
101
        perform_sibling(opts)
1✔
102
    }
103
}
2✔
104

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

128
#[cfg(test)]
129
mod tests {
130
    use super::*;
131

132
    #[test]
133
    fn test_nexter_example() {
1✔
134
        let opts_r = cli::CliOpts::try_parse_from(vec!["sibling", "."]);
1✔
135

136
        if let Err(e) = &opts_r {
1✔
137
            eprintln!("{e}");
×
138
        }
1✔
139
        assert!(opts_r.is_ok());
1✔
140
        let r = perform(opts_r.unwrap());
1✔
141
        assert_eq!(r.len(), 1);
1✔
142
        match r.first().unwrap() {
1✔
143
            Err(e) => eprintln!("{e}"),
×
144
            Ok(result) => println!("{result}"),
1✔
145
        }
146
    }
1✔
147

148
    #[test]
149
    fn test_from_file() {
1✔
150
        let opts_r = cli::CliOpts::try_parse_from(vec![
1✔
151
            "sibling",
152
            "--input",
1✔
153
            "testdata/basic/dirlist.txt",
1✔
154
            "--type",
1✔
155
            "previous",
1✔
156
        ]);
157

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