feat(migrate): progress in the migration process
This commit is contained in:
parent
58e048900c
commit
e3cdaa91fb
|
@ -18,28 +18,112 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
|
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
|
||||||
use yaml_rust::yaml::Hash;
|
use yaml_rust::{yaml::Hash, Yaml, YamlEmitter};
|
||||||
|
|
||||||
pub fn convert(input_files: HashMap<String, Hash>) -> HashMap<String, Hash> {
|
pub fn convert(input_files: HashMap<String, Hash>) -> HashMap<String, Hash> {
|
||||||
let mut output_files = HashMap::new();
|
let mut output_files = HashMap::new();
|
||||||
|
|
||||||
let sorted_input_files = sort_input_files(&input_files);
|
let sorted_input_files = sort_input_files(&input_files);
|
||||||
|
|
||||||
|
let mut config_names_to_path = HashMap::new();
|
||||||
|
|
||||||
for input_path in sorted_input_files {
|
for input_path in sorted_input_files {
|
||||||
let yaml = input_files
|
let yaml = input_files
|
||||||
.get(&input_path)
|
.get(&input_path)
|
||||||
.expect("received unexpected file in input function");
|
.expect("received unexpected file in input function");
|
||||||
|
|
||||||
if let Some((file_name, file_name_without_extension)) = extract_name_information(&input_path) {
|
let yaml_matches = yaml_get_vec(yaml, "matches");
|
||||||
println!("file: {}, {}", file_name, file_name_without_extension);
|
let yaml_global_vars = yaml_get_vec(yaml, "global_vars");
|
||||||
|
|
||||||
// TODO: execute the actual conversion
|
let yaml_parent = yaml_get_string(yaml, "parent");
|
||||||
|
let yaml_name = yaml_get_string(yaml, "name");
|
||||||
|
|
||||||
} else {
|
let should_generate_match = yaml_matches.is_some() || yaml_global_vars.is_some();
|
||||||
eprintln!("unable to extract filename from path: {}", input_path);
|
if should_generate_match {
|
||||||
|
let should_underscore = !input_path.starts_with("default") && yaml_parent != Some("default");
|
||||||
|
let match_output_path = calculate_output_match_path(&input_path, should_underscore);
|
||||||
|
if match_output_path.is_none() {
|
||||||
|
eprintln!(
|
||||||
|
"unable to determine output path for {}, skipping...",
|
||||||
|
input_path
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let match_output_path = match_output_path.unwrap();
|
||||||
|
|
||||||
|
if let Some(name) = yaml_name {
|
||||||
|
config_names_to_path.insert(name.to_string(), match_output_path.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let output_yaml = output_files.entry(match_output_path).or_insert(Hash::new());
|
||||||
|
|
||||||
|
if let Some(global_vars) = yaml_global_vars {
|
||||||
|
let output_global_vars = output_yaml
|
||||||
|
.entry(Yaml::String("global_vars".to_string()))
|
||||||
|
.or_insert(Yaml::Array(Vec::new()));
|
||||||
|
if let Yaml::Array(out_global_vars) = output_global_vars {
|
||||||
|
out_global_vars.extend(global_vars.clone());
|
||||||
|
} else {
|
||||||
|
eprintln!("unable to transform global_vars for file: {}", input_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(matches) = yaml_matches {
|
||||||
|
let output_matches = output_yaml
|
||||||
|
.entry(Yaml::String("matches".to_string()))
|
||||||
|
.or_insert(Yaml::Array(Vec::new()));
|
||||||
|
if let Yaml::Array(out_matches) = output_matches {
|
||||||
|
out_matches.extend(matches.clone());
|
||||||
|
} else {
|
||||||
|
eprintln!("unable to transform matches for file: {}", input_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let yaml_filter_class = yaml_get_string(yaml, "filter_class");
|
||||||
|
let yaml_filter_title = yaml_get_string(yaml, "filter_title");
|
||||||
|
let yaml_filter_exec = yaml_get_string(yaml, "filter_exec");
|
||||||
|
|
||||||
|
let should_generate_config = input_path.starts_with("default")
|
||||||
|
|| yaml_filter_class.is_some()
|
||||||
|
|| yaml_filter_exec.is_some()
|
||||||
|
|| yaml_filter_title.is_some();
|
||||||
|
|
||||||
|
if should_generate_config {
|
||||||
|
let config_output_path = calculate_output_config_path(&input_path);
|
||||||
|
|
||||||
|
let mut output_yaml = Hash::new();
|
||||||
|
|
||||||
|
copy_field_if_present(yaml, "filter_title", &mut output_yaml, "filter_title");
|
||||||
|
copy_field_if_present(yaml, "filter_class", &mut output_yaml, "filter_class");
|
||||||
|
copy_field_if_present(yaml, "filter_exec", &mut output_yaml, "filter_exec");
|
||||||
|
|
||||||
|
// TODO: copy other config fields: https://github.com/federico-terzi/espanso/blob/master/src/config/mod.rs#L169
|
||||||
|
|
||||||
|
// TODO: if a match file was created above of type "underscored", then explicitly include it here
|
||||||
|
// depending on whether "exclude_default_entries" is set, use "includes" or "extra_includes"
|
||||||
|
|
||||||
|
output_files.insert(config_output_path, output_yaml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: create config file
|
||||||
|
|
||||||
|
// TODO: execute the actual conversion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: here resolve parent: name imports
|
||||||
|
|
||||||
|
// TODO: remove this prints
|
||||||
|
for (file, content) in output_files {
|
||||||
|
let mut out_str = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut out_str);
|
||||||
|
emitter.dump(&Yaml::Hash(content)).unwrap(); // dump the YAML object to a String
|
||||||
|
}
|
||||||
|
println!("\n------- {} ------------\n{}", file, out_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!();
|
||||||
output_files
|
output_files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,10 +143,58 @@ fn sort_input_files(input_files: &HashMap<String, Hash>) -> Vec<String> {
|
||||||
files
|
files
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_name_information(path: &str) -> Option<(String, String)> {
|
// TODO: test
|
||||||
|
fn calculate_output_match_path(path: &str, is_underscored: bool) -> Option<String> {
|
||||||
let path_buf = PathBuf::from(path);
|
let path_buf = PathBuf::from(path);
|
||||||
let file_name = path_buf.file_name()?.to_string_lossy().to_string();
|
let file_name = path_buf.file_name()?.to_string_lossy().to_string();
|
||||||
let extension = path_buf.extension()?.to_string_lossy().to_string();
|
|
||||||
let file_name_without_extension = file_name.trim_end_matches(&format!(".{}", extension)).to_string();
|
let path = if is_underscored {
|
||||||
Some((file_name, file_name_without_extension))
|
path.replace(&file_name, &format!("_{}", file_name))
|
||||||
}
|
} else {
|
||||||
|
path.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(if path.starts_with("user/") {
|
||||||
|
format!("match/{}", path.trim_start_matches("user/"))
|
||||||
|
} else if path.starts_with("packages/") {
|
||||||
|
format!("match/packages/{}", path.trim_start_matches("packages/"))
|
||||||
|
} else if path == "default.yml" {
|
||||||
|
"match/base.yml".to_string()
|
||||||
|
} else {
|
||||||
|
format!("match/{}", path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
fn calculate_output_config_path(path: &str) -> String {
|
||||||
|
if path.starts_with("user/") {
|
||||||
|
format!("config/{}", path.trim_start_matches("user/"))
|
||||||
|
} else if path.starts_with("packages/") {
|
||||||
|
format!("config/packages/{}", path.trim_start_matches("packages/"))
|
||||||
|
} else {
|
||||||
|
format!("config/{}", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn yaml_get_vec<'a>(yaml: &'a Hash, name: &str) -> Option<&'a Vec<Yaml>> {
|
||||||
|
yaml
|
||||||
|
.get(&Yaml::String(name.to_string()))
|
||||||
|
.and_then(|v| v.as_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn yaml_get_string<'a>(yaml: &'a Hash, name: &str) -> Option<&'a str> {
|
||||||
|
yaml
|
||||||
|
.get(&Yaml::String(name.to_string()))
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_field_if_present(
|
||||||
|
input_yaml: &Hash,
|
||||||
|
input_field_name: &str,
|
||||||
|
output_yaml: &mut Hash,
|
||||||
|
output_field_name: &str,
|
||||||
|
) {
|
||||||
|
if let Some(value) = input_yaml.get(&Yaml::String(input_field_name.to_string())) {
|
||||||
|
output_yaml.insert(Yaml::String(output_field_name.to_string()), value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -57,21 +57,29 @@ mod load;
|
||||||
|
|
||||||
// TODO: test also with non-lowercase file names
|
// TODO: test also with non-lowercase file names
|
||||||
|
|
||||||
// TODO: test packages in another directory
|
// 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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use test_case::test_case;
|
|
||||||
use include_dir::{include_dir, Dir};
|
use include_dir::{include_dir, Dir};
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
static BASE_CASE: Dir = include_dir!("test/base");
|
static BASE_CASE: Dir = include_dir!("test/base");
|
||||||
|
|
||||||
#[test_case(&BASE_CASE; "base case")]
|
#[test_case(&BASE_CASE; "base case")]
|
||||||
fn test_migration(test_data: &Dir) {
|
fn test_migration(test_data: &Dir) {
|
||||||
let input_files = load::load(&PathBuf::from(r"")).unwrap();
|
let input_files = load::load(&PathBuf::from(
|
||||||
|
r"",
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
convert::convert(input_files);
|
convert::convert(input_files);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
Loading…
Reference in New Issue
Block a user