-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathlogtime
More file actions
191 lines (151 loc) · 6.52 KB
/
logtime
File metadata and controls
191 lines (151 loc) · 6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env python
"""
CLI utility for logging the time you spend on things.
Usage: `logtime --help`
"""
from __future__ import print_function
from builtins import str
from builtins import range
from datetime import date, datetime, timedelta
import os
import re
import click
import logtime_cli.logfile_data as logfile_data
import logtime_cli.logfile_io as logfile_io
import logtime_cli.logtime_config as logtime_config
@click.group(context_settings=dict(help_option_names=['-h', '--help']))
def entry_point():
"""logtime"""
@entry_point.command()
@click.option('--previous', '-p', type=int, help='Use the logfile X days in the past.')
def calc(previous):
"""Print calculated time for the day.
Records beginning in `*` are considered "non-work hours".
"""
if previous:
logdate = (date.today() - timedelta(days=previous))
else:
logdate = date.today()
if not logfile_io.exists(logdate):
print("No logfile exists for " + str(logdate) + ".")
return
log_data = logfile_io.load_logfile(logdate)
all_hours = sum([x.duration() for x in log_data.entries])
work_hours = sum([x.duration() for x in log_data.entries if x.task[:1] == '*'])
non_work_hours = sum([x.duration() for x in log_data.entries if x.task[:1] != '*'])
print(logdate)
print("All Hours: " + str(all_hours))
print("Non-Work Hours: " + str(work_hours))
print("Work Hours: " + str(non_work_hours))
@entry_point.command()
@click.option('--previous', '-p', type=int, help='Use the logfile X days in the past.')
def count_tasks(previous):
"""Print number of tasks logged for the given day."""
if previous:
logdate = (date.today() - timedelta(days=previous))
else:
logdate = date.today()
if not logfile_io.exists(logdate):
print("No logfile exists for " + str(logdate) + ".")
return
log_data = logfile_io.load_logfile(logdate)
print(len(log_data.entries))
@entry_point.command()
def list(): #pylint: disable=redefined-builtin
"""List existing logfiles, along with how many days back it is (for use with `-p`)"""
log_file_directory = logtime_config.get_option('DEFAULT', 'logfile_directory')
iso_date_regex = r'[0-9]{4}-[0-9]{2}-[0-9]{2}\.md'
file_names = [f for f in os.listdir(log_file_directory)
if re.match(iso_date_regex, f)
and not os.path.isdir(os.path.join(log_file_directory, f))]
for name in file_names:
file_date = datetime.strptime(name, '%Y-%m-%d.md')
delta = datetime.today() - file_date
print('{date} - {days}'.format(days=delta.days, date=name))
@entry_point.command()
@click.option('--previous', '-p', type=int,
help='Use the week X weeks in the past; Monday begins the week.')
def summarize_week(previous):
"""Print Summary section for every day of the chosen week."""
if previous:
logdate = (date.today() - timedelta(weeks=previous))
else:
logdate = date.today()
first_day_delta = 0 - logdate.weekday() # 0 is Monday
last_day_delta = 7 - logdate.weekday() # 7 is the number of weekdays
week_range = range(first_day_delta, last_day_delta)
# Center the list on this week; start on Monday
weekdays = [(logdate + timedelta(days=x)) for x in week_range]
for day in weekdays:
if logfile_io.exists(day):
log_data = logfile_io.load_logfile(day)
notes = logfile_data.get_notes_data(log_data)
notes_sections = notes.get_subsections()
summaries = [x.full_text for x in notes_sections if x.name == 'Summary']
if len(summaries) > 1:
raise NotImplementedError(
'Found more than one Summary for {}. Combine them.'.format(day))
if len(summaries) == 1:
print('## {}'.format(day))
print(summaries[0])
print('')
def _get_sections_at_depth(notes_sections, current_depth, depth_to_search):
"""Only get sections at *exactly* the given depth_to_search"""
sections_at_depth = []
if current_depth == depth_to_search:
sections_at_depth = notes_sections
else:
for section in notes_sections:
subsections = section.get_subsections()
sections_at_depth.extend(
_get_sections_at_depth(subsections, current_depth+1, depth_to_search)
)
return sections_at_depth
def _get_sections_all_depths(notes_sections):
"""Get every single section, at any depth"""
sections = notes_sections
for section in notes_sections:
subsections = section.get_subsections()
sections.extend(
_get_sections_all_depths(subsections)
)
return sections
@entry_point.command()
@click.argument('section_name')
@click.option('--depth', '-d', type=int,
help='Depth of subsection to search.'
' Will only search this depth. Default 1.')
@click.option('--all-depths', '-a', is_flag=True,
help='Indicates searching all depths at once.'
' Useful for finding sections at unknown depths.')
def section_report(section_name, depth, all_depths):
"""
Find all instances of the given section_name at the given depth, for all logfiles.
Print that section's contents.
"""
if not depth:
depth = 1
log_file_directory = logtime_config.get_option('DEFAULT', 'logfile_directory')
iso_date_regex = r'[0-9]{4}-[0-9]{2}-[0-9]{2}\.md'
file_names = [f for f in os.listdir(log_file_directory)
if re.match(iso_date_regex, f)
and not os.path.isdir(os.path.join(log_file_directory, f))]
for name in file_names:
file_date = datetime.strptime(name, '%Y-%m-%d.md').date()
log_data = logfile_io.load_logfile(file_date)
notes = logfile_data.get_notes_data(log_data)
notes_sections = notes.get_subsections()
if all_depths:
sections_to_search = _get_sections_all_depths(notes_sections)
else:
sections_to_search = _get_sections_at_depth(notes_sections, 1, depth)
found_sections = [x.full_text for x in sections_to_search if x.name == section_name]
if len(found_sections) > 1:
raise NotImplementedError(
'Found two or more Sections with that name for {}. Combine them.'.format(file_date))
if len(found_sections) == 1:
print('## {}'.format(file_date))
print(found_sections[0])
print('')
if __name__ == '__main__':
entry_point() #pylint: disable=no-value-for-parameter