Allow merging when migrating from z (#33)

If the user passes the `--merge` flag to the `migrate` subcommand, all
duplicate entries will have their ranks and epochs updated: the rank
will be the sum of the stored rank and the newly-parsed rank, while the
epoch will be the maximum of the stored epoch and the newly-parsed
epoch.

This allows one to import from the `z` database even after having used
`zoxide` for any amount of time. This also permits a user who has
already sourced the init script to import their old database without
needing to do something like `rm ~/.zo && zoxide migrate ~/.z`.
This commit is contained in:
Cole Helbling 2020-03-15 11:18:59 -07:00 committed by GitHub
parent f4cd1159c5
commit 083a834310
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 6 deletions

View File

@ -70,11 +70,11 @@ impl DB {
Ok(())
}
pub fn migrate<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
if !self.dirs.is_empty() {
pub fn migrate<P: AsRef<Path>>(&mut self, path: P, merge: bool) -> Result<()> {
if !self.dirs.is_empty() && !merge {
bail!(
"To prevent conflicts, you can only migrate from z with an empty \
zoxide database!"
"To prevent conflicts, you can only migrate from z with an empty zoxide database!
If you wish to merge the two, specify the `--merge` flag."
);
}
@ -87,7 +87,10 @@ impl DB {
let line = if let Ok(line) = read_line {
line
} else {
eprintln!("could not read line {}: {:?}", line_number, read_line);
eprintln!(
"could not read entry at line {}: {:?}",
line_number, read_line
);
continue;
};
@ -131,6 +134,17 @@ impl DB {
}
};
if merge {
// If the path exists in the database, add the ranks and set the epoch to
// the largest of the parsed epoch and the already present epoch.
if let Some(dir) = self.dirs.iter_mut().find(|dir| dir.path == path_str) {
dir.rank += rank;
dir.last_accessed = Epoch::max(epoch, dir.last_accessed);
continue;
};
}
// FIXME: When we switch to PathBuf for storing directories inside Dir, just
// pass `PathBuf::from(path_str)`
self.dirs.push(Dir {

View File

@ -7,10 +7,13 @@ use structopt::StructOpt;
#[structopt(about = "Migrate from z database")]
pub struct Migrate {
path: String,
#[structopt(long, help = "Merge entries into existing database")]
merge: bool,
}
impl Migrate {
pub fn run(&self, env: &Env) -> Result<()> {
util::get_db(env)?.migrate(&self.path)
util::get_db(env)?.migrate(&self.path, self.merge)
}
}