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 7e490dbd930be4c573317e2c9d9b2c1d0ef2466d
parent 86efd9b77bc799b5fb4f37d957bbb1b2ae5974ba
Author: nolash <dev@holbrook.no>
Date:   Sun, 30 Aug 2020 01:01:57 +0200

Add taskwarrior id resolve, abort on empty input for add subcmd

Diffstat:
MCHANGELOG | 3+++
MROADMAP | 1-
MVERSION | 2+-
Mfeedwarrior/cmd/add.py | 27++++++++++++++++++++-------
Mfeedwarrior/cmd/entry.py | 18+++++++++++++-----
Mfeedwarrior/common.py | 32++++++++++++++++++++++++++++++++
Mfeedwarrior/config.py | 16++++++++++++----
Mscripts/feedwarrior | 6++++--
Msetup.py | 5+++--
9 files changed, 88 insertions(+), 22 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,6 @@ +* 0.5.0 + - Add taskwarrior uuid lookup and id to uuid resolve + - Abort add on empty input * 0.4.2 - Add "add" subcommand * 0.4.1 diff --git a/ROADMAP b/ROADMAP @@ -1,2 +1 @@ -- Auto-resolve taskwarrior task numbers to uuids and add to X header - Sign entries with PGP diff --git a/VERSION b/VERSION @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/feedwarrior/cmd/add.py b/feedwarrior/cmd/add.py @@ -1,4 +1,5 @@ # standard imports +import sys import os from email.message import EmailMessage from email.mime.multipart import MIMEMultipart @@ -9,11 +10,14 @@ import json import gzip import tempfile import base64 +import uuid # local imports import feedwarrior from feedwarrior import entry as feedentry from feedwarrior.adapters import fileadapter +from feedwarrior.entry import extension +from feedwarrior.common import task_ids_to_uuids, check_task_uuids logg = logging.getLogger() @@ -23,7 +27,8 @@ def get_editor(): 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('--task-id', dest='task_id', type=int, action='append', help='add taskwarrior task id relations translated to uuis (cannot be used with --task-uuid') + argparser.add_argument('--task-uuid', dest='task_uuid', type=str, action='append', help='add taskwarrior task uuid relations (cannot be used with --task-id') argparser.add_argument('-s', type=str, help='entry subject') return True @@ -34,6 +39,13 @@ def check_args(args): # TODO: move logic to package to get symmetry with the show.py logic def execute(config, feed, args): + task_uuids = [] + if args.task_id != None: + task_uuids += task_ids_to_uuids(config.task_dir, args.task_id) + + if args.task_uuid != None: + task_uuids += check_task_uuids(config.task_dir, args.task_uuid) + d = tempfile.TemporaryDirectory() t = tempfile.NamedTemporaryFile(mode='w+', dir=d.name) editor_path = get_editor() @@ -42,6 +54,10 @@ def execute(config, feed, args): s = os.stat(t.name) t.close() logg.debug('file {} {}'.format(t.name, s.st_size)) + if s.st_size == 0: + logg.error('empty input') + sys.stderr.write('No input. aborting.\n') + sys.exit(1) content = f.read(s.st_size) f.close() @@ -63,14 +79,11 @@ def execute(config, feed, args): 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) + for t in task_uuids: + uu = feedwarrior.common.parse_uuid(t) + entry.add_extension(feedwarrior.extension.TASKWARRIOR, uu) uu = str(entry.uuid) logg.debug('adding entry {}'.format(uu)) diff --git a/feedwarrior/cmd/entry.py b/feedwarrior/cmd/entry.py @@ -10,13 +10,15 @@ import gzip import feedwarrior from feedwarrior import entry as feedentry from feedwarrior.adapters import fileadapter +from feedwarrior.common import task_ids_to_uuids, check_task_uuids logg = logging.getLogger() 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('--task-id', dest='task_id', type=int, action='append', help='add taskwarrior task id relations translated to uuis (cannot be used with --task-uuid') + argparser.add_argument('--task-uuid', dest='task_uuid', type=str, action='append', help='add taskwarrior task uuid relations (cannot be used with --task-id') argparser.add_argument('path', help='multipart file to use for content') return True @@ -27,11 +29,17 @@ def check_args(args): # TODO: move logic to package to get symmetry with the show.py logic def execute(config, feed, args): + task_uuids = [] + if args.task_id != None: + task_uuids += task_ids_to_uuids(config.task_dir, args.task_id) + + if args.task_uuid != None: + task_uuids += check_task_uuids(config.task_dir, args.task_uuid) + 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) + for t in task_uuids: + uu = feedwarrior.common.parse_uuid(t) + entry.add_extension(feedwarrior.extension.TASKWARRIOR, uu) uu = str(entry.uuid) logg.debug('adding entry {}'.format(uu)) diff --git a/feedwarrior/common.py b/feedwarrior/common.py @@ -1,12 +1,44 @@ # standard imports import uuid import hashlib +import logging + +# third-party imports +import tasklib + +logg = logging.getLogger(__file__) defaulthashers = [hashlib.sha256, hashlib.sha1] + def parse_uuid(uu): if type(uu).__name__ == 'str': return uuid.UUID('urn:uuid:' + uu) elif type(uu).__name__ == 'UUID': return uu raise ValueError('invalid uuid') + + +def task_ids_to_uuids(task_path, task_ids): + task_uuids = [] + tw = tasklib.TaskWarrior(task_path) + for task_id in task_ids: + # third-party imports + t = tw.tasks.pending().get(id=task_id) + task_uuid = t['uuid'] + logg.debug('resolved task uuid {} for id {}'.format(task_uuid, task_id)) + task_uuids.append(task_uuid) + return task_uuids + + +def check_task_uuids(task_path, task_uuids): + task_ok_uuids = [] + tw = tasklib.TaskWarrior(task_path) + for task_uuid in task_uuids: + t = tw.tasks.pending().get(uuid=task_uuid) + task_uuid = t['uuid'] + logg.debug('verified task uuid {}'.format(task_uuid)) + task_ok_uuids.append(task_uuid) + return task_ok_uuids + + diff --git a/feedwarrior/config.py b/feedwarrior/config.py @@ -14,18 +14,20 @@ class config: def __init__(self, filename=None): self.data_dir = BaseDirectory.save_data_path('feedwarrior') + self.task_dir = os.path.join(os.environ.get('HOME'), '.task') cp = configparser.ConfigParser() config_paths = [filename] config_loaded = False - - if filename == None: - config_paths = BaseDirectory.load_config_paths('feedwarrior') + + # TODO: this make no sense + # if filename == None: + config_paths = BaseDirectory.load_config_paths('feedwarrior') if filename != None: for p in config_paths: try: - cp.read(filename) + cp.read(os.path.join(p, filename)) logg.info('successfully read config {}'.format(p)) config_loaded = True break @@ -36,6 +38,12 @@ class config: if cp.has_option('FEEDWARRIOR', 'datadir'): self.data_dir = cp['FEEDWARRIOR']['datadir'] + if cp.has_option('FEEDWARRIOR', 'taskdir'): + self.task_dir = cp['FEEDWARRIOR']['taskdir'] + + logg.info('using data dir {}'.format(self.data_dir)) + logg.info('using task dir {}'.format(self.task_dir)) + self.feeds_dir = os.path.join(self.data_dir, 'feeds') self.alias_dir = os.path.join(self.feeds_dir, 'names') self.entries_dir = os.path.join(self.data_dir, 'entries') diff --git a/scripts/feedwarrior b/scripts/feedwarrior @@ -33,7 +33,7 @@ def matches_part(full, 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') +argparser.add_argument('-c', type=str, default='config.ini', help='configuration file') argparser.add_argument('-v', action='store_true', help='be verbose') argparser.add_argument('--headers', action='store_true', help='add headers in output') sub = argparser.add_subparsers() @@ -108,7 +108,9 @@ try: os.makedirs(os.path.join(config.feeds_dir, 'names'), mode=0o777, exist_ok=False) logg.debug('creating datadir {}'.format(config.data_dir)) except FileExistsError as e: - logg.debug('using datadir {}'.format(config.data_dir)) + logg.debug('found existing datadir {}'.format(config.data_dir)) + +cmd_mod.check_args(args) if __name__ == '__main__': cmd_mod.execute(config, feed_current, args) diff --git a/setup.py b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( name='feedwarrior', - version='0.4.2', + version='0.5.0', description='feeds, warrior style', author='Louis Holbrook', author_email='dev@holbrook.no', @@ -12,7 +12,8 @@ setup( 'feedwarrior.adapters' ], install_requires=[ - 'pyxdg>=0.26' + 'pyxdg>=0.26', + 'tasklib>=1.3.0,<2.0.0', ], scripts = [ 'scripts/feedwarrior',