#!/usr/bin/python # Copyright 2010 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 . import optparse import os import re import subprocess import sys import tempfile import time import traceback template = '''\ [[!meta title="%(title)s"]] [[!tag ]] [[!meta date="%(date)s"]] ''' class AppException(Exception): pass class App(object): def __init__(self): pass def parse_args(self): p = optparse.OptionParser() p.add_option('--base', default=os.path.expanduser('~/Journal')) return p.parse_args() def main(self): commands = { 'new': self.new_entry, 'list': self.list_entries, 'edit': self.edit_entry, 'remove': self.remove_entry, 'finish': self.finish_entry, } opts, args = self.parse_args() if args and args[0] in commands: commands[args[0]](args[1:], opts) else: raise AppException('Usage: journal-note [options] cmd args...') def drafts(self, opts): return os.path.join(opts.base, 'drafts') def draftname(self, opts, draft_id): return os.path.join(opts.base, 'drafts', '%s.mdwn' % draft_id) def gedit_file(self, pathname): subprocess.check_call(['gedit', '--new-window', pathname]) def new_entry(self, args, opts): if not args: raise AppException('Usage: journal-note new TITLE') for i in range(1000): name = self.draftname(opts, i) if not os.path.exists(name): break else: raise AppException('ERROR: too many existing drafts') values = { 'title': args[0], 'date': time.strftime('%Y-%m-%d %H:%M') } f = open(name, 'w') f.write(template % values) f.close() self.gedit_file(name) def list_entries(self, args, opts): drafts = self.drafts(opts) for name in os.listdir(drafts): if name.endswith('.mdwn'): f = open(os.path.join(drafts, name)) for line in f: m = re.match('\[\[!meta title="(?P.*)("\]\])$', line) if m: title = m.group('title') break else: title = 'unknown title' f.close() print name[:-len('.mdwn')], title def edit_entry(self, args, opts): if not args: raise AppException('Usage: journal-note edit ID') pathname = self.draftname(opts, args[0]) if not os.path.exists(pathname): raise AppException('draft %s does not exist' % args[0]) self.gedit_file(pathname) def remove_entry(self, args, opts): if not args: raise AppException('Usage: journal-note remove ID') pathname = self.draftname(opts, args[0]) os.remove(pathname) def finish_entry(self, args, opts): if not args: raise AppException('Usage: journal-note finish ID') draft = self.draftname(opts, args[0]) if not os.path.exists(draft): raise AppException('draft %s does not exist' % args[0]) basename = time.strftime('%Y-%m-%d-%H:%M.mdwn') i = 0 while True: finished = os.path.join(opts.base, 'src', 'notes', basename) if not os.path.exists(finished): break i += 1 basename = '%s-%d.mdwn' % (time.strftime('%Y-%m-%d-%H:%M:%S-'), i) os.rename(draft, finished) src = os.path.join(opts.base, 'src') subprocess.check_call(['bzr', 'add', finished], cwd=src) subprocess.check_call(['bzr', 'commit', '-m', 'new note'], cwd=src) subprocess.check_call(['ikiwiki', '--setup', '../ikiwiki.setup', '--refresh'], cwd=src) if __name__ == '__main__': try: App().main() except KeyboardInterrupt: sys.exit(1) except AppException, e: sys.stderr.write('%s\n' % str(e)) sys.exit(1) except SystemExit, e: sys.exit(e.code) except BaseException, e: sys.stderr.write(traceback.format_exc(e)) sys.exit(1)