111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
|
#!/usr/bin/env python
|
||
|
import datetime
|
||
|
import json
|
||
|
import re
|
||
|
import sys
|
||
|
import subprocess
|
||
|
from taskw import TaskWarrior
|
||
|
|
||
|
TIME_FORMAT = '%Y%m%dT%H%M%SZ'
|
||
|
UDA_KEY = 'dailyactivetime'
|
||
|
|
||
|
w = TaskWarrior()
|
||
|
config = w.load_config()
|
||
|
if ('max_active_tasks' in config):
|
||
|
MAX_ACTIVE = int(config['max_active_tasks'])
|
||
|
else:
|
||
|
MAX_ACTIVE = 1
|
||
|
|
||
|
ISO8601DURATION = re.compile(
|
||
|
"P((\d*)Y)?((\d*)M)?((\d*)D)?T((\d*)H)?((\d*)M)?((\d*)S)?")
|
||
|
|
||
|
# Convert duration string into a timedelta object.
|
||
|
# Valid formats for duration_str include
|
||
|
# - int (in seconds)
|
||
|
# - string ending in seconds e.g "123seconds"
|
||
|
# - ISO-8601: e.g. "PT1H10M31S"
|
||
|
def duration_str_to_time_delta(duration_str):
|
||
|
if (duration_str.startswith("P")):
|
||
|
match = ISO8601DURATION.match(duration_str)
|
||
|
if (match):
|
||
|
year = match.group(2)
|
||
|
month = match.group(4)
|
||
|
day = match.group(6)
|
||
|
hour = match.group(8)
|
||
|
minute = match.group(10)
|
||
|
second = match.group(12)
|
||
|
value = 0
|
||
|
if (second):
|
||
|
value += int(second)
|
||
|
if (minute):
|
||
|
value += int(minute)*60
|
||
|
if (hour):
|
||
|
value += int(hour)*3600
|
||
|
if (day):
|
||
|
value += int(day)*3600*24
|
||
|
if (month):
|
||
|
# Assume a month is 30 days for now.
|
||
|
value += int(month)*3600*24*30
|
||
|
if (year):
|
||
|
# Assume a year is 365 days for now.
|
||
|
value += int(year)*3600*24*365
|
||
|
else:
|
||
|
value = int(duration_str)
|
||
|
elif (duration_str.endswith("seconds")):
|
||
|
value = int(duration_str.rstrip("seconds"))
|
||
|
else:
|
||
|
value = int(duration_str)
|
||
|
return datetime.timedelta(seconds=value)
|
||
|
|
||
|
def main():
|
||
|
original = json.loads(sys.stdin.readline())
|
||
|
modified = json.loads(sys.stdin.readline())
|
||
|
|
||
|
# An inactive task has just been started.
|
||
|
if 'start' in modified and 'start' not in original:
|
||
|
# Check if `task +ACTIVE count` is greater than MAX_ACTIVE. If so
|
||
|
# prevent this task from starting.
|
||
|
p = subprocess.Popen(
|
||
|
['task', '+ACTIVE', 'status:pending', 'count', 'rc.verbose:off'],
|
||
|
stdout=subprocess.PIPE)
|
||
|
out, err = p.communicate()
|
||
|
count = int(out.rstrip())
|
||
|
if count >= MAX_ACTIVE:
|
||
|
print("Only %d task(s) can be active at a time. "
|
||
|
"See 'max_active_tasks' in .taskrc." % (MAX_ACTIVE))
|
||
|
sys.exit(1)
|
||
|
|
||
|
# An active task has just been stopped.
|
||
|
if 'start' in original and 'start' not in modified:
|
||
|
# Let's see how much time has elapsed
|
||
|
start = datetime.datetime.strptime(original['start'], TIME_FORMAT)
|
||
|
end = datetime.datetime.utcnow()
|
||
|
|
||
|
if UDA_KEY not in modified:
|
||
|
modified[UDA_KEY] = 0
|
||
|
|
||
|
this_duration = (end - start)
|
||
|
total_duration = (
|
||
|
this_duration
|
||
|
+ duration_str_to_time_delta(str(modified[UDA_KEY]))
|
||
|
)
|
||
|
print(
|
||
|
"Daily Time Tracked: %s (%s in this instance)" % (
|
||
|
total_duration,
|
||
|
this_duration,
|
||
|
)
|
||
|
)
|
||
|
modified[UDA_KEY] = str(int(
|
||
|
total_duration.days * (60 * 60 * 24) + total_duration.seconds
|
||
|
)) + "seconds"
|
||
|
|
||
|
return json.dumps(modified, separators=(',',':'))
|
||
|
|
||
|
|
||
|
def cmdline():
|
||
|
sys.stdout.write(main())
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
cmdline()
|