use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use clap::Clap;
use libpijul::changestore::ChangeStore;
use libpijul::{Hash, MutTxnT, MutTxnTExt, TxnT, TxnTExt};
use crate::repository::Repository;
#[derive(Clap, Debug)]
pub struct Upgrade {
/// Set the repository where this command should run Defaults to the first ancestor of the current directory that contains a `.pijul` directory.
#[clap(long = "repository")]
repo_path: Option<PathBuf>,
}
impl Upgrade {
pub fn run(self) -> Result<(), anyhow::Error> {
let mut channels = HashMap::new();
{
let repo = Repository::find_root(self.repo_path.clone())?;
let txn = repo.pristine.txn_begin()?;
let mut hashes = HashSet::new();
for channel in txn.iter_channels("") {
let channel = channel.borrow();
let name = channel.name();
let e = channels.entry(name.to_string()).or_insert(Vec::new());
hashes.clear();
for (_, (h, _)) in txn.reverse_log(&channel, None) {
if !hashes.insert(h) {
continue;
}
let path = repo.changes.filename(&h);
let change = libpijul::change::v3::LocalChange3::deserialize(
path.to_str().unwrap(),
Some(&h),
)
.unwrap();
e.push((h, change))
}
}
std::fs::rename(repo.path.join(".pijul"), repo.path.join(".pijul.old"))?;
}
let repo2 = Repository::init(self.repo_path)?;
let mut txn2 = repo2.pristine.mut_txn_begin();
let mut translations = HashMap::new();
translations.insert(None, None);
translations.insert(Some(Hash::None), Some(Hash::None));
for (channel_name, mut changes) in channels {
let mut channel = txn2.open_or_create_channel(&channel_name)?;
while let Some((old_h, c)) = changes.pop() {
let h = repo2.changes.save_change(&c.to_v4(&translations))?;
translations.insert(Some(old_h), Some(h));
txn2.apply_change(&repo2.changes, &mut channel, h)?;
}
}
txn2.commit()?;
Ok(())
}
}