#!/usr/bin/env python """ Module is a copy/paste of https://github.com/mlaradji/task-relative-recur.git Difference is, we'll execute completeRecurDue and completeRecurWait as strings. Usage example: task add 'Do the dishes' completeRecurWait:"tomorrow +17hours" completeRecurDue:"tomorrow +1day" """ import json import sys import subprocess import uuid import os import tempfile import time TIME_FORMAT = "%Y%m%dT%H%M%SZ" UDA_DUE = "completeRecurDue" UDA_WAIT = "completeRecurWait" env = os.environ.copy() # Hand back duration format parsing to task warrior def calc(statement): calc = subprocess.Popen( ["task", "rc.verbose=nothing", "rc.date.iso=yes", "calc", statement], stdout=subprocess.PIPE, env=env, ) out, err = calc.communicate() # Workaround for TW-1254 (https://bug.tasktools.org/browse/TW-1254) return out.decode("utf-8") # Parse the modified task original = json.loads(sys.stdin.readline()) modified = sys.stdin.readline() # Return the unmodified modified task, so it is actually changed print(modified) modified = json.loads(modified) # Has a task with UDA been marked as completed? if ( (UDA_DUE in original or UDA_WAIT in original) and original["status"] != "completed" and modified["status"] == "completed" ): del original["modified"] if "start" in original: del original["start"] if UDA_DUE in original: original["due"] = calc(original[UDA_DUE]) if UDA_WAIT in original: original["wait"] = calc(original[UDA_WAIT]) original["status"] = "waiting" else: original["status"] = "pending" print("Created follow-up task") original["entry"] = modified["end"] original["uuid"] = str(uuid.uuid4()) # Wait for taskwarrior to finish, so we can safely `task import` the new # task. sys.stdout.flush() task_pid = os.getppid() if 0 < os.fork(): sys.exit(0) else: # Taskwarrior also waits for stdout to close try: os.close(sys.stdout.fileno()) except OSError: pass # Thrown because of closing stdout. Don't worry, that's fine. # Wait for taskwarrior to finish # while os.path.exists("/proc/%s" % str(task_pid)): time.sleep(1) # Import the follow-up task with tempfile.NamedTemporaryFile(mode="wt") as new_task: new_task.write(json.dumps(original)) new_task.flush() add = subprocess.Popen( ["task", "rc.verbose=nothing", "import", new_task.name], env=env, ) add.communicate()