diff --git a/features/data/journals/empty_folder/empty.txt b/features/data/journals/empty_folder/empty similarity index 100% rename from features/data/journals/empty_folder/empty.txt rename to features/data/journals/empty_folder/empty diff --git a/features/folder.feature b/features/folder.feature new file mode 100644 index 00000000..b747e6c1 --- /dev/null +++ b/features/folder.feature @@ -0,0 +1,43 @@ +Feature: Testing a journal with a root directory and multiple files in the format of yyyy/mm/dd.txt + + Scenario: Opening an folder that's not a DayOne folder should treat as folder journal + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 july 2013: Testing folder journal." + Then we should see the message "Entry added" + When we run "jrnl -1" + Then the output should be + """ + 2013-07-23 09:00 Testing folder journal. + """ + + Scenario: Adding entries to a Folder journal should generate date files + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 July 2013: Testing folder journal." + Then we should see the message "Entry added" + When the journal directory is listed + Then the output should contain "2013/07/23.txt" + + + Scenario: Adding multiple entries to a Folder journal should generate multiple date files + Given we use the config "empty_folder.yaml" + When we run "jrnl 23 July 2013: Testing folder journal." + And we run "jrnl 3/7/2014: Second entry of journal." + Then we should see the message "Entry added" + When the journal directory is listed + Then the output should contain "2013/07/23.txt" + And the output should contain "2014/03/07.txt" + + + Scenario: Out of order entries to a Folder journal should be listed in date order + Given we use the config "empty_folder.yaml" + When we run "jrnl 3/7/2014 4:37pm: Second entry of journal." + Then we should see the message "Entry added" + When we run "jrnl 23 July 2013: Testing folder journal." + Then we should see the message "Entry added" + When we run "jrnl -2" + Then the output should be + """ + 2013-07-23 09:00 Testing folder journal. + + 2014-03-07 16:37 Second entry of journal. + """ diff --git a/features/steps/core.py b/features/steps/core.py index 83981d13..4387fb39 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -254,6 +254,15 @@ def check_journal_entries(context, number, journal_name="default"): journal = open_journal(journal_name) assert len(journal.entries) == number +@when('the journal directory is listed') +def list_journal_directory(context, journal="default"): + files=[] + with open(install.CONFIG_FILE_PATH) as config_file: + config = yaml.load(config_file, Loader=yaml.FullLoader) + journal_path = config['journals'][journal] + for root, dirnames, f in os.walk(journal_path): + for file in f: + print(os.path.join(root,file)) @then('fail') def debug_fail(context): diff --git a/jrnl/FolderJournal.py b/jrnl/FolderJournal.py new file mode 100644 index 00000000..4ca55335 --- /dev/null +++ b/jrnl/FolderJournal.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from __future__ import absolute_import, unicode_literals +from . import Entry +from . import Journal +import codecs +import os +import fnmatch + +def get_files(journal_config): + """Searches through sub directories starting with journal_config and find all text files""" + filenames = [] + for root, dirnames, f in os.walk(journal_config): + for filename in fnmatch.filter(f, '*.txt'): + filenames.append(os.path.join(root, filename)) + return filenames + + +class Folder(Journal.Journal): + """A Journal handling multiple files in a folder""" + + def __init__(self, **kwargs): + self.entries = [] + self._diff_entry_dates = [] + super(Folder, self).__init__(**kwargs) + + + def open(self): + filenames = [] + self.entries = [] + filenames = get_files(self.config['journal']) + for filename in filenames: + with codecs.open(filename, "r", "utf-8") as f: + journal = f.read() + self.entries.extend(self._parse(journal)) + self.sort() + return self + + def write(self): + """Writes only the entries that have been modified into proper files.""" + #Create a list of dates of modified entries. Start with diff_entry_dates + modified_dates = self._diff_entry_dates + seen_dates = set(self._diff_entry_dates) + for e in self.entries: + if e.modified: + if e.date not in seen_dates: + modified_dates.append(e.date) + seen_dates.add(e.date) + + #For every date that had a modified entry, write to a file + for d in modified_dates: + write_entries=[] + filename = os.path.join(self.config['journal'], d.strftime("%Y"), d.strftime("%m"), d.strftime("%d")+".txt") + dirname = os.path.dirname(filename) + #create directory if it doesn't exist + if not os.path.exists(dirname): + os.makedirs(dirname) + for e in self.entries: + if e.date.year == d.year and e.date.month == d.month and e.date.day == d.day: + write_entries.append(e) + journal = "\n".join([e.__unicode__() for e in write_entries]) + with codecs.open(filename, 'w', "utf-8") as journal_file: + journal_file.write(journal) + #look for and delete empty files + filenames = [] + filenames = get_files(self.config['journal']) + for filename in filenames: + if os.stat(filename).st_size <= 0: + #print("empty file: {}".format(filename)) + os.remove(filename) + + def parse_editable_str(self, edited): + """Parses the output of self.editable_str and updates it's entries.""" + mod_entries = self._parse(edited) + diff_entries = set(self.entries) - set(mod_entries) + for e in diff_entries: + self._diff_entry_dates.append(e.date) + # Match those entries that can be found in self.entries and set + # these to modified, so we can get a count of how many entries got + # modified and how many got deleted later. + for entry in mod_entries: + entry.modified = not any(entry == old_entry for old_entry in self.entries) + self.entries = mod_entries diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 72fe94b1..dd1bd370 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -347,11 +347,8 @@ def open_journal(name, config, legacy=False): from . import DayOneJournal return DayOneJournal.DayOne(**config).open() else: - util.prompt( - u"[Error: {0} is a directory, but doesn't seem to be a DayOne journal either.".format(config['journal']) - ) - - sys.exit(1) + from . import FolderJournal + return FolderJournal.Folder(**config).open() if not config['encrypt']: if legacy: