summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/advanced.md19
-rw-r--r--jrnl/args.py25
-rw-r--r--jrnl/config.py9
-rw-r--r--jrnl/install.py45
-rw-r--r--jrnl/jrnl.py2
-rw-r--r--tests/bdd/features/config_file.feature92
-rw-r--r--tests/bdd/test_features.py1
-rw-r--r--tests/lib/given_steps.py8
-rw-r--r--tests/unit/test_config_file.py22
-rw-r--r--tests/unit/test_parse_args.py1
10 files changed, 209 insertions, 15 deletions
diff --git a/docs/advanced.md b/docs/advanced.md
index b1b7bef0..a9f1fb27 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -85,6 +85,25 @@ jrnl --config-override display_format fancy --config-override linewrap 20 \
```
+### Using an alternate config
+
+You can specify an alternate configuration file for the current instance of `jrnl` using `--config-file CONFIG_FILE_PATH` where
+`CONFIG_FILE_PATH` is a path to an alternate `jrnl` configuration file.
+
+#### Examples:
+
+```
+# Use personalised configuration file for personal journal entries
+jrnl --config-file ~/foo/jrnl/personal-config.yaml
+
+# Use alternate configuration file for work-related entries
+jrnl --config-file ~/foo/jrnl/work-config.yaml
+
+# Use default configuration file (created on installation)
+jrnl
+```
+
+
## Multiple journal files
You can configure `jrnl`to use with multiple journals (eg.
diff --git a/jrnl/args.py b/jrnl/args.py
index 972fe802..604f9c0e 100644
--- a/jrnl/args.py
+++ b/jrnl/args.py
@@ -337,6 +337,31 @@ def parse_args(args=[]):
""",
)
+ alternate_config = parser.add_argument_group(
+ "Specifies alternate config to be used",
+ textwrap.dedent("Applies alternate config for current session"),
+ )
+
+ alternate_config.add_argument(
+ "--config-file",
+ dest="config_file_path",
+ type=str,
+ default="",
+ help="""
+ Overrides default (created when first installed) config file for this command only.
+
+ Examples: \n
+ \t - Use a work config file for this jrnl entry, call: \n
+ \t jrnl --config-file /home/user1/work_config.yaml
+ \t - Use a personal config file stored on a thumb drive: \n
+ \t jrnl --config-file /media/user1/my-thumb-drive/personal_config.yaml
+ """,
+ )
+
+ alternate_config.add_argument(
+ "--cf", dest="config_file_path", type=str, default="", help=argparse.SUPPRESS
+ )
+
# Handle '-123' as a shortcut for '-n 123'
num = re.compile(r"^-(\d+)$")
args = [num.sub(r"-n \1", arg) for arg in args]
diff --git a/jrnl/config.py b/jrnl/config.py
index a0482405..035fb34a 100644
--- a/jrnl/config.py
+++ b/jrnl/config.py
@@ -47,9 +47,14 @@ def make_yaml_valid_dict(input: list) -> dict:
return runtime_modifications
-def save_config(config):
+def save_config(config, alt_config_path=None):
+ """Supply alt_config_path if using an alternate config through --config-file."""
config["version"] = __version__
- with open(get_config_path(), "w", encoding=YAML_FILE_ENCODING) as f:
+ with open(
+ alt_config_path if alt_config_path else get_config_path(),
+ "w",
+ encoding=YAML_FILE_ENCODING,
+ ) as f:
yaml.safe_dump(
config,
f,
diff --git a/jrnl/install.py b/jrnl/install.py
index b0ae2aa1..b2b583cf 100644
--- a/jrnl/install.py
+++ b/jrnl/install.py
@@ -19,32 +19,53 @@ from .prompt import yesno
from .upgrade import is_old_version
-def upgrade_config(config):
+def upgrade_config(config_data, alt_config_path=None):
"""Checks if there are keys missing in a given config dict, and if so, updates the config file accordingly.
This essentially automatically ports jrnl installations if new config parameters are introduced in later
- versions."""
+ versions.
+ Supply alt_config_path if using an alternate config through --config-file."""
default_config = get_default_config()
- missing_keys = set(default_config).difference(config)
+ missing_keys = set(default_config).difference(config_data)
if missing_keys:
for key in missing_keys:
- config[key] = default_config[key]
- save_config(config)
+ config_data[key] = default_config[key]
+ save_config(config_data, alt_config_path)
+ config_path = alt_config_path if alt_config_path else get_config_path()
print(
- f"[Configuration updated to newest version at {get_config_path()}]",
+ f"[Configuration updated to newest version at {config_path}]",
file=sys.stderr,
)
-def load_or_install_jrnl():
- """
- If jrnl is already installed, loads and returns a config object.
- Else, perform various prompts to install jrnl.
- """
+def find_default_config():
config_path = (
get_config_path()
if os.path.exists(get_config_path())
else os.path.join(os.path.expanduser("~"), ".jrnl_config")
)
+ return config_path
+
+
+def find_alt_config(alt_config):
+ if os.path.exists(alt_config):
+ return alt_config
+ else:
+ print(
+ "Alternate configuration file not found at path specified.", file=sys.stderr
+ )
+ print("Exiting.", file=sys.stderr)
+ sys.exit(1)
+
+
+def load_or_install_jrnl(alt_config_path):
+ """
+ If jrnl is already installed, loads and returns a default config object.
+ If alternate config is specified via --config-file flag, it will be used.
+ Else, perform various prompts to install jrnl.
+ """
+ config_path = (
+ find_alt_config(alt_config_path) if alt_config_path else find_default_config()
+ )
if os.path.exists(config_path):
logging.debug("Reading configuration from file %s", config_path)
@@ -68,7 +89,7 @@ def load_or_install_jrnl():
print("Exiting.", file=sys.stderr)
sys.exit(1)
- upgrade_config(config)
+ upgrade_config(config, alt_config_path)
verify_config_colors(config)
else:
diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py
index bc7e0b88..9d128a3a 100644
--- a/jrnl/jrnl.py
+++ b/jrnl/jrnl.py
@@ -36,7 +36,7 @@ def run(args):
# Load the config, and extract journal name
try:
- config = install.load_or_install_jrnl()
+ config = install.load_or_install_jrnl(args.config_file_path)
original_config = config.copy()
# Apply config overrides
diff --git a/tests/bdd/features/config_file.feature b/tests/bdd/features/config_file.feature
new file mode 100644
index 00000000..ce4f042b
--- /dev/null
+++ b/tests/bdd/features/config_file.feature
@@ -0,0 +1,92 @@
+Feature: Multiple journals
+
+ Scenario: Read a journal from an alternate config
+ Given the config "basic_onefile.yaml" exists
+ And we use the config "multiple.yaml"
+ When we run "jrnl --cf basic_onefile.yaml -999"
+ Then the output should not contain "My first entry" # from multiple.yaml
+ And the output should contain "Lorem ipsum" # from basic_onefile.yaml
+
+ Scenario: Write to default journal by default using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl --cf multiple.yaml this goes to default"
+ And we run "jrnl -1"
+ Then the output should not contain "this goes to default"
+ When we run "jrnl --cf multiple.yaml -1"
+ Then the output should contain "this goes to default"
+
+ Scenario: Write to specified journal using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl work --cf multiple.yaml a long day in the office"
+ And we run "jrnl default --cf multiple.yaml -1"
+ Then the output should contain "But I'm better"
+ When we run "jrnl work --cf multiple.yaml -1"
+ Then the output should contain "a long day in the office"
+
+ Scenario: Tell user which journal was used while using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl --cf multiple.yaml work a long day in the office"
+ Then we should see the message "Entry added to work journal"
+
+ Scenario: Write to specified journal with a timestamp using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl work --cf multiple.yaml 23 july 2012: a long day in the office"
+ And we run "jrnl --cf multiple.yaml -1"
+ Then the output should contain "But I'm better"
+ When we run "jrnl --cf multiple.yaml work -1"
+ Then the output should contain "a long day in the office"
+ And the output should contain "2012-07-23"
+
+ Scenario: Write to specified journal without a timestamp but with colon using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl work --cf multiple.yaml : a long day in the office"
+ And we run "jrnl --cf multiple.yaml -1"
+ Then the output should contain "But I'm better"
+ When we run "jrnl --cf multiple.yaml work -1"
+ Then the output should contain "a long day in the office"
+
+ Scenario: Create new journals as required using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl ideas -1"
+ Then the output should be empty
+ When we run "jrnl ideas --cf multiple.yaml 23 july 2012: sell my junk on ebay and make lots of money"
+ Then the output should contain "Journal 'ideas' created"
+ When we run "jrnl ideas --cf multiple.yaml -1"
+ Then the output should contain "sell my junk on ebay and make lots of money"
+
+ Scenario: Don't crash if no default journal is specified using an alternate config
+ Given the config "bug343.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl --cf bug343.yaml a long day in the office"
+ Then we should see the message "No default journal configured"
+
+ Scenario: Don't crash if no file exists for a configured encrypted journal using an alternate config
+ Given the config "multiple.yaml" exists
+ And we use the config "basic_onefile.yaml"
+ When we run "jrnl new_encrypted --cf multiple.yaml Adding first entry" and enter
+ these three eyes
+ these three eyes
+ n
+ Then we should see the message "Encrypted journal 'new_encrypted' created"
+
+ Scenario: Don't overwrite main config when encrypting a journal in an alternate config
+ Given the config "basic_onefile.yaml" exists
+ And we use the config "multiple.yaml"
+ When we run "jrnl --cf basic_onefile.yaml --encrypt" and enter
+ these three eyes
+ these three eyes
+ n
+ Then we should see the message "Journal encrypted to features/journals/basic_onefile.journal"
+ And the config should contain "encrypt: false" # multiple.yaml remains unchanged
+
+ Scenario: Don't overwrite main config when decrypting a journal in an alternate config
+ Given the config "editor_encrypted.yaml" exists
+ And we use the config "basic_encrypted.yaml"
+ When we run "jrnl --cf editor_encrypted.yaml --decrypt"
+ Then the config should contain "encrypt: true" # basic_encrypted remains unchanged
diff --git a/tests/bdd/test_features.py b/tests/bdd/test_features.py
index 1509e92d..5ef3506e 100644
--- a/tests/bdd/test_features.py
+++ b/tests/bdd/test_features.py
@@ -1,6 +1,7 @@
from pytest_bdd import scenarios
scenarios("features/build.feature")
+scenarios("features/config_file.feature")
scenarios("features/core.feature")
scenarios("features/datetime.feature")
scenarios("features/delete.feature")
diff --git a/tests/lib/given_steps.py b/tests/lib/given_steps.py
index 649d44c5..f3e6b69c 100644
--- a/tests/lib/given_steps.py
+++ b/tests/lib/given_steps.py
@@ -105,6 +105,14 @@ def we_use_the_config(config_file, temp_dir, working_dir):
return config_dest
+@given(parse('the config "{config_file}" exists'), target_fixture="config_path")
+@given('the config "<config_file>" exists', target_fixture="config_path")
+def config_exists(config_file, temp_dir, working_dir):
+ config_source = os.path.join(working_dir, "data", "configs", config_file)
+ config_dest = os.path.join(temp_dir.name, config_file)
+ shutil.copy2(config_source, config_dest)
+
+
@given(parse('we use the password "{pw}" if prompted'), target_fixture="password")
def use_password_forever(pw):
return pw
diff --git a/tests/unit/test_config_file.py b/tests/unit/test_config_file.py
new file mode 100644
index 00000000..04766f4a
--- /dev/null
+++ b/tests/unit/test_config_file.py
@@ -0,0 +1,22 @@
+import pytest
+import os
+
+from jrnl.install import find_alt_config
+
+
+def test_find_alt_config(request):
+ work_config_path = os.path.join(
+ request.fspath.dirname, "..", "data", "configs", "basic_onefile.yaml"
+ )
+ found_alt_config = find_alt_config(work_config_path)
+ assert found_alt_config == work_config_path
+
+
+def test_find_alt_config_not_exist(request):
+ bad_config_path = os.path.join(
+ request.fspath.dirname, "..", "data", "configs", "not-existing-config.yaml"
+ )
+ with pytest.raises(SystemExit) as ex:
+ found_alt_config = find_alt_config(bad_config_path)
+ assert found_alt_config is not None
+ assert isinstance(ex.value, SystemExit)
diff --git a/tests/unit/test_parse_args.py b/tests/unit/test_parse_args.py
index 0725d33d..f408c9aa 100644
--- a/tests/unit/test_parse_args.py
+++ b/tests/unit/test_parse_args.py
@@ -37,6 +37,7 @@ def expected_args(**kwargs):
"tags": False,
"text": [],
"config_override": [],
+ "config_file_path": "",
}
return {**default_args, **kwargs}