diff --git a/src/commands/version.rs b/src/commands/version.rs index c0cd145..1d8ab13 100644 --- a/src/commands/version.rs +++ b/src/commands/version.rs @@ -1,14 +1,16 @@ use anyhow::Result; use clap::Parser; use conventional_commit::ConventionalCommit; -use git2::{string_array::StringArray, Oid, Repository}; +use git2::{Oid, Repository}; use semver::Version; use semver_bump_trait::SemverBump; -use slog::{info, warn}; +use slog::{debug, info}; use std::cmp::Ordering; use std::collections::HashMap; use std::str::FromStr; +use crate::tags::get_tag_map; + /// Gets the current version based on commits. #[derive(Debug, Parser)] pub struct VersionCommand {} @@ -23,19 +25,25 @@ enum VersionBump { impl VersionCommand { pub async fn run(&self, log: slog::Logger) -> Result<()> { - // Figure out the path we are loading. + // Figure out the path we're searching and which one we found. let current_dir = "/home/dmoonfire/src/mfgames/mfgames-cil/src/MfGames.Nitride"; - info!(log, "using current directory {:?}", current_dir); + info!(log, "searching from {:?}", current_dir); // Load the repository so we can walk through it. let repo = Repository::discover(current_dir)?; + let git_dir = &repo.workdir(); + + if let Some(git_dir) = git_dir { + info!(log, "git root at {:?}", git_dir); + } else { + info!(log, "working with a bare repository"); + } // Load a map of all commits that are pointed to by a tag. let tag_prefix = "MfGames.Nitride-*"; - let tag_name_list = &repo.tag_names(Some(tag_prefix))?; let tag_map: HashMap = - self.get_tag_map(&log, &repo, &tag_prefix, tag_name_list)?; + get_tag_map(&log, &repo, &tag_prefix)?; // Figure out the head. let head = repo.head()?; @@ -51,17 +59,31 @@ impl VersionCommand { // // Failing everything, we use our fallback. let mut version = Version::parse("0.0.1").unwrap(); - let mut check_list = vec![(commit.id(), VersionBump::None)]; + let mut check_list = vec![(commit.id(), VersionBump::None, 0usize)]; + let mut count = 0; while !&check_list.is_empty() { - info!(log, "checking {:?} entries", &check_list.len()); + count += 1; + + info!( + log, + " checking {:?} entries, round {}", + &check_list.len(), + count + ); let old_list = check_list.clone(); check_list.clear(); - for (oid, bump) in old_list { + for (oid, bump, depth) in old_list { // First check to see if we have a version for this commit. - info!(log, "checking oid {:?}, currently {:?}", oid, bump); + info!( + log, + " checking oid {:?}, bump {:?}, depth {}", + oid, + bump, + depth + ); if let Some(tag_version) = &tag_map.get(&oid) { // We have a tag, so use our gathered operation to figure @@ -84,7 +106,7 @@ impl VersionCommand { info!( log, - "found tag {} + {:?} -> {}", + " found tag {} + {:?} -> {}", &tag_version, &bump, &bump_version @@ -110,19 +132,23 @@ impl VersionCommand { let commit = &repo.find_commit(oid)?; let parent_count = commit.parent_count(); - info!(log, "something {:?}", commit.id()); - info!(log, " message {:?}", message); - info!(log, " type {:?}", conv.type_()); - info!( + debug!(log, " commit {:?}", commit.id()); + debug!(log, " message {:?}", message); + debug!(log, " type {:?}", conv.type_()); + debug!( log, - " bump {:?} + {:?} -> {:?}", &bump, &commit_bump, new_bump + " bump {:?} + {:?} -> {:?}", + &bump, + &commit_bump, + new_bump ); - info!(log, " parent_count {:?}", parent_count); + debug!(log, " parent_count {:?}", parent_count); // Since we haven't found a tag, insert the entry into the new // list. for parent in commit.parent_ids() { - check_list.push((parent, new_bump.clone())); + debug!(log, " parent {:?}", parent); + check_list.push((parent, new_bump.clone(), depth + 1)); } } } @@ -151,54 +177,4 @@ impl VersionCommand { _ => VersionBump::None, }; } - - fn get_tag_map<'a>( - &'a self, - log: &slog::Logger, - repo: &Repository, - tag_prefix: &str, - tag_name_list: &'a StringArray, - ) -> Result> { - let mut tag_map: HashMap = HashMap::new(); - - info!(log, "looking for {}", tag_prefix); - - for name in tag_name_list.into_iter() { - // Get the object that we're pointing to. - let name = name.unwrap(); - let obj = repo.revparse_single(&name)?; - - if let Some(_tag) = obj.as_tag() { - warn!(log, "cannot handle a tag pointing to another tag"); - } else if let Some(commit) = obj.as_commit() { - // Keep the OID since that is how we will look up the commits. - let oid = commit.id(); - - // Strip off the version and convert it into a semver. - let version = name.chars(); - let version = version.skip(tag_prefix.len() - 1); - let version: String = version.collect(); - let version = Version::parse(&version).unwrap(); - - if let Some(old_version) = tag_map.get(&oid) { - if version.cmp(old_version) == Ordering::Greater { - tag_map.insert(oid, version); - } - } else { - tag_map.insert(oid, version); - } - } else { - warn!(log, "cannot handle a tag pointing to something other than a commit"); - } - } - - let tag_map_len = &tag_map.len(); - - info!( - log, - "loaded in {:?} tags matching {:?}", tag_map_len, tag_prefix - ); - - Ok(tag_map) - } } diff --git a/src/main.rs b/src/main.rs index 2ade3df..ce8813a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use anyhow::Result; use clap::Parser; mod commands; +mod tags; #[tokio::main] async fn main() { diff --git a/src/tags.rs b/src/tags.rs new file mode 100644 index 0000000..afd77d5 --- /dev/null +++ b/src/tags.rs @@ -0,0 +1,85 @@ +use anyhow::Result; +use git2::{Oid, Repository}; +use semver::Version; +use slog::{debug, info, warn}; +use std::cmp::Ordering; +use std::collections::HashMap; + +pub fn get_tag_map<'a>( + log: &slog::Logger, + repo: &Repository, + tag_prefix: &str, +) -> Result> { + let tag_name_list = &repo.tag_names(Some(tag_prefix))?; + let mut tag_map: HashMap = HashMap::new(); + + info!(log, "looking for {}", tag_prefix); + + for name in tag_name_list.into_iter() { + // Get the object that we're pointing to. + let name = name.unwrap(); + let obj = repo.revparse_single(&name)?; + + if let Some(_tag) = obj.as_tag() { + warn!(log, "cannot handle a tag pointing to another tag"); + } else if let Some(commit) = obj.as_commit() { + // Keep the OID since that is how we will look up the commits. + let oid = commit.id(); + + // Strip off the version and convert it into a semver. + let version = name.chars(); + let version = version.skip(tag_prefix.len() - 1); + let version: String = version.collect(); + + // Try to convert the results into a semver. + let semver = Version::parse(&version); + + if semver.is_err() { + warn!(log, "cannot parse {:?} from commit {}", version, oid); + continue; + } + + let new_version = semver.unwrap(); + + if let Some(old_version) = tag_map.get(&oid) { + if new_version.cmp(old_version) == Ordering::Greater { + debug!( + log, + "updating version for {:?}: {} + {} -> {}", + oid, + old_version, + new_version, + new_version + ); + tag_map.insert(oid, new_version); + } else { + debug!( + log, + "updating version for {:?}: {} + {} -> {}", + oid, + old_version, + new_version, + old_version + ); + } + } else { + debug!(log, "setting version for {:?}: {}", oid, new_version); + tag_map.insert(oid, new_version); + } + } else { + warn!( + log, + "cannot handle a tag pointing to something other than a commit" + ); + } + } + + let tag_map_len = &tag_map.len(); + + info!( + log, + "loaded in {:?} tags matching {:?}", tag_map_len, tag_prefix + ); + + Ok(tag_map) +}