radicle: Implement migration callback mechanism
Add the ability to have native migrations and progress callback functions in migration code for the COB cache.
This commit is contained in:
parent
088339850b
commit
6c8ee4330e
|
|
@ -9,6 +9,7 @@ use radicle::issue::cache::Issues as _;
|
|||
use radicle::patch::cache::Patches as _;
|
||||
use thiserror::Error;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::git::raw;
|
||||
use radicle::identity::doc;
|
||||
use radicle::identity::doc::{DocError, RepoId};
|
||||
|
|
@ -182,8 +183,8 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
info.push([term::format::bold(proj.name()).into()]);
|
||||
info.push([term::format::italic(proj.description()).into()]);
|
||||
|
||||
let issues = profile.issues(&repo)?.counts()?;
|
||||
let patches = profile.patches(&repo)?.counts()?;
|
||||
let issues = profile.issues(&repo, migrate::ignore)?.counts()?;
|
||||
let patches = profile.patches(&repo, migrate::ignore)?.counts()?;
|
||||
|
||||
info.push([term::Line::spaced([
|
||||
term::format::tertiary(issues.open).into(),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use anyhow::anyhow;
|
|||
use chrono::prelude::*;
|
||||
use nonempty::NonEmpty;
|
||||
use radicle::cob;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::Op;
|
||||
use radicle::identity::Identity;
|
||||
use radicle::issue::cache::Issues;
|
||||
|
|
@ -180,13 +181,13 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
let oid = &oid.resolve(&repo.backend)?;
|
||||
|
||||
if options.type_name == cob::patch::TYPENAME.clone() {
|
||||
let patches = profile.patches(&repo)?;
|
||||
let patches = profile.patches(&repo, migrate::ignore)?;
|
||||
let Some(patch) = patches.get(oid)? else {
|
||||
anyhow::bail!(cob::store::Error::NotFound(options.type_name, *oid))
|
||||
};
|
||||
serde_json::to_writer_pretty(std::io::stdout(), &patch)?
|
||||
} else if options.type_name == cob::issue::TYPENAME.clone() {
|
||||
let issues = profile.issues(&repo)?;
|
||||
let issues = profile.issues(&repo, migrate::ignore)?;
|
||||
let Some(issue) = issues.get(oid)? else {
|
||||
anyhow::bail!(cob::store::Error::NotFound(options.type_name, *oid))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use anyhow::anyhow;
|
|||
|
||||
use git_ref_format::Qualified;
|
||||
use localtime::LocalTime;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::TypedId;
|
||||
use radicle::identity::Identity;
|
||||
use radicle::issue::cache::Issues as _;
|
||||
|
|
@ -271,8 +272,8 @@ where
|
|||
let (_, head) = repo.head()?;
|
||||
let doc = repo.identity_doc()?;
|
||||
let proj = doc.project()?;
|
||||
let issues = profile.issues(&repo)?;
|
||||
let patches = profile.patches(&repo)?;
|
||||
let issues = profile.issues(&repo, migrate::ignore)?;
|
||||
let patches = profile.patches(&repo, migrate::ignore)?;
|
||||
|
||||
let mut notifs = notifs.by_repo(&rid, sort_by.field)?.collect::<Vec<_>>();
|
||||
if !sort_by.reverse {
|
||||
|
|
@ -535,7 +536,7 @@ fn show(
|
|||
|
||||
match n.kind {
|
||||
NotificationKind::Cob { typed_id } if typed_id.is_issue() => {
|
||||
let issues = profile.issues(&repo)?;
|
||||
let issues = profile.issues(&repo, migrate::ignore)?;
|
||||
let issue = issues.get(&typed_id.id)?.unwrap();
|
||||
|
||||
term::issue::show(
|
||||
|
|
@ -546,7 +547,7 @@ fn show(
|
|||
)?;
|
||||
}
|
||||
NotificationKind::Cob { typed_id } if typed_id.is_patch() => {
|
||||
let patches = profile.patches(&repo)?;
|
||||
let patches = profile.patches(&repo, migrate::ignore)?;
|
||||
let patch = patches.get(&typed_id.id)?.unwrap();
|
||||
|
||||
term::patch::show(&patch, &typed_id.id, false, &repo, None, profile)?;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ use std::str::FromStr;
|
|||
use anyhow::{anyhow, Context as _};
|
||||
|
||||
use radicle::cob::common::{Label, Reaction};
|
||||
use radicle::cob::issue;
|
||||
use radicle::cob::issue::{CloseReason, State};
|
||||
use radicle::cob::thread;
|
||||
use radicle::cob::{issue, migrate, thread};
|
||||
use radicle::crypto::Signer;
|
||||
use radicle::issue::cache::Issues as _;
|
||||
use radicle::prelude::{Did, RepoId};
|
||||
|
|
@ -461,7 +460,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
| Operation::Comment { .. }
|
||||
);
|
||||
|
||||
let mut issues = profile.issues_mut(&repo)?;
|
||||
let mut issues = profile.issues_mut(&repo, migrate::ignore)?;
|
||||
|
||||
match options.op {
|
||||
Operation::Edit {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::issue::IssueId;
|
||||
use radicle::storage::git::Repository;
|
||||
use radicle::storage::ReadStorage as _;
|
||||
|
|
@ -37,8 +38,9 @@ pub fn run(mode: CacheMode, profile: &Profile) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
fn cache(id: Option<IssueId>, repository: &Repository, profile: &Profile) -> anyhow::Result<()> {
|
||||
let mut issues = profile.issues_mut(repository)?;
|
||||
let mut issues = profile.issues_mut(repository, migrate::ignore)?;
|
||||
|
||||
// FIXME: Should this change?
|
||||
match id {
|
||||
Some(id) => {
|
||||
issues.write(&id)?;
|
||||
|
|
@ -48,7 +50,7 @@ fn cache(id: Option<IssueId>, repository: &Repository, profile: &Profile) -> any
|
|||
match result {
|
||||
Ok((id, _)) => term::success!(
|
||||
"Successfully cached issue {id} ({}/{})",
|
||||
progress.seen(),
|
||||
progress.current(),
|
||||
progress.total()
|
||||
),
|
||||
Err(e) => term::warning(format!("Failed to retrieve issue: {e}")),
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ use std::ffi::OsString;
|
|||
use anyhow::anyhow;
|
||||
|
||||
use radicle::cob::patch::PatchId;
|
||||
use radicle::cob::{patch, Label};
|
||||
use radicle::cob::{migrate, patch, Label};
|
||||
use radicle::git::RefString;
|
||||
use radicle::patch::cache::Patches as _;
|
||||
use radicle::storage::git::transport;
|
||||
|
|
@ -928,7 +928,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
label::run(&patch_id, add, delete, &profile, &repository)?;
|
||||
}
|
||||
Operation::Set { patch_id, remote } => {
|
||||
let patches = profile.patches(&repository)?;
|
||||
let patches = profile.patches(&repository, migrate::ignore)?;
|
||||
let patch_id = patch_id.resolve(&repository.backend)?;
|
||||
let patch = patches
|
||||
.get(&patch_id)?
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::*;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(mut patch) = patches.get_mut(patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::collections::BTreeSet;
|
|||
|
||||
use super::*;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::prelude::Did;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(mut patch) = patches.get_mut(patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::patch::PatchId;
|
||||
use radicle::storage::git::Repository;
|
||||
use radicle::storage::ReadStorage as _;
|
||||
|
|
@ -37,7 +38,7 @@ pub fn run(mode: CacheMode, profile: &Profile) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
fn cache(id: Option<PatchId>, repository: &Repository, profile: &Profile) -> anyhow::Result<()> {
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
|
||||
match id {
|
||||
Some(id) => {
|
||||
|
|
@ -48,7 +49,7 @@ fn cache(id: Option<PatchId>, repository: &Repository, profile: &Profile) -> any
|
|||
match result {
|
||||
Ok((id, _)) => term::success!(
|
||||
"Successfully cached patch {id} ({}/{})",
|
||||
progress.seen(),
|
||||
progress.current(),
|
||||
progress.total()
|
||||
),
|
||||
Err(e) => term::warning(format!("Failed to retrieve patch: {e}")),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use anyhow::anyhow;
|
||||
|
||||
use git_ref_format::Qualified;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::patch::RevisionId;
|
||||
use radicle::git::RefString;
|
||||
|
|
@ -38,7 +39,7 @@ pub fn run(
|
|||
profile: &Profile,
|
||||
opts: Options,
|
||||
) -> anyhow::Result<()> {
|
||||
let patches = profile.patches(stored)?;
|
||||
let patches = profile.patches(stored, migrate::ignore)?;
|
||||
let patch = patches
|
||||
.get(patch_id)?
|
||||
.ok_or_else(|| anyhow!("Patch `{patch_id}` not found"))?;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use super::*;
|
||||
|
||||
use radicle::cob;
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::thread::CommentId;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::patch::ByRevision;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
|
@ -20,7 +20,7 @@ pub fn run(
|
|||
profile: &Profile,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repo)?;
|
||||
let mut patches = profile.patches_mut(repo, migrate::ignore)?;
|
||||
|
||||
let revision_id = revision_id.resolve::<cob::EntryId>(&repo.backend)?;
|
||||
let ByRevision {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use radicle::cob::migrate;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
|
|
@ -5,7 +6,7 @@ use super::*;
|
|||
|
||||
pub fn run(patch_id: &PatchId, profile: &Profile, repository: &Repository) -> anyhow::Result<()> {
|
||||
let signer = &term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
patches.remove(patch_id, signer)?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::process;
|
||||
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -11,7 +11,7 @@ pub fn run(
|
|||
stored: &Repository,
|
||||
profile: &Profile,
|
||||
) -> anyhow::Result<()> {
|
||||
let patches = profile.patches(stored)?;
|
||||
let patches = profile.patches(stored, migrate::ignore)?;
|
||||
let Some(patch) = patches.get(patch_id)? else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::*;
|
||||
|
||||
use radicle::cob::{self, patch};
|
||||
use radicle::cob;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::crypto;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
|
@ -15,7 +16,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(patch) = patches.get_mut(patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::*;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
use crate::terminal as term;
|
||||
|
|
@ -12,7 +13,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(mut patch) = patches.get_mut(patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::patch::{Patch, PatchId};
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::patch::cache::Patches as _;
|
||||
use radicle::prelude::*;
|
||||
use radicle::profile::Profile;
|
||||
|
|
@ -21,7 +21,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
profile: &Profile,
|
||||
) -> anyhow::Result<()> {
|
||||
let patches = profile.patches(repository)?;
|
||||
let patches = profile.patches(repository, migrate::ignore)?;
|
||||
|
||||
let mut all = Vec::new();
|
||||
let iter = match filter {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::*;
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<bool> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(mut patch) = patches.get_mut(patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use radicle::cob::patch;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::git::Oid;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
|
@ -13,7 +13,7 @@ pub fn run(
|
|||
repository: &Repository,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = &term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
|
||||
let revision_id = revision_id.resolve::<Oid>(&repository.backend)?;
|
||||
let patch::ByRevision {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow::anyhow;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::thread::CommentId;
|
||||
use radicle::patch::{self, PatchId};
|
||||
use radicle::patch::{cache::Patches as _, ReviewId};
|
||||
|
|
@ -15,7 +16,7 @@ pub fn resolve(
|
|||
profile: &Profile,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repo)?;
|
||||
let mut patches = profile.patches_mut(repo, migrate::ignore)?;
|
||||
let patch = patches
|
||||
.get(&patch_id)?
|
||||
.ok_or_else(|| anyhow!("Patch `{patch_id}` not found"))?;
|
||||
|
|
@ -32,7 +33,7 @@ pub fn unresolve(
|
|||
profile: &Profile,
|
||||
) -> anyhow::Result<()> {
|
||||
let signer = term::signer(profile)?;
|
||||
let mut patches = profile.patches_mut(repo)?;
|
||||
let mut patches = profile.patches_mut(repo, migrate::ignore)?;
|
||||
let patch = patches
|
||||
.get(&patch_id)?
|
||||
.ok_or_else(|| anyhow!("Patch `{patch_id}` not found"))?;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ mod builder;
|
|||
|
||||
use anyhow::{anyhow, Context};
|
||||
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::patch::{PatchId, RevisionId, Verdict};
|
||||
use radicle::git;
|
||||
use radicle::prelude::*;
|
||||
|
|
@ -61,7 +62,7 @@ pub fn run(
|
|||
"couldn't load repository {} from local state",
|
||||
repository.id
|
||||
))?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let mut patch = patches
|
||||
.get_mut(&patch_id)
|
||||
.context(format!("couldn't find patch {patch_id} locally"))?;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::process;
|
||||
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::git;
|
||||
use radicle::storage::git::Repository;
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ pub fn run(
|
|||
stored: &Repository,
|
||||
workdir: Option<&git::raw::Repository>,
|
||||
) -> anyhow::Result<()> {
|
||||
let patches = profile.patches(stored)?;
|
||||
let patches = profile.patches(stored, migrate::ignore)?;
|
||||
let Some(patch) = patches.get(patch_id).map_err(|e| Error::WithHint {
|
||||
err: e.into(),
|
||||
hint: "reset the cache with `rad patch cache` and try again",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use radicle::cob::patch;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::git;
|
||||
use radicle::prelude::*;
|
||||
use radicle::storage::git::Repository;
|
||||
|
|
@ -19,7 +19,7 @@ pub fn run(
|
|||
let head_branch = try_branch(workdir.head()?)?;
|
||||
|
||||
let (_, target_oid) = get_merge_target(repository, &head_branch)?;
|
||||
let mut patches = profile.patches_mut(repository)?;
|
||||
let mut patches = profile.patches_mut(repository, migrate::ignore)?;
|
||||
let Ok(mut patch) = patches.get_mut(&patch_id) else {
|
||||
anyhow::bail!("Patch `{patch_id}` not found");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::path::Path;
|
|||
|
||||
use localtime::LocalDuration;
|
||||
use localtime::LocalTime;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::git;
|
||||
use radicle::issue::cache::Issues as _;
|
||||
use radicle::node::address;
|
||||
|
|
@ -95,8 +96,8 @@ pub fn run(_options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
|
||||
for repo in storage.repositories()? {
|
||||
let repo = storage.repository(repo.rid)?;
|
||||
let issues = profile.issues(&repo)?.counts()?;
|
||||
let patches = profile.patches(&repo)?.counts()?;
|
||||
let issues = profile.issues(&repo, migrate::ignore)?.counts()?;
|
||||
let patches = profile.patches(&repo, migrate::ignore)?.counts()?;
|
||||
|
||||
stats.local.issues += issues.total();
|
||||
stats.local.patches += patches.total();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use radicle::profile;
|
|||
use thiserror::Error;
|
||||
|
||||
use radicle::cob;
|
||||
use radicle::cob::migrate;
|
||||
use radicle::git;
|
||||
use radicle::storage::git::transport::local::Url;
|
||||
use radicle::storage::ReadRepository;
|
||||
|
|
@ -87,7 +88,7 @@ fn patch_refs<R: ReadRepository + cob::Store + 'static>(
|
|||
profile: &Profile,
|
||||
stored: &R,
|
||||
) -> Result<(), Error> {
|
||||
let patches = profile.patches(stored)?;
|
||||
let patches = profile.patches(stored, migrate::ignore)?;
|
||||
for patch in patches.list()? {
|
||||
let Ok((id, patch)) = patch else {
|
||||
// Ignore patches that fail to decode.
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use thiserror::Error;
|
|||
|
||||
use radicle::cob;
|
||||
use radicle::cob::object::ParseObjectId;
|
||||
use radicle::cob::patch;
|
||||
use radicle::cob::patch::cache::Patches as _;
|
||||
use radicle::cob::{migrate, patch};
|
||||
use radicle::crypto::Signer;
|
||||
use radicle::explorer::ExplorerResource;
|
||||
use radicle::git::canonical;
|
||||
|
|
@ -227,7 +227,7 @@ pub fn run(
|
|||
&nid,
|
||||
&working,
|
||||
stored,
|
||||
profile.patches_mut(stored)?,
|
||||
profile.patches_mut(stored, migrate::ignore)?,
|
||||
&signer,
|
||||
profile,
|
||||
opts.clone(),
|
||||
|
|
@ -247,7 +247,7 @@ pub fn run(
|
|||
&nid,
|
||||
&working,
|
||||
stored,
|
||||
profile.patches_mut(stored)?,
|
||||
profile.patches_mut(stored, migrate::ignore)?,
|
||||
&signer,
|
||||
opts.clone(),
|
||||
)
|
||||
|
|
@ -320,7 +320,7 @@ pub fn run(
|
|||
&nid,
|
||||
&working,
|
||||
stored,
|
||||
profile.patches_mut(stored)?,
|
||||
profile.patches_mut(stored, migrate::ignore)?,
|
||||
&signer,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::collections::HashSet;
|
|||
use std::env;
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use radicle::cob::migrate;
|
||||
use radicle::cob::patch::{PatchId, RevisionId};
|
||||
use radicle::git::Oid;
|
||||
use radicle::storage::ReadStorage;
|
||||
|
|
@ -26,7 +27,7 @@ fn main() -> anyhow::Result<()> {
|
|||
let profile = radicle::Profile::load()?;
|
||||
let (working, rid) = radicle::rad::cwd()?;
|
||||
let stored = profile.storage.repository(rid)?;
|
||||
let mut patches = profile.patches_mut(&stored)?;
|
||||
let mut patches = profile.patches_mut(&stored, migrate::ignore)?;
|
||||
let mut patch = patches.get_mut(&pid)?;
|
||||
|
||||
if patch.is_merged() {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub mod thread;
|
|||
#[cfg(test)]
|
||||
pub mod test;
|
||||
|
||||
pub use cache::{migrate, MigrateCallback};
|
||||
pub use common::*;
|
||||
pub use op::{ActorId, Op};
|
||||
pub use radicle_cob::{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,58 @@ const DB_WRITE_TIMEOUT: time::Duration = time::Duration::from_secs(6);
|
|||
|
||||
/// Database migrations.
|
||||
/// The first migration is the creation of the initial tables.
|
||||
const MIGRATIONS: &[&str] = &[include_str!("cache/migrations/1.sql")];
|
||||
const MIGRATIONS: &[Migration] = &[Migration::Sql(include_str!("cache/migrations/1.sql"))];
|
||||
|
||||
/// Function signature for native migrations.
|
||||
type MigrateFn = fn(&sql::Connection, Progress, &dyn MigrateCallback) -> Result<usize, Error>;
|
||||
|
||||
/// A database migration.
|
||||
enum Migration {
|
||||
/// Migration written in SQL.
|
||||
Sql(&'static str),
|
||||
/// Migration function written in Rust.
|
||||
#[allow(dead_code)]
|
||||
Native(MigrateFn),
|
||||
}
|
||||
|
||||
/// Something that can process migration progress.
|
||||
pub trait MigrateCallback {
|
||||
/// A migration has progressed.
|
||||
/// The first [`Progress`] parameter refers to the progress within the list of migrations.
|
||||
/// The second [`Progress`] parameter refers to the progress within the current migration.
|
||||
fn progress(&mut self, migration: Progress, item: Progress) -> Result<bool, Error>;
|
||||
}
|
||||
|
||||
impl<F> MigrateCallback for F
|
||||
where
|
||||
F: Fn(Progress, Progress) -> Result<bool, Error>,
|
||||
{
|
||||
fn progress(&mut self, migration: Progress, item: Progress) -> Result<bool, Error> {
|
||||
(self)(migration, item)
|
||||
}
|
||||
}
|
||||
|
||||
/// Migration functions that implement [`MigrateCallback`].
|
||||
pub mod migrate {
|
||||
use super::*;
|
||||
|
||||
/// Log progress via installed logger at "info" level.
|
||||
pub fn log(migration: Progress, item: Progress) -> Result<bool, Error> {
|
||||
log::info!(
|
||||
target: "db",
|
||||
"Migration {}/{} in progress.. ({}%)",
|
||||
migration.current() + 1,
|
||||
migration.total(),
|
||||
item.percentage()
|
||||
);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Ignore progress, just migrate.
|
||||
pub fn ignore(_migration: Progress, _item: Progress) -> Result<bool, Error> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
|
|
@ -97,7 +148,7 @@ impl Store<Write> {
|
|||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
|
||||
let mut db = sql::Connection::open_thread_safe(path)?;
|
||||
db.set_busy_timeout(DB_WRITE_TIMEOUT.as_millis() as usize)?;
|
||||
migrate(&db)?;
|
||||
migrate(&db, migrate::ignore)?;
|
||||
|
||||
Ok(Self {
|
||||
db: Arc::new(db),
|
||||
|
|
@ -108,7 +159,7 @@ impl Store<Write> {
|
|||
/// Create a new in-memory database.
|
||||
pub fn memory() -> Result<Self, Error> {
|
||||
let db = Arc::new(sql::Connection::open_thread_safe(":memory:")?);
|
||||
migrate(&db)?;
|
||||
migrate(&db, migrate::ignore)?;
|
||||
|
||||
Ok(Self {
|
||||
db,
|
||||
|
|
@ -164,17 +215,34 @@ fn bump(db: &sql::Connection) -> Result<usize, Error> {
|
|||
}
|
||||
|
||||
/// Migrate the database to the latest schema.
|
||||
fn migrate(db: &sql::Connection) -> Result<usize, Error> {
|
||||
fn migrate<M>(db: &sql::Connection, mut callback: M) -> Result<usize, Error>
|
||||
where
|
||||
M: MigrateCallback,
|
||||
{
|
||||
let mut version = version(db)?;
|
||||
for (i, migration) in MIGRATIONS.iter().enumerate() {
|
||||
if i >= version {
|
||||
transaction(db, |db| {
|
||||
db.execute(migration)?;
|
||||
version = bump(db)?;
|
||||
let total = MIGRATIONS.len();
|
||||
|
||||
Ok::<_, Error>(())
|
||||
})?;
|
||||
for (i, migration) in MIGRATIONS.iter().enumerate() {
|
||||
if i < version {
|
||||
continue;
|
||||
}
|
||||
transaction(db, |db| {
|
||||
match migration {
|
||||
Migration::Sql(query) => {
|
||||
db.execute(query)?;
|
||||
callback.progress(
|
||||
Progress { total, current: i },
|
||||
Progress::done(db.change_count()),
|
||||
)?;
|
||||
}
|
||||
Migration::Native(migrate) => {
|
||||
migrate(db, Progress { total, current: i }, &callback)?;
|
||||
}
|
||||
}
|
||||
version = bump(db)?;
|
||||
|
||||
Ok::<_, Error>(())
|
||||
})?;
|
||||
}
|
||||
Ok(version)
|
||||
}
|
||||
|
|
@ -283,20 +351,28 @@ impl<T> Remove<T> for NoCache {
|
|||
///
|
||||
/// See [`crate::cob::issue::Cache::write_all`] and
|
||||
/// [`crate::cob::patch::Cache::write_all`].
|
||||
pub struct WriteAllProgress {
|
||||
pub struct Progress {
|
||||
current: usize,
|
||||
total: usize,
|
||||
seen: usize,
|
||||
}
|
||||
|
||||
impl WriteAllProgress {
|
||||
impl Progress {
|
||||
/// Create a new progress tracker with the given `total` amount.
|
||||
pub fn new(total: usize) -> Self {
|
||||
Self { total, seen: 0 }
|
||||
Self { current: 0, total }
|
||||
}
|
||||
|
||||
/// Increment the [`WriteAllProgress::seen`] progress.
|
||||
/// Create a new progress tracker that is "done".
|
||||
pub fn done(total: usize) -> Self {
|
||||
Self {
|
||||
current: total,
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
/// Increment the [`Progress::current`] progress.
|
||||
pub fn inc(&mut self) {
|
||||
self.seen += 1;
|
||||
self.current += 1;
|
||||
}
|
||||
|
||||
/// Return the `total` amount.
|
||||
|
|
@ -304,9 +380,9 @@ impl WriteAllProgress {
|
|||
self.total
|
||||
}
|
||||
|
||||
/// Return the `seen` amount.
|
||||
pub fn seen(&self) -> usize {
|
||||
self.seen
|
||||
/// Return the `current` amount.
|
||||
pub fn current(&self) -> usize {
|
||||
self.current
|
||||
}
|
||||
|
||||
/// Return the percentage of the progress made.
|
||||
|
|
@ -315,6 +391,6 @@ impl WriteAllProgress {
|
|||
///
|
||||
/// If the `total` provided is `0`.
|
||||
pub fn percentage(&self) -> f32 {
|
||||
(self.seen as f32 / self.total as f32) * 100.0
|
||||
(self.current as f32 / self.total as f32) * 100.0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,10 +143,7 @@ impl<'a, R, C> Cache<super::Issues<'a, R>, C> {
|
|||
/// or break from the process.
|
||||
pub fn write_all(
|
||||
&mut self,
|
||||
on_issue: impl Fn(
|
||||
&Result<(IssueId, Issue), store::Error>,
|
||||
&cache::WriteAllProgress,
|
||||
) -> ControlFlow<()>,
|
||||
on_issue: impl Fn(&Result<(IssueId, Issue), store::Error>, &cache::Progress) -> ControlFlow<()>,
|
||||
) -> Result<(), super::Error>
|
||||
where
|
||||
R: ReadRepository + cob::Store,
|
||||
|
|
@ -158,7 +155,7 @@ impl<'a, R, C> Cache<super::Issues<'a, R>, C> {
|
|||
.map_err(|e| super::Error::CacheRemoveAll { err: e.into() })?;
|
||||
|
||||
let issues = self.store.all()?;
|
||||
let mut progress = cache::WriteAllProgress::new(issues.len());
|
||||
let mut progress = cache::Progress::new(issues.len());
|
||||
for issue in self.store.all()? {
|
||||
progress.inc();
|
||||
match on_issue(&issue, &progress) {
|
||||
|
|
|
|||
|
|
@ -210,10 +210,7 @@ impl<'a, R, C> Cache<super::Patches<'a, R>, C> {
|
|||
/// or break from the process.
|
||||
pub fn write_all(
|
||||
&mut self,
|
||||
callback: impl Fn(
|
||||
&Result<(PatchId, Patch), store::Error>,
|
||||
&cache::WriteAllProgress,
|
||||
) -> ControlFlow<()>,
|
||||
callback: impl Fn(&Result<(PatchId, Patch), store::Error>, &cache::Progress) -> ControlFlow<()>,
|
||||
) -> Result<(), super::Error>
|
||||
where
|
||||
R: ReadRepository + cob::Store,
|
||||
|
|
@ -225,7 +222,7 @@ impl<'a, R, C> Cache<super::Patches<'a, R>, C> {
|
|||
.map_err(|e| super::Error::CacheRemoveAll { err: e.into() })?;
|
||||
|
||||
let patches = self.store.all()?;
|
||||
let mut progress = cache::WriteAllProgress::new(patches.len());
|
||||
let mut progress = cache::Progress::new(patches.len());
|
||||
for patch in self.store.all()? {
|
||||
progress.inc();
|
||||
match callback(&patch, &progress) {
|
||||
|
|
|
|||
|
|
@ -562,58 +562,70 @@ impl Home {
|
|||
}
|
||||
|
||||
/// Return a read-only handle for the issues cache.
|
||||
pub fn issues<'a, R>(
|
||||
pub fn issues<'a, R, M>(
|
||||
&self,
|
||||
repository: &'a R,
|
||||
_migrate: M,
|
||||
) -> Result<cob::issue::Cache<cob::issue::Issues<'a, R>, cob::cache::StoreReader>, Error>
|
||||
where
|
||||
M: cob::MigrateCallback,
|
||||
R: ReadRepository + cob::Store,
|
||||
{
|
||||
let path = self.cobs().join(cob::cache::COBS_DB_FILE);
|
||||
let db = cob::cache::Store::reader(path)?;
|
||||
let store = cob::issue::Issues::open(repository)?;
|
||||
|
||||
Ok(cob::issue::Cache::reader(store, db))
|
||||
}
|
||||
|
||||
/// Return a read-write handle for the issues cache.
|
||||
pub fn issues_mut<'a, R>(
|
||||
pub fn issues_mut<'a, R, M>(
|
||||
&self,
|
||||
repository: &'a R,
|
||||
_migrate: M,
|
||||
) -> Result<cob::issue::Cache<cob::issue::Issues<'a, R>, cob::cache::StoreWriter>, Error>
|
||||
where
|
||||
M: cob::MigrateCallback,
|
||||
R: ReadRepository + cob::Store,
|
||||
{
|
||||
let path = self.cobs().join(cob::cache::COBS_DB_FILE);
|
||||
let db = cob::cache::Store::open(path)?;
|
||||
let store = cob::issue::Issues::open(repository)?;
|
||||
|
||||
Ok(cob::issue::Cache::open(store, db))
|
||||
}
|
||||
|
||||
/// Return a read-only handle for the patches cache.
|
||||
pub fn patches<'a, R>(
|
||||
pub fn patches<'a, R, M>(
|
||||
&self,
|
||||
repository: &'a R,
|
||||
_migrate: M,
|
||||
) -> Result<cob::patch::Cache<cob::patch::Patches<'a, R>, cob::cache::StoreReader>, Error>
|
||||
where
|
||||
M: cob::MigrateCallback,
|
||||
R: ReadRepository + cob::Store,
|
||||
{
|
||||
let path = self.cobs().join(cob::cache::COBS_DB_FILE);
|
||||
let db = cob::cache::Store::reader(path)?;
|
||||
let store = cob::patch::Patches::open(repository)?;
|
||||
|
||||
Ok(cob::patch::Cache::reader(store, db))
|
||||
}
|
||||
|
||||
/// Return a read-write handle for the patches cache.
|
||||
pub fn patches_mut<'a, R>(
|
||||
pub fn patches_mut<'a, R, M>(
|
||||
&self,
|
||||
repository: &'a R,
|
||||
_migrate: M,
|
||||
) -> Result<cob::patch::Cache<cob::patch::Patches<'a, R>, cob::cache::StoreWriter>, Error>
|
||||
where
|
||||
M: cob::MigrateCallback,
|
||||
R: ReadRepository + cob::Store,
|
||||
{
|
||||
let path = self.cobs().join(cob::cache::COBS_DB_FILE);
|
||||
let db = cob::cache::Store::open(path)?;
|
||||
let store = cob::patch::Patches::open(repository)?;
|
||||
|
||||
Ok(cob::patch::Cache::open(store, db))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue