initial commit
commit
0046fa3020
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# For taskwarrior users:
|
||||||
|
# Delete all overdue & duplicate tasks and keep only the first of a kind.
|
||||||
|
#
|
||||||
|
# Needs the taskw Python bindings to run.
|
||||||
|
|
||||||
|
__requires__ = ["taskw >= 0.8.3"]
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
import pytz
|
||||||
|
import taskw
|
||||||
|
|
||||||
|
|
||||||
|
def task_delete(uuid):
|
||||||
|
"""Delete the given task."""
|
||||||
|
|
||||||
|
assert isinstance(uuid, UUID)
|
||||||
|
|
||||||
|
# This is somewhat a hack, but as TaskWwarrior 2.4.0 does NOT disable
|
||||||
|
# the 'Do you want to delete all pending recurrences ...' confirmation
|
||||||
|
# on rc.confirmation=off, so this is necessary.
|
||||||
|
DEVNULL = open(os.devnull, 'wb')
|
||||||
|
p = Popen(['task', 'rc.confirmation=off', str(uuid), 'delete'],
|
||||||
|
stdin=PIPE, stdout=DEVNULL, stderr=STDOUT)
|
||||||
|
p.communicate(input=bytes('no', 'UTF-8'))
|
||||||
|
|
||||||
|
|
||||||
|
w = taskw.TaskWarrior(marshal=True)
|
||||||
|
tasks = w.load_tasks()
|
||||||
|
|
||||||
|
|
||||||
|
# Only (over-)due and recurring tasks are considered for deletion:
|
||||||
|
due_before = datetime.datetime.utcnow()
|
||||||
|
due_before = due_before.replace(tzinfo=pytz.utc)
|
||||||
|
recurring_tasks_due = [task for task in tasks['pending']
|
||||||
|
if 'recur' in task
|
||||||
|
and 'parent' in task
|
||||||
|
and 'due' in task and task['due'] < due_before]
|
||||||
|
|
||||||
|
# Delete all but the first of all (over-)due and duplicate tasks:
|
||||||
|
parents = collections.Counter([task['parent']
|
||||||
|
for task in recurring_tasks_due])
|
||||||
|
for parent in parents:
|
||||||
|
count = parents[parent]
|
||||||
|
if count > 1:
|
||||||
|
dupe_tasks = [task for task in recurring_tasks_due
|
||||||
|
if task['parent'] == parent]
|
||||||
|
dupe_tasks = sorted(dupe_tasks, key=lambda t: t['due'])
|
||||||
|
|
||||||
|
dupe_tasks_to_keep = dupe_tasks[0:1]
|
||||||
|
dupe_tasks_to_trash = dupe_tasks[1:]
|
||||||
|
|
||||||
|
print('Deleting {} duplicate due tasks: "{}"'.format(
|
||||||
|
len(dupe_tasks_to_trash), dupe_tasks_to_trash[0]['description']))
|
||||||
|
for task in dupe_tasks_to_trash:
|
||||||
|
task_delete(task['uuid'])
|
Reference in New Issue