/* * 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 . */ #[macro_use] extern crate lazy_static; #[macro_use] #[cfg(test)] extern crate include_dir; #[macro_use] #[cfg(test)] extern crate test_case; use anyhow::Result; use thiserror::Error; mod convert; mod load; // TODO: implement // Use yaml-rust with "preserve-order" = true // Strategy: // 1. Backup the current config directory in a zip archive (also with the packages) // 2. Create a temporary directory alonside the legacy one called "espanso-new" // 3. Convert all the files and write the output into "espanso-new" // 4. Rename the legacy dir to "espanso-old" // 5. Rename new dir to "espanso" // 6. If the legacy directory was a symlink, try to recreate it (ask the user first) // TODO: before attempting the migration strategy, check if the current // espanso config directory is a symlink and, if so, attempt to remap // the symlink with the new dir (after asking the user) // This is necessary because in order to be safe, the migration strategy // creates the new config on a new temporary directory and then "swaps" // the old with the new one // TODO: test case with packages // TODO: keep other non-standard directories such as "images/" and "script/" // TODO: test also with non-lowercase file names // TODO: test packages in another directory (a possible strategy is to copy // the packages dir and the config dir into a temporary one, with the packages // as a directory at the same level of user/) // TODO: when dumping the output file, remove the front-matter at the top (generated by YamlEmitter) // and insert a comment with "Automatically generated from {{file_name}} by migration tool" #[cfg(test)] mod tests { use std::{fs::create_dir_all, path::{Path}}; use super::*; use include_dir::{include_dir, Dir}; use tempdir::TempDir; use test_case::test_case; use pretty_assertions::{assert_eq as assert_peq}; fn run_with_temp_dir(test_data: &Dir, action: impl FnOnce(&Path, &Path)) { let tmp_dir = TempDir::new("espanso-migration").unwrap(); let tmp_path = tmp_dir.path(); let legacy_path = tmp_dir.path().join("legacy"); let expected_path = tmp_dir.path().join("expected"); for entry in test_data.find("**/*").unwrap() { let entry_path = entry.path(); let entry_path_str = entry_path.to_string_lossy().to_string(); if entry_path_str.is_empty() { continue; } let target = tmp_path.join(entry_path); if entry_path.extension().is_none() { create_dir_all(target).unwrap(); } else { std::fs::write(target, test_data.get_file(entry_path).unwrap().contents()).unwrap(); } } action(&legacy_path, &expected_path); } static SIMPLE_CASE: Dir = include_dir!("test/simple"); static BASE_CASE: Dir = include_dir!("test/base"); #[test_case(&SIMPLE_CASE; "simple case")] #[test_case(&BASE_CASE; "base case")] fn test_migration(test_data: &Dir) { run_with_temp_dir(test_data, |legacy, expected| { let legacy_files = load::load(legacy).unwrap(); let expected_files = load::load(expected).unwrap(); let converted_files = convert::convert(legacy_files); assert_eq!(converted_files.len(), expected_files.len()); for (file, content) in converted_files { assert_peq!(&content, expected_files.get(&file).unwrap()); } }); } }