Skip to main content

ocpi_tariffs_cli/
guess_version.rs

1//! Guess the version of a CDR or tariff.
2
3use std::{fmt, path::PathBuf};
4
5use console::style;
6use ocpi_tariffs::{cdr, guess, json, schema, tariff, warning, Versioned as _};
7
8use crate::{load_object_file, load_object_from_stdin, print, Error, ObjectKind};
9
10/// The arguments for the `guess` command.
11#[derive(clap::Parser)]
12pub struct Command {
13    /// The arguments for the `guess` command.
14    #[command(flatten)]
15    args: Arguments,
16}
17
18/// The arguments for the `guess` command.
19#[derive(clap::Args)]
20struct Arguments {
21    /// The type of OCPI object contained in the given JSON.
22    #[arg(short = 't', long = "type")]
23    kind: ObjectKind,
24
25    /// A path to JSON file for the specified object.
26    #[arg(short = 'f', long)]
27    file: Option<PathBuf>,
28
29    /// Check if all fields are allowed to be there according to the OCPI spec.
30    #[arg(long)]
31    validate: bool,
32}
33
34impl fmt::Display for ObjectKind {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            ObjectKind::Cdr => f.write_str("CDR"),
38            ObjectKind::Tariff => f.write_str("tariff"),
39        }
40    }
41}
42
43/// The outcome of running the guess command.
44struct Outcome {
45    /// The kind of object given.
46    object_kind: ObjectKind,
47
48    /// The guessed version of the object given.
49    version: guess::Version<ocpi_tariffs::Version, ()>,
50
51    /// The schema validation warnings for the object.
52    ///
53    /// This is `None` when `--validate` was not requested, or when the guessed
54    /// `Version` is `Uncertain` (there is no schema to validate against).
55    warnings: Option<warning::Set<schema::Warning>>,
56}
57
58impl Command {
59    /// Run the `guess` Command.
60    pub fn run(self) -> Result<(), Error> {
61        let Self {
62            args:
63                Arguments {
64                    kind: object_kind,
65                    file: path,
66                    validate,
67                },
68        } = self;
69
70        let json = if let Some(path) = path.as_deref() {
71            load_object_file(path, object_kind)?
72        } else {
73            load_object_from_stdin(object_kind)?
74        };
75
76        let outcome = match object_kind {
77            ObjectKind::Cdr => {
78                let cdr = json::parse_object(&json)?;
79                let guess = cdr::infer_version(cdr);
80                let version = guess.as_version();
81
82                // Validate against the schema only when the version is certain.
83                let warnings = match (validate, guess) {
84                    (true, guess::Version::Certain(cdr)) => {
85                        let cdr_version = cdr.version();
86                        let (_cdr, warnings) = cdr::build(cdr.into_doc(), cdr_version).into_parts();
87                        Some(warnings)
88                    }
89                    _ => None,
90                };
91
92                Outcome {
93                    object_kind,
94                    version,
95                    warnings,
96                }
97            }
98            ObjectKind::Tariff => {
99                let tariff = json::parse_object(&json)?;
100                let guess = tariff::infer_version(tariff);
101                let version = guess.as_version();
102
103                // Validate against the schema only when the version is certain.
104                let warnings = match (validate, guess) {
105                    (true, guess::Version::Certain(tariff)) => {
106                        let tariff_version = tariff.version();
107                        let (_tariff, warnings) =
108                            tariff::build(tariff.into_doc(), tariff_version).into_parts();
109                        Some(warnings)
110                    }
111                    _ => None,
112                };
113
114                Outcome {
115                    object_kind,
116                    version,
117                    warnings,
118                }
119            }
120        };
121
122        let Outcome {
123            object_kind,
124            warnings,
125            version,
126        } = outcome;
127
128        if let Some(warnings) = warnings {
129            print::warning_set("version guessing", &warnings);
130        }
131
132        print_version(object_kind, &version);
133
134        Ok(())
135    }
136}
137
138/// Print the version to the CLI.
139fn print_version(object_kind: ObjectKind, version: &guess::Version<ocpi_tariffs::Version, ()>) {
140    match version {
141        guess::Version::Uncertain(()) => {
142            eprintln!(
143                "Unable to guess the version of the given {} JSON",
144                style(object_kind).green()
145            );
146        }
147        guess::Version::Certain(version) => {
148            println!("{version}");
149        }
150    }
151}