adnv 1.5.0

CLI that tracks, checks and auto-updates infrastructure dependency versions across Terraform, Helm, Docker, Git and npm
Documentation
use core::ops::Deref;

use crate::error::ErrorWithData;
use std::cmp::Ordering;

pub mod data;
pub mod list;
pub mod parse;
pub mod resolve;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Source {
    pub data: data::Source,
    pub loc: Option<parse::Location>,
}

impl Source {
    pub fn new(data: data::Source) -> Self {
        Self { data, loc: None }
    }

    pub fn location(&self) -> Option<&parse::Location> {
        self.loc.as_ref()
    }

    pub fn with_location(self, loc: parse::Location) -> Self {
        Self {
            loc: Some(loc),
            ..self
        }
    }
}

impl Deref for Source {
    type Target = data::Source;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Into<data::Source>> From<T> for Source {
    fn from(value: T) -> Self {
        Self::new(value.into())
    }
}

pub type Version = String;
pub type VersionReq = String;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VersionedSource {
    pub source: Source,
    pub current: Option<VersionReq>,
    pub required: Option<VersionReq>,
}

impl VersionedSource {
    pub fn new<T: Into<Source>>(source: T) -> Self {
        Self {
            source: source.into(),
            current: None,
            required: None,
        }
    }

    pub fn with_current(self, current: impl Into<VersionReq>) -> Self {
        Self {
            current: Some(current.into()),
            ..self
        }
    }

    pub fn with_required(self, required: impl Into<VersionReq>) -> Self {
        Self {
            required: Some(required.into()),
            ..self
        }
    }

    pub fn with_location(self, loc: parse::Location) -> Self {
        Self {
            source: self.source.with_location(loc),
            ..self
        }
    }
}

impl PartialOrd for VersionedSource {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for VersionedSource {
    fn cmp(&self, other: &Self) -> Ordering {
        // First compare sources
        let source_cmp = self
            .source
            .data
            .describe()
            .cmp(&other.source.data.describe());
        if source_cmp != Ordering::Equal {
            return source_cmp;
        }

        // Then compare current versions
        let current_cmp = self.current.cmp(&other.current);
        if current_cmp != Ordering::Equal {
            return current_cmp;
        }

        // Finally compare required versions
        self.required.cmp(&other.required)
    }
}
pub fn print_errors(errors: Vec<ErrorWithData<VersionedSource>>) {
    for (err, source) in errors.into_iter().map(ErrorWithData::split) {
        // Sources given on the command line or in the config have no location
        // in a file, only the parsed ones do.
        match source.source.location() {
            Some(loc) => println!(
                "Error at `{}`:\n\t{}\n\t\t{:?}",
                loc,
                source.source.describe(),
                miette::Report::new(err)
            ),
            None => println!(
                "Error for `{}`:\n\t{:?}",
                source.source.describe(),
                miette::Report::new(err)
            ),
        }
    }
}