https://www.marcelpost.com/wiki/index.php?title=Worklog&feed=atom&action=history
Worklog - Revision history
2024-03-29T11:26:54Z
Revision history for this page on the wiki
MediaWiki 1.39.5
https://www.marcelpost.com/wiki/index.php?title=Worklog&diff=16&oldid=prev
Admin at 02:02, 30 August 2011
2011-08-30T02:02:10Z
<p></p>
<p><b>New page</b></p><div>Worklog<br />
<br />
<pre><br />
#!/bin/sh<br />
<br />
# worklog<br />
#<br />
# (C)2010 Marcel Post. All Rights Reserved<br />
# Last modified: 22 December 2010 (optimised for Bashv4, possibly Dash too)<br />
#<br />
# This script tracks changes made to files in a target directory.<br />
# The way it works is that it will calculate the time between when<br />
# a file was first edited (poll every 5 minutes) and when the last<br />
# change was made (assuming that no edits were made for 60 minutes).<br />
#<br />
# For permissions, the cron executer must own the 'worklog' file<br />
#<br />
# Example cron entry:<br />
#<br />
# */5 * * * * /usr/local/bin/worklog /var/www/attendance [path-to-worklog-file]<br />
#<br />
#<br />
# BUGS<br />
#<br />
# once had that a file could not be 'stat' by worklog, as if it was locked by<br />
# vi when I was writing back the changes or so..<br />
#<br />
#<br />
# TODO<br />
# - add a --help switch with version number etc<br />
#<br />
<br />
# User Variables:<br />
<br />
WL=worklog # name and location of the worklog file<br />
TMPDIR=/tmp # a temp directory that we can safely write to<br />
IDLEMINS=20 # when we should consider an edit to be finished<br />
DEBUG=0 # turn on for more verbose output<br />
<br />
<br />
# --- script follows ---<br />
<br />
if test $# -lt 1<br />
then<br />
<br />
# no arguments provided<br />
<br />
echo "Syntax: worklog [path-to-worklog-file]"<br />
exit 1<br />
fi<br />
<br />
if test $# -lt 2<br />
then<br />
# one argument provided. Can either be:<br />
# -show to display the worklog file, or<br />
# to find changes in the 'path' files and directories and<br />
# write the updates to the worklog file located in 'path'<br />
<br />
<br />
if test $1 = "-show"<br />
then<br />
# use current directory to find the workdir file<br />
DEBUG=2<br />
<br />
# set projectdir<br />
PROJECTDIR=`pwd`<br />
<br />
# set worklog file<br />
WORKLOG=$PROJECTDIR/$WL<br />
<br />
else<br />
<br />
# using project directory as specified with argument 1<br />
# also use the path directory to find the worklog file<br />
<br />
if test -d $1<br />
then<br />
# project dir exists ok<br />
PROJECTDIR=$1<br />
<br />
# set worklog file<br />
WORKLOG=$PROJECTDIR/$WL<br />
<br />
else<br />
echo "Project directory does not exist"<br />
exit 1<br />
fi<br />
fi<br />
<br />
else<br />
<br />
# at least two arguments provided. Can either be:<br />
# -show to display the worklog file in the<br />
# specified 'path'<br />
# update worklog in a possibly different<br />
# location than the 'path' specification<br />
<br />
<br />
if test $1 = "-show"<br />
then<br />
# use second argument to find the worklog file<br />
DEBUG=2<br />
<br />
# set location of worklog file<br />
<br />
if test -f $2<br />
then<br />
# worklog file exists ok<br />
WORKLOG=$2<br />
else<br />
echo "Could not access worklog file at $2"<br />
echo "Please create a worklog file by running an update first"<br />
echo "Syntax: worklog [path-to-worklog-file]"<br />
exit 1<br />
fi<br />
<br />
else<br />
# test if arguments link to an existing directory and a worklogfile<br />
<br />
if test -d $1<br />
then<br />
# project dir exists ok<br />
PROJECTDIR=$1<br />
else<br />
echo "Project directory does not exist"<br />
exit 1<br />
fi<br />
<br />
# just set the name and location of the worklog file to the second argument<br />
# testing if it exists happens further in the script<br />
WORKLOG=$2<br />
<br />
fi<br />
<br />
fi<br />
<br />
<br />
<br />
<br />
# uncomment for debugging purposes<br />
#if test $# -eq 2<br />
#then<br />
# if test $2 = "-d"<br />
# then<br />
# DEBUG=1<br />
# echo<br />
# fi<br />
# if test $2 = "-show"<br />
# then<br />
# # show real dates instead of timestamps<br />
# DEBUG=2<br />
# echo<br />
# fi<br />
#fi<br />
<br />
# test if project directory exists<br />
if ! test -d $PROJECTDIR<br />
then<br />
echo "Project directory not found"<br />
exit 1<br />
fi<br />
<br />
<br />
# test if logfile exists<br />
if test -f $WORKLOG<br />
then<br />
<br />
# -- check existing worklog file --<br />
<br />
# check if worklog has a filesize greater than zero<br />
if test -s $WORKLOG<br />
then<br />
<br />
# check if we can recognise the header of the file<br />
WORKLOG_HEADER=`head -n 1 $WORKLOG`<br />
<br />
if test `echo $WORKLOG_HEADER | awk -F : '{print $1}'` = "LAST-CHANGED" > /dev/null 2>&1<br />
then<br />
NEWFILE=0<br />
else<br />
echo "The worklog file seems corrupt. Please check."<br />
echo "if possible delete $WORKLOG"<br />
exit 1<br />
fi<br />
<br />
else<br />
<br />
NEWFILE=1<br />
<br />
fi<br />
<br />
# check permissions<br />
<br />
if ! test -O $WORKLOG<br />
then<br />
if test $DEBUG != 2<br />
then<br />
echo "File $WORKLOG is not owned by the user running this script! Exiting now."<br />
exit 1<br />
fi<br />
fi<br />
<br />
<br />
# check if we have write permissions to the worklog file<br />
<br />
# who is running this script<br />
RUNUID=`set | grep ^UID | awk -F = '{print $2}'`<br />
<br />
#get stat from logfile<br />
LOGFSTAT=`/usr/bin/stat $WORKLOG | grep Uid`<br />
#check if Uid is same as the user running this script<br />
<br />
LOGF_PERMS=`echo $LOGFSTAT | awk -F Uid '{print $1}' | awk -F / '{print $2}' | cut -c 3`<br />
<br />
if test "$LOGF_PERMS" != "w"<br />
then<br />
echo "No write permissions to worklog file! Exiting now."<br />
exit 1<br />
fi<br />
<br />
<br />
# Excellent!<br />
<br />
# if we're still in the running here, we've got:<br />
#<br />
# - an existing worklog file (maybe zero length)<br />
<br />
# - owned by the runner of this script<br />
# - with write permissions<br />
<br />
else<br />
<br />
# -- create new worklog file --<br />
<br />
if test $DEBUG = 2<br />
then<br />
<br />
echo "Please create a worklog file by running an update first"<br />
echo "Syntax: worklog [path-to-worklog-file]"<br />
exit 1<br />
<br />
else<br />
<br />
echo "Worklog at $WORKLOG not found"<br />
echo -n "Attempting to create a new worklog file... "<br />
if touch $WORKLOG > /dev/null 2>&1<br />
then<br />
echo "ok"<br />
if test $DEBUG = 1<br />
then<br />
echo "new worklog created"<br />
fi<br />
NEWFILE=1<br />
else<br />
echo "Permission denied!"<br />
exit 1<br />
fi<br />
<br />
fi<br />
<br />
fi<br />
<br />
<br />
<br />
# -- part 1 b --<br />
<br />
# show human readable dates and summarise time spent<br />
<br />
# if we were called with the -show argument now is the<br />
# time to display the worklog file using real date (ymd)<br />
# instead of timestamps.<br />
<br />
<br />
if test $DEBUG = 2<br />
then<br />
echo "worklog for $1"<br />
<br />
TOTALTIME=0<br />
TOTALTIME_W=0<br />
TOTALTIME_C=0<br />
MAXLINES=`grep -c minutes $WORKLOG`<br />
MAXLINES=$((MAXLINES + 2))<br />
LINENR=3<br />
PREVWEEK=0<br />
DO_WEEKSUMMARY=0<br />
while test $LINENR -le $MAXLINES<br />
do<br />
<br />
READLN=`cat $WORKLOG | head -n $LINENR | tail -n 1`<br />
<br />
# only process completed entries..<br />
if echo $READLN | grep minutes > /dev/null 2>&1<br />
then<br />
<br />
DO_PRINT=1<br />
<br />
BEGINTIME=`echo $READLN | awk '{print $1}'`<br />
WEEKNR=`date -d @$BEGINTIME +%U`<br />
if test $PREVWEEK -eq 0<br />
then<br />
PREVWEEK=$WEEKNR<br />
else<br />
<br />
if test $WEEKNR != $PREVWEEK<br />
then<br />
DO_WEEKSUMMARY=1<br />
fi<br />
fi<br />
<br />
else<br />
# incomplete line detected. Don't print anything<br />
DO_PRINT=0<br />
<br />
fi<br />
<br />
<br />
# show week summary line<br />
if test $DO_WEEKSUMMARY -eq 1<br />
then<br />
<br />
if test $TOTALTIME -gt 0<br />
then<br />
<br />
# new week detected<br />
TOTAL_HOURS_W=$((TOTALTIME_W / 60))<br />
TOTAL_HXM_W=$((TOTAL_HOURS_W * 60))<br />
TOTAL_MINUTES_W=$((TOTALTIME_W - TOTAL_HXM_W))<br />
echo -n "Summary for week $PREVWEEK: $TOTALTIME_W minutes $TOTAL_HOURS_W h $TOTAL_MINUTES_W m"<br />
<br />
# cumulative week totals<br />
TOTALTIME_C=$((TOTALTIME_C + TOTALTIME_W))<br />
TOTAL_HOURS_C=$((TOTALTIME_C / 60))<br />
TOTAL_HXM_C=$((TOTAL_HOURS_C * 60))<br />
TOTAL_MINUTES_C=$((TOTALTIME_C - TOTAL_HXM_C))<br />
<br />
echo " ($TOTAL_HOURS_C h $TOTAL_MINUTES_C m)"<br />
echo "--"<br />
<br />
PREVWEEK=$WEEKNR<br />
fi<br />
DO_WEEKSUMMARY=0<br />
TOTALTIME_W=0<br />
<br />
fi<br />
<br />
BEGINTIME=`date -d @$BEGINTIME`<br />
ENDTIME=`echo $READLN | awk '{print $2}'`<br />
ENDTIME=`date -d @$ENDTIME`<br />
<br />
DIFFERENCE=`echo $READLN | awk '{print $3}'`<br />
TOTALTIME_W=$((TOTALTIME_W + DIFFERENCE))<br />
TOTALTIME=$((TOTALTIME + DIFFERENCE))<br />
<br />
# print entry on screen<br />
echo "$BEGINTIME to $ENDTIME = $DIFFERENCE minutes"<br />
<br />
# show week summary if we've reached the last line<br />
if test $LINENR -eq $MAXLINES<br />
then<br />
TOTAL_HOURS_W=$((TOTALTIME_W / 60))<br />
TOTAL_HXM_W=$((TOTAL_HOURS_W * 60))<br />
TOTAL_MINUTES_W=$((TOTALTIME_W - TOTAL_HXM_W))<br />
<br />
echo -n "Summary for week $PREVWEEK: $TOTALTIME_W minutes $TOTAL_HOURS_W h $TOTAL_MINUTES_W m"<br />
<br />
# cumulative week totals<br />
TOTALTIME_C=$((TOTALTIME_C + TOTALTIME_W))<br />
TOTAL_HOURS_C=$((TOTALTIME_C / 60))<br />
TOTAL_HXM_C=$((TOTAL_HOURS_C * 60))<br />
TOTAL_MINUTES_C=$((TOTALTIME_C - TOTAL_HXM_C))<br />
<br />
if test $TOTALTIME_C -eq $TOTALTIME_W<br />
then<br />
echo<br />
else<br />
<br />
echo " ($TOTAL_HOURS_C h $TOTAL_MINUTES_C m)"<br />
fi<br />
<br />
echo "--"<br />
<br />
fi<br />
<br />
LINENR=$((LINENR + 1))<br />
<br />
done<br />
<br />
echo "---------------------------"<br />
echo -n " $TOTALTIME minutes"<br />
<br />
TOTAL_HOURS=$((TOTALTIME / 60))<br />
TOTAL_HXM=$((TOTAL_HOURS * 60))<br />
TOTAL_MINUTES=$((TOTALTIME - TOTAL_HXM))<br />
echo " $TOTAL_HOURS h $TOTAL_MINUTES m"<br />
exit 1<br />
fi<br />
<br />
<br />
<br />
<br />
<br />
<br />
# -- part 2 --<br />
# track changes<br />
<br />
# find out which file was lastly changed<br />
# the first line of the worklog file will be used to track changes<br />
#<br />
# Example:<br />
# LAST-CHANGED : 1273572131 left.php<br />
<br />
<br />
# get just the file name of a regular file that was changed last<br />
LC_FILENAME=`/bin/ls -tr1 $PROJECTDIR | grep -v $WL | tail -n 1`<br />
<br />
# get the timestamp for this file<br />
LC_TIMESTAMP=`/usr/bin/stat --format=%Y $PROJECTDIR/$LC_FILENAME`<br />
<br />
# compare this with what's in the worklog<br />
<br />
# -- create worklog header in case of new file --<br />
if test $NEWFILE = 1<br />
then<br />
WORKLOG_HEADER="LAST-CHANGED : $LC_TIMESTAMP $LC_FILENAME"<br />
echo $WORKLOG_HEADER > $WORKLOG<br />
echo "--" >> $WORKLOG<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "created new worklog header for file: $LC_FILENAME"<br />
fi<br />
<br />
fi<br />
<br />
# update the header if a change has been detected<br />
if echo $WORKLOG_HEADER | grep -e "$LC_TIMESTAMP $LC_FILENAME" > /dev/null 2>&1<br />
then<br />
# no changes detected<br />
CHANGES=0<br />
if test $DEBUG = 1<br />
then<br />
echo "no changes detected"<br />
fi<br />
else<br />
CHANGES=1<br />
# a recent change has been made<br />
if test $DEBUG = 1<br />
then<br />
echo "changes detected in file: $LC_FILENAME"<br />
echo "updating header"<br />
<br />
fi<br />
<br />
# update the worklog header<br />
<br />
# get the total number of lines in the worklog (minus one)<br />
WL_MAXLINES=`wc -l $WORKLOG | awk '{print $1}'`<br />
WL_MAXLINES=$((WL_MAXLINES - 1))<br />
<br />
#set the new header<br />
WORKLOG_HEADER="LAST-CHANGED : $LC_TIMESTAMP $LC_FILENAME"<br />
<br />
#rewrite the worklog file<br />
cat $WORKLOG | tail -n $WL_MAXLINES > $TMPDIR/tmpfil_worklog.001<br />
echo $WORKLOG_HEADER > $WORKLOG<br />
cat $TMPDIR/tmpfil_worklog.001 >> $WORKLOG<br />
rm $TMPDIR/tmpfil_worklog.001<br />
<br />
fi<br />
<br />
<br />
<br />
# -- lastline updating --<br />
<br />
# get the last line of the worklog<br />
WL_LASTLINE=`tail -n 1 $WORKLOG`<br />
WL_LL_LENGTH=${#WL_LASTLINE}<br />
<br />
# the length of the line is an indication as to what's written in it<br />
# length up to 18 chars = unknown<br />
# length is greater than 30 chars = minutes have been calculated<br />
<br />
if test $CHANGES = 1<br />
then<br />
if test $WL_LL_LENGTH = 2 || test $WL_LL_LENGTH -gt 18<br />
then<br />
# open new lastline<br />
WL_LASTLINE="$LC_TIMESTAMP unknown"<br />
echo $WL_LASTLINE >> $WORKLOG<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "opening new tracker line"<br />
fi<br />
<br />
fi<br />
<br />
fi<br />
<br />
<br />
<br />
<br />
# -- timestamp updating --<br />
<br />
# are we checking after the idle time?<br />
<br />
# get timestamp for right now<br />
TIME_NOW=`date +%s`<br />
<br />
# create timestamp for LC_TIMESTAMP + ( N x 60 )<br />
IDLESECS=$((IDLEMINS * 60))<br />
TIMESTAMP_IDLE=$((LC_TIMESTAMP + IDLESECS))<br />
<br />
<br />
# test if our present time is the IDLE time past the Last Changed time<br />
if test $TIME_NOW -gt $TIMESTAMP_IDLE<br />
then<br />
<br />
# we're past our idle time<br />
<br />
# update 'unknown' with the last known time from the header<br />
# and calculate the difference<br />
#<br />
# just exit if unkown is not the last keyword<br />
<br />
<br />
if test $WL_LL_LENGTH = 18<br />
then<br />
<br />
# line has not been closed yet, do so now<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "past idle time, closing tracker line"<br />
fi<br />
<br />
<br />
# get the last known change time from the header<br />
WL_TS=`head -n 1 $WORKLOG | awk '{print $3}'`<br />
<br />
<br />
#rewrite the last line of the logfile<br />
# get the total number of lines in the worklog (minus one)<br />
WL_MAXLINES=`wc -l $WORKLOG | awk '{print $1}'`<br />
WL_MAXLINES=$((WL_MAXLINES - 1))<br />
<br />
#set the lastline with an updated timestamp<br />
WL_LASTLINE_PRE=`echo "$WL_LASTLINE" | awk '{print $1}'`<br />
<br />
#calculate the time between start and finish<br />
WL_STARTTIME=`tail -n 1 $WORKLOG | awk '{print $1}'`<br />
TIMESPAN=$((WL_TS - WL_STARTTIME))<br />
TIMESPAN=$((TIMESPAN / 60))<br />
<br />
WL_LASTLINE="$WL_LASTLINE_PRE $WL_TS $TIMESPAN minutes"<br />
<br />
#rewrite the worklog file<br />
cat $WORKLOG | head -n $WL_MAXLINES > $TMPDIR/tmpfil_worklog.001<br />
cat $TMPDIR/tmpfil_worklog.001 > $WORKLOG<br />
<br />
if [ $TIMESPAN -le 0 ] || [ $TIMESPAN -gt 720 ]<br />
then<br />
# ignore updating the last line, it was probably faulty anyway<br />
echo > /dev/null<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "timespan zero, negative or too big, not writing tracker line"<br />
echo "details:"<br />
echo "original starttime: $WL_STARTTIME"<br />
echo "last changed time: $WL_TS"<br />
fi<br />
<br />
else<br />
echo $WL_LASTLINE >> $WORKLOG<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "updating tracker line with timespan"<br />
fi<br />
<br />
fi<br />
<br />
rm $TMPDIR/tmpfil_worklog.001<br />
<br />
fi<br />
<br />
fi<br />
<br />
if test $DEBUG = 1<br />
then<br />
echo "Timestamp now: `date +%s` `date`"<br />
fi<br />
<br />
<br />
<br />
# That's all folks<br />
</pre></div>
Admin