ocpi_tariffs_cli/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod analyzse;
4mod opts;
5mod print;
6mod validate;
7
8use std::{
9    env, fmt,
10    io::{self, IsTerminal as _},
11    path::PathBuf,
12};
13
14use clap::Parser;
15
16#[doc(hidden)]
17#[derive(Parser)]
18pub struct Opts {
19    #[clap(subcommand)]
20    command: opts::Command,
21}
22
23impl Opts {
24    pub fn run(self) -> Result<(), Error> {
25        self.command.run()
26    }
27}
28
29#[doc(hidden)]
30#[derive(Debug)]
31pub enum Error {
32    File {
33        path: PathBuf,
34        error: io::Error,
35    },
36    StdIn {
37        error: io::Error,
38    },
39    Internal(ocpi_tariffs::Error),
40    /// The calculated totals deviate from the totals in the CDR.
41    TotalsDoNotMatch,
42}
43impl std::error::Error for Error {}
44
45impl fmt::Display for Error {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Self::File { path, error } => {
49                write!(f, "File error `{}`: {}", path.display(), error)
50            }
51            Self::StdIn { error } => {
52                write!(f, "Stdin error {error}")
53            }
54            Self::Internal(e) => write!(f, "{e}"),
55            Self::TotalsDoNotMatch => {
56                f.write_str("Calculation does not match all totals in the CDR")
57            }
58        }
59    }
60}
61
62impl From<ocpi_tariffs::Error> for Error {
63    fn from(err: ocpi_tariffs::Error) -> Self {
64        Self::Internal(err)
65    }
66}
67
68impl Error {
69    pub fn file(path: PathBuf, error: io::Error) -> Self {
70        Self::File { path, error }
71    }
72
73    pub fn stdin(error: io::Error) -> Self {
74        Self::StdIn { error }
75    }
76}
77
78#[doc(hidden)]
79pub fn setup_logging() -> Result<(), &'static str> {
80    let stderr = io::stderr();
81    let builder = tracing_subscriber::fmt()
82        .without_time()
83        .with_writer(io::stderr)
84        .with_ansi(stderr.is_terminal());
85
86    let level = match env::var("RUST_LOG") {
87        Ok(s) => s.parse().unwrap_or(tracing::Level::INFO),
88        Err(err) => match err {
89            env::VarError::NotPresent => tracing::Level::INFO,
90            env::VarError::NotUnicode(_) => {
91                return Err("RUST_LOG is not unicode");
92            }
93        },
94    };
95
96    builder.with_max_level(level).init();
97
98    Ok(())
99}