use nix_uri::FlakeRef;
use crate::change::{Change, ChangeId};
use super::{Error, Result};
#[derive(Default)]
pub struct UriOptions<'a> {
pub ref_or_rev: Option<&'a str>,
pub shallow: bool,
}
pub(super) enum BuildKind {
Add { no_flake: bool },
Change,
}
pub(super) fn build_uri_change(
kind: BuildKind,
id: String,
uri: String,
opts: &UriOptions<'_>,
) -> Result<Change> {
let final_uri = transform_uri(uri, opts.ref_or_rev, opts.shallow)?;
let id = ChangeId::parse(&id).map_err(|source| Error::InvalidInputId { id, source })?;
Ok(match kind {
BuildKind::Add { no_flake } => Change::Add {
id: Some(id),
uri: Some(final_uri),
flake: !no_flake,
},
BuildKind::Change => Change::Change {
id: Some(id),
uri: Some(final_uri),
},
})
}
pub(super) fn apply_uri_options(
flake_ref: FlakeRef,
ref_or_rev: Option<&str>,
shallow: bool,
) -> FlakeRef {
let mut flake_ref = if let Some(ror) = ref_or_rev {
flake_ref.with_ref(Some(ror.to_string()))
} else {
flake_ref
};
if shallow {
flake_ref.set_shallow(true);
}
flake_ref
}
pub(super) fn transform_uri(
uri: String,
ref_or_rev: Option<&str>,
shallow: bool,
) -> Result<String> {
let flake_ref: FlakeRef = uri.parse().map_err(|source| Error::InvalidUri {
uri: uri.clone(),
source,
})?;
if ref_or_rev.is_none() && !shallow {
return Ok(uri);
}
Ok(apply_uri_options(flake_ref, ref_or_rev, shallow).into_uri())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn malformed_id_surfaces_as_invalid_input_id() {
let opts = UriOptions::default();
let err = build_uri_change(
BuildKind::Change,
"a..b".to_string(),
"github:owner/repo".to_string(),
&opts,
)
.expect_err("a malformed id must not build a Change");
assert!(
matches!(&err, Error::InvalidInputId { id, .. } if id == "a..b"),
"expected InvalidInputId for 'a..b', got: {err:?}"
);
}
}