[GH-632] confirming that each journal can be parsed during upgrade, and aborting upgrade if not

[GH-632] raising exception in upgrade.py on fail
Handling it in install.py to prevent config from being overwritten when upgrade fails
[GH-632] removing unnecessary whitespace
[GH-632] removing unreachable return statement
[GH-632] adding call to action to report issue when upgrade fails
This commit is contained in:
Micah Jerome Ellison 2019-08-24 13:50:10 -07:00
parent 328faa401c
commit 8abbdf4db5
6 changed files with 68 additions and 30 deletions

View file

@ -29,14 +29,3 @@
When we run "jrnl simple -n 1" When we run "jrnl simple -n 1"
Then we should not see the message "Password" Then we should not see the message "Password"
and the output should contain "2013-06-10 15:40 Life is good" 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"

View file

@ -43,17 +43,6 @@ Feature: Zapped bugs should stay dead.
| Hope to get a lot of traffic. | 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 Scenario: Integers in square brackets should not be read as dates
Given we use the config "brackets.yaml" Given we use the config "brackets.yaml"
When we run "jrnl -1" When we run "jrnl -1"

23
features/upgrade.feature Normal file
View file

@ -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"

View file

@ -84,9 +84,20 @@ class Journal(object):
def write(self, filename=None): def write(self, filename=None):
"""Dumps the journal into the config file, overwriting it""" """Dumps the journal into the config file, overwriting it"""
filename = filename or self.config['journal'] filename = filename or self.config['journal']
text = "\n".join([e.__unicode__() for e in self.entries]) text = self._to_text()
self._store(filename, 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): def _load(self, filename):
raise NotImplementedError raise NotImplementedError

View file

@ -14,6 +14,7 @@ from .Journal import PlainJournal
from .EncryptedJournal import EncryptedJournal from .EncryptedJournal import EncryptedJournal
import yaml import yaml
import logging import logging
import sys
DEFAULT_CONFIG_NAME = 'jrnl.yaml' DEFAULT_CONFIG_NAME = 'jrnl.yaml'
DEFAULT_JOURNAL_NAME = 'journal.txt' DEFAULT_JOURNAL_NAME = 'journal.txt'
@ -85,8 +86,18 @@ def load_or_install_jrnl():
if os.path.exists(config_path): if os.path.exists(config_path):
log.debug('Reading configuration from file %s', config_path) log.debug('Reading configuration from file %s', config_path)
config = util.load_config(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.")
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) upgrade_config(config)
return config return config
else: else:
log.debug('Configuration file not found, installing jrnl...') log.debug('Configuration file not found, installing jrnl...')

View file

@ -44,6 +44,7 @@ older versions of jrnl anymore.
encrypted_journals = {} encrypted_journals = {}
plain_journals = {} plain_journals = {}
other_journals = {} other_journals = {}
all_journals = []
for journal_name, journal_conf in config['journals'].items(): for journal_name, journal_conf in config['journals'].items():
if isinstance(journal_conf, dict): if isinstance(journal_conf, dict):
@ -85,19 +86,33 @@ older versions of jrnl anymore.
util.prompt("\nUpgrading encrypted '{}' journal stored in {}...".format(journal_name, path)) util.prompt("\nUpgrading encrypted '{}' journal stored in {}...".format(journal_name, path))
backup(path, binary=True) backup(path, binary=True)
old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True)
new_journal = EncryptedJournal.from_journal(old_journal) all_journals.append(EncryptedJournal.from_journal(old_journal))
new_journal.write()
util.prompt(" Done.")
for journal_name, path in plain_journals.items(): for journal_name, path in plain_journals.items():
util.prompt("\nUpgrading plain text '{}' journal stored in {}...".format(journal_name, path)) util.prompt("\nUpgrading plain text '{}' journal stored in {}...".format(journal_name, path))
backup(path) backup(path)
old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True) old_journal = Journal.open_journal(journal_name, util.scope_config(config, journal_name), legacy=True)
new_journal = Journal.PlainJournal.from_journal(old_journal) all_journals.append(Journal.PlainJournal.from_journal(old_journal))
new_journal.write()
util.prompt(" Done.") # 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))
)
raise UpgradeValidationException
# write all journals - or - don't
for j in all_journals:
j.write()
util.prompt("\nUpgrading config...") util.prompt("\nUpgrading config...")
backup(config_path) backup(config_path)
util.prompt("\nWe're all done here and you can start enjoying jrnl 2.".format(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