From 0a1966e3b3197b44164ccb41f07f8ac9933741d4 Mon Sep 17 00:00:00 2001 From: Justin Proffitt Date: Sun, 28 Jul 2019 21:57:53 -0400 Subject: [PATCH 01/19] Add '-not' flag for excluding tags from filter --- jrnl/Journal.py | 9 +++++++-- jrnl/cli.py | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 94e89144..cfb85d1e 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -176,7 +176,7 @@ class Journal(object): tag_counts = set([(tags.count(tag), tag) for tag in tags]) return [Tag(tag, count=count) for count, tag in sorted(tag_counts)] - def filter(self, tags=[], start_date=None, end_date=None, starred=False, strict=False, short=False): + def filter(self, tags=[], start_date=None, end_date=None, starred=False, strict=False, short=False, exclude=[]): """Removes all entries from the journal that don't match the filter. tags is a list of tags, each being a string that starts with one of the @@ -187,19 +187,24 @@ class Journal(object): starred limits journal to starred entries If strict is True, all tags must be present in an entry. If false, the - entry is kept if any tag is present.""" + + exclude is a list of the tags which should not appear in the results. + entry is kept if any tag is present, unless they appear in exclude.""" self.search_tags = set([tag.lower() for tag in tags]) + excluded_tags = set([tag.lower() for tag in exclude]) end_date = time.parse(end_date, inclusive=True) start_date = time.parse(start_date) # If strict mode is on, all tags have to be present in entry tagged = self.search_tags.issubset if strict else self.search_tags.intersection + excluded = lambda tags: len([tag for tag in tags if tag in excluded_tags]) > 0 result = [ entry for entry in self.entries if (not tags or tagged(entry.tags)) and (not starred or entry.starred) and (not start_date or entry.date >= start_date) and (not end_date or entry.date <= end_date) + and (not exclude or not excluded(entry.tags)) ] self.entries = result diff --git a/jrnl/cli.py b/jrnl/cli.py index 72eff470..7ddd1052 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -39,6 +39,7 @@ def parse_args(args=None): reading.add_argument('-and', dest='strict', action="store_true", help='Filter by tags using AND (default: OR)') reading.add_argument('-starred', dest='starred', action="store_true", help='Show only starred entries') reading.add_argument('-n', dest='limit', default=None, metavar="N", help="Shows the last n entries matching the filter. '-n 3' and '-3' have the same effect.", nargs="?", type=int) + reading.add_argument('-not', dest='excluded', nargs='+', default=[], metavar="E", help="Exclude entries with these tags") exporting = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal') exporting.add_argument('-s', '--short', dest='short', action="store_true", help='Show only titles or line containing the search tags') @@ -234,7 +235,8 @@ def run(manual_args=None): start_date=args.start_date, end_date=args.end_date, strict=args.strict, short=args.short, - starred=args.starred) + starred=args.starred, + exclude=args.excluded) journal.limit(args.limit) # Reading mode From 451360995430d3a68616e263583d614a3103961a Mon Sep 17 00:00:00 2001 From: MinchinWeb Date: Mon, 13 Nov 2017 18:04:24 -0700 Subject: [PATCH 02/19] Switch to hashmark Markdown headers on export Closes #487 --- jrnl/plugins/markdown_exporter.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jrnl/plugins/markdown_exporter.py b/jrnl/plugins/markdown_exporter.py index 147e8ac5..0a237af4 100644 --- a/jrnl/plugins/markdown_exporter.py +++ b/jrnl/plugins/markdown_exporter.py @@ -68,12 +68,10 @@ class MarkdownExporter(TextExporter): for e in journal.entries: if not e.date.year == year: year = e.date.year - out.append(str(year)) - out.append("=" * len(str(year)) + "\n") + out.append("# " + str(year)) if not e.date.month == month: month = e.date.month - out.append(e.date.strftime("%B")) - out.append('-' * len(e.date.strftime("%B")) + "\n") + out.append("## " + e.date.strftime("%B")) out.append(cls.export_entry(e, False)) result = "\n".join(out) return result From 1884a6ce23f14aaf45950e74aa6f8ff75a21074d Mon Sep 17 00:00:00 2001 From: MinchinWeb Date: Thu, 1 Aug 2019 21:00:53 -0600 Subject: [PATCH 03/19] [Markdown Export] deal with linebreaks in jrnl files --- features/exporting.feature | 6 ++---- jrnl/plugins/markdown_exporter.py | 11 +++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/features/exporting.feature b/features/exporting.feature index 1b4285ed..db2ef5b3 100644 --- a/features/exporting.feature +++ b/features/exporting.feature @@ -42,11 +42,9 @@ Feature: Exporting a Journal When we run "jrnl --export markdown" Then the output should be """ - 2015 - ==== + # 2015 - April - ----- + ## April ### 2015-04-14 13:23 Heading Test diff --git a/jrnl/plugins/markdown_exporter.py b/jrnl/plugins/markdown_exporter.py index 0a237af4..19b5404d 100644 --- a/jrnl/plugins/markdown_exporter.py +++ b/jrnl/plugins/markdown_exporter.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals, print_function from .text_exporter import TextExporter +import os import re import sys from ..util import WARNING_COLOR, RESET_COLOR @@ -30,17 +31,17 @@ class MarkdownExporter(TextExporter): previous_line = '' warn_on_heading_level = False for line in body.splitlines(True): - if re.match(r"#+ ", line): + if re.match(r"^#+ ", line): """ATX style headings""" newbody = newbody + previous_line + heading + line - if re.match(r"#######+ ", heading + line): + if re.match(r"^#######+ ", heading + line): warn_on_heading_level = True line = '' - elif re.match(r"=+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^=+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H1""" newbody = newbody + heading + "# " + previous_line line = '' - elif re.match(r"-+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^-+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H2""" newbody = newbody + heading + "## " + previous_line line = '' @@ -69,9 +70,11 @@ class MarkdownExporter(TextExporter): if not e.date.year == year: year = e.date.year out.append("# " + str(year)) + out.append("") if not e.date.month == month: month = e.date.month out.append("## " + e.date.strftime("%B")) + out.append("") out.append(cls.export_entry(e, False)) result = "\n".join(out) return result From e95290f92f22b93d31875b185446bbc538436a8a Mon Sep 17 00:00:00 2001 From: MinchinWeb Date: Thu, 1 Aug 2019 21:21:55 -0600 Subject: [PATCH 04/19] [YAML Exporter] apply fix just applied to Markdown Exporter --- jrnl/plugins/yaml_exporter.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jrnl/plugins/yaml_exporter.py b/jrnl/plugins/yaml_exporter.py index 1442adcc..c0735811 100644 --- a/jrnl/plugins/yaml_exporter.py +++ b/jrnl/plugins/yaml_exporter.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals, print_function from .text_exporter import TextExporter +import os import re import sys from ..util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR @@ -34,17 +35,17 @@ class YAMLExporter(TextExporter): previous_line = '' warn_on_heading_level = False for line in entry.body.splitlines(True): - if re.match(r"#+ ", line): + if re.match(r"^#+ ", line): """ATX style headings""" newbody = newbody + previous_line + heading + line - if re.match(r"#######+ ", heading + line): + if re.match(r"^#######+ ", heading + line): warn_on_heading_level = True line = '' - elif re.match(r"=+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^=+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H1""" newbody = newbody + heading + "# " + previous_line line = '' - elif re.match(r"-+$", line) and not re.match(r"^$", previous_line): + elif re.match(r"^-+$", line.rstrip()) and not re.match(r"^$", previous_line.strip()): """Setext style H2""" newbody = newbody + heading + "## " + previous_line line = '' From 960573c103ea75173dec7cd59f6e2c3137f098e5 Mon Sep 17 00:00:00 2001 From: Dawid Zych Date: Wed, 7 Aug 2019 19:12:04 +0200 Subject: [PATCH 05/19] Handle KeyboardInterrupt when installing journal --- jrnl/cli.py | 9 +++++++-- jrnl/install.py | 7 ++++++- jrnl/upgrade.py | 12 +++++++----- jrnl/util.py | 4 ++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/jrnl/cli.py b/jrnl/cli.py index 72eff470..6d88685a 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -13,7 +13,7 @@ from . import Journal from . import util from . import install from . import plugins -from .util import ERROR_COLOR, RESET_COLOR +from .util import ERROR_COLOR, RESET_COLOR, UserAbort import jrnl import argparse import sys @@ -143,7 +143,12 @@ def run(manual_args=None): print(util.py2encode(version_str)) sys.exit(0) - config = install.load_or_install_jrnl() + try: + config = install.load_or_install_jrnl() + except UserAbort as err: + util.prompt("\n{}".format(err)) + sys.exit(1) + if args.ls: util.prnt(list_journals(config)) sys.exit(0) diff --git a/jrnl/install.py b/jrnl/install.py index 7cc8f880..e24d36af 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -12,6 +12,7 @@ from . import upgrade from . import __version__ from .Journal import PlainJournal from .EncryptedJournal import EncryptedJournal +from .util import UserAbort import yaml import logging @@ -90,7 +91,11 @@ def load_or_install_jrnl(): return config else: log.debug('Configuration file not found, installing jrnl...') - return install() + try: + config = install() + except KeyboardInterrupt: + raise UserAbort("Installation aborted") + return config def install(): diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index 3784c9f6..12d5054b 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -4,7 +4,7 @@ from . import __version__ from . import Journal from . import util from .EncryptedJournal import EncryptedJournal -import sys +from .util import UserAbort import os import codecs @@ -76,10 +76,12 @@ older versions of jrnl anymore. for journal, path in other_journals.items(): util.prompt(" {:{pad}} -> {}".format(journal, path, pad=longest_journal_name)) - cont = util.yesno("\nContinue upgrading jrnl?", default=False) - if not cont: - util.prompt("jrnl NOT upgraded, exiting.") - sys.exit(1) + try: + cont = util.yesno("\nContinue upgrading jrnl?", default=False) + if not cont: + raise KeyboardInterrupt + except KeyboardInterrupt: + raise UserAbort("jrnl NOT upgraded, exiting.") for journal_name, path in encrypted_journals.items(): util.prompt("\nUpgrading encrypted '{}' journal stored in {}...".format(journal_name, path)) diff --git a/jrnl/util.py b/jrnl/util.py index 7f6688d8..bc36ba9b 100644 --- a/jrnl/util.py +++ b/jrnl/util.py @@ -47,6 +47,10 @@ SENTENCE_SPLITTER = re.compile(r""" )""", re.UNICODE | re.VERBOSE) +class UserAbort(Exception): + pass + + def getpass(prompt="Password: "): if not TEST: return gp.getpass(bytes(prompt)) From 31a4607a7de70c8c1df4903475cdb472105dcc07 Mon Sep 17 00:00:00 2001 From: Justin Proffitt Date: Wed, 7 Aug 2019 20:58:35 -0400 Subject: [PATCH 06/19] Add tests for the excluding tags with -not --- features/tagging.feature | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/features/tagging.feature b/features/tagging.feature index cc686673..2cbf7ce1 100644 --- a/features/tagging.feature +++ b/features/tagging.feature @@ -50,3 +50,35 @@ Feature: Tagging @foo : 1 @bar : 1 """ + + Scenario: Excluding a tag should filter it + Given we use the config "basic.yaml" + When we run "jrnl today: @foo came over, we went to a bar" + When we run "jrnl I have decided I did not enjoy that @bar" + When we run "jrnl --tags -not @bar" + Then the output should be + """ + @foo : 1 + """ + + Scenario: Excluding a tag should filter an entry, even if an unfiltered tag is in that entry + Given we use the config "basic.yaml" + When we run "jrnl today: I do @not think this will show up @thought" + When we run "jrnl today: I think this will show up @thought" + When we run "jrnl --tags -not @not" + Then the output should be + """ + @thought : 1 + """ + + Scenario: Excluding multiple tags should filter them + Given we use the config "basic.yaml" + When we run "jrnl today: I do @not think this will show up @thought" + When we run "jrnl today: I think this will show up @thought" + When we run "jrnl today: This should @never show up @thought" + When we run "jrnl today: What a nice day for filtering @thought" + When we run "jrnl --tags -not @not @never" + Then the output should be + """ + @thought : 2 + """ From 2c994418037a86896a98de916ec18202fca97083 Mon Sep 17 00:00:00 2001 From: Manuel Ebert Date: Fri, 23 Aug 2019 18:38:05 -0700 Subject: [PATCH 07/19] Smaller doc fixes, fixes #486 --- README.md | 2 +- docs/advanced.md | 16 +++++++--------- docs/recipes.md | 49 +++++++++++++++++++++++++++--------------------- docs/usage.md | 17 +++++++++-------- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index e43857d4..0f444ab2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Optionally, your journal can be encrypted using the [256-bit AES](http://en.wiki ### Why keep a journal? -Journals aren't just for angsty teenagers and people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. For personal use, make it a good habit to write at least 20 words a day. Just to reflect what made this day special, why you haven't wasted it. For professional use, consider a text-based journal to be the perfect complement to your GTD todo list - a documentation of what and how you've done it. +Journals aren't just for people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. For personal use, make it a good habit to write at least 20 words a day. Just to reflect what made this day special, why you haven't wasted it. For professional use, consider a text-based journal to be the perfect complement to your GTD todo list - a documentation of what and how you've done it. In a Nutshell ------------- diff --git a/docs/advanced.md b/docs/advanced.md index 6a78da95..2a6fd6b4 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -135,13 +135,11 @@ that journal. this option will most likely result in your journal file being impossible to load. -### Known Issues +## Known Issues - - The Windows shell prior to Windows 7 has issues with unicode - encoding. If you want to use non-ascii characters, change the - codepage with `chcp 1252` before using - `jrnl` (Thanks to Yves Pouplard for - solving this!) - - `jrnl`relies on the PyCrypto - package to encrypt journals, which has some known problems with - installing on Windows and within virtual environments. +### Unicode on Windows + +The Windows shell prior to Windows 7 has issues with unicode encoding. +To use non-ascii characters, first tweak Python to recognize the encoding by adding `'cp65001': 'utf_8'`, to `Lib/encoding/aliases.py`. Then, change the codepage with `chcp 1252` before using `jrnl`. + +(Related issue: [#486](https://github.com/jrnl-org/jrnl/issues/486)) diff --git a/docs/recipes.md b/docs/recipes.md index 1c272e05..7af5b246 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -15,9 +15,8 @@ And will get something like `@melo: 9`, meaning there are 9 entries where both `@alberto` and `@melo` are tagged. How does this work? First, `jrnl @alberto` will filter the journal to only entries containing the tag `@alberto`, and then the `--tags` option will print out how often -each tag occurred in this filtered -journal. Finally, we pipe this to `grep` which will only display the -line containing `@melo`. +each tag occurred in this filtered journal. Finally, we pipe this to +`grep` which will only display the line containing `@melo`. ### Combining filters @@ -66,17 +65,19 @@ If you do that often, consider creating a function in your `.bashrc` or ``` sh jrnlimport () { - echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' $1` `cat $1` | jrnl + echo `stat -f %Sm -t '%d %b %Y at %H:%M: ' $1` `cat $1` | jrnl } ``` ### Using templates Say you always want to use the same template for creating new entries. -If you have an `external editor ` set up, you can use this : +If you have an [external editor](../advanced) set up, you can use this: - jrnl < my_template.txt - $ jrnl -1 --edit +```sh +jrnl < my_template.txt +jrnl -1 --edit +``` Another nice solution that allows you to define individual prompts comes from [Jacobo de @@ -105,8 +106,10 @@ close the file to save the changes to jrnl. To use Sublime Text, install the command line tools for Sublime Text and configure your `.jrnl_config` like this: -``` javascript -"editor": "subl -w" +``` json +{ + "editor": "subl -w" +} ``` Note the `-w` flag to make sure jrnl waits for Sublime Text to close the @@ -118,8 +121,10 @@ Similar to Sublime Text, MacVim must be started with a flag that tells the the process to wait until the file is closed before passing control back to journal. In the case of MacVim, this is `-f`: -``` javascript -"editor": "mvim -f" +``` json +{ + "editor": "mvim -f" +} ``` ### iA Writer @@ -128,8 +133,10 @@ On OS X, you can use the fabulous [iA Writer](http://www.iawriter.com/mac) to write entries. Configure your `.jrnl_config` like this: -``` javascript -"editor": "open -b pro.writer.mac -Wn" +``` json +{ + "editor": "open -b pro.writer.mac -Wn" +} ``` What does this do? `open -b ...` opens a file using the application @@ -142,9 +149,7 @@ you can find the right string to use by inspecting iA Writer's `Info.plist` file in your shell: ``` sh -$ grep -A 1 CFBundleIdentifier /Applications/iA\ Writer.app/Contents/Info.plist - CFBundleIdentifier - pro.writer.mac +grep -A 1 CFBundleIdentifier /Applications/iA\ Writer.app/Contents/Info.plist ``` ### Notepad++ on Windows @@ -152,8 +157,10 @@ $ grep -A 1 CFBundleIdentifier /Applications/iA\ Writer.app/Contents/Info.plist To set [Notepad++](http://notepad-plus-plus.org/) as your editor, edit the jrnl config file (`.jrnl_config`) like this: -``` javascript -"editor": "C:\\Program Files (x86)\\Notepad++\\notepad++.exe -multiInst -nosession", +``` json +{ + "editor": "C:\\Program Files (x86)\\Notepad++\\notepad++.exe -multiInst -nosession", +} ``` The double backslashes are needed so jrnl can read the file path @@ -164,9 +171,9 @@ its own Notepad++ window. To set [Visual Studo Code](https://code.visualstudio.com) as your editor on Linux, edit `.jrnl_config` like this: -```javascript +```json { - "editor": "/usr/bin/code --wait", + "editor": "/usr/bin/code --wait", } ``` @@ -183,7 +190,7 @@ Then you can add: ```javascript { - "editor": "code --wait", + "editor": "code --wait", } ``` diff --git a/docs/usage.md b/docs/usage.md index 0ad8e056..fa5050a0 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -37,7 +37,8 @@ jrnl today at 3am: I just met Steve Buscemi in a bar! He looked funny. !!! note Most shell contains a certain number of reserved characters, such as `#` and `*`. Unbalanced quotes, parenthesis, and so on will also get into - the way of your editing. For writing longer entries, just enter `jrnl` + the way of your editing. + For writing longer entries, just enter `jrnl` and hit `return`. Only then enter the text of your journal entry. Alternatively, `use an external editor `). @@ -75,9 +76,9 @@ The following options are equivalent: - `jrnl Best day of my life.*` !!! note - Just make sure that the asterisk sign is **not** surrounded by - whitespaces, e.g. `jrnl Best day of my life! *` will **not** work (the - reason being that the `*` sign has a special meaning on most shells). + Just make sure that the asterisk sign is **not** surrounded by + whitespaces, e.g. `jrnl Best day of my life! *` will **not** work (the + reason being that the `*` sign has a special meaning on most shells). ## Viewing @@ -126,9 +127,9 @@ You can change which symbols you'd like to use for tagging in the configuration. !!! note - `jrnl @pinkie @WorldDomination` will switch to viewing mode because - although **no** command line arguments are given, all the input strings - look like tags - *jrnl* will assume you want to filter by tag. + `jrnl @pinkie @WorldDomination` will switch to viewing mode because + although **no** command line arguments are given, all the input strings + look like tags - *jrnl* will assume you want to filter by tag. ## Editing older entries @@ -164,7 +165,7 @@ DayOne journals can be edited exactly the same way, however the output looks a little bit different because of the way DayOne stores its entries: -``` output +```md # af8dbd0d43fb55458f11aad586ea2abf 2013-05-02 15:30 I told everyone I built my @robot wife for sex. But late at night when we're alone we mostly play Battleship. From 47117b4ef5f6a6fcab76479b4346e8ad2bf9ac4d Mon Sep 17 00:00:00 2001 From: Manuel Ebert Date: Fri, 23 Aug 2019 18:39:49 -0700 Subject: [PATCH 08/19] Found and removed another angsty teenager --- docs/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/overview.md b/docs/overview.md index c634ae8e..8a0ec10f 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -17,7 +17,7 @@ AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). ## Why keep a journal? -Journals aren't just for angsty teenagers and people who have too much +Journals aren't just for people who have too much time on their summer vacation. A journal helps you to keep track of the things you get done and how you did them. Your imagination may be limitless, but your memory isn't. From 3bfd9f487b67d74b8990a8fd5e0141510b94db54 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison <4383304+micahellison@users.noreply.github.com> Date: Sat, 24 Aug 2019 13:50:10 -0700 Subject: [PATCH 09/19] [GH-632] confirming that each journal can be parsed during upgrade, and aborting upgrade if not --- features/encryption.feature | 11 ----------- features/regression.feature | 11 ----------- features/upgrade.feature | 23 +++++++++++++++++++++++ jrnl/Journal.py | 13 ++++++++++++- jrnl/upgrade.py | 23 +++++++++++++++++------ 5 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 features/upgrade.feature diff --git a/features/encryption.feature b/features/encryption.feature index ebb3cc02..82d971eb 100644 --- a/features/encryption.feature +++ b/features/encryption.feature @@ -29,14 +29,3 @@ When we run "jrnl simple -n 1" Then we should not see the message "Password" and the output should contain "2013-06-10 15:40 Life is good" - - Scenario: Upgrading a journal encrypted with jrnl 1.x - Given we use the config "encrypted_old.json" - When we run "jrnl -n 1" and enter - """ - Y - bad doggie no biscuit - bad doggie no biscuit - """ - Then we should see the message "Password" - and the output should contain "2013-06-10 15:40 Life is good" diff --git a/features/regression.feature b/features/regression.feature index 21078a1c..3e644b19 100644 --- a/features/regression.feature +++ b/features/regression.feature @@ -43,17 +43,6 @@ Feature: Zapped bugs should stay dead. | Hope to get a lot of traffic. """ - Scenario: Upgrade and parse journals with square brackets - Given we use the config "upgrade_from_195.json" - When we run "jrnl -9" and enter "Y" - Then the output should contain - """ - 2010-06-10 15:00 A life without chocolate is like a bad analogy. - - 2013-06-10 15:40 He said "[this] is the best time to be alive". - """ - Then the journal should have 2 entries - Scenario: Integers in square brackets should not be read as dates Given we use the config "brackets.yaml" When we run "jrnl -1" diff --git a/features/upgrade.feature b/features/upgrade.feature new file mode 100644 index 00000000..bce026b8 --- /dev/null +++ b/features/upgrade.feature @@ -0,0 +1,23 @@ +Feature: Upgrading Journals from 1.x.x to 2.x.x + + Scenario: Upgrade and parse journals with square brackets + Given we use the config "upgrade_from_195.json" + When we run "jrnl -9" and enter "Y" + Then the output should contain + """ + 2010-06-10 15:00 A life without chocolate is like a bad analogy. + + 2013-06-10 15:40 He said "[this] is the best time to be alive". + """ + Then the journal should have 2 entries + + Scenario: Upgrading a journal encrypted with jrnl 1.x + Given we use the config "encrypted_old.json" + When we run "jrnl -n 1" and enter + """ + Y + bad doggie no biscuit + bad doggie no biscuit + """ + Then we should see the message "Password" + and the output should contain "2013-06-10 15:40 Life is good" diff --git a/jrnl/Journal.py b/jrnl/Journal.py index cf336bdc..7feb49a6 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -84,9 +84,20 @@ class Journal(object): def write(self, filename=None): """Dumps the journal into the config file, overwriting it""" filename = filename or self.config['journal'] - text = "\n".join([e.__unicode__() for e in self.entries]) + text = self._to_text() self._store(filename, text) + def validate_parsing(self): + """Confirms that the jrnl is still parsed correctly after being dumped to text.""" + new_entries = self._parse(self._to_text()) + for i, entry in enumerate(self.entries): + if entry != new_entries[i]: + return False + return True + + def _to_text(self): + return "\n".join([e.__unicode__() for e in self.entries]) + def _load(self, filename): raise NotImplementedError diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index 3784c9f6..1f4f999a 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -44,6 +44,7 @@ older versions of jrnl anymore. encrypted_journals = {} plain_journals = {} other_journals = {} + all_journals = [] for journal_name, journal_conf in config['journals'].items(): if isinstance(journal_conf, dict): @@ -85,17 +86,27 @@ older versions of jrnl anymore. util.prompt("\nUpgrading encrypted '{}' journal stored in {}...".format(journal_name, path)) backup(path, binary=True) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) - new_journal = EncryptedJournal.from_journal(old_journal) - new_journal.write() - util.prompt(" Done.") + all_journals.append(EncryptedJournal.from_journal(old_journal)) for journal_name, path in plain_journals.items(): util.prompt("\nUpgrading plain text '{}' journal stored in {}...".format(journal_name, path)) backup(path) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) - new_journal = Journal.PlainJournal.from_journal(old_journal) - new_journal.write() - util.prompt(" Done.") + all_journals.append(Journal.PlainJournal.from_journal(old_journal)) + + # loop through lists to validate + failed_journals = [j for j in all_journals if not j.validate_parsing()] + if len(failed_journals) > 0: + util.prompt("\nThe following journal{} failed to upgrade:\n{}".format( + 's' if len(failed_journals) > 1 else '', "\n".join(j.name for j in failed_journals)) + ) + + util.prompt("Aborting upgrade.") + return + + # write all journals - or - don't + for j in all_journals: + j.write() util.prompt("\nUpgrading config...") backup(config_path) From a4e881942a17cde05cd16b2bc34e92998ed9dea7 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison <4383304+micahellison@users.noreply.github.com> Date: Sat, 24 Aug 2019 15:01:23 -0700 Subject: [PATCH 10/19] [GH-632] raising exception in upgrade.py on fail Handling it in install.py to prevent config from being overwritten when upgrade fails --- jrnl/install.py | 10 +++++++++- jrnl/upgrade.py | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/jrnl/install.py b/jrnl/install.py index 7cc8f880..68cfb6ea 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -14,6 +14,7 @@ from .Journal import PlainJournal from .EncryptedJournal import EncryptedJournal import yaml import logging +import sys DEFAULT_CONFIG_NAME = 'jrnl.yaml' DEFAULT_JOURNAL_NAME = 'journal.txt' @@ -85,8 +86,15 @@ def load_or_install_jrnl(): if os.path.exists(config_path): log.debug('Reading configuration from file %s', config_path) config = util.load_config(config_path) - upgrade.upgrade_jrnl_if_necessary(config_path) + + try: + upgrade.upgrade_jrnl_if_necessary(config_path) + except upgrade.UpgradeValidationException: + util.prompt("Aborting upgrade. Exiting.") + sys.exit(1) + upgrade_config(config) + return config else: log.debug('Configuration file not found, installing jrnl...') diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index 1f4f999a..b3d39984 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -96,12 +96,14 @@ older versions of jrnl anymore. # loop through lists to validate failed_journals = [j for j in all_journals if not j.validate_parsing()] + if len(failed_journals) > 0: util.prompt("\nThe following journal{} failed to upgrade:\n{}".format( 's' if len(failed_journals) > 1 else '', "\n".join(j.name for j in failed_journals)) ) - util.prompt("Aborting upgrade.") + raise UpgradeValidationException + return # write all journals - or - don't @@ -112,3 +114,7 @@ older versions of jrnl anymore. backup(config_path) util.prompt("\nWe're all done here and you can start enjoying jrnl 2.".format(config_path)) + +class UpgradeValidationException(Exception): + """Raised when the contents of an upgraded journal do not match the old journal""" + pass From 4d0640e613761a2007533db2669e03fe583c829a Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison <4383304+micahellison@users.noreply.github.com> Date: Sat, 24 Aug 2019 15:14:15 -0700 Subject: [PATCH 11/19] [GH-632] removing unnecessary whitespace --- jrnl/install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jrnl/install.py b/jrnl/install.py index 68cfb6ea..9b6965fa 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -86,7 +86,7 @@ def load_or_install_jrnl(): if os.path.exists(config_path): log.debug('Reading configuration from file %s', config_path) config = util.load_config(config_path) - + try: upgrade.upgrade_jrnl_if_necessary(config_path) except upgrade.UpgradeValidationException: @@ -94,7 +94,7 @@ def load_or_install_jrnl(): sys.exit(1) upgrade_config(config) - + return config else: log.debug('Configuration file not found, installing jrnl...') From 244165664b125da0b3c2897e6d1ddc3d6f1c6ce6 Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison <4383304+micahellison@users.noreply.github.com> Date: Sat, 24 Aug 2019 15:25:05 -0700 Subject: [PATCH 12/19] [GH-632] removing unreachable return statement --- jrnl/upgrade.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/jrnl/upgrade.py b/jrnl/upgrade.py index b3d39984..4e315f82 100644 --- a/jrnl/upgrade.py +++ b/jrnl/upgrade.py @@ -104,8 +104,6 @@ older versions of jrnl anymore. raise UpgradeValidationException - return - # write all journals - or - don't for j in all_journals: j.write() From be35904912efe6284fff70461830fe0ab65ca60b Mon Sep 17 00:00:00 2001 From: Micah Jerome Ellison <4383304+micahellison@users.noreply.github.com> Date: Sat, 24 Aug 2019 15:47:13 -0700 Subject: [PATCH 13/19] [GH-632] adding call to action to report issue when upgrade fails --- jrnl/install.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jrnl/install.py b/jrnl/install.py index 9b6965fa..417497aa 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -90,7 +90,10 @@ def load_or_install_jrnl(): try: upgrade.upgrade_jrnl_if_necessary(config_path) except upgrade.UpgradeValidationException: - util.prompt("Aborting upgrade. Exiting.") + util.prompt("Aborting upgrade.") + util.prompt("Please tell us about this problem at the following URL:") + util.prompt("https://github.com/jrnl-org/jrnl/issues/new?title=UpgradeValidationException") + util.prompt("Exiting.") sys.exit(1) upgrade_config(config) From f9ff5196791fe01d454cf7158f5ddafa9aada6b3 Mon Sep 17 00:00:00 2001 From: Manuel Ebert Date: Wed, 18 Sep 2019 10:33:01 -0700 Subject: [PATCH 14/19] Fix references to Sphinx in contributing.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56a59a61..989ccf7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ If you use jrnl, you can totally make our day by just saying "thanks for the cod Docs & Typos ------------ -If you find a typo or a mistake in the docs, please fix it right away and send a pull request. The Right Way™ to fix the docs is to edit the `docs/*.rst` files on the **master** branch. You can see the result if you run `make html` inside the project's root directory, and then open `docs/_build/html/index.html` in your browser. Note that this requires [lessc](http://lesscss.org/) and [Sphinx](https://pypi.python.org/pypi/Sphinx) to be installed. Changes to the CSS or Javascript should be made on `docs/_themes/jrnl/`. The `gh-pages` branch is automatically maintained and updates from `master`; you should never have to edit that. +If you find a typo or a mistake in the docs, please fix it right away and send a pull request. The Right Way™ to fix the docs is to edit the `docs/*.md` files on the **master** branch. You can see the result if you run `make html` inside the project's root directory, which will open a browser that hot-reloads as you change the docs. This requires [mkdocs](https://www.mkdocs.org) to be installed. The `gh-pages` branch is automatically maintained and updates from `master`; you should never have to edit that. Bugs ---- From 9bc0340280042154d0cbc154243ebb1b63e515eb Mon Sep 17 00:00:00 2001 From: etienne Date: Tue, 24 Sep 2019 17:13:05 +0200 Subject: [PATCH 15/19] Change pyYAML required version Full Loader only avalaible from v5.1: --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1cc8a3c5..9d06b96f 100644 --- a/setup.py +++ b/setup.py @@ -85,7 +85,7 @@ setup( "six>=1.10.0", "cryptography>=1.4", "tzlocal>=1.2", - "pyyaml>=3.11", + "pyyaml>=5.1", "keyring>=7.3", "passlib>=1.6.2", "pyxdg>=0.25", From a5519b9804ff2b12047a787188114fc44a8eb58a Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 5 Oct 2019 15:59:39 -0700 Subject: [PATCH 16/19] update requirements to include pyyaml >= 5.1 --- poetry.lock | 55 ++++++++------------------------------------------ pyproject.toml | 1 + 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/poetry.lock b/poetry.lock index f1ed472d..e772b2d2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -34,11 +34,6 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "19.1.0" -[package.extras] -dev = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface"] - [[package]] category = "dev" description = "behave is behaviour-driven development, Python style" @@ -52,10 +47,6 @@ parse = ">=1.8.2" parse-type = ">=0.4.2" six = ">=1.11" -[package.extras] -develop = ["coverage", "pytest (>=3.0)", "pytest-cov", "tox", "invoke (>=0.21.0)", "path.py (>=8.1.2)", "pycmd", "pathlib", "modernize (>=0.5)", "pylint"] -docs = ["sphinx (>=1.6)", "sphinx-bootstrap-theme (>=0.6)"] - [[package]] category = "dev" description = "The uncompromising code formatter." @@ -70,9 +61,6 @@ attrs = ">=17.4.0" click = ">=6.5" toml = ">=0.9.4" -[package.extras] -d = ["aiohttp (>=3.3.2)"] - [[package]] category = "main" description = "Foreign Function Interface for Python calling C code." @@ -114,13 +102,6 @@ asn1crypto = ">=0.21.0" cffi = ">=1.8,<1.11.3 || >1.11.3" six = ">=1.4.1" -[package.extras] -docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"] -docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] -idna = ["idna (>=2.1)"] -pep8test = ["flake8", "flake8-import-order", "pep8-naming"] -test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] - [[package]] category = "main" description = "Discover and load entry points from installed packages." @@ -154,7 +135,7 @@ version = "0.17.1" [[package]] category = "main" description = "Low-level, pure Python DBus protocol wrapper." -marker = "python_version >= \"3.3\" and python_version < \"4.0\" and sys_platform == \"linux\"" +marker = "sys_platform == \"linux\"" name = "jeepney" optional = false python-versions = ">=3.5" @@ -171,13 +152,9 @@ version = "2.10.1" [package.dependencies] MarkupSafe = ">=0.23" -[package.extras] -i18n = ["Babel (>=0.8)"] - [[package]] category = "main" description = "Store and access your passwords safely." -marker = "python_version >= \"3.3\" and python_version < \"4.0\"" name = "keyring" optional = false python-versions = ">=3.5" @@ -188,10 +165,6 @@ entrypoints = "*" pywin32-ctypes = "<0.1.0 || >0.1.0,<0.1.1 || >0.1.1" secretstorage = "*" -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs", "pytest-flake8", "pytest-black-multipy"] - [[package]] category = "dev" description = "Python LiveReload is an awesome tool for web developers" @@ -215,9 +188,6 @@ version = "3.1.1" [package.dependencies] setuptools = ">=36" -[package.extras] -testing = ["coverage", "pyyaml"] - [[package]] category = "dev" description = "Safely add untrusted strings to HTML/XML markup." @@ -278,10 +248,6 @@ version = "0.4.2" parse = ">=1.8" six = ">=1.11" -[package.extras] -develop = ["coverage", "pytest (>=3.0)", "pytest-cov", "tox"] -docs = ["sphinx (>=1.2)"] - [[package]] category = "main" description = "Parse human-readable date/time text." @@ -301,11 +267,6 @@ optional = false python-versions = "*" version = "1.7.1" -[package.extras] -argon2 = ["argon2-cffi (>=16.2)"] -bcrypt = ["bcrypt (>=3.1.0)"] -totp = ["cryptography"] - [[package]] category = "dev" description = "Python style guide checker" @@ -352,7 +313,7 @@ version = "2019.1" [[package]] category = "main" description = "" -marker = "python_version >= \"3.3\" and python_version < \"4.0\" and sys_platform == \"win32\"" +marker = "sys_platform == \"win32\"" name = "pywin32-ctypes" optional = false python-versions = "*" @@ -367,17 +328,17 @@ python-versions = "*" version = "0.26" [[package]] -category = "dev" +category = "main" description = "YAML parser and emitter for Python" name = "pyyaml" optional = false -python-versions = "*" -version = "5.1.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "5.1.2" [[package]] category = "main" description = "Python bindings to FreeDesktop.org Secret Service API" -marker = "python_version >= \"3.3\" and python_version < \"4.0\" and sys_platform == \"linux\"" +marker = "sys_platform == \"linux\"" name = "secretstorage" optional = false python-versions = ">=3.5" @@ -423,7 +384,7 @@ version = "1.5.1" pytz = "*" [metadata] -content-hash = "dfea1af4681213904e1a1a226754c6ca97ffe666c75b9772b0dd30c27525e0f6" +content-hash = "9896cf59c7552b6ad95219ee5555c7445a3fab39c2e4f4c6f3d991a36635e44b" python-versions = "^3.7" [metadata.hashes] @@ -460,7 +421,7 @@ python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493d pytz = ["303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", "d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"] pywin32-ctypes = ["24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942", "9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"] pyxdg = ["1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e", "fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"] -pyyaml = ["57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3", "588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043", "68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7", "70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265", "86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391", "a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778", "a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225", "b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955", "cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e", "ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190", "fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd"] +pyyaml = ["0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", "01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", "5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", "5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", "7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", "7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", "87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", "9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", "a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", "b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", "b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", "bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", "f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8"] secretstorage = ["20c797ae48a4419f66f8d28fc221623f11fc45b6828f96bdb1ad9990acb59f92", "7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a"] six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] diff --git a/pyproject.toml b/pyproject.toml index 69b54646..75df2256 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ tzlocal = "^1.5" asteval = "^0.9.14" colorama = {version = "^0.4.1",platform = "win32"} python-dateutil = "^2.8" +pyyaml = "^5.1" [tool.poetry.dev-dependencies] behave = "^1.2" From 9e0ed536433424581179eda834905243cf3eeb25 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 5 Oct 2019 16:06:16 -0700 Subject: [PATCH 17/19] update version and author emails --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 75df2256..7c2f123a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [tool.poetry] name = "jrnl" -version = "2.0.0" +version = "2.1" description = "Collect your thoughts and notes without leaving the command line." authors = [ "Manuel Ebert ", - "Jonathan Wren", - "Micah Ellison" + "Jonathan Wren ", + "Micah Ellison " ] license = "MIT" readme = "README.md" From 0328a748d3c689f731cfab42c5ec4f7ad5b631e1 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 5 Oct 2019 16:07:34 -0700 Subject: [PATCH 18/19] update makefile to use poetry for more things --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6219c1e6..de491e1f 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,11 @@ clean: rm -f *.html html: - mkdocs serve + poetry run mkdocs serve # Build GitHub Page from docs docs: - mkdocs gh-deploy + poetry run mkdocs gh-deploy format: ## check style with flake8 poetry run black features jrnl @@ -31,7 +31,7 @@ dist: clean ## builds source and wheel package release: dist ## package and upload a release poetry publish - mkdocs gh-deploy + poetry run mkdocs gh-deploy install: clean ## install the package to the active Python's site-packages poetry install From ee5d450cbedaa709b3e8883ed606d289baae2658 Mon Sep 17 00:00:00 2001 From: Jonathan Wren Date: Sat, 5 Oct 2019 16:27:18 -0700 Subject: [PATCH 19/19] remove faulty conditional --- jrnl/install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jrnl/install.py b/jrnl/install.py index 77247508..5a80562f 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -65,7 +65,7 @@ def upgrade_config(config): This essentially automatically ports jrnl installations if new config parameters are introduced in later versions.""" missing_keys = set(default_config).difference(config) - if missing_keys or config['version'] != __version__: + if missing_keys: for key in missing_keys: config[key] = default_config[key] save_config(config)