xvc_pipeline/pipeline/
outs.rs

1use std::fs;
2use std::{ffi::OsStr, path::Path};
3
4use rayon::*;
5
6use strum_macros::Display;
7use xvc_core::{XvcPath, XvcRoot};
8use xvc_core::persist;
9
10use crate::error::{Error, Result};
11
12use serde::{Deserialize, Serialize};
13
14/// Possible formats for recognized metrics formats.
15/// Metrics files are where the pipeline writes its output in a structured format.
16/// We can read these files and use them to generate reports
17#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
18pub enum XvcMetricsFormat {
19    /// Unknown format, we don't know how to read it
20    Unknown,
21    /// Comma,separated,values
22    CSV,
23    /// JavaScript Object Notation
24    JSON,
25    /// Tab separated   values
26    TSV,
27}
28
29impl XvcMetricsFormat {
30    /// Decide the format from extension of the given path
31    pub fn from_path(path: &Path) -> Self {
32        match path
33            .extension()
34            .unwrap_or_else(|| OsStr::new(""))
35            .to_ascii_lowercase()
36            .to_str()
37            .unwrap_or("")
38        {
39            "csv" => Self::CSV,
40            "json" => Self::JSON,
41            "tsv" => Self::TSV,
42            _ => Self::Unknown,
43        }
44    }
45}
46
47/// Possible outputs for the pipeline.
48///
49/// These outputs can be defined with `xvc pipeline output` command.
50#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, PartialOrd, Ord)]
51pub enum XvcOutput {
52    /// A (possibly binary) file.
53    File {
54        /// Path to the file
55        path: XvcPath,
56    },
57    /// A textual metrics file with a known [`XvcMetricsFormat`]
58    Metric {
59        /// Path to the file
60        path: XvcPath,
61        /// Format of the file
62        format: XvcMetricsFormat,
63    },
64    /// An image file, like a plot or generated file
65    Image {
66        /// Path to the file
67        path: XvcPath,
68        // TODO: Should we add a `format` field here?
69    },
70    // TODO: We can add `Model` here.
71}
72
73persist!(XvcOutput, "xvc-output");
74
75impl From<XvcOutput> for XvcPath {
76    /// Return the path of a given output
77    fn from(out: XvcOutput) -> XvcPath {
78        match out {
79            XvcOutput::File { path } => path,
80            XvcOutput::Metric { path, .. } => path,
81            XvcOutput::Image { path, .. } => path,
82        }
83    }
84}
85
86impl From<&XvcOutput> for XvcPath {
87    /// Return the path of a given output
88    fn from(out: &XvcOutput) -> XvcPath {
89        match out {
90            XvcOutput::File { path } => path.clone(),
91            XvcOutput::Metric { path, .. } => path.clone(),
92            XvcOutput::Image { path, .. } => path.clone(),
93        }
94    }
95}
96
97impl XvcOutput {
98    /// Used to check whether pipeline / step output is changed (or missing.)
99    pub fn fs_metadata(&self, xvc_root: &XvcRoot) -> Result<fs::Metadata> {
100        let xvc_path: XvcPath = self.into();
101        let abs_path = xvc_path.to_absolute_path(xvc_root);
102        abs_path
103            .metadata()
104            .map_err(|source| Error::IoError { source })
105    }
106}