Compare commits

...

5 Commits

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
### Added
- add crate version info to verbose status
## [v0.2.0] - 2022-08-04 ## [v0.2.0] - 2022-08-04
### Changed ### Changed

881
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
[package] [package]
name = "cargo-vcs" name = "cargo-vcs"
version = "0.2.0" version = "0.2.1"
description = "Cargo workspace helper for Version Control System project management" description = "Cargo workspace helper for Version Control System project management"
edition = "2021" edition = "2021"
license = "AGPL-3.0-only" license = "AGPL-3.0-only"
@ -12,11 +12,12 @@ categories = ["development-tools::cargo-plugins", "command-line-utilities"]
repository = "https://codeberg.org/almindor/cargo-vcs" repository = "https://codeberg.org/almindor/cargo-vcs"
[dependencies] [dependencies]
clap = { version = "3.2", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
crossterm = "0.24" crossterm = "0.28"
enumset = "1.0" enumset = "1.0"
git2 = "0.14" git2 = "0.19"
machine-uid = "0.2" machine-uid = "0.5"
semver = "1.0" semver = "1.0"
termtree = "0.4" serde = "1.0"
toml = "0.5" termtree = "0.5"
toml = "0.8"

@ -6,10 +6,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use toml::{ use toml::{map::Map, value::Table, Value};
value::{Map, Table},
Value,
};
pub mod cli; pub mod cli;
mod colors; mod colors;
@ -201,8 +198,9 @@ impl Vcs {
if let Some(section) = vcs_section.as_table_mut() { if let Some(section) = vcs_section.as_table_mut() {
section.insert(profile_name.into(), value); section.insert(profile_name.into(), value);
} else { } else {
return Err(Error::Upstream(Box::new(toml::ser::Error::Custom( use serde::ser::Error as _;
"Existing vcs section not a table".into(), return Err(Error::Upstream(Box::new(toml::ser::Error::custom(
"Existing vcs section not a table",
)))); ))));
} }
} else { } else {
@ -326,9 +324,12 @@ impl Vcs {
} }
} }
let current_ref = project.repo.current_ref()?;
// stash changes before moving project off to a new ref // stash changes before moving project off to a new ref
let stashed_changes = project.repo.stash_changes(&current_ref)?; let stashed_changes = if let Some(current_ref) = project.current_ref()? {
project.repo.stash_changes(&current_ref)?
} else {
false
};
// try to switch to new ref using provided setter // try to switch to new ref using provided setter
let new_ref = match setter(project) { let new_ref = match setter(project) {
@ -371,8 +372,9 @@ impl Vcs {
let mut table = Table::new(); let mut table = Table::new();
for project in &self.projects { for project in &self.projects {
let head_ref_name = project.repo.current_ref()?; if let Some(head_ref_name) = project.current_ref()? {
table.insert(project.name().into(), Value::String(head_ref_name)); table.insert(project.name().into(), Value::String(head_ref_name));
}
} }
Ok(Value::Table(table)) Ok(Value::Table(table))

@ -4,5 +4,6 @@ pub const PROJECT_COLOR: Color = Color::Red;
pub const PROFILE_COLOR: Color = Color::Blue; pub const PROFILE_COLOR: Color = Color::Blue;
pub const ERROR_COLOR: Color = Color::DarkRed; pub const ERROR_COLOR: Color = Color::DarkRed;
pub const CHANGES_COLOR: Color = Color::Cyan; pub const CHANGES_COLOR: Color = Color::Cyan;
pub const VERSION_COLOR: Color = Color::DarkGreen;
pub const REFS_COLOR: Color = Color::DarkYellow; pub const REFS_COLOR: Color = Color::DarkYellow;
pub const MSRV_COLOR: Color = Color::DarkCyan; pub const MSRV_COLOR: Color = Color::DarkCyan;

@ -17,6 +17,7 @@ pub struct Project {
path: PathBuf, path: PathBuf,
name: String, name: String,
msrv: Option<Version>, msrv: Option<Version>,
crate_version: Version,
pub repo: Box<dyn Repository>, pub repo: Box<dyn Repository>,
profile_map: HashMap<String, String>, // vcs profile name to branch names profile_map: HashMap<String, String>, // vcs profile name to branch names
} }
@ -48,12 +49,17 @@ impl Project {
.to_owned(); .to_owned();
let repo = GitRepository::open(&path)?; let repo = GitRepository::open(&path)?;
let msrv = Self::parse_msrv(&path)?; let msrv = Self::parse_version(&path, "rust-version")?;
let crate_version = match Self::parse_version(&path, "version")? {
Some(v) => v,
None => return Err(Error::cargo_error("Crate version not found")),
};
Ok(Self { Ok(Self {
path, path,
name, name,
msrv, msrv,
crate_version,
repo, repo,
profile_map, profile_map,
}) })
@ -67,9 +73,25 @@ impl Project {
&self.path &self.path
} }
pub fn current_ref(&self) -> Result<Option<String>, Error> {
match self.repo.current_ref() {
Ok(val) => Ok(Some(val)),
Err(err) => {
eprintln!("{}: {}\n", self.name(), err);
Ok(None)
}
}
}
pub fn current_profile(&self) -> Result<Option<String>, Error> { pub fn current_profile(&self) -> Result<Option<String>, Error> {
let current_ref = self.repo.current_ref()?; // repo.current_ref can fail if repo has no head yet (e.g. post init)
if let Some(val) = self.profile_map.iter().find(|v| v.1 == &current_ref) { let current_ref = self.current_ref()?;
if let Some(val) = self
.profile_map
.iter()
.find(|v| Some(v.1) == current_ref.as_ref())
{
return Ok(Some(val.0.clone())); return Ok(Some(val.0.clone()));
} }
@ -92,18 +114,18 @@ impl Project {
self.msrv.as_ref() self.msrv.as_ref()
} }
fn parse_msrv(path: &Path) -> Result<Option<Version>, Error> { fn parse_version(path: &Path, key: &str) -> Result<Option<Version>, Error> {
let toml_path = path.join("Cargo.toml"); let toml_path = path.join("Cargo.toml");
let toml_contents = std::fs::read_to_string(toml_path)?; let toml_contents = std::fs::read_to_string(toml_path)?;
let cargo: toml::Value = toml::from_str(&toml_contents)?; let cargo: toml::Value = toml::from_str(&toml_contents)?;
if let Some(pkg) = cargo.get("package") { if let Some(pkg) = cargo.get("package") {
if let Some(value) = pkg.get("rust-version") { if let Some(value) = pkg.get(key) {
if value.is_str() { if value.is_str() {
let mut ver_str = value let mut ver_str = value
.as_str() .as_str()
.ok_or_else(|| Error::cargo_error("Unparsable rust-version in Cargo.toml"))? .ok_or_else(|| Error::cargo_error("Unparsable version in Cargo.toml"))?
.to_owned(); .to_owned();
let dots = ver_str.chars().filter(|c| *c == '.').count(); let dots = ver_str.chars().filter(|c| *c == '.').count();
if !(1..=2).contains(&dots) { if !(1..=2).contains(&dots) {
@ -125,9 +147,12 @@ impl Project {
pub fn display(&self, options: EnumSet<ProjectDisplayOptions>) -> Result<Tree<String>, Error> { pub fn display(&self, options: EnumSet<ProjectDisplayOptions>) -> Result<Tree<String>, Error> {
let title = format!( let title = format!(
"{}: {} [{}]", "{}@{}: {} [{}]",
self.name().bold().with(PROJECT_COLOR), self.name().bold().with(PROJECT_COLOR),
self.repo.current_ref()?.with(REFS_COLOR), format!("v{}", self.crate_version).with(VERSION_COLOR),
self.current_ref()?
.unwrap_or_else(|| "???".into())
.with(REFS_COLOR),
format!("{}", self.path().display()).italic(), format!("{}", self.path().display()).italic(),
); );
let mut root = Tree::new(title); let mut root = Tree::new(title);

Loading…
Cancel
Save