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 TotalsDoNotMatch,
42
43 CdrRequired,
45}
46impl std::error::Error for Error {}
47
48impl fmt::Display for Error {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::File { path, error } => {
52 write!(f, "File error `{}`: {}", path.display(), error)
53 }
54 Self::StdIn { error } => {
55 write!(f, "Stdin error {error}")
56 }
57 Self::Internal(e) => write!(f, "{e}"),
58 Self::TotalsDoNotMatch => {
59 f.write_str("Calculation does not match all totals in the CDR")
60 }
61 Self::CdrRequired => f.write_str("`--cdr` is required when the process is a TTY"),
62 }
63 }
64}
65
66impl From<ocpi_tariffs::Error> for Error {
67 fn from(err: ocpi_tariffs::Error) -> Self {
68 Self::Internal(err)
69 }
70}
71
72impl Error {
73 pub fn file(path: PathBuf, error: io::Error) -> Self {
74 Self::File { path, error }
75 }
76
77 pub fn stdin(error: io::Error) -> Self {
78 Self::StdIn { error }
79 }
80}
81
82#[doc(hidden)]
83pub fn setup_logging() -> Result<(), &'static str> {
84 let stderr = io::stderr();
85 let builder = tracing_subscriber::fmt()
86 .without_time()
87 .with_writer(io::stderr)
88 .with_ansi(stderr.is_terminal());
89
90 let level = match env::var("RUST_LOG") {
91 Ok(s) => s.parse().unwrap_or(tracing::Level::INFO),
92 Err(err) => match err {
93 env::VarError::NotPresent => tracing::Level::INFO,
94 env::VarError::NotUnicode(_) => {
95 return Err("RUST_LOG is not unicode");
96 }
97 },
98 };
99
100 builder.with_max_level(level).init();
101
102 Ok(())
103}