-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathResolveTracker.functions
471 lines (463 loc) · 15.3 KB
/
ResolveTracker.functions
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#!/bin/bash -
#
# Copyright (C) 2014 cstackpole
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT file for full notice.
#
#
#
# Please see ResolveTracker.sh for the main program.
# ResolveTracer.functions is just the support functions.
#
# The fields tracked are: Date, StartTime, TimeInvested, Tags, Score, Notes
# Date: The day of the event. (20140128)
# StartTime: When the event began in HH:MM format (eg: 15:30)
# TimeInvested: The amount of time invested in the event in minutes. (eg: 70)
# Tags: Originally "Title", this field allows for comma seperated list of tags
# for sorting, statistics, and whatnot.
# Score: Was the effort and time invested worth it? Feel free to leave this 0
# I am experimenting with its usefulness.
# Notes: Any details you might want to associate with this event.
#
# Exit Codes:
# 1: Function usage called
# 2: Wrong binary
# 3: Need version 3 or better of sqlite
# 4: User bailed on creating a new database
# 5: Found a database file that does not appear to be a SQLite 3.x database
# 6: Found a file the user doesn't want to overwrite.
# 7: Found a database without the RslvTrkr table
# 8: Database entry failed
#
# Quick notes on stuff I want to remember:
# Get the last row
# $sqliteapp $rtdb "select max(id) from 'RslvTrkr'"
#
#
# A note about the functions.
# I know a lot of them are very similar and I could probably save a few cpu
# cycles cramming them together, but that was part of the reason for this
# rewrite. The first revision of this program tried to do everything in a single
# loop and it just got nasty to maintain and debug. Simple functions for me...
# at least for now... :-)
#
################################################################################
# Usage Function
################################################################################
function usage (){
echo "Please pass the proper parameters."
echo "-c option creates a new db."
echo "-d is the full path to the sqlite database."
echo " Default: ~/.ResolveTracker/ResolveTracker.db"
echo "-h will print this menu"
echo "-j # jumps to the selection number."
echo "-s is the full path to sqlite."
exit 1
}
################################################################################
# Test if a variable is a positive number
################################################################################
function TestNumber() {
# swiped code from jilles at
# http://stackoverflow.com/questions/806906/how-do-i-test-if-a-variable-is-a-number-in-bash
case ${1} in
''|*[!0-9]*) echo 1 ;;
*) echo 0 ;;
esac
}
################################################################################
# Non Number Error. Tired of updating so many places.
################################################################################
function NonNumError(){
echo "${1} is not a positive number."
}
################################################################################
# Code for checking a year was getting a bit long. Moving it into it's own function.
################################################################################
function CheckUserYear(){
yearloop=0
while [ "${yearloop}" == "0" ]
do
echo "Please enter the date you wish to use."
echo "YYYY-MM-DD"
read storedate
chkyear=`echo ${storedate} | cut -d '-' -f1`
chkmonth=`echo ${storedate} | cut -d '-' -f2`
chkday=`echo ${storedate} | cut -d '-' -f3`
if [ "`TestNumber ${chkyear}`" == "1" ]
then
NonNumError ${chkyear}
elif [ "${chkyear}" -lt "1970" ]
then
echo "${chkyear} is a invalid year. Should be greater then 1970."
elif [ "`TestNumber ${chkmonth}`" == "1" ]
then
NonNumError ${chkmonth}
elif [ "${chkmonth}" -eq "0" -o "${chkmonth}" -gt "12" ]
then
echo "${chkmonth} is a invalid month. Should be between 1 and 12."
elif [ "`TestNumber ${chkday}`" == "1" ]
then
NonNumError ${chkday}
elif [ "${chkday}" -eq "0" -o "${chkday}" -gt "31" ]
then
echo "${chkday} is a invalid day. Should be between 1 and 31."
else
yearloop=1
fi
done
}
################################################################################
# Add Event Menu
################################################################################
function AddEvent() {
echo "Adding an event!"
# Get the date of the event
dloop=0
storedate=''
while [ ${dloop} -ne 1 ]
do
echo "Do you want to use todays date? [y/n]"
read usersdate
if [ "${usersdate}" == "y" -o "${usersdate}" == "Y" ]
then
storedate=`date '+%F'`
dloop=1
elif [ "${usersdate}" == "n" -o "${usersdate}" == "N" ]
then
CheckUserYear
dloop=1
else
echo "I don't understand that input. Please try again."
fi
done
# Get the time of the event
timeloop=0
while [ "${timeloop}" == "0" ]
do
echo "What time did you start the event?"
echo "HH:MM in ISO 8601 24hr format."
read userstime
chkhour=`echo ${userstime} | cut -d ':' -f1`
chkminute=`echo ${userstime} | cut -d ':' -f2`
# First check if we have a valid format of xx:xx.
if [ -z "`echo ${userstime} | grep :`" ]
then
echo "${userstime} is not a valid HH:MM format. Please try again."
# Then check if we have a valid number.
elif [ "`TestNumber ${chkhour}`" == "1" ]
then
NonNumError ${chkhour}
# Then check if the number is greater then 23 (24th hour is not valid).
elif [ "${chkhour}" -gt "23" ]
then
echo "${chkhour} is a invalid hour. Should be between 00 and 24."
# Then check if we have a valid minute.
elif [ "`TestNumber ${chkminute}`" == "1" ]
then
NonNumError ${chkminute}
# Then check if the number is greater then 59 (60th minute is not valid).
elif [ "${chkminute}" -gt "59" ]
then
echo "${chkminute} is a invalid minute. Should be between 00 and 60."
# Looks like everything is good! Break the loop and keep the result.
else
timeloop=1
# Format the hour/minute in case the user inputs 1:3 instead of 01:03
userstime=`printf %02d:%02d ${chkhour} ${chkminute}`
fi
done
storedate=`echo ${storedate} ${userstime}`
# Get length of time
timelenloop=0
while [ "${timelenloop}" == "0" ]
do
echo "How long did you spend at the event."
read userstimelength
if [ "`TestNumber ${userstimelength}`" == "1" ]
then
NonNumError ${userstimelength}
else
timelenloop=1
fi
done
# Get the list of tags
echo "Please enter a comma seperate list of tags."
read userstags
# Get the score
scoreloop=0
while [ "${scoreloop}" == "0" ]
do
echo "Please enter a score."
read usersscore
isneg=0
if [ "`echo ${usersscore:0:1}`" == "-" ]
then
isneg=1
usersscore=${usersscore:1}
fi
if [ "`TestNumber ${usersscore}`" == "1" ]
then
NonNumError ${usersscore}
else
scoreloop=1
fi
if [ "${isneg}" == "1" ]
then
usersscore=`echo -${usersscore}`
fi
done
# Get the note
echo "Please enter a note."
read usersnote
# Verify we don't have any single quotes as that messes with SQLite.
# Instead we need to enter two single quotes. Using the hex escapes
# ( \x27 == ' ) as getting single quotes to work consistently across a
# few different platforms seems to be an effort in insanity.
if [ ! -z "`echo ${usersnote} | grep "'"`" ]
then
# Found a single quote somewhere.
usersnote=`echo ${usersnote} | sed -e 's/\x27/\x27\x27/g'`
fi
${sqliteapp} ${rtdb} "INSERT into 'RslvTrkr' (date,time,tags,score,notes) VALUES ('${storedate}',${userstimelength},'${userstags}',${usersscore},'${usersnote}')"
if [ "`echo $?`" -ne "0" ]
then
echo "Ack! Database entry failed. Here is what I tried to do."
echo "${sqliteapp} ${rtdb} \"INSERT into 'RslvTrkr' (date,time,tags,score,notes) VALUES ('${storedate}',${userstimelength},'${userstags}',${usersscore},'${usersnote}')\""
exit 8
fi
}
################################################################################
# Display Events
################################################################################
function DisplayEvents(){
# Yeah, I know. Not very pretty output. Need to bump this on the todo.
${sqliteapp} ${rtdb} "select * from 'RslvTrkr'"
}
################################################################################
# Calculate average score
################################################################################
function CalcAvgScore(){
calavg=0
caltot=0
for i in `${sqliteapp} ${rtdb} "select score from 'RslvTrkr'"`
do
# track total amount of records
caltot=$((${caltot}+1))
calavg=$((${calavg}+${i}))
done
echo ""
echo "Total score over ${caltot} events is ${calavg}."
calavg=$((${calavg}/${caltot}))
echo "Average score is ${calavg}."
echo ""
}
################################################################################
# Calculate average time
################################################################################
function CalcAvgTime(){
timeavg=0
timetot=0
for i in `${sqliteapp} ${rtdb} "select time from 'RslvTrkr'"`
do
# track total amount of records
timetot=$((${timetot}+1))
timeavg=$((${timeavg}+${i}))
done
timeavg=$((${timeavg}/${timetot}))
echo "Average amount of time spent per event is ${timeavg} minutes."
echo ""
}
################################################################################
# Calculate Morning/Afternoon frequency
################################################################################
function CalcAMPMStats(){
amavg=0
pmavg=0
# select the date, cut only the time field, cut only the hour.
for i in `${sqliteapp} ${rtdb} "select date from 'RslvTrkr'" \
| cut -d' ' -f 2 | cut -d ':' -f 1`
do
case $i in
# Grab all numbers between 1-9, 01-09, 10, 11
[0-9] | 0[0-9] | 1[01]) amavg=$((${amavg}+1)) ;;
# Grab all numbers between 11-19, 20-23
1[2-9] | 2[0-3]) pmavg=$((${pmavg}+1)) ;;
# Catch all for something we don't recognize
*) echo "Can not calculate ${i} average. Ignoring." 1>&2 ;;
esac
done
echo "Morning frequency : ${amavg}"
echo "Afternoon frequency : ${pmavg}"
echo ""
}
################################################################################
# Calculate common day of the week.
################################################################################
function CalcDOWStats(){
sunavg=0
monavg=0
tueavg=0
wedavg=0
thuavg=0
friavg=0
satavg=0
# select the date, cut only the date field.
for i in `${sqliteapp} ${rtdb} "select date from 'RslvTrkr'" \
| cut -d' ' -f 1`
do
dowtmp=`date -d $i +%a`
case $dowtmp in
Sun) sunavg=$((${sunavg}+1));;
Mon) monavg=$((${monavg}+1));;
Tue) tueavg=$((${tueavg}+1));;
Wed) wedavg=$((${wedavg}+1));;
Thu) thuavg=$((${thuavg}+1));;
Fri) friavg=$((${friavg}+1));;
Sat) satavg=$((${satavg}+1));;
*) echo "Can not calculate date ${i}. Ignoring." 1>&2 ;;
esac
done
echo "Day of Week Frequency:"
echo " Sun: ${sunavg}"
echo " Mon: ${monavg}"
echo " Tue: ${tueavg}"
echo " Wed: ${wedavg}"
echo " Thu: ${thuavg}"
echo " Fri: ${friavg}"
echo " Sat: ${satavg}"
echo ""
}
################################################################################
# Calculate the frequency of the tags by year.
################################################################################
function CalcTagStats(){
# This is the nastiest of the code that I am porting over. This is /after/
# I have cleaned it up too! I am not going to lie. I could use some help
# tidying this up.
#
# First we need to set our IFS for dealing with spaces
tmpIFS=`echo ${IFS}`
IFS=`echo -e "\012\015"`
# Blank our header variable
yearheader=''
yeartotals=''
yearalltotals=0
yeartmpount=''
# Create a array of years. Pull from db, cut only the year, sort/uniq
yeararray=(`${sqliteapp} ${rtdb} "select date from 'RslvTrkr'"\
| cut -d"-" -f1 | sort -u`)
# Set variables for colors
greencolor="\x1b[32;01m"
redcolor="\x1b[31;01m"
resetcolor="\x1b[39;49;00m"
# Build our header of years first.
for j in ${yeararray[@]}
do
# Create a year header banner.
yearheader=`echo -e "${yearheader}${j}\t| "`
# Previously, I had a crazy complex formula with a half-
# dozen variables to calculate total events every year.
# This is much simpler.
yeartmpcount=`${sqliteapp} ${rtdb} "select date from 'RslvTrkr' where date like '${j}%'" | wc -l`
yeartotals=`echo -e "${yeartotals}${yeartmpcount}\t| "`
yearalltotals=$((${yearalltotals}+${yeartmpcount}))
done
yearheader=`echo -e "${yearheader}Total"`
echo ${yearheader}
# Loop through all of the tags first so we can build a complete list
for i in `${sqliteapp} ${rtdb} "select tags from 'RslvTrkr'"\
| sed -e 's/, /\n/g' -e 's/,/\n/g' | sort -u`
do
# Reset temp variables.
tmpcount=''
prevcount=0
totalcount=0
# Now cycle through the years so we know how many tags per year
for j in ${yeararray[@]}
do
# Find all elements in the db that match both the year
# and the tag.
dbcmdarray=(`${sqliteapp} ${rtdb}\
"select id from 'RslvTrkr' where date like '${j}%' and\
tags like '%${i}%'"`)
if [ "${#dbcmdarray[@]}" -lt "${prevcount}" ]
then
tmpcount=`echo -e "${tmpcount}${redcolor}${#dbcmdarray[@]}${resetcolor}\t| "`
elif [ "${#dbcmdarray[@]}" -gt "${prevcount}" ]
then
tmpcount=`echo -e "${tmpcount}${greencolor}${#dbcmdarray[@]}${resetcolor}\t| "`
else
tmpcount=`echo -e "${tmpcount}${#dbcmdarray[@]}\t| "`
fi
prevcount=${#dbcmdarray[@]}
totalcount=$((${totalcount}+${#dbcmdarray[@]}))
done
echo -e "${tmpcount}${totalcount}\t| ${i}"
done
echo ""
echo "Total number of recorded events per year."
echo ${yearheader}
echo -e "${yeartotals}${yearalltotals}"
# Reset our IFS
IFS=`echo $tmpIFS`
}
################################################################################
# Display Stats
################################################################################
function DisplayStats(){
CalcAvgScore
CalcAvgTime
CalcAMPMStats
CalcDOWStats
CalcTagStats
}
################################################################################
# Main menu
################################################################################
function menu() {
echo ""
echo "Greetings! Welcome to Resolve Tracker."
echo "This is a simple program to help track your progress on any event"
echo "you wish to log and record your activty on."
echo ""
echo "Please select an option to begin."
echo ""
loop=0
while [ ${loop} -ne 1 ]
do
echo "Enter 1 to create a new event."
echo "Enter 2 to view all events."
echo "Enter 3 to view stats."
#echo "Enter 4 to view stats w/ calendar."
#echo "Enter 5 to view calendar stats only."
echo "Enter q to quit (exit 0)."
if [ ! -z ${1} ]
then
userchoice=${1}
else
read userchoice
fi
case "${userchoice}" in
q|Q) echo "Quiting." ; exit 0 ;;
1) AddEvent; loop=1 ;;
2) DisplayEvents; loop=1 ;;
3) DisplayStats; loop=1 ;;
*) echo "Not a valid option." ;;
esac
done
}