From 15dcfcc06d2aebfd324c5f9349d24131e0a2ec99 Mon Sep 17 00:00:00 2001 From: Jonathan van der Steege Date: Tue, 14 Jun 2022 19:35:18 +0200 Subject: [PATCH] Check for duplicate keys in config file --- jrnl/config.py | 57 ++++++++++++++++++++++++++ jrnl/messages/MsgText.py | 6 +++ tests/bdd/features/config_file.feature | 5 +++ tests/data/configs/double_keys.yaml | 27 ++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 tests/data/configs/double_keys.yaml diff --git a/jrnl/config.py b/jrnl/config.py index c9b860bb..3f5e16e9 100644 --- a/jrnl/config.py +++ b/jrnl/config.py @@ -15,6 +15,8 @@ from jrnl.messages import MsgStyle from .path import home_dir +from collections import Counter + # Constants DEFAULT_CONFIG_NAME = "jrnl.yaml" XDG_RESOURCE = "jrnl" @@ -157,6 +159,15 @@ def verify_config_colors(config): def load_config(config_path): """Tries to load a config file from YAML.""" + # If duplicate keys at same level in config file, print warning + duplicate_keys = config_duplicate_keys(config_path) + if duplicate_keys: + print_msg( + Message( + MsgText.ConfigDoubleKeys, MsgStyle.WARNING, {"duplicate_keys": duplicate_keys} + ) + ) + with open(config_path, encoding=YAML_FILE_ENCODING) as f: yaml = YAML(typ="safe") yaml.allow_duplicate_keys = True @@ -206,3 +217,49 @@ def get_journal_name(args, config): logging.debug("Using journal name: %s", args.journal_name) return args + + +def config_duplicate_keys(config_path): + if is_config_json(config_path): + return None + + duplicate_keys = [] + + with open(config_path) as f: + keys = [] + current_serie = [] + temp_store = [] + leading_spaces = 0 + + for line in f: + line_lead = len(line) - len(line.lstrip(" ")) + + if line_lead > leading_spaces: + temp_store.append(current_serie) + current_serie = [] + + elif line_lead < leading_spaces: + while (leading_spaces - line_lead) > 2: + keys.append(current_serie) + current_serie = temp_store.pop() + leading_spaces -= 2 + + keys.append(current_serie) + current_serie = temp_store.pop() + + if line.strip().split(":")[0]: + current_serie.append(line.strip().split(":")[0]) + leading_spaces = line_lead + + keys.append(current_serie) + + for serie in keys: + count = Counter(serie) + for i in count.keys(): + if count[i] > 1: + duplicate_keys.append(i) + + if len(duplicate_keys) > 0: + return duplicate_keys + + return None diff --git a/jrnl/messages/MsgText.py b/jrnl/messages/MsgText.py index f8e85b60..e705aa6f 100644 --- a/jrnl/messages/MsgText.py +++ b/jrnl/messages/MsgText.py @@ -193,6 +193,12 @@ class MsgText(Enum): Configuration updated to newest version at {config_path} """ + ConfigDoubleKeys = """ + Warning: One or more keys appear multiple times at the same level + in your configuration file: + {duplicate_keys} + """ + # --- Password --- # Password = "Password:" PasswordFirstEntry = "Enter password for journal '{journal_name}': " diff --git a/tests/bdd/features/config_file.feature b/tests/bdd/features/config_file.feature index 168cd7aa..c943811d 100644 --- a/tests/bdd/features/config_file.feature +++ b/tests/bdd/features/config_file.feature @@ -103,3 +103,8 @@ Feature: Multiple journals And we use the config "basic_onefile.yaml" When we run "jrnl --cf empty_file.yaml" Then the error output should contain "Unable to parse config file" + + Scenario: Show a warning message when the config file contains double keys at the same level + Given we use the config "double_keys.yaml" + When we run "jrnl -1" + Then the output should contain "One or more keys appear multiple times at the same level" \ No newline at end of file diff --git a/tests/data/configs/double_keys.yaml b/tests/data/configs/double_keys.yaml new file mode 100644 index 00000000..ca74c738 --- /dev/null +++ b/tests/data/configs/double_keys.yaml @@ -0,0 +1,27 @@ +default_hour: 9 +default_minute: 0 +editor: '' +encrypt: false +highlight: true +template: false +template: false +journals: + default: + encrypt: false + journal: features/journals/simple.journal + journal: features/journals/simple.journal + ideas: + encrypt: false + journal: features/journals/does-not-exist.journal + simple: + encrypt: false + journal: features/journals/simple.journal + encrypt: false + work: + encrypt: false + journal: features/journals/work.journal +linewrap: 80 +tagsymbols: '@' +editor: nano +timeformat: '%Y-%m-%d %H:%M' +indent_character: "|"