From 7e1b5316aa92d25fb1c6f00f464c36b70f64989f Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:20:57 +0530 Subject: [PATCH 01/11] Add default export folder config Signed-off-by: Aniket Pant --- jrnl/Journal.py | 1 + jrnl/install.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 9cbe41e2..732a491e 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -45,6 +45,7 @@ class Journal(object): 'tagsymbols': '@', 'highlight': True, 'linewrap': 80, + 'folder': os.path.expanduser("~/journal/"), } self.config.update(kwargs) diff --git a/jrnl/install.py b/jrnl/install.py index acb519a9..53b98052 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -32,6 +32,7 @@ default_config = { 'tagsymbols': '@', 'highlight': True, 'linewrap': 80, + 'folder': os.path.expanduser("~/journal/"), } @@ -94,4 +95,7 @@ def install_jrnl(config_path='~/.jrnl_config'): config['password'] = password return config - + # Where to export files? + path_query = 'Path to your journal folder (leave blank for ~/journal): ' + folder_path = raw_input(path_query).strip() or os.path.expanduser('~/journal') + default_config['folder'] = os.path.expanduser(folder_path) From a38d9df4735015f692436b95c4f4384e5bc043ed Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:22:02 +0530 Subject: [PATCH 02/11] Add new export option Support for json and md retained All export types moved to --export except tags Signed-off-by: Aniket Pant --- jrnl/exporters.py | 44 +++++++++++++++++++++++++++++++++++++++++--- jrnl/jrnl.py | 20 +++++++++++++------- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/jrnl/exporters.py b/jrnl/exporters.py index 4a4b0245..bba105a0 100644 --- a/jrnl/exporters.py +++ b/jrnl/exporters.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # encoding: utf-8 +import os +try: from slugify import slugify +except ImportError: import slugify try: import simplejson as json except ImportError: import json @@ -28,16 +31,18 @@ def to_tag_list(journal): result += "\n".join(u"{0:20} : {1}".format(tag, n) for n, tag in sorted(tag_counts, reverse=False)) return result -def to_json(journal): +def to_json(journal, output): """Returns a JSON representation of the Journal.""" tags = get_tags_count(journal) result = { "tags": dict((tag, count) for count, tag in tags), "entries": [e.to_dict() for e in journal.entries] } + if output is not False: + write_file(json.dumps(result, indent=2), output) return json.dumps(result, indent=2) -def to_md(journal): +def to_md(journal, output): """Returns a markdown representation of the Journal""" out = [] year, month = -1, -1 @@ -51,4 +56,37 @@ def to_md(journal): out.append(e.date.strftime("%B")) out.append('-' * len(e.date.strftime("%B")) + "\n") out.append(e.to_md()) - return "\n".join(out) + result = "\n".join(out) + if output is not False: + write_file(result, output) + return result + +def to_txt(journal, output): + """Returns the complete text of the Journal.""" + if output is not False: + write_file(unicode(journal), output) + return unicode(journal) + +def to_files(journal, output): + """Turns your journal into separate files for each entry.""" + if output is False: + output = journal.config['folder'] + "*.txt" # default path + path, extension = os.path.splitext(os.path.expanduser(output)) + head, tail = os.path.split(path) + if tail == '*': # if wildcard is specified + path = head + '/' + if not os.path.exists(path): # if the folder doesn't exist, create it + os.makedirs(path) + for e in journal.entries: + date = e.date.strftime('%Y-%m-%d') + title = slugify(unicode(e.title)) + filename = date + '-' + title + fullpath = path + filename + extension + write_file(unicode(e), fullpath) + return ("Journal exported") + +def write_file(content, path): + """Writes content to the file provided""" + f = open(path, 'w+') + f.write(content) + f.close() diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py index 2af9b60c..f23cc799 100755 --- a/jrnl/jrnl.py +++ b/jrnl/jrnl.py @@ -45,8 +45,8 @@ def parse_args(): exporting = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal') exporting.add_argument('--tags', dest='tags', action="store_true", help='Returns a list of all tags and number of occurences') - exporting.add_argument('--json', dest='json', action="store_true", help='Returns a JSON-encoded version of the Journal') - exporting.add_argument('--markdown', dest='markdown', action="store_true", help='Returns a Markdown-formated version of the Journal') + exporting.add_argument('--export', metavar='TYPE', dest='export', help='Export your journal to Markdown, JSON, Text or multiple files', nargs='?', default=False, const=None) + exporting.add_argument('-o', metavar='OUTPUT', dest='output', help='The output of the file can be provided when using with --export', nargs='?', 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) exporting.add_argument('--decrypt', metavar='FILENAME', dest='decrypt', help='Decrypts your journal and stores it in plain text', nargs='?', default=False, const=None) exporting.add_argument('--delete-last', dest='delete_last', help='Deletes the last entry from your journal file.', action="store_true") @@ -57,7 +57,7 @@ def guess_mode(args, config): """Guesses the mode (compose, read or export) from the given arguments""" compose = True export = False - if args.json or args.decrypt is not False or args.encrypt is not False or args.markdown or args.tags or args.delete_last: + if args.decrypt is not False or args.encrypt is not False or args.export is not False or args.tags or args.delete_last: compose = False export = True elif args.start_date or args.end_date or args.limit or args.strict or args.short: @@ -190,11 +190,17 @@ def cli(): elif args.tags: print(exporters.to_tag_list(journal)) - elif args.json: # export to json - print(exporters.to_json(journal)) + elif args.export == 'json': # export to json + print(exporters.to_json(journal, args.output)) - elif args.markdown: # export to json - print(exporters.to_md(journal)) + elif args.export == 'markdown' or args.export == 'md': # export to markdown + print(exporters.to_md(journal, args.output)) + + elif args.export == 'text' or args.export == 'txt': # export to text + print(exporters.to_txt(journal, args.output)) + + elif args.export == 'files': # export to files + print(exporters.to_files(journal, args.output)) elif (args.encrypt is not False or args.decrypt is not False) and not PYCRYPTO: print("PyCrypto not found. To encrypt or decrypt your journal, install the PyCrypto package from http://www.pycrypto.org.") From 1c5a42d46e51e4a11c8cd6a00cc1d5a046f4f963 Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:22:28 +0530 Subject: [PATCH 03/11] Add slugify to requirements Signed-off-by: Aniket Pant --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index a4a16eb3..7533fb7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ parsedatetime >= 1.1.2 colorama >= 0.2.5 pycrypto >= 2.6 argparse==1.2.1 +slugify==0.0.1 From 3207dd10aa755d9908240545aff5961379768efe Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:23:27 +0530 Subject: [PATCH 04/11] Update readme Information on new export options added Signed-off-by: Aniket Pant --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 903c3618..58c7a7d2 100644 --- a/README.md +++ b/README.md @@ -114,16 +114,59 @@ you'll get a list of all tags you used in your journal, sorted by most frequent. Can do: - jrnl --json + jrnl --export json Why not create a beautiful [timeline](http://timeline.verite.co/) of your journal? ### Markdown export - jrnl --markdown +Use: + + jrnl --export markdown + +or + + jrnl --export md Markdown is a simple markup language that is human readable and can be used to be rendered to other formats (html, pdf). This README for example is formatted in markdown and github makes it look nice. +### Text export + + jrnl --export text + +or + + jrnl --export txt + +Prettyprints your entire journal. + +### Export to multiple files + + jrnl --export files + +This export option allows you to get your entire journal into individual files for each entry. +By default, files are exported as `txt` files. You can specify any extension. + +**Output file** + +You can specify an output file with your export options. It works with `json`, `markdown`, `txt` and `files` option. + +For using it with multiple files, you can use it like this: + + jrnl --export files -o ~/journal/*.txt + +If you wish to output to a directory without specifying a file: + + jrnl --export files -o ~/journal/ + +Other methods to use this option + + jrnl --export json -o jrnl.json + jrnl --export md -o jrnl.md + jrnl --export txt -o jrnl.txt + +These will output the given filename in the current working directory. + Encryption ---------- From b03c8fa039700d31db53a36a25d1bdeadc4a629c Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:23:46 +0530 Subject: [PATCH 05/11] Update version to 1.1.1 Signed-off-by: Aniket Pant --- jrnl/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jrnl/__init__.py b/jrnl/__init__.py index 4c3a2b79..79103a7b 100644 --- a/jrnl/__init__.py +++ b/jrnl/__init__.py @@ -7,7 +7,7 @@ jrnl is a simple journal application for your command line. """ __title__ = 'jrnl' -__version__ = '1.1.0' +__version__ = '1.1.1' __author__ = 'Manuel Ebert' __license__ = 'MIT License' __copyright__ = 'Copyright 2013 Manuel Ebert' From 15a7f21eb186f5a2ff2183cf9a43b380b91564d5 Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Fri, 21 Jun 2013 19:23:54 +0530 Subject: [PATCH 06/11] Update changelog Signed-off-by: Aniket Pant --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4de8d5f..5571d2a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +#### 1.1.1 + +* [New] Export to multiple files +* [New] Feature to export to given output file + #### 1.1.0 * [New] JSON export exports tags as well. From d91165c9465ff1ca725bdb6e37f4bd75c3398c0d Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Wed, 26 Jun 2013 11:20:58 +0530 Subject: [PATCH 07/11] Fix changelog Signed-off-by: Aniket Pant --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a4ca086..1d83cc4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,11 @@ Changelog #### 1.1.1 -<<<<<<< HEAD * [New] Export to multiple files * [New] Feature to export to given output file - -#### 1.1.0 -======= * [Fixed] Unicode and Python3 issues resolved. ### 1.1.0 ->>>>>>> master * [New] JSON export exports tags as well. * [Improved] Nicer error message when there is a syntactical error in your config file. From a93e9fff13f1e5c83faa15338079296e8a8febad Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Wed, 26 Jun 2013 13:04:50 +0530 Subject: [PATCH 08/11] Remove default folder config Signed-off-by: Aniket Pant --- jrnl/Journal.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jrnl/Journal.py b/jrnl/Journal.py index ce5f9634..193d89a6 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -45,7 +45,6 @@ class Journal(object): 'tagsymbols': '@', 'highlight': True, 'linewrap': 80, - 'folder': os.path.expanduser("~/journal/"), } self.config.update(kwargs) From 55fc36a0d2f33c2142a250446b5d5b9db04945f9 Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Wed, 26 Jun 2013 13:05:13 +0530 Subject: [PATCH 09/11] Improve export functionality Signed-off-by: Aniket Pant --- jrnl/exporters.py | 90 ++++++++++++++++++++++++++++++++++++----------- jrnl/jrnl.py | 5 +-- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/jrnl/exporters.py b/jrnl/exporters.py index bba105a0..85efd43b 100644 --- a/jrnl/exporters.py +++ b/jrnl/exporters.py @@ -2,6 +2,7 @@ # encoding: utf-8 import os +import string try: from slugify import slugify except ImportError: import slugify try: import simplejson as json @@ -20,7 +21,7 @@ def get_tags_count(journal): return tag_counts def to_tag_list(journal): - """Prints a list of all tags and the number of occurances.""" + """Prints a list of all tags and the number of occurrences.""" tag_counts = get_tags_count(journal) result = "" if not tag_counts: @@ -39,8 +40,14 @@ def to_json(journal, output): "entries": [e.to_dict() for e in journal.entries] } if output is not False: - write_file(json.dumps(result, indent=2), output) - return json.dumps(result, indent=2) + path = output_path('json', output) + if not is_globable(path): + message = write_file(json.dumps(result, indent=2), path) + else: + message = to_files(journal, path) + return message + else: + return json.dumps(result, indent=2) def to_md(journal, output): """Returns a markdown representation of the Journal""" @@ -58,35 +65,78 @@ def to_md(journal, output): out.append(e.to_md()) result = "\n".join(out) if output is not False: - write_file(result, output) - return result + path = output_path('md', output) + if not is_globable(path): + message = write_file(result, path) + else: + message = to_files(journal, path) + return message + else: + return result def to_txt(journal, output): """Returns the complete text of the Journal.""" if output is not False: - write_file(unicode(journal), output) - return unicode(journal) + path = output_path('txt', output) + if not is_globable(path): + message = write_file(unicode(journal), path) + else: + message = to_files(journal, path) + return message + else: + return unicode(journal) def to_files(journal, output): """Turns your journal into separate files for each entry.""" - if output is False: - output = journal.config['folder'] + "*.txt" # default path + path, extension = os.path.splitext(os.path.expanduser(output)) + + for e in journal.entries: + content = "" + date = e.date.strftime('%C-%m-%d') + title = slugify(unicode(e.title)) + + filename = string.replace(path, "%C-%m-%d", date) + filename = string.replace(filename, "slug", title) + + fullpath = filename + extension + + if extension == '.json': + content = json.dumps(e.to_dict(), indent=2) + elif extension == '.md': + content = e.to_md() + elif extension == '.txt': + content = unicode(e) + write_file(content, fullpath) + + return ("Journal exported.") + +def is_globable(output): path, extension = os.path.splitext(os.path.expanduser(output)) head, tail = os.path.split(path) - if tail == '*': # if wildcard is specified - path = head + '/' - if not os.path.exists(path): # if the folder doesn't exist, create it - os.makedirs(path) - for e in journal.entries: - date = e.date.strftime('%Y-%m-%d') - title = slugify(unicode(e.title)) - filename = date + '-' + title - fullpath = path + filename + extension - write_file(unicode(e), fullpath) - return ("Journal exported") + + if tail == "%C-%m-%d_slug": + return True + else: + return False + +def output_path(file_ext, output): + path, extension = os.path.splitext(os.path.expanduser(output)) + + head, tail = os.path.split(path) + if head != '': + if not os.path.exists(head): # if the folder doesn't exist, create it + os.makedirs(head) + fullpath = head + '/' + tail + '.' + file_ext + else: + fullpath = tail + '.' + file_ext + + return fullpath def write_file(content, path): """Writes content to the file provided""" + f = open(path, 'w+') f.write(content) f.close() + + return ("File exported to " + path) diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py index f23cc799..eafc05e4 100755 --- a/jrnl/jrnl.py +++ b/jrnl/jrnl.py @@ -45,7 +45,7 @@ def parse_args(): exporting = parser.add_argument_group('Export / Import', 'Options for transmogrifying your journal') exporting.add_argument('--tags', dest='tags', action="store_true", help='Returns a list of all tags and number of occurences') - exporting.add_argument('--export', metavar='TYPE', dest='export', help='Export your journal to Markdown, JSON, Text or multiple files', nargs='?', default=False, const=None) + exporting.add_argument('--export', metavar='TYPE', dest='export', help='Export your journal to Markdown, JSON or Text', nargs='?', default=False, const=None) exporting.add_argument('-o', metavar='OUTPUT', dest='output', help='The output of the file can be provided when using with --export', nargs='?', 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) exporting.add_argument('--decrypt', metavar='FILENAME', dest='decrypt', help='Decrypts your journal and stores it in plain text', nargs='?', default=False, const=None) @@ -199,9 +199,6 @@ def cli(): elif args.export == 'text' or args.export == 'txt': # export to text print(exporters.to_txt(journal, args.output)) - elif args.export == 'files': # export to files - print(exporters.to_files(journal, args.output)) - elif (args.encrypt is not False or args.decrypt is not False) and not PYCRYPTO: print("PyCrypto not found. To encrypt or decrypt your journal, install the PyCrypto package from http://www.pycrypto.org.") From ae010721974b23a27238af6df431fb87474db844 Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Wed, 26 Jun 2013 13:05:24 +0530 Subject: [PATCH 10/11] Update readme in accordance to changes Signed-off-by: Aniket Pant --- README.md | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 58c7a7d2..3d6492cf 100644 --- a/README.md +++ b/README.md @@ -140,32 +140,17 @@ or Prettyprints your entire journal. -### Export to multiple files +### Export to files - jrnl --export files + jrnl --export md -o journal -This export option allows you to get your entire journal into individual files for each entry. -By default, files are exported as `txt` files. You can specify any extension. +The above command will generate a file named `journal.md`. The extension will be generated on the type of export option. This way a json export will generate a `.json` file and a plain text export will generate a `.txt` file. -**Output file** +In case you wish to export to multiple files, you can use a glob-able filename. -You can specify an output file with your export options. It works with `json`, `markdown`, `txt` and `files` option. + jrnl --export markdown -o %C-%m-%d_slug -For using it with multiple files, you can use it like this: - - jrnl --export files -o ~/journal/*.txt - -If you wish to output to a directory without specifying a file: - - jrnl --export files -o ~/journal/ - -Other methods to use this option - - jrnl --export json -o jrnl.json - jrnl --export md -o jrnl.md - jrnl --export txt -o jrnl.txt - -These will output the given filename in the current working directory. +It also works with `json` and `text` export types. Encryption ---------- From d4a97f873c681f99cbfb1ee57535fe87ec1afdc2 Mon Sep 17 00:00:00 2001 From: Aniket Pant Date: Wed, 26 Jun 2013 13:08:29 +0530 Subject: [PATCH 11/11] Update installation after removal of default folder config Signed-off-by: Aniket Pant --- jrnl/install.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/jrnl/install.py b/jrnl/install.py index 53b98052..2037e8aa 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -32,7 +32,6 @@ default_config = { 'tagsymbols': '@', 'highlight': True, 'linewrap': 80, - 'folder': os.path.expanduser("~/journal/"), } @@ -94,8 +93,3 @@ def install_jrnl(config_path='~/.jrnl_config'): if password: config['password'] = password return config - - # Where to export files? - path_query = 'Path to your journal folder (leave blank for ~/journal): ' - folder_path = raw_input(path_query).strip() or os.path.expanduser('~/journal') - default_config['folder'] = os.path.expanduser(folder_path)