piknik

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README | LICENSE

commit f538f58df8c52e37511c84eedb5cd11467dcbf2d
parent 5d193d14d5afb0621c94dad47799f6fbda6b6d0a
Author: lash <dev@holbrook.no>
Date:   Sun, 19 Mar 2023 10:47:31 +0000

WIP organize subcommands

Diffstat:
Apiknik/cli/__init__.py | 18++++++++++++++++++
Apiknik/cli/add.py | 30++++++++++++++++++++++++++++++
Apiknik/cli/mod.py | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apiknik/cli/session.py | 1+
Apiknik/cli/show.py | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpiknik/runnable/show.py | 103++++++++++++++++---------------------------------------------------------------
6 files changed, 247 insertions(+), 83 deletions(-)

diff --git a/piknik/cli/__init__.py b/piknik/cli/__init__.py @@ -0,0 +1,18 @@ +# standard imports +import os + +# local imports +from piknik import Basket +from piknik.store import FileStoreFactory + + +class Context: + + def __init__(self, arg, assembler, mode=0, gpg_home=os.environ.get('GPGHOME')): + self.issue_id = arg.issue_id + self.files_dir = arg.files_dir + #self.store_factory = FileStoreFactory(arg.d) + store_factory = FileStoreFactory(arg.d) + self.basket = Basket(store_factory) + self.gpg_home = gpg_home + assembler(self, arg) diff --git a/piknik/cli/add.py b/piknik/cli/add.py @@ -0,0 +1,30 @@ +# standard imports +import sys + +# local imports +from piknik import Issue + +ctx = None + + +def subparser(argp): + arg = argp.add_parser('add') + arg.add_argument('title', type=str, nargs='*', help='issue title') + return argp + + +def assembler(o, arg): + o.title = arg.title + + +def main(): + title = '' + for s in ctx.title: + if s == ' ': + continue + if title != '': + title += ' ' + title += s + o = Issue(title) + v = ctx.basket.add(o) + sys.stdout.write(v + '\n') diff --git a/piknik/cli/mod.py b/piknik/cli/mod.py @@ -0,0 +1,77 @@ +ctx = None + + +def subparser(argp): + arg = argp.add_parser('mod') + arg.add_argument('--accept', action='store_true', help='Accept proposed issue') + arg.add_argument('--block', action='store_true', help='Set issue as blocked') + arg.add_argument('--unblock', action='store_true', help='Set issue as unblocked') + arg.add_argument('--finish', action='store_true', help='Set issue as finished (alias of -s finish)') + arg.add_argument('-s', '--state', type=str, help='Move to state') + arg.add_argument('-t', '--tag', type=str, action='append', default=[], help='Add tag to issue') + arg.add_argument('-u', '--untag', type=str, action='append', default=[], help='Remove tag from issue') + #argp.add_argument('-f', '--file', type=str, action='append', help='Add message file part') + #argp.add_argument('-m', '--message', type=str, action='append', default=[], help='Add message text part') + arg.add_argument('-a', '--assign', type=str, action='append', default=[], help='Assign given identity to issue') + arg.add_argument('--unassign', type=str, action='append', default=[], help='Unassign given identity from issue') + arg.add_argument('-o', '--owner', type=str, help='Set given identity as owner of issue') + arg.add_argument('--dep', action='append', default=[], type=str, help='Set issue dependency') + arg.add_argument('--undep', action='append', default=[], type=str, help='Remove issue dependency') + return argp + + +def assembler(o, arg): + o.owner = arg.owner + o.block = arg.block + o.unblock = arg.unblock + o.state = arg.state + o.finish = arg.finish + o.accept = arg.accept + o.tag = arg.tag + o.untag = arg.untag + o.assign = arg.assign + o.unassign = arg.unassign + o.dep = arg.dep + o.undep = arg.undep + + +def main(): + global ctx + + o = ctx.basket.get(ctx.issue_id) + + if ctx.block: + ctx.basket.block(ctx.issue_id) + elif ctx.unblock: + ctx.basket.unblock(ctx.issue_id) + + if ctx.state != None: + m = getattr(ctx.basket, 'state_' + ctx.state) + m(ctx.issue_id) + elif ctx.finish: + ctx.basket.state_finish(ctx.issue_id) + elif ctx.accept: + if ctx.basket.get_state(ctx.issue_id) != 'PROPOSED': + raise ValueError('Issue already accepted') + ctx.basket.advance(ctx.issue_id) + + for v in ctx.tag: + ctx.basket.tag(ctx.issue_id, v) + + for v in ctx.untag: + ctx.basket.untag(ctx.issue_id, v) + + for v in ctx.unassign: + ctx.basket.unassign(ctx.issue_id, v) + + for v in ctx.assign: + ctx.basket.assign(ctx.issue_id, v) + + for v in ctx.undep: + ctx.basket.undep(ctx.issue_id, v) + + for v in ctx.dep: + ctx.basket.dep(ctx.issue_id, v) + + if ctx.owner: + ctx.basket.owner(ctx.issue_id, ctx.owner) diff --git a/piknik/cli/session.py b/piknik/cli/session.py @@ -0,0 +1 @@ + diff --git a/piknik/cli/show.py b/piknik/cli/show.py @@ -0,0 +1,101 @@ +# standard imports +import os +import logging +import importlib + +# local imports +from piknik import Issue +from piknik.crypto import PGPSigner + +ctx = None +accumulator_f = None +accumulator = None + +logg = logging.getLogger(__name__) + + + +def set_accumulator(ctx, issue_id=None): + global accumulator_f + global accumulator + global m + if ctx.files_dir != None: + fb = None + if issue_id == None: + fb = 'index.html' + else: + fb = issue_id + '.html' + fp = os.path.join(ctx.files_dir, fb) + accumulator_f = open(fp, 'w') + accumulator = m.Accumulator(w=accumulator_f) + return accumulator.add + return None + + +def reset_accumulator(): + global accumulator_f + global accumulator + if accumulator_f != None: + accumulator_f.close() + accumulator_f = None + issues = accumulator.issues + accumulator = None + return issues + return [] + + +def subparser(argp): + arg = argp.add_parser('show') + arg.add_argument('-r', '--renderer', type=str, default='default', help='Renderer module for output') + arg.add_argument('-s', '--state', type=str, action='append', default=[], help='Limit results to state(s)') + arg.add_argument('--show-finished', dest='show_finished', action='store_true', help='Include finished issues') + arg.add_argument('--reverse', action='store_true', help='Sort comments by oldest first') + return argp + + +def assembler(o, arg): + o.renderer = arg.renderer + + +def main(): + global ctx + + renderer_s = ctx.renderer + if renderer_s == 'default': + renderer_s = 'piknik.render.plain' + elif renderer_s == 'html': + renderer_s = 'piknik.render.html' + + m = None + try: + m = importlib.import_module(renderer_s) + except ModuleNotFoundError: + renderer_s = 'piknik.render.' + renderer_s + m = importlib.import_module(renderer_s) + + accumulator = None + accumulator_f = None + + issues = [] + if ctx.issue_id: + issues.append(ctx.issue_id) + + if ctx.issue_id == None: + accumulator = set_accumulator(ctx) + renderer = m.Renderer(ctx.basket, accumulator=accumulator) + renderer.apply() + issues = reset_accumulator() + + for issue_id in issues: + accumulator = set_accumulator(ctx, issue_id=issue_id) + issue = ctx.basket.get(issue_id) + tags = ctx.basket.tags(issue_id) + state = ctx.basket.get_state(issue_id) + verifier = PGPSigner(home_dir=ctx.gpg_home, skip_verify=False) + renderer = m.Renderer(ctx.basket, wrapper=verifier, accumulator=accumulator) + + renderer.apply_begin() + renderer.apply_issue(state, issue, tags) + renderer.apply_end() + + reset_accumulator() diff --git a/piknik/runnable/show.py b/piknik/runnable/show.py @@ -10,10 +10,10 @@ from email.utils import parsedate_to_datetime import importlib # local imports -from piknik import Basket -from piknik import Issue -from piknik.store import FileStoreFactory -from piknik.crypto import PGPSigner +from piknik.cli import Context +from piknik.cli.show import subparser as subparser_show +from piknik.cli.mod import subparser as subparser_mod +from piknik.cli.add import subparser as subparser_add logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() @@ -22,88 +22,25 @@ argp = argparse.ArgumentParser() argp.add_argument('-d', type=str, help='Data directory') argp.add_argument('-f', '--files', dest='f', action='store_true', help='Save attachments to filesystem') argp.add_argument('-o', '--files-dir', dest='files_dir', type=str, help='Directory to output saved files to') -argp.add_argument('-r', '--renderer', type=str, default='default', help='Renderer module for output') -argp.add_argument('-s', '--state', type=str, action='append', default=[], help='Limit results to state(s)') -argp.add_argument('--show-finished', dest='show_finished', action='store_true', help='Include finished issues') -#argp.add_argument('--reverse', action='store_true', help='Sort comments by oldest first') -argp.add_argument('issue_id', type=str, nargs='?', default=None, help='Issue id to show') -arg = argp.parse_args(sys.argv[1:]) - -store_factory = FileStoreFactory(arg.d) -basket = Basket(store_factory) - -gpg_home = os.environ.get('GPGHOME') +argp.add_argument('-i','--issue-id', type=str, help='Issue id to show') -renderer_s = arg.renderer -if renderer_s == 'default': - renderer_s = 'piknik.render.plain' -elif renderer_s == 'html': - renderer_s = 'piknik.render.html' +argsub = argp.add_subparsers(title='subcommand', dest='subcmd') +argsub = subparser_show(argsub) +argsub = subparser_mod(argsub) +argsub = subparser_add(argsub) +arg = argp.parse_args(sys.argv[1:]) m = None -try: - m = importlib.import_module(renderer_s) -except ModuleNotFoundError: - renderer_s = 'piknik.render.' + renderer_s - m = importlib.import_module(renderer_s) - -accumulator = None -accumulator_f = None - -def set_accumulator(issue_id=None): - global accumulator_f - global accumulator - global m - if arg.files_dir != None: - fb = None - if issue_id == None: - fb = 'index.html' - else: - fb = issue_id + '.html' - fp = os.path.join(arg.files_dir, fb) - accumulator_f = open(fp, 'w') - accumulator = m.Accumulator(w=accumulator_f) - return accumulator.add - return None - - -def reset_accumulator(): - global accumulator_f - global accumulator - if accumulator_f != None: - accumulator_f.close() - accumulator_f = None - issues = accumulator.issues - accumulator = None - return issues - return [] - - -def main(): - issues = [] - if arg.issue_id: - issues.append(arg.issue_id) - - if arg.issue_id == None: - accumulator = set_accumulator() - renderer = m.Renderer(basket, accumulator=accumulator) - renderer.apply() - issues = reset_accumulator() - - for issue_id in issues: - accumulator = set_accumulator(issue_id=issue_id) - issue = basket.get(issue_id) - tags = basket.tags(issue_id) - state = basket.get_state(issue_id) - verifier = PGPSigner(home_dir=gpg_home, skip_verify=False) - renderer = m.Renderer(basket, wrapper=verifier, accumulator=accumulator) +if arg.subcmd == 'show': + m = importlib.import_module('piknik.cli.show') +elif arg.subcmd == 'mod': + m = importlib.import_module('piknik.cli.mod') +elif arg.subcmd == 'add': + m = importlib.import_module('piknik.cli.add') +else: + raise ValueError('invalid subcommand: ' + arg.subcmd) - renderer.apply_begin() - renderer.apply_issue(state, issue, tags) - renderer.apply_end() - - reset_accumulator() - +m.ctx = Context(arg, m.assembler) if __name__ == '__main__': - main() + m.main()