From 1080298930b3b718d89f0285fbd22d30fdece8a6 Mon Sep 17 00:00:00 2001 From: timetoplatypus Date: Sat, 26 Aug 2017 20:15:04 -0400 Subject: [PATCH] Adds import feature for JSON formatted journals. --- jrnl/cli.py | 9 +++++++-- jrnl/importers.py | 21 +++++++++++++++++++++ jrnl/util.py | 28 +++++++++++++--------------- 3 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 jrnl/importers.py diff --git a/jrnl/cli.py b/jrnl/cli.py index 35764734..fb067aa3 100644 --- a/jrnl/cli.py +++ b/jrnl/cli.py @@ -11,6 +11,7 @@ from __future__ import absolute_import, unicode_literals from . import Journal from . import DayOneJournal from . import util +from . import importers from . import exporters from . import install import jrnl @@ -45,6 +46,7 @@ def parse_args(args=None): exporting = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal') exporting.add_argument('--short', dest='short', action="store_true", help='Show only titles or line containing the search tags') exporting.add_argument('--tags', dest='tags', action="store_true", help='Returns a list of all tags and number of occurences') + exporting.add_argument('--import-json', metavar='FILEPATH', dest='import_json', help='Import a journal from a JSON file.', default=False, const=None) exporting.add_argument('--export', metavar='TYPE', dest='export', choices=['text', 'txt', 'markdown', 'md', 'json'], help='Export your journal. TYPE can be json, markdown, or text.', default=False, const=None) exporting.add_argument('-o', metavar='OUTPUT', dest='output', help='Optionally specifies output file when using --export. If OUTPUT is a directory, exports each entry into an individual file instead.', default=False, const=None) exporting.add_argument('--encrypt', metavar='FILENAME', dest='encrypt', help='Encrypts your existing journal with a new password', nargs='?', default=False, const=None) @@ -58,7 +60,7 @@ def guess_mode(args, config): """Guesses the mode (compose, read or export) from the given arguments""" compose = True export = False - if args.decrypt is not False or args.encrypt is not False or args.export is not False or any((args.short, args.tags, args.edit)): + if args.decrypt is not False or args.encrypt is not False or args.import_json is not False or args.export is not False or any((args.short, args.tags, args.edit)): compose = False export = True elif any((args.start_date, args.end_date, args.on_date, args.limit, args.strict, args.starred)): @@ -138,7 +140,7 @@ def run(manual_args=None): config = install.install_jrnl(CONFIG_PATH) else: log.debug('Reading configuration from file %s', CONFIG_PATH) - config = util.load_and_fix_json(CONFIG_PATH) + config = util.load_and_fix_json(CONFIG_PATH, "configuration") install.upgrade_config(config, config_path=CONFIG_PATH) if args.ls: @@ -247,6 +249,9 @@ def run(manual_args=None): elif args.tags: print(util.py2encode(exporters.to_tag_list(journal))) + elif args.import_json is not False: + importers.import_json(args.import_json, config) + elif args.export is not False: print(util.py2encode(exporters.export(journal, args.export, args.output))) diff --git a/jrnl/importers.py b/jrnl/importers.py new file mode 100644 index 00000000..e522d0f5 --- /dev/null +++ b/jrnl/importers.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +import os +import json +import sys +from . import util + +def import_json(path, jrnl_config): + json_data = util.load_and_fix_json(path, "JSON") + + new_jrnl = open(jrnl_config["journal"], "w") + for element in json_data["entries"]: + new_jrnl.write( + element["date"] + + " " + + element["time"] + + " " + + element["title"] + + "\n" + + element["body"] + ) + new_jrnl.close() diff --git a/jrnl/util.py b/jrnl/util.py index e9df0fb1..6653d9a2 100644 --- a/jrnl/util.py +++ b/jrnl/util.py @@ -93,36 +93,34 @@ def yesno(prompt, default=True): raw = py23_input(prompt) return {'y': True, 'n': False}.get(raw.lower(), default) -def load_and_fix_json(json_path): +def load_and_fix_json(json_path, target_file): """Tries to load a json object from a file. If that fails, tries to fix common errors (no or extra , at end of the line). """ with open(json_path) as f: json_str = f.read() - log.debug('Configuration file %s read correctly', json_path) - config = None + log.debug('%s file %s read correctly', target_file, json_path) + data = None try: return json.loads(json_str) except ValueError as e: - log.debug('Could not parse configuration %s: %s', json_str, e, - exc_info=True) + log.debug('Could not parse %s %s: %s', target_file, json_str, e, exc_info=True) # Attempt to fix extra , json_str = re.sub(r",[ \n]*}", "}", json_str) # Attempt to fix missing , json_str = re.sub(r"([^{,]) *\n *(\")", r"\1,\n \2", json_str) try: - log.debug('Attempting to reload automatically fixed configuration file %s', - json_str) - config = json.loads(json_str) + log.debug('Attempting to reload automatically fixed %s file %s', target_file, json_str) + data = json.loads(json_str) with open(json_path, 'w') as f: - json.dump(config, f, indent=2) - log.debug('Fixed configuration saved in file %s', json_path) - prompt("[Some errors in your jrnl config have been fixed for you.]") - return config + json.dump(data, f, indent=2) + log.debug('Fixed %s saved in file %s', target_file, json_path) + prompt("[Some errors in your {0} file have been fixed for you.]".format(target_file)) + return data except ValueError as e: - log.debug('Could not load fixed configuration: %s', e, exc_info=True) - prompt("[There seems to be something wrong with your jrnl config at {0}: {1}]".format(json_path, e.message)) - prompt("[Entry was NOT added to your journal]") + log.debug('Could not load fixed %s: %s', target_file, e, exc_info=True) + prompt("[There seems to be something wrong with your {0} file at {1}: {2}]".format(target_file, json_path, e.message)) + prompt("[Journal was NOT modified]") sys.exit(1) def get_text_from_editor(config, template=""):