use crate::cli::args::*;
use pinto::i18n::{Message, current};
use pinto::service::{InitOutcome, MigrateOutcome, init_board, migrate_storage, rebalance};
use pinto::storage::StorageBackend;
use std::process::ExitCode;
pub(super) async fn cmd_rebalance(args: RebalanceArgs) -> anyhow::Result<ExitCode> {
let dir = std::env::current_dir()?;
let outcome = rebalance(&dir, args.dry_run).await?;
if outcome.changed == 0 {
println!(
"{}",
current().format(
Message::RebalanceAlreadyBalanced,
[
("count", outcome.total.to_string().as_str()),
("max_length", outcome.before.max_len.to_string().as_str()),
],
)
);
} else {
let message = if args.dry_run {
Message::RebalanceDryRun
} else {
Message::RebalanceCompleted
};
println!(
"{}",
current().format(
message,
[
("changed", outcome.changed.to_string().as_str()),
("total", outcome.total.to_string().as_str()),
("before", outcome.before.max_len.to_string().as_str()),
("after", outcome.after.max_len.to_string().as_str()),
],
)
);
}
Ok(ExitCode::SUCCESS)
}
pub(super) async fn cmd_migrate(args: MigrateArgs) -> anyhow::Result<ExitCode> {
let dir = std::env::current_dir()?;
let target = match args.to {
MigrateTarget::File => StorageBackend::File,
MigrateTarget::Git => StorageBackend::Git,
MigrateTarget::Sqlite => {
#[cfg(feature = "sqlite")]
{
StorageBackend::Sqlite
}
#[cfg(not(feature = "sqlite"))]
{
eprintln!(
"{} {}",
current().text(Message::ErrorPrefix),
current().text(Message::MigrationSqliteUnavailable)
);
return Ok(ExitCode::from(1));
}
}
};
match migrate_storage(&dir, target).await? {
MigrateOutcome::Migrated {
from,
to,
items,
sprints,
} => {
let localizer = current();
println!(
"{}",
localizer.format(
Message::MigrationCompleted,
[
("items", items.to_string().as_str()),
("sprints", sprints.to_string().as_str()),
("from", from.to_string().as_str()),
("to", to.to_string().as_str()),
],
)
);
println!(
"{}",
localizer.format(
Message::MigrationBackendUpdated,
[("backend", to.to_string().as_str())],
)
);
}
MigrateOutcome::AlreadyUsing(backend) => {
println!(
"{}",
current().format(
Message::MigrationAlreadyUsing,
[("backend", backend.to_string().as_str())],
)
);
}
}
Ok(ExitCode::SUCCESS)
}
pub(super) async fn cmd_doctor(args: DoctorArgs) -> anyhow::Result<ExitCode> {
let dir = std::env::current_dir()?;
let report = pinto::service::doctor(&dir, args.fix).await?;
let localizer = current();
if report.issues.is_empty() {
println!("{}", localizer.text(Message::DoctorHealthy));
} else {
println!(
"{}",
localizer.format(
Message::DoctorIssues,
[("count", report.issues.len().to_string().as_str())],
)
);
}
for fix in &report.fixes {
println!(
"{}",
localizer.format(
Message::DoctorFixed,
[("description", fix.description.as_str())]
)
);
}
for issue in &report.issues {
let kind = doctor_issue_kind_name(issue.kind, localizer);
println!(
"{}",
localizer.format(
Message::DoctorIssue,
[
("kind", kind.as_str()),
("location", issue.location.as_str()),
("detail", issue.detail.as_str()),
("repair", issue.repair.as_str()),
],
)
);
}
Ok(if report.issues.is_empty() {
ExitCode::SUCCESS
} else {
ExitCode::from(1)
})
}
fn doctor_issue_kind_name(
kind: pinto::service::DoctorIssueKind,
localizer: &pinto::i18n::Localizer,
) -> String {
match kind {
pinto::service::DoctorIssueKind::DanglingDependency => {
localizer.text(Message::DoctorKindDanglingDependency)
}
pinto::service::DoctorIssueKind::DanglingParent => {
localizer.text(Message::DoctorKindDanglingParent)
}
pinto::service::DoctorIssueKind::DanglingSprint => {
localizer.text(Message::DoctorKindDanglingSprint)
}
pinto::service::DoctorIssueKind::ParentCycle => {
localizer.text(Message::DoctorKindParentCycle)
}
pinto::service::DoctorIssueKind::DependencyCycle => {
localizer.text(Message::DoctorKindDependencyCycle)
}
pinto::service::DoctorIssueKind::DuplicateId => {
localizer.text(Message::DoctorKindDuplicateId)
}
pinto::service::DoctorIssueKind::IssuedId => localizer.text(Message::DoctorKindIssuedId),
pinto::service::DoctorIssueKind::InvalidStatus => {
localizer.text(Message::DoctorKindInvalidStatus)
}
pinto::service::DoctorIssueKind::RankAnomaly => {
localizer.text(Message::DoctorKindRankAnomaly)
}
pinto::service::DoctorIssueKind::Collision => localizer.text(Message::DoctorKindCollision),
pinto::service::DoctorIssueKind::MalformedRecord => {
localizer.text(Message::DoctorKindMalformedRecord)
}
pinto::service::DoctorIssueKind::Filename => localizer.text(Message::DoctorKindFilename),
}
}
pub(super) async fn cmd_init() -> anyhow::Result<ExitCode> {
let dir = std::env::current_dir()?;
match init_board(&dir).await? {
InitOutcome::Created(path) => {
println!(
"{}",
current().format(
Message::InitializedBoardAt,
[("path", path.display().to_string().as_str())],
)
);
}
InitOutcome::AlreadyInitialized(path) => {
println!(
"{}",
current().format(
Message::AlreadyInitialized,
[("path", path.display().to_string().as_str())],
)
);
}
}
Ok(ExitCode::SUCCESS)
}