feedwarrior

Slim, portable tooling for creating and distributing decentralized append logs
git clone git://git.defalsify.org/logwarrior.git
Log | Files | Refs | README | LICENSE

commit 3375325620af7d5c30dfb0f44eb83966c5038995
parent 798fdbd5e8a4be6a6d940cb53c7fc5cca9edb43d
Author: nolash <dev@holbrook.no>
Date:   Fri, 28 Aug 2020 00:19:07 +0200

Add add subcmd for adding directly with editor

Diffstat:
MCHANGELOG | 2++
AROADMAP | 3+++
Afeedwarrior/cmd/add.py | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfeedwarrior/cmd/show.py | 16++++++++++------
Mfeedwarrior/entry.py | 5+++++
Mfeedwarrior/feed.py | 2+-
Mscripts/feedwarrior | 30+++++++++++++++++++++---------
Msetup.py | 6++++--
8 files changed, 127 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,5 @@ +* 0.4.1 + - Add list feeds subcommand * 0.4.0 - Consolidate put and get methods on same adapter interface - Resolve uncompressed path bug diff --git a/ROADMAP b/ROADMAP @@ -0,0 +1,3 @@ +- Add attachments to add command +- Auto-resolve taskwarrior task numbers to uuids and add to X header +- Sign entries with PGP diff --git a/feedwarrior/cmd/add.py b/feedwarrior/cmd/add.py @@ -0,0 +1,81 @@ +# standard imports +import os +from email.message import EmailMessage +from email.mime.multipart import MIMEMultipart +import email +import logging +import uuid +import json +import gzip +import tempfile +import base64 + +# local imports +import feedwarrior +from feedwarrior import entry as feedentry +from feedwarrior.adapters import fileadapter + +logg = logging.getLogger() + + +def get_editor(): + return 'vim' + +def parse_args(argparser): + argparser.add_argument('-z', action='store_true', help='compress entry with gzip') + argparser.add_argument('--task', action='append', help='add taskwarrior task uuid relation') + argparser.add_argument('-s', type=str, help='entry subject') + return True + + +def check_args(args): + pass + + +# TODO: move logic to package to get symmetry with the show.py logic +def execute(config, feed, args): + d = tempfile.TemporaryDirectory() + t = tempfile.NamedTemporaryFile(mode='w+', dir=d.name) + editor_path = get_editor() + os.system('{} {}'.format(get_editor(), t.name)) + f = open(t.name, 'rb') + s = os.stat(t.name) + t.close() + logg.debug('file {} {}'.format(t.name, s.st_size)) + content = f.read(s.st_size) + f.close() + + entry_date = str(email.utils.formatdate()) + subject = args.s + if subject == None: + subject = entry_date + m = EmailMessage() + m.add_header('Content-Type', 'text/plain') + m.add_header('Content-Disposition', 'inline') + m.add_header('Content-Transfer-Encoding', 'base64') + m.set_param('filename', subject) + m.set_param('filename', subject, 'Content-Disposition') + bsf = base64.encodebytes(content) + m.set_payload(bsf.decode('utf-8')) + + + mm = MIMEMultipart() + mm.attach(m) + mm.add_header('Subject', subject) + mm.add_header('Date', entry_date) + print(mm) + + entry = feedentry.from_multipart(mm) + #entry = feedentry.from_multipart_file(args.path) + if args.task != None: + for t in args.task: + uu = feedwarrior.common.parse_uuid(t) + entry.add_extension(feedwarrior.extension.TASKWARRIOR, uu) + + uu = str(entry.uuid) + logg.debug('adding entry {}'.format(uu)) + + fa = fileadapter(config.data_dir, feed.uuid) + fa.put(entry.uuid, entry, compress=args.z) + + feed.add(entry) diff --git a/feedwarrior/cmd/show.py b/feedwarrior/cmd/show.py @@ -2,6 +2,10 @@ import json import email import time +import sys +import logging + +logg = logging.getLogger(__file__) def parse_args(argparser): pass @@ -16,7 +20,7 @@ def execute(config, feed, args): while 1: try: e = feed.next_entry() - except IndexError: + except IndexError as e: break j = json.loads(e) m = email.message_from_string(j['payload']) @@ -42,16 +46,16 @@ def execute(config, feed, args): body += '>>> {}\n\n{}\n\n\n'.format(subject, p.get_payload(decode=True).decode('utf-8')) if i > 0: - print('----') + sys.stdout.write('----\n') if body != None: if args.headers: for k in m.keys(): print('{}: {}'.format(k, m.get(k))) - print('{} - {}\n'.format(ts, j['uuid'])) - print(body) + sys.stdout.write('{} - {}\n'.format(ts, j['uuid'])) + sys.stdout.write('{}'.format(body)) for a in attachments: - print('+ {}'.format(a)) + sys.stdout.write('+ {}'.format(a)) i += 1 - pass + sys.stdout.flush() diff --git a/feedwarrior/entry.py b/feedwarrior/entry.py @@ -52,6 +52,7 @@ class entry: logg.debug('complete message {}'.format(self.message)) d = email.utils.parsedate(self.message.get('Date')) + logg.debug('date {} {}'.format(d, self.message.get('Date'))) ts = time.mktime(d) return { @@ -70,6 +71,10 @@ def from_multipart_file(filename, hashers=defaulthashers): f = gzip.open(filename + '.gz', 'rb') m = email.message_from_file(f) f.close() + return from_multipart(m, hashers) + + +def from_multipart(m, hashers=defaulthashers): if not m.is_multipart(): raise ValueError('{} is not a MIME multipart message'.format(filename)) diff --git a/feedwarrior/feed.py b/feedwarrior/feed.py @@ -66,7 +66,7 @@ class feed: def _sort_entries(self): - logg.debug('entries for {}'.format(self.uuid), self.entries) + logg.debug('entries for {} {}'.format(self.uuid, self.entries)) new_entries = [] for e in self.entries: entry = self.getter.get(e) diff --git a/scripts/feedwarrior b/scripts/feedwarrior @@ -18,11 +18,19 @@ from feedwarrior.cmd import create as cmd_create from feedwarrior.cmd import entry as cmd_entry from feedwarrior.cmd import show as cmd_show from feedwarrior.cmd import ls as cmd_list +from feedwarrior.cmd import add as cmd_add logging.basicConfig(level=logging.ERROR) logg = logging.getLogger() +def matches_part(full, part): + if len(part) > len(full): + return False + return full[:len(part)] == part + + + argparser = argparse.ArgumentParser(description='create and manipulate feedwarrior feeds') argparser.add_argument('-l', help='feed log to operate on') argparser.add_argument('-c', type=str, help='configuration file') @@ -39,7 +47,8 @@ sub_create = sub.add_parser('create', help='create new feed') cmd_create.parse_args(sub_create) sub_list = sub.add_parser('list', help='list feeds') cmd_list.parse_args(sub_list) - +sub_add = sub.add_parser('add', help='add new entry with editor') +cmd_add.parse_args(sub_add) args = argparser.parse_known_args() @@ -72,20 +81,23 @@ if args.l != None: sys.exit(1) + cmd_mod = None -if args.command == 'create': - feed_current = feedwarrior.feed(parent=feed_current) - cmd_mod = cmd_create -elif args.command == 'entry': - cmd_mod = cmd_entry -elif args.command == 'list': - cmd_mod = cmd_list -elif args.command == 'show' or args.command == None: +if args.command == None or matches_part('show', args.command): if feed_current == None: sys.stderr.write('plesae speficy a feed for showing\n') sys.exit(1) feed_current = feedwarrior.load_feed(config.data_dir, feed_current.uuid) cmd_mod = cmd_show +elif matches_part('create', args.command): + feed_current = feedwarrior.feed(parent=feed_current) + cmd_mod = cmd_create +elif matches_part('entry', args.command): + cmd_mod = cmd_entry +elif matches_part('list', args.command) or args.command == 'ls': + cmd_mod = cmd_list +elif matches_part('add', args.command): + cmd_mod = cmd_add else: sys.stderr.write('invalid command {}\n'.format(args.command)) sys.exit(1) diff --git a/setup.py b/setup.py @@ -2,12 +2,14 @@ from setuptools import setup setup( name='feedwarrior', - version='0.4.0', + version='0.4.1', description='feeds, warrior style', author='Louis Holbrook', author_email='dev@holbrook.no', packages=['feedwarrior', 'feedwarrior.cmd'], - install_requires=['xdg'], + install_requires=[ + 'xdg' + ], scripts = [ 'scripts/feedwarrior', ]