use std::borrow::Cow;
static DFSG_REGEX: &lazy_regex::Lazy<lazy_regex::Regex> =
lazy_regex::regex!(r"^(.*)([\+~])(dfsg|ds)([0-9]*)$");
const DFSG_DEFAULT_STYLE: &str = "+ds";
pub fn strip_dfsg_suffix(version: &str) -> Option<&str> {
if let Some(m) = DFSG_REGEX.captures(version) {
Some(m.get(1).unwrap().as_str())
} else {
None
}
}
pub fn add_dfsg_suffix(upstream_version: &str, old_upstream_version: Option<&str>) -> String {
let style = if let Some(m) = old_upstream_version.and_then(|d| DFSG_REGEX.captures(d)) {
let part2 = m.get(2).unwrap().as_str();
let part3 = m.get(3).unwrap().as_str();
let part4 = m.get(4).unwrap().as_str();
Cow::Owned(if part4.is_empty() {
format!("{}{}", part2, part3)
} else {
format!("{}{}1", part2, part3)
})
} else {
Cow::Borrowed(DFSG_DEFAULT_STYLE)
};
format!("{}{}", upstream_version, style)
}
#[derive(Debug, Clone, PartialEq)]
pub enum VcsSnapshot {
Git {
date: Option<chrono::NaiveDate>,
sha: Option<String>,
snapshot: Option<usize>,
},
Bzr {
revno: String,
},
Svn {
revno: usize,
},
}
impl VcsSnapshot {
fn to_suffix(&self) -> String {
match self {
VcsSnapshot::Git {
date,
sha,
snapshot,
} => match (sha.as_deref(), snapshot, date.as_ref()) {
(Some(sha), Some(snapshot), Some(date)) => {
let gitid = &sha[..sha.len().min(7)];
format!("git{}.{}.{}", date.format("%Y%m%d"), snapshot, gitid)
}
(Some(sha), None, Some(date)) => {
let gitid = &sha[..sha.len().min(7)];
format!("git{}.{}", date.format("%Y%m%d"), gitid)
}
(Some(sha), _, None) => {
let gitid = &sha[..sha.len().min(7)];
format!("git{}", gitid)
}
(None, _, Some(date)) => {
format!("git{}", date.format("%Y%m%d"))
}
(None, _, None) => "git".to_string(),
},
VcsSnapshot::Bzr { revno } => format!("bzr{}", revno),
VcsSnapshot::Svn { revno } => format!("svn{}", revno),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Direction {
Before,
After,
}
impl From<&str> for Direction {
fn from(s: &str) -> Self {
match s {
"~" => Direction::Before,
"+" => Direction::After,
_ => panic!("Invalid direction"),
}
}
}
impl Direction {
pub const fn as_str(&self) -> &'static str {
match self {
Direction::Before => "~",
Direction::After => "+",
}
}
}
impl From<Direction> for &str {
fn from(d: Direction) -> Self {
d.as_str()
}
}
pub fn get_revision(version_string: &str) -> (&str, Option<(Direction, VcsSnapshot)>) {
if let Some((_, b, s, r)) =
lazy_regex::regex_captures!(r"^(.*)([\+~])bzr(\d+)$", version_string)
{
(
b,
Some((
s.into(),
VcsSnapshot::Bzr {
revno: r.to_string(),
},
)),
)
} else if let Some((_, b, s, d, i)) =
lazy_regex::regex_captures!(r"^(.*)([\+~-])git(\d{8})\.([a-f0-9]{7})$", version_string)
{
(
b,
Some((
s.into(),
VcsSnapshot::Git {
date: chrono::NaiveDate::parse_from_str(d, "%Y%m%d").ok(),
sha: Some(i.to_string()),
snapshot: None,
},
)),
)
} else if let Some((_, b, s, d, r, i)) = lazy_regex::regex_captures!(
r"^(.*)([\+~-])git(\d{8})\.(\d+)\.([a-f0-9]{7})$",
version_string
) {
(
b,
Some((
s.into(),
VcsSnapshot::Git {
date: chrono::NaiveDate::parse_from_str(d, "%Y%m%d").ok(),
sha: Some(i.to_string()),
snapshot: r.parse().ok(),
},
)),
)
} else if let Some((_, b, s, r)) =
lazy_regex::regex_captures!(r"^(.*)([\+~-])svn(\d+)$", version_string)
{
(
b,
Some((
s.into(),
VcsSnapshot::Svn {
revno: r.parse().unwrap(),
},
)),
)
} else {
(version_string, None)
}
}
pub fn upstream_version_add_revision(
version_string: &str,
mut vcs_snapshot: VcsSnapshot,
sep: Option<Direction>,
) -> String {
let plain_version = strip_dfsg_suffix(version_string).unwrap_or(version_string);
let (base_version, current_sep, current_vcs) = match get_revision(plain_version) {
(base_version, Some((sep, current_vcs))) => (base_version, Some(sep), Some(current_vcs)),
(base_version, None) => (base_version, None, None),
};
let sep = sep.or(current_sep).unwrap_or(Direction::After);
if let (
VcsSnapshot::Git {
date,
sha,
snapshot,
},
Some(VcsSnapshot::Git {
date: c_date,
sha: c_sha,
snapshot: c_snapshot,
}),
) = (&mut vcs_snapshot, current_vcs.as_ref())
{
if snapshot.is_none() {
*snapshot = if date.as_ref() == c_date.as_ref() && sha.as_ref() != c_sha.as_ref() {
c_snapshot.map(|s| s + 1)
} else {
Some(1)
};
}
if c_date.is_none() {
*date = None;
}
if c_sha.is_none() {
*sha = None;
}
}
let sep = sep.as_str();
format!("{}{}{}", base_version, sep, vcs_snapshot.to_suffix())
}
#[cfg(test)]
mod tests {
#[test]
fn test_strip_dfsg_suffix() {
assert_eq!(super::strip_dfsg_suffix("1.2.3+dfsg1"), Some("1.2.3"));
assert_eq!(super::strip_dfsg_suffix("1.2.3+ds1"), Some("1.2.3"));
assert_eq!(super::strip_dfsg_suffix("1.2.3"), None);
}
#[test]
fn test_add_dfsg_suffix() {
assert_eq!(super::add_dfsg_suffix("1.2.3", None), "1.2.3+ds");
assert_eq!(
super::add_dfsg_suffix("1.2.3", Some("1.2.3+dfsg1")),
"1.2.3+dfsg1"
);
assert_eq!(
super::add_dfsg_suffix("1.2.3", Some("1.2.3+ds1")),
"1.2.3+ds1"
);
assert_eq!(super::add_dfsg_suffix("1.2.3", Some("1.2.3")), "1.2.3+ds");
}
#[test]
fn test_to_suffix() {
assert_eq!(
"git",
super::VcsSnapshot::Git {
date: None,
sha: None,
snapshot: None,
}
.to_suffix()
);
assert_eq!(
"git20210101",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: None,
snapshot: None,
}
.to_suffix()
);
assert_eq!(
"gitabcdefa",
super::VcsSnapshot::Git {
date: None,
sha: Some("abcdefa".to_string()),
snapshot: None,
}
.to_suffix()
);
assert_eq!(
"git20210101.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: Some("abcdefa".to_string()),
snapshot: None,
}
.to_suffix()
);
assert_eq!(
"git20210101.1.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: Some("abcdefa".to_string()),
snapshot: Some(1),
}
.to_suffix()
);
assert_eq!(
"bzr123",
super::VcsSnapshot::Bzr {
revno: "123".to_string(),
}
.to_suffix()
);
assert_eq!("svn123", super::VcsSnapshot::Svn { revno: 123 }.to_suffix());
}
#[test]
fn test_upstream_version_add_new_suffix_bzr() {
assert_eq!(
"1.2.3+bzr123",
super::upstream_version_add_revision(
"1.2.3",
super::VcsSnapshot::Bzr {
revno: "123".to_string()
},
None
)
);
}
#[test]
fn test_upstream_version_add_existing_suffix_bzr() {
assert_eq!(
"1.2.3+bzr124",
super::upstream_version_add_revision(
"1.2.3+bzr123",
super::VcsSnapshot::Bzr {
revno: "124".to_string()
},
None
)
);
}
#[test]
fn test_upstream_version_add_new_suffix_git() {
assert_eq!(
"1.2.3+git20210101",
super::upstream_version_add_revision(
"1.2.3",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: None,
snapshot: None,
},
None
)
);
}
#[test]
fn test_upstream_version_add_existing_suffix_git() {
assert_eq!(
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: Some("abcdefa".to_string()),
snapshot: None,
},
super::get_revision("1.2.3+git20210101.abcdefa")
.1
.unwrap()
.1
);
assert_eq!(
"1.2.3+gitabcdefa",
super::upstream_version_add_revision(
"1.2.3+git20210101.1.abcdefa",
super::VcsSnapshot::Git {
date: None,
sha: Some("abcdefa".to_string()),
snapshot: None,
},
None
)
);
}
#[test]
fn test_upstream_version_add_new_suffix_svn() {
assert_eq!(
"1.2.3+svn123",
super::upstream_version_add_revision(
"1.2.3",
super::VcsSnapshot::Svn { revno: 123 },
None
)
);
}
#[test]
fn test_upstream_version_add_existing_suffix_svn() {
assert_eq!(
super::VcsSnapshot::Svn { revno: 123 },
super::get_revision("1.2.3+svn123").1.unwrap().1
);
assert_eq!(
"1.2.3+svn124",
super::upstream_version_add_revision(
"1.2.3+svn123",
super::VcsSnapshot::Svn { revno: 124 },
None
)
);
}
#[test]
fn test_upstream_version_add_revision_git_snapshot_increment() {
let result = super::upstream_version_add_revision(
"1.2.3+git20210101.1.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: Some("bcdefgh".to_string()),
snapshot: None,
},
None,
);
assert_eq!("1.2.3+git20210101.2.bcdefgh", result);
let result2 = super::upstream_version_add_revision(
"1.2.3+git20210101.5.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 2).unwrap()),
sha: Some("bcdefgh".to_string()),
snapshot: None,
},
None,
);
assert_eq!("1.2.3+git20210102.1.bcdefgh", result2);
let result3 = super::upstream_version_add_revision(
"1.2.3+git20210101.1.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 1).unwrap()),
sha: Some("abcdefa".to_string()),
snapshot: None,
},
None,
);
assert_eq!("1.2.3+git20210101.1.abcdefa", result3);
let result4 = super::upstream_version_add_revision(
"1.2.3+git20210101.3.abcdefa",
super::VcsSnapshot::Git {
date: Some(chrono::NaiveDate::from_ymd_opt(2021, 1, 3).unwrap()),
sha: Some("bcdefgh".to_string()),
snapshot: None,
},
None,
);
assert_eq!("1.2.3+git20210103.1.bcdefgh", result4);
}
}