diff options
| -rw-r--r-- | .editorconfig | 2 | ||||
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | .vscode/extensions.json | 5 | ||||
| -rw-r--r-- | makefile | 5 | ||||
| -rw-r--r-- | time.txt | 53 | ||||
| -rwxr-xr-x | time2tex.py | 200 | ||||
| -rw-r--r-- | timerep.tex | 11 | 
7 files changed, 270 insertions, 9 deletions
diff --git a/.editorconfig b/.editorconfig index 1bd7da9..cb52f84 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ indent_style = tab  end_of_line = lf  insert_final_newline = true -[*.{md,yml}] +[*.{md,yml,py}]  indent_style = space  indent_size = 2 @@ -25,9 +25,12 @@  *.d  *.nav  *.snm +*-SAVE-ERROR  # output files  *.pdf  !img/*.pdf  img/*.puml.pdf +# generated files +time.tex diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..e2e2139 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ +	"recommendations": [ +		"EditorConfig.EditorConfig" +	] +} @@ -9,3 +9,8 @@ LATEXMKFLAGS += -interaction=nonstopmode  	plantuml -tpdf $<  	mv $*.pdf $@ +%.tex: %.txt +	./time2tex.py $< > $@ + +timerep.pdf: time.tex + @@ -1,12 +1,49 @@ -# <who>: <when> <how long> <what> +loek: 2024-09-02 1h project meeting :: project kickoff +loek: 2024-09-02 45m project meeting  loek: 2024-09-02 1h4m repository scaffolding  loek: 2024-09-03 25m repository scaffolding -loek: 2024-09-03 1h30m repository scaffolding / engine repository, unit testing -loek: 2024-09-04 1h30m repository scaffolding / latex example code -loek: 2024-09-04 50m poc / dynamic library linking test example -loek: 2024-09-04 45m repository scaffolding / visual studio code latex configuration -loek: 2024-09-04 20m repository scaffolding / visual studio code cmake configuration -loek: 2024-09-05 15m repository scaffolding / additional latex contributing guidelines +loek: 2024-09-03 1h30m repository scaffolding :: engine repository, unit testing +loek: 2024-09-04 1h30m repository scaffolding :: latex example code +loek: 2024-09-04 50m poc :: dynamic library linking test example +loek: 2024-09-04 45m repository scaffolding :: visual studio code latex configuration +loek: 2024-09-04 20m repository scaffolding :: visual studio code cmake configuration +loek: 2024-09-05 15m repository scaffolding :: additional latex contributing guidelines +loek: 2024-09-05 1h40m project meeting +loek: 2024-09-05 1h24m time report script +loek: 2024-09-06 55m time report script +loek: 2024-09-09 30m feedback :: niels code style guide -# vim:ft=cfg +max: 2024-09-02 1h project meeting :: project kickoff +max: 2024-09-02 45m project meeting +max: 2024-09-04 1h30m installing and configuring latex +max: 2024-09-04 2h reading project info +max: 2024-09-05 20m discussing GitHub with Jaro +max: 2024-09-05 1h30m first group meeting + +wouter: 2024-09-02 1h project meeting :: project kickoff +wouter: 2024-09-02 45m project meeting +wouter: 2024-09-03 1h reading project info +wouter: 2024-09-04 1h setting up working environment +wouter: 2024-09-04 1h30m researching 3rd party tools +wouter: 2024-09-05 1h30m first group meeting +wouter: 2024-09-05 20m setting up research document +wouter: 2024-09-05 1h researching game enigne + +niels: 2024-09-02 1h project meeting :: project kickoff +niels: 2024-09-02 45m project meeting +niels: 2024-09-03 1h reading project info +niels: 2024-09-04 30m validation app ideas +niels: 2024-09-04 2h setting up vimtex on neovim +niels: 2024-09-04 1h researching different code styles and c++ guidelines +niels: 2024-09-05 1h30m first group meeting +niels: 2024-09-06 2h added c++ guidelines in the contributing.md +jaro: 2024-09-02 1h project meeting :: project kickoff +jaro: 2024-09-02 45m project meeting +jaro: 2024-09-02 1h45m scrumboard(miro), installing dependencies +jaro: 2024-09-04 4h15m latex environment, code environment and project plan +jaro: 2024-09-05 2h preparing meeting, project plan, discussing github with max +jaro: 2024-09-05 1h30m project meeting +jaro: 2024-09-05 1h documentatie review and improving environment + +# vim:ft=cfg diff --git a/time2tex.py b/time2tex.py new file mode 100755 index 0000000..fe3091f --- /dev/null +++ b/time2tex.py @@ -0,0 +1,200 @@ +#!/bin/python3 +import sys +from datetime import datetime, timedelta + +def fmt_duration(sec): +  mins = (sec + 59) // 60 # integer divide, round up +  out = [] + +  if mins == 0: +    return "--" + +  hour = mins // 60 +  if hour > 0: +    out.append("%02dh" % (hour, )) +    mins = mins % 60 + +  out.append("%02dm" % (mins, )) + +  return "\\,".join(out) + +def fmt_percentage(fac): +  return f"{{\\footnotesize\\itshape({round(fac * 100)}\\%)}}" + +def fmt_member_overview(times): +  # calculations +  out = "" +  members = {} +  total_time = 0 +  for time in times: +    if not time["name"] in members: +      members[time["name"]] = 0 +    members[time["name"]] += time["duration"] +    total_time += time["duration"] + +  # begin table +  out += r"\begin{table}\centering" +  out += r"\begin{tabular}{lr@{~}l}\toprule" +  out += r"\textbf{Member} & \textbf{Tracked} &\\\midrule{}" + +  # member overview +  for name, tracked in members.items(): +    out += f"{name} & {fmt_duration(tracked)} & {fmt_percentage(tracked / total_time)}\\\\" +  out += r"\midrule{}" + +  # sum +  out += f"&{fmt_duration(total_time)}&\\\\" + +  # end table +  out += r"\bottomrule\end{tabular}" +  out += r"\caption{Tracked time per group member}\label{tab:time-member}" +  out += r"\end{table}" + +  return out + +def fmt_weekly_overview(times): +  # calculations +  out = "" +  weeks = [] +  member_totals = {} +  total_time = sum(time["duration"] for time in times) +  members = list(set(time["name"] for time in times)) +  time_start = min(time["date"] for time in times) +  time_end = max(time["date"] for time in times) +  week_start = time_start - timedelta(days=time_start.weekday()) # round down to nearest monday +  week_end = time_end + timedelta(days=7-time_end.weekday()) + +  week = week_start +  week_num = 1 +  while week < week_end: +    week_times = [time for time in times if time["date"] >= week and time["date"] < (week + timedelta(days=7))] + +    week_entry = { +      "num": week_num, +      "members": {}, +      "total": sum(time["duration"] for time in week_times) +    } + +    for member in members: +      week_entry["members"][member] = sum(time["duration"] for time in week_times if time["name"] == member) + +    weeks.append(week_entry) +    week_num += 1 +    week += timedelta(days=7) +  for member in members: +    member_totals[member] = sum(time["duration"] for time in times if time["name"] == member) + +  # begin table +  out += r"\begin{table}\centering" +  out += f"\\begin{{tabular}}{{l{'r@{~}l' * len(members)}@{{\\qquad}}r}}\\toprule" +  out += r"\textbf{\#}" +  for member in members: +    out += f"&\\textbf{{{member}}}&" +  out += r"&\textbf{Subtotal}\\\midrule{}" + +  for entry in weeks: +    out += f"{entry['num']}" +    for member in members: +      out += f"&{fmt_duration(entry['members'][member])}&{fmt_percentage(entry['members'][member] / entry['total'])}" +    out += f"&{fmt_duration(entry['total'])}\\\\" + +  out += r"\midrule{}" +  for member in members: +    out += f"&{fmt_duration(member_totals[member])}&{fmt_percentage(member_totals[member] / total_time)}" +  out += f"&{fmt_duration(total_time)}\\\\" + +  # end table +  out += r"\bottomrule\end{tabular}" +  out += r"\caption{Tracked time per week}\label{tab:time-weekly}" +  out += r"\end{table}" + +  return out + +def duration2secs(duration): +  out = 0 # output (seconds) +  cur = 0 # current figure (unknown) +  for c in duration: +    if c.isdigit(): +      cur = cur * 10 + int(c) +      continue +    if c == "h": +      out += cur * 3600 +      cur = 0 +      continue +    if c == "m": +      out += cur * 60 +      cur = 0 +      continue +    if c == "s": +      out += cur * 1 +      cur = 0 +      continue + +    raise Exception("invalid duration format") +  if cur != 0: raise Exception("invalid duration format") +  return out + +def line2data(line): +  # parse fields from input string +  data = {} +  next = line.find(':') +  data["name"] = line[0:next].strip() +  line = line[next+1:].strip() +  next = line.find(' ') +  data["date"] = line[0:next].strip() +  line = line[next+1:].strip() +  next = line.find(' ') +  data["duration"] = line[0:next].strip() +  line = line[next+1:].strip() +  data["description"] = line + +  # deserialize parsed fields +  data["name"] = data["name"].title() +  data["date"] = datetime.strptime(data["date"], '%Y-%m-%d') +  data["duration"] = duration2secs(data["duration"]) +  data["description"] = [el.strip() for el in data["description"].split("::")] + +  return data + +def parse(content): +  # split content at newlines +  lines = content.split("\n") +  out = [] +  for i, line in enumerate(lines): +    line = line.strip() +    if line.startswith("#"): continue +    if len(line) == 0: continue + +    try: out.append(line2data(line)) +    except Exception as e: raise Exception(f"line {i+1}: {e}") +  return out + +def fmt(times): +  # TODO: Task overview +  print(f""" +\\section{{Overviews}}\n +\\subsection{{Members}}\n +{fmt_member_overview(times)} +\\subsection{{Weekly}}\n +{fmt_weekly_overview(times)} +""") + +def main(): +  input_file = sys.argv[1] +  content = "" +  with open(input_file, "r") as file: +    content = file.read() + +  try: parsed = parse(content) +  except Exception as e: +    print(f"{input_file}: {e}") +    exit(1) + +  fmt(parsed) + +if __name__ == "__main__": +  if len(sys.argv) != 2: +    print("usage: time2tex <input>") +    exit(1) +  main() + diff --git a/timerep.tex b/timerep.tex new file mode 100644 index 0000000..7590217 --- /dev/null +++ b/timerep.tex @@ -0,0 +1,11 @@ +\documentclass{projdoc} +\input{meta.tex} + +\title{Time Report} + +\begin{document} + +\input{time.tex} + +\end{document} +  |