commit ba5fdd999ad28386d0d61d52ccc51df72e11deb0
parent 6557794f6ee296d4abf6014a98095aa4e0fc0be9
Author: nolash <dev@holbrook.no>
Date: Sun, 28 Jun 2020 20:43:54 +0200
Add common name resolver for feeds
Diffstat:
7 files changed, 175 insertions(+), 40 deletions(-)
diff --git a/src/feedwarrior/__init__.py b/src/feedwarrior/__init__.py
@@ -1,3 +1,4 @@
+from .feed import load as load_feed
from .feed import feed
from . import entry
from .config import load_config
diff --git a/src/feedwarrior/cmd/create.py b/src/feedwarrior/cmd/create.py
@@ -0,0 +1,28 @@
+# standard imports
+import os
+import sys
+import json
+import logging
+
+logg = logging.getLogger(__name__)
+
+# TODO: move to submodule asap
+def parse_args(argparser):
+ pass
+
+
+def check_args(argparser):
+ pass
+
+
+def execute(config, feed, args):
+ uu = str(feed.uuid)
+ logg.debug('new feed {}'.format(uu))
+ feed_path = os.path.join(config.feeds_dir, str(uu))
+ os.mkdir(feed_path)
+ os.mkdir(os.path.join(feed_path, 'entries'))
+
+ feed_meta_path = os.path.join(feed_path, '.log')
+ f = open(feed_meta_path, 'x')
+ json.dump(feed.serialize(), f)
+ f.close()
diff --git a/src/feedwarrior/cmd/entry.py b/src/feedwarrior/cmd/entry.py
@@ -44,3 +44,5 @@ def execute(config, feed, args):
feeds_entry_path = os.path.join(feeds_entries_dir, uu)
os.symlink(entry_path, feeds_entry_path)
+
+ feed.add(entry)
diff --git a/src/feedwarrior/cmd/log.py b/src/feedwarrior/cmd/log.py
@@ -1,28 +0,0 @@
-# standard imports
-import os
-import sys
-import json
-import logging
-
-logg = logging.getLogger(__name__)
-
-# TODO: move to submodule asap
-def parse_args(argparser):
- pass
-
-
-def check_args(argparser):
- pass
-
-
-def execute(config, feed, args):
- if args.command == None:
- uu = str(feed.uuid)
- logg.debug('new log {}'.format(uu))
- log_path = os.path.join(config.feeds_dir, str(uu))
- os.mkdir(log_path)
-
- log_meta_path = os.path.join(log_path, '.log')
- f = open(log_meta_path, 'x')
- json.dump(feed.serialize(), f)
- f.close()
diff --git a/src/feedwarrior/cmd/show.py b/src/feedwarrior/cmd/show.py
@@ -0,0 +1,13 @@
+def parse_args(argparser):
+ pass
+
+def check_args(args):
+ pass
+
+def execute(config, feed, args):
+ while 1:
+ try:
+ print(feed.next_entry())
+ except IndexError:
+ break
+ pass
diff --git a/src/feedwarrior/feed.py b/src/feedwarrior/feed.py
@@ -1,8 +1,31 @@
# standard imports
+import email
+import os
import uuid
import copy
import time
-from .common import parse_uuid
+import json
+import logging
+
+# local imports
+from feedwarrior.common import parse_uuid
+
+logg = logging.getLogger()
+
+
+class filegetter:
+
+ def __init__(self, source_directory):
+ self.src = source_directory
+
+
+ def get(self, uu):
+ entry_path = os.path.join(self.src, str(uu))
+ f = open(entry_path, 'r')
+ c = f.read()
+ f.close()
+ return c
+
class feed:
@@ -11,7 +34,7 @@ class feed:
if uu == None:
self.uuid = uuid.uuid4()
else:
- self.uuid = parse_uuid(uu)
+ self.uuid = uu
self.parent = None
if parent != None:
@@ -19,6 +42,8 @@ class feed:
raise ValueError('wrong type for parent: {}'.format(type(parent).__name__))
self.parent = copy.copy(parent)
+ self.updated = 0
+ self.created = 0
if created != None:
self.created = created
if updated == None:
@@ -31,6 +56,12 @@ class feed:
self.updated = updated
self.entries = []
+ self.entries_cursor = 0
+ self.entries_sorted = False
+
+
+ def add(self, entry):
+ self.entries.append(entry)
def serialize(self):
@@ -43,3 +74,69 @@ class feed:
o['parent_uuid'] = str(self.parent.uuid)
return o
+
+
+ def _sort_entries(self):
+ new_entries = []
+ for e in self.entries:
+ entry = self.getter.get(e)
+ o = json.loads(entry)
+ m = email.message_from_string(o['payload'])
+ d = email.utils.parsedate(m.get('Date'))
+ t = time.mktime(d)
+ ts = str(t)
+ if not m.is_multipart():
+ raise ValueError('invalid entry {}'.format(e))
+ logg.debug('date {} {}'.format(e, ts))
+ new_entries.append('_'.join([ts, e]))
+
+ self.entries = []
+ for ne in new_entries:
+ logg.debug(ne)
+ e = ne.split('_', maxsplit=1)
+ self.entries.append(e[1])
+
+ self.entries_cursor = 0
+ self.entries_sorted = True
+
+
+ def set_getter(self, getter):
+ self.getter = getter
+
+
+ def next_entry(self):
+ if not self.entries_sorted:
+ self._sort_entries()
+ if self.entries_cursor == len(self.entries):
+ raise IndexError('no more entries')
+
+ e = self.getter.get(self.entries[self.entries_cursor])
+ self.entries_cursor += 1
+ return e
+
+
+
+# TODO: add input checking for timestamps
+# TODO: check state of symlink index
+def load(path):
+ feed_meta_path = os.path.join(path, '.log')
+ f = open(feed_meta_path, 'r')
+ o = json.load(f)
+ uu = parse_uuid(o['uuid'])
+ puu = None
+ p = None
+ if o.get('parent_uuid') != None:
+ puu = parse_uuid(o['parent_uuid'])
+ p = feed(puu)
+ feed_loaded = feed(uu, p, int(o['created']), int(o['updated']))
+
+ feed_entries_path = os.path.join(path, 'entries')
+ for entry in os.listdir(feed_entries_path):
+ feed_loaded.entries.append(entry)
+
+ fg = filegetter(os.path.join(path, 'entries'))
+ feed_loaded.set_getter(fg)
+
+ return feed_loaded
+
+
diff --git a/src/main.py b/src/main.py
@@ -14,23 +14,29 @@ import logging
# local imports
import feedwarrior
-from feedwarrior.cmd import log as cmd_log
+from feedwarrior.cmd import create as cmd_create
from feedwarrior.cmd import entry as cmd_entry
+from feedwarrior.cmd import show as cmd_show
logging.basicConfig(level=logging.ERROR)
logg = logging.getLogger()
-argparser = argparse.ArgumentParser(description='create and manipulate feedwarrior logs')
+argparser = argparse.ArgumentParser(description='create and manipulate feedwarrior feeds')
argparser.add_argument('-l', help='feed log to operate on')
argparser.add_argument('-c', required=True, type=str, help='configuration file')
argparser.add_argument('-v', action='store_true', help='be verbose')
sub = argparser.add_subparsers()
# TODO: add subparser to same level flags as main parser
sub.dest = 'command'
-sub_entry = sub.add_parser('entry', help='add entry to log')
+sub_entry = sub.add_parser('entry', help='add entry to feed')
cmd_entry.parse_args(sub_entry)
+sub_show = sub.add_parser('show', help='view feed log')
+cmd_show.parse_args(sub_show)
+sub_create = sub.add_parser('create', help='create new feed')
+cmd_create.parse_args(sub_create)
+
args = argparser.parse_args(sys.argv[1:])
if args.v:
@@ -40,27 +46,43 @@ logg.debug('loading config {}'.format(args.c))
config = feedwarrior.load_config(args.c)
+def get_feed_by_name(s):
+ index_path = os.path.join(config.feeds_dir, 'names', s)
+ resolved_path = os.path.realpath(index_path)
+ logg.debug('attempting to resolve feed with path {}'.format(resolved_path))
+ os.stat(resolved_path)
+ return os.path.basename(resolved_path)
+
feed_current = None
if args.l != None:
try:
- feed_current = feedwarrior.feed(args.l)
- except ValueError as e:
- logg.error('invalid parent {}: {}'.format(args.l, e))
- sys.exit(1)
+ uu = feedwarrior.common.parse_uuid(args.l)
+ feed_current = feedwarrior.feed(uu)
+ except ValueError:
+ try:
+ uu = get_feed_by_name(args.l)
+ feed_current = feedwarrior.feed(uu)
+ except FileNotFoundError as e:
+ sys.stderr.write('cannot resolve feed {}\n'.format(args.l))
+ sys.exit(1)
cmd_mod = None
-if args.command == None:
+if args.command == 'create':
feed_current = feedwarrior.feed(parent=feed_current)
- cmd_mod = cmd_log
+ cmd_mod = cmd_create
elif args.command == 'entry':
cmd_mod = cmd_entry
+elif args.command == 'show' or args.command == None:
+ feed_current = feedwarrior.load_feed(os.path.join(config.feeds_dir, str(feed_current.uuid)))
+ cmd_mod = cmd_show
else:
- log.error('invalid command {}'.format(args.command))
+ sys.stderr.write('invalid command {}\n'.format(args.command))
sys.exit(1)
try:
os.makedirs(config.entries_dir, mode=0o777, exist_ok=False)
os.makedirs(config.feeds_dir, mode=0o777, exist_ok=False)
+ 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))