#!/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 shutil
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,
'attach': self.attach_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 find_drafts(self, opts):
drafts = self.drafts(opts)
for name in os.listdir(drafts):
if name.endswith('.mdwn'):
yield name[:-len('.mdwn')], name
def list_entries(self, args, opts):
for draft_id, name in self.find_drafts(opts):
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 draft_id, title
def choose_entry(self, args, opts):
if len(args) == 0:
drafts = list(self.find_drafts(opts))
if len(drafts) == 1:
draft_id, filename = drafts[0]
return draft_id
else:
raise AppException('Cannot choose entry automatically')
elif len(args) == 1:
return args[0]
elif len(args) > 1:
raise AppException('Must give only one entry')
def edit_entry(self, args, opts):
draft_id = self.choose_entry(args, opts)
pathname = self.draftname(opts, draft_id)
if not os.path.exists(pathname):
raise AppException('draft %s does not exist' % args[0])
self.gedit_file(pathname)
def attach_entry(self, args, opts):
if len(args) < 2:
raise AppException('Usage: journal-note attach ID file...')
pathname = self.draftname(opts, args[0])
if not os.path.exists(pathname):
raise AppException('draft %s does not exist' % args[0])
dirname, ext = os.path.splitext(pathname)
if not os.path.exists(dirname):
os.mkdir(dirname)
for filename in args[1:]:
shutil.copy(filename, dirname)
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):
draft_id = self.choose_entry(args, opts)
draft = self.draftname(opts, draft_id)
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)
draft_dir, ext = os.path.splitext(draft)
finished_dir, ext = os.path.splitext(finished)
if os.path.exists(draft_dir):
if os.path.exists(finished_dir):
raise obnamlib.AppException('%s already exists' %
finished_dir)
os.rename(draft_dir, finished_dir)
src = os.path.join(opts.base, 'src')
argv = ['bzr', 'add', finished]
if os.path.exists(finished_dir):
argv.append(finished_dir)
subprocess.check_call(argv, 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)