diff options
author | Lars Wirzenius <liw@liw.fi> | 2015-10-03 09:48:00 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2015-10-03 10:24:46 +0300 |
commit | e8d1f422888d1ea4d703b446cf732331d0fff116 (patch) | |
tree | 88b50a1016d5f0836fcfd32ce1cea0a2674e60fa /jtlib | |
parent | b3855d34fcd7ac7b2819d04a400f841d3091790a (diff) | |
download | jt-e8d1f422888d1ea4d703b446cf732331d0fff116.tar.gz |
Move app class to jtlib, commands to plugins
Diffstat (limited to 'jtlib')
-rw-r--r-- | jtlib/__init__.py | 1 | ||||
-rw-r--r-- | jtlib/app.py | 95 | ||||
-rw-r--r-- | jtlib/plugins/attach_plugin.py | 43 | ||||
-rw-r--r-- | jtlib/plugins/edit_plugin.py | 38 | ||||
-rw-r--r-- | jtlib/plugins/finish_plugin.py | 87 | ||||
-rw-r--r-- | jtlib/plugins/list_plugin.py | 36 | ||||
-rw-r--r-- | jtlib/plugins/new_person_plugin.py | 70 | ||||
-rw-r--r-- | jtlib/plugins/new_plugin.py | 82 | ||||
-rw-r--r-- | jtlib/plugins/new_topic_plugin.py | 61 | ||||
-rw-r--r-- | jtlib/plugins/remove_plugin.py | 37 |
10 files changed, 550 insertions, 0 deletions
diff --git a/jtlib/__init__.py b/jtlib/__init__.py index 972c289..959f715 100644 --- a/jtlib/__init__.py +++ b/jtlib/__init__.py @@ -19,5 +19,6 @@ from .version import __version__ from .draftsdir import DraftsDirectory from .git import commit_to_git, push_git +from .app import JournalTool __all__ = locals() diff --git a/jtlib/app.py b/jtlib/app.py new file mode 100644 index 0000000..a560c26 --- /dev/null +++ b/jtlib/app.py @@ -0,0 +1,95 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import time + +import jtlib + + +class JournalTool(cliapp.Application): + + def add_settings(self): + self.settings.string( + ['source'], + 'use journal source tree in DIR', + metavar='DIR') + + self.settings.boolean( + ['git'], + 'add entries to git automatically', + default=True) + + self.settings.string( + ['editor'], + 'editor to launch for journal entries. Must include %s to ' + 'indicate where the filename goes', + default='sensible-editor %s') + + self.settings.boolean( + ['push'], + 'push finished articles with git?') + + self.settings.string( + ['topic'], + 'new entry belongs to TOPIC', + metavar='TOPIC') + + self.settings.string( + ['new-note-template'], + 'use FILE as the template for new journal notes', + metavar='FILE') + + self.settings.string( + ['pretend-time'], + 'pretend that the time is NOW (form: YYYY-MM-DD HH:MM:DD form)', + metavar='NOW') + + def process_args(self, args): + if self.settings['pretend-time']: + self.now_tuple = time.strptime( + self.settings['pretend-time'], '%Y-%m-%d %H:%M:%S') + else: + self.now_tuple = time.localtime() + cliapp.Application.process_args(self, args) + + def drafts_dir(self): + return os.path.join(self.settings['source'], 'drafts') + + def edit_file(self, pathname): + safe_pathname = cliapp.shell_quote(pathname) + cmdline = ['sh', '-c', self.settings['editor'] % safe_pathname] + self.runcmd(cmdline, stdin=None, stdout=None, stderr=None) + + def choose_draft(self, drafts_dir, args): + if len(args) == 0: + drafts = list(drafts_dir.get_drafts()) + if len(drafts) == 1: + draft_id, filename = drafts[0] + return draft_id, filename + elif len(drafts) == 0: + raise cliapp.AppException('No drafts to choose from') + else: + raise cliapp.AppException( + 'Cannot choose entry draft automatically') + elif len(args) == 1: + pathname = drafts_dir.get_draft_pathname(args[0]) + if not os.path.exists(pathname): + raise cliapp.AppException('draft %s does not exist' % args[0]) + return args[0], pathname + elif len(args) > 1: + raise cliapp.AppException('Must give at most one draft number') diff --git a/jtlib/plugins/attach_plugin.py b/jtlib/plugins/attach_plugin.py new file mode 100644 index 0000000..1644c1d --- /dev/null +++ b/jtlib/plugins/attach_plugin.py @@ -0,0 +1,43 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class AttachCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand( + 'attach', self.run, arg_synopsis='DRAFT-ID [FILE]...') + + def run(self, args): + '''Attach files to a journal entry draft.''' + + if len(args) < 2: + raise cliapp.AppException('Usage: journal-note attach ID file...') + + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + dirname = drafts_dir.get_draft_attachments_dirname(args[0]) + if not os.path.exists(dirname): + os.mkdir(dirname) + for filename in args[1:]: + shutil.copy(filename, dirname) diff --git a/jtlib/plugins/edit_plugin.py b/jtlib/plugins/edit_plugin.py new file mode 100644 index 0000000..3371939 --- /dev/null +++ b/jtlib/plugins/edit_plugin.py @@ -0,0 +1,38 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class EditCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('edit', self.run, arg_synopsis='[DRAFT-ID]') + + def run(self, args): + '''Edit a draft journal entry.''' + + if len(args) > 1: + raise cliapp.AppException('Must be given at most one draft ID') + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + _, pathname = self.app.choose_draft(drafts_dir, args) + self.app.edit_file(pathname) diff --git a/jtlib/plugins/finish_plugin.py b/jtlib/plugins/finish_plugin.py new file mode 100644 index 0000000..b443a9f --- /dev/null +++ b/jtlib/plugins/finish_plugin.py @@ -0,0 +1,87 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class FinishCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('finish', self.run, arg_synopsis='[DRAFT-ID]') + + def run(self, args): + '''Publish a draft journal entry.''' + + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + + draft_id, draft_mdwn = self.app.choose_draft(drafts_dir, args) + draft_attch = drafts_dir.get_draft_attachments_dirname(draft_id) + + title = drafts_dir.get_draft_title(draft_id) + if not title: + raise Exception("%s has no title" % draft_mdwn) + + pub_attch = os.path.join( + self._published_dir(), + self._summarise_title(title)) + pub_mdwn = pub_attch + '.mdwn' + + if os.path.exists(pub_mdwn): + raise cliapp.AppException('%s already exists' % pub_mdwn) + + self._publish_draft(draft_mdwn, draft_attch, pub_mdwn, pub_attch) + + if self.app.settings['git']: + if os.path.exists(pub_attch): + self._commit_to_git([pub_mdwn, pub_attch]) + else: + self._commit_to_git([pub_mdwn]) + if self.app.settings['push']: + self._push_git() + + def _published_dir(self): + subdir = time.strftime('notes/%Y/%m/%d', self.app.now_tuple) + return os.path.join(self.app.settings['source'], subdir) + + def _summarise_title(self, title): + basename = '' + acceptable = set(string.ascii_letters + string.digits + '-_') + for c in title.lower(): + if c in acceptable: + basename += c + elif not basename.endswith('_'): + basename += '_' + return basename + + def _publish_draft(self, draft_mdwn, draft_attch, pub_mdwn, pub_attch): + parent_dir = os.path.dirname(pub_mdwn) + if not os.path.exists(parent_dir): + os.makedirs(parent_dir) + os.rename(draft_mdwn, pub_mdwn) + if os.path.exists(draft_attch): + os.rename(draft_attch, pub_attch) + + def _commit_to_git(self, pathnames): + jtlib.commit_to_git(self.app.settings['source'], pathnames) + + def _push_git(self): + jtlib.push_git(self.app.settings['source']) diff --git a/jtlib/plugins/list_plugin.py b/jtlib/plugins/list_plugin.py new file mode 100644 index 0000000..3de83d9 --- /dev/null +++ b/jtlib/plugins/list_plugin.py @@ -0,0 +1,36 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class ListCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('list', self.run, arg_synopsis='') + + def run(self, args): + '''List journal entry drafts.''' + + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + for draft_id, _ in drafts_dir.get_drafts(): + print draft_id, drafts_dir.get_draft_title(draft_id) diff --git a/jtlib/plugins/new_person_plugin.py b/jtlib/plugins/new_person_plugin.py new file mode 100644 index 0000000..43db172 --- /dev/null +++ b/jtlib/plugins/new_person_plugin.py @@ -0,0 +1,70 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class NewPersonCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('new-person', self.run) + + def run(self, args): + '''Create a page to list all notes referring to a person. + + This is probably only useful to Lars's personal journal. + + ''' + + if len(args) != 1: + raise cliapp.AppException( + 'Need the name of a person (in Last, First form)') + + def normalise(name): + s = name.lower() + s = ' '.join(s.split(',')) + s = '.'.join(s.split()) + return s + + name = args[0] + basename = normalise(name) + pathname = os.path.join( + self.app.settings['source'], 'people', basename + '.mdwn') + + if os.path.exists(pathname): + raise cliapp.AppException('File %s already exists' % pathname) + + template = '''\ +[[!meta title="%(name)s"]] + +[[!inline archive=yes pages="link(.)"]] +''' + + with open(pathname, 'w') as f: + f.write( + template % + { + 'name': name, + 'basename': basename, + }) + + diff --git a/jtlib/plugins/new_plugin.py b/jtlib/plugins/new_plugin.py new file mode 100644 index 0000000..b10b4a1 --- /dev/null +++ b/jtlib/plugins/new_plugin.py @@ -0,0 +1,82 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class NewCommand(cliapp.Plugin): + + _default_new_note_template = '''\ +[[!meta title="%(title)s"]] +[[!tag ]] +[[!meta date="%(date)s"]] +%(topiclink)s + +''' + + def enable(self): + self.app.add_subcommand('new', self.run, arg_synopsis='TITLE') + + def run(self, args): + '''Create a new journal entry draft.''' + + self._check_args_and_settings(args) + + topic = self.app.settings['topic'] + values = { + 'title': args[0], + 'date': time.strftime('%Y-%m-%d %H:%M', self.app.now_tuple), + 'topiclink': self._get_topic_link(topic), + } + + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + drafts_dir.create_if_missing() + draft_id = drafts_dir.create_draft( + self._get_new_note_template() % values) + self.app.edit_file(drafts_dir.get_draft_pathname(draft_id)) + + def _check_args_and_settings(self, args): + if not args: + raise cliapp.AppException('Usage: journal-note new TITLE') + + self.app.settings.require('source') + topic = self.app.settings['topic'] + if topic and not self._topic_page_exists(topic): + raise cliapp.AppException('Topic %s does not exist yet' % topic) + + def _topic_page_exists(self, topic): + pathname = os.path.join(self.app.settings['source'], topic + '.mdwn') + return os.path.exists(pathname) + + def _get_topic_link(self, topic): + if topic: + return '[[!meta link="%s"]]' % topic + else: + return '' + + def _get_new_note_template(self): + filename = self.app.settings['new-note-template'] + if filename: + with open(filename) as f: + return f.read() + else: + return self._default_new_note_template diff --git a/jtlib/plugins/new_topic_plugin.py b/jtlib/plugins/new_topic_plugin.py new file mode 100644 index 0000000..09fcbd5 --- /dev/null +++ b/jtlib/plugins/new_topic_plugin.py @@ -0,0 +1,61 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class NewTopicCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('new-topic', self.run) + + def run(self, args): + '''Create a new topic page.''' + + if len(args) != 2: + raise cliapp.AppException( + 'Must be given two args (page path, title) (%r)' % args) + + pathname = self._topic_pathname(args[0]) + self._create_topic_page(pathname, args[1]) + jtlib.commit_to_git(self.app.settings['source'], [pathname]) + if self.app.settings['push']: + jtlib.push_git(self.app.settings['source']) + + def _topic_pathname(self, page_path): + return os.path.join(self.app.settings['source'], page_path + '.mdwn') + + def _create_topic_page(self, pathname, title): + dirname = os.path.dirname(pathname) + if not os.path.exists(dirname): + os.makedirs(dirname) + + template = '''\ +[[!meta title="%(title)s"]] + + + +[[!inline pages="link(.)" archive=yes reverse=yes trail=yes]] +''' + + with open(pathname, 'w') as f: + f.write(template % {'title': title}) diff --git a/jtlib/plugins/remove_plugin.py b/jtlib/plugins/remove_plugin.py new file mode 100644 index 0000000..9c84e9e --- /dev/null +++ b/jtlib/plugins/remove_plugin.py @@ -0,0 +1,37 @@ +# Copyright 2010-2015 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import cliapp +import os +import shutil +import string +import time + +import jtlib + + +class RemoveCommand(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand('remove', self.run, arg_synopsis='DRAFT-ID') + + def run(self, args): + '''Remove a draft.''' + + if not args: + raise cliapp.AppException('Usage: journal-note remove ID') + drafts_dir = jtlib.DraftsDirectory(self.app.drafts_dir()) + drafts_dir.remove_draft(args[0]) |