feat(core): introduce migrate cli command

This commit is contained in:
Federico Terzi 2021-06-02 11:54:00 +02:00
parent f98ab3dffd
commit 2cf6cafdb6
5 changed files with 226 additions and 1 deletions

65
Cargo.lock generated
View File

@ -170,6 +170,32 @@ dependencies = [
"vec_map",
]
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]]
name = "console"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"regex",
"terminal_size",
"unicode-width",
"winapi",
]
[[package]]
name = "const_fn"
version = "0.4.5"
@ -281,6 +307,18 @@ dependencies = [
"libdbus-sys",
]
[[package]]
name = "dialoguer"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9dd058f8b65922819fabb4a41e7d1964e56344042c26efbccd465202c23fa0c"
dependencies = [
"console",
"lazy_static",
"tempfile",
"zeroize",
]
[[package]]
name = "diff"
version = "0.1.12"
@ -348,6 +386,12 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "enum-as-inner"
version = "0.3.3"
@ -366,7 +410,9 @@ version = "1.0.0"
dependencies = [
"anyhow",
"clap",
"colored",
"crossbeam",
"dialoguer",
"dirs 3.0.1",
"enum-as-inner",
"espanso-clipboard",
@ -376,11 +422,13 @@ dependencies = [
"espanso-inject",
"espanso-ipc",
"espanso-match",
"espanso-migrate",
"espanso-modulo",
"espanso-path",
"espanso-render",
"espanso-ui",
"fs2",
"fs_extra",
"html2text",
"lazy_static",
"log",
@ -392,6 +440,7 @@ dependencies = [
"serde_json",
"serde_yaml",
"simplelog",
"tempdir",
"thiserror",
"winapi",
]
@ -1554,6 +1603,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "test-case"
version = "1.1.0"
@ -1811,6 +1870,12 @@ dependencies = [
"linked-hash-map",
]
[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
[[package]]
name = "zip"
version = "0.5.12"

View File

@ -31,6 +31,7 @@ espanso-render = { path = "../espanso-render" }
espanso-path = { path = "../espanso-path" }
espanso-ipc = { path = "../espanso-ipc" }
espanso-modulo = { path = "../espanso-modulo", optional = true }
espanso-migrate = { path = "../espanso-migrate" }
maplit = "1.0.2"
simplelog = "0.9.0"
log = "0.4.14"
@ -48,6 +49,10 @@ html2text = "0.2.1"
log-panics = "2.0.0"
fs2 = "0.4.3"
serde_yaml = "0.8.17"
fs_extra = "1.2.0"
dialoguer = "0.8.0"
colored = "2.0.0"
tempdir = "0.3.7"
[target.'cfg(windows)'.dependencies]
named_pipe = "0.4.1"

144
espanso/src/cli/migrate.rs Normal file
View File

@ -0,0 +1,144 @@
/*
* This file is part of espanso.
*
* Copyright (C) 2019-2021 Federico Terzi
*
* espanso is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* espanso is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use std::path::PathBuf;
use super::{CliModule, CliModuleArgs};
use colored::*;
use dialoguer::Confirm;
use fs_extra::dir::CopyOptions;
use tempdir::TempDir;
pub fn new() -> CliModule {
CliModule {
requires_paths: true,
requires_config: true,
subcommand: "migrate".to_string(),
entry: migrate_main,
..Default::default()
}
}
fn migrate_main(args: CliModuleArgs) -> i32 {
let paths = args.paths.expect("missing paths argument");
if !args.is_legacy_config {
eprintln!("Can't migrate configurations, as the default directory [1] is already encoded with the new format");
eprintln!("[1]: {:?}", paths.config);
eprintln!("The migration tool is only meant to convert the espanso's legacy configuration format (prior to");
eprintln!("version 0.7.3) to the new one (since version 2.0)");
return 1;
}
// TODO: check if legacy version is still running
let target_backup_dir = find_available_backup_dir();
println!("\n{}\n", "Welcome to espanso v2!".bold());
println!("This migration tool will help you to smoothly transition to the new espanso v2 configuration format.");
println!("");
println!(
"1. Firstly, espanso will {} your current configuration, located in:\n",
"backup".green().bold()
);
println!(" {}\n", paths.config.to_string_lossy().italic());
println!(" into this folder:\n");
println!(" {}\n", target_backup_dir.to_string_lossy().italic());
println!(
"2. Then, it will {} your configuration to the new format, replacing",
"convert".bold().green()
);
println!(" the current content of the config directory.");
println!("");
if !Confirm::new()
.with_prompt("Do you want to proceed?")
.default(true)
.interact()
.expect("unable to read choice")
{
return 2;
}
println!("Backing up your configuration...");
fs_extra::dir::copy(
&paths.config,
&target_backup_dir,
&CopyOptions {
copy_inside: true,
..Default::default()
},
)
.expect("unable to backup the current config");
println!("{}", "Backup completed!".green());
println!("Converting the configuration...");
let temp_dir = TempDir::new("espanso-migrate-out").expect("unable to create temporary directory");
let temp_out_dir = temp_dir.path().join("out");
espanso_migrate::migrate(&paths.config, &paths.packages, &temp_out_dir)
.expect("an error occurred while converting the configuration");
println!("{}", "Conversion completed!".green());
println!("Replacing old configuration with the new one...");
let mut to_be_removed = Vec::new();
let legacy_dir_content = fs_extra::dir::get_dir_content(&paths.config).expect("unable to list legacy dir files");
to_be_removed.extend(legacy_dir_content.files);
to_be_removed.extend(legacy_dir_content.directories);
fs_extra::remove_items(&to_be_removed).expect("unable to remove previous configuration");
fs_extra::dir::copy(
&temp_out_dir,
&paths.config,
&CopyOptions {
copy_inside: true,
..Default::default()
},
)
.expect("unable to copy new configuration into target location");
let target_packages_dir = &paths.config.join("match").join("packages");
if !target_packages_dir.is_dir() {
std::fs::create_dir_all(target_packages_dir).expect("unable to create new packages directory");
}
println!("{}", "Configuration successfully migrated!".green());
0
}
fn find_available_backup_dir() -> PathBuf {
for i in 1..20 {
let num = if i > 1 {
format!("-{}", i)
} else {
"".to_string()
};
let target_backup_dir = dirs::document_dir()
.expect("unable to generate backup directory")
.join(format!("espanso-migrate-backup{}", num));
if !target_backup_dir.is_dir() {
return target_backup_dir;
}
}
panic!("could not generate valid backup directory");
}

View File

@ -23,6 +23,7 @@ use espanso_path::Paths;
pub mod daemon;
pub mod log;
pub mod migrate;
pub mod modulo;
pub mod path;
pub mod worker;

View File

@ -27,7 +27,7 @@ use std::path::PathBuf;
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use cli::{CliModule, CliModuleArgs};
use log::{error, info};
use log::{error, info, warn};
use logging::FileProxy;
use simplelog::{
CombinedLogger, ConfigBuilder, LevelFilter, TermLogger, TerminalMode, WriteLogger,
@ -55,6 +55,7 @@ lazy_static! {
cli::worker::new(),
cli::daemon::new(),
cli::modulo::new(),
cli::migrate::new(),
];
}
@ -218,6 +219,10 @@ fn main() {
)
.subcommand(SubCommand::with_name("base").about("Print the default match file path.")),
)
.subcommand(
SubCommand::with_name("migrate")
.about("Automatically migrate legacy config files to the new v2 format.")
)
// .subcommand(SubCommand::with_name("match")
// .about("List and execute matches from the CLI")
// .subcommand(SubCommand::with_name("list")
@ -353,6 +358,11 @@ fn main() {
cli_args.is_legacy_config = is_legacy_config;
cli_args.config_store = Some(config_store);
cli_args.match_store = Some(match_store);
if is_legacy_config {
warn!("espanso is reading the configuration using compatibility mode, thus some features might not be available");
warn!("you can migrate to the new configuration format by running 'espanso migrate' in a terminal");
}
}
if handler.enable_logs {