]>
git.defcon.no Git - trk/blob - trk
3 use Digest
::MD5
qw(md5_hex);
8 my $trk_dir = "$ENV{HOME}/.trk";
21 printf("It seems you require assistance\n");
25 printf("How to start\n") if $code == START
;
26 printf("How to time\n") if $code == TIMEFORMAT
;
34 my $id_length = shift;
35 $id_length = 32 if not defined $id_length;
39 for(my $i=0 ; $i<128;)
41 my $tc = chr(int(rand(127)));
42 if($tc =~ /[a-zA-Z0-9]/)
50 while ( length($w) < $id_length )
52 $w .= gen_puuid
( $id_length - length( $w ) );
55 $w = substr( $w, 0, $id_length );
59 # Input to parse_time is:
60 # * date -> date-string in the form YYYY-MM-DD
61 # * time -> time-string in the form HH:MM
62 # Return value is a unix timestamp, as returned by time()
65 my ( $Y, $M, $D ) = split ("-", shift );
66 my ( $h, $m ) = split(":", shift );
67 return timelocal
(0, $m, $h, $D, ($M-1), $Y);
73 return 0 if not $i =~ m/(\d\d\d\d-\d\d-\d\d) (\d\d:\d\d)/;
74 return parse_time
($1, $2);
80 return strftime
("%Y-%m-%d %H:%M", localtime($t));
83 sub parse_arguments
($)
88 my $start_time = time;
91 if (( $#ARGV >= 1) && ( $ARGV[1] eq "at" ))
93 # Start and Activity require a title to be present.
94 # All other (stop, main...) do not ^^.
95 if ( ($step == START
) || ($step == TASK
) )
97 # TODO: Allow no title!
98 # If no title is given, read ID of previously used track in stead :)
99 help
($step) unless $#ARGV > 3;
100 $title = join(" ", @ARGV[4..$#ARGV]);
102 help
(TIMEFORMAT
) unless ( $ARGV[2] =~ m/\d\d\d\d-\d\d-\d\d/ && $ARGV[3] =~ m/\d\d:\d\d/);
104 $start_time = parse_time
( $ARGV[2], $ARGV[3] );
106 elsif ( ($step == START
) || ($step == TASK
) || ($step == EDIT
))
109 $title = join(" ", @ARGV);
112 if ( not defined $title )
118 return ( $start_time, $title );
125 my $wrk_dir = $trk_dir;
126 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
128 return undef if ( ! -f
$wrk_dir . "/last" );
129 open ( CUR
, "<" . $wrk_dir . "/last" ) or die ("Unable to read last track file");
136 sub get_current_id
(;$)
139 my $wrk_dir = $trk_dir;
140 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
142 return undef if ( ! -f
$wrk_dir . "/current" );
143 open ( CUR
, "<" . $wrk_dir . "/current" ) or die ("Unable to read current track file");
150 sub set_current_id
($;$)
154 my $wrk_dir = $trk_dir;
155 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
157 return undef if ( -f
$wrk_dir . "/current" );
158 open ( CUR
, ">" . $wrk_dir . "/current" ) or die ("Unable to write current track file");
159 printf(CUR
"%s\n", $id );
162 open ( LAST
, ">" . $wrk_dir . "/last" ) or die ("Unable to write last track file");
163 printf(LAST
"%s\n", $id );
170 my $wrk_dir = $trk_dir;
171 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
176 foreach my $d ( <$wrk_dir/*> )
179 next if not -f
$d . "/info";
181 my $id = basename
($d);
182 my $title = get_track_name
( $id, $trk_id );
184 $tracks{$id} = $title unless not defined $title;
191 sub get_track_id
($;$)
196 # Get hash of track-id's and -names from get_tracks
197 my $tracks = get_tracks
($trk_id);
199 # Look up name in list
200 foreach my $id ( keys %$tracks )
203 return $id if ( $tracks->{$id} eq $title )
206 # If no match, return undef.
210 sub get_track_name
($;$)
214 my $wrk_dir = $trk_dir;
215 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
217 open(PRO
, "<" . $wrk_dir . "/" . $id . "/info" ) or die ("Unable to read track medatata file!");
221 next if not $_ =~ /^title:(.*)/;
228 sub create_track
($;$)
232 my $wrk_dir = $trk_dir;
233 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
240 } while ( -d
$wrk_dir . "/" . $id );
241 mkdir ( $wrk_dir . "/" . $id );
243 open(PRO
, ">" . $wrk_dir . "/" . $id . "/info" ) or die ("Unable to create track medatata file!");
244 printf(PRO
"title:%s\n", $title);
250 sub start_track
($$;$)
252 my $start_time = shift;
256 my $wrk_dir = $trk_dir;
257 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
259 my $current = get_current_id
($trk_id);
264 $current = get_last_id
( $trk_id );
268 $current = get_track_id
( $title, $trk_id );
271 printf("No track by that name! Creating a new one.\n");
272 $current = create_track
($title, $trk_id);
276 # Break off here if we haven't gotten an ID yet.
277 return undef if not $current;
279 set_current_id
($current, $trk_id);
281 # First iteration is VERY naive: simply add the start time to the bottom of the tracking file
282 # Will have to do more logic: if the start point is before one of the times already in the track,
283 # the file will have to be manipulated to get coherent tracking!
284 open (TRACK
, ">>" . $wrk_dir . "/" . $current . "/tracking" ) or die ("Unable to open file, $!");
285 printf(TRACK
"[%s]", time2str
($start_time));
294 sub close_track
($;$)
297 my $stop_time = shift;
299 my $wrk_dir = $trk_dir;
300 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
302 my $current = get_current_id
( $trk_id );
304 die ("Project exists, but tracking file does not!") if ( not -f
$wrk_dir . "/" . $current . "/tracking" );
306 # First iteration is VERY naive: simply add the stop time to the bottom line of the tracking file
307 # Will have to do more logic: if the start point is before one of the times already in the track,
308 # the file will have to be manipulated to get coherent tracking!
309 # In addtion to this: actually do some file sanity checking!
310 open (TRACK
, ">>" . $wrk_dir . "/" . $current . "/tracking" ) or die ("Unable to open file, $!");
311 printf(TRACK
" to [%s]\n", time2str
($stop_time));
314 unlink ( $wrk_dir . "/current" );
322 my $wrk_dir = $trk_dir;
323 $wrk_dir = $trk_dir . "/" . $trk_id if $trk_id;
327 my $name = get_track_name
( $current, $trk_id );
328 printf("# Report for '%s':\n\n", $name);
330 open (TRACK
, "<" . $wrk_dir . "/" . $current . "/tracking" ) or die ("Unable to open file, $!");
333 next if not $_ =~ m/\[(.*)\] to \[(.*)\]/;
336 my $t_start = str2time
( $start );
337 my $t_end = str2time
( $end );
338 my $delta = $t_end - $t_start;
341 my $hours = $t / 3600;
343 my $minutes = $t / 60;
345 printf(" %s to %s => %d hours %d minutes\n", $start, $end, $hours, $minutes);
353 my $hours = $t / 3600;
355 my $minutes = $t / 60;
357 printf("\nTotal: %d hours %d minutes\n", $hours, $minutes);
360 ############################################################
364 mkdir $trk_dir or die("Unable to create data directory");
372 my $command = $ARGV[0];
374 if ( ( $command eq "start") || ($command eq "on" ) )
381 my ( $start_time, $title ) = parse_arguments
(START
);
383 my $current = get_current_id
();
386 $current = start_track
( $start_time, $title );
390 printf("Something weird happened.\n");
396 printf("A project is being tracked: %s\n", get_track_name
( $current ) );
397 close_track
($start_time);
398 $current = start_track
( $start_time, $title );
401 printf("Started tracking of '%s' at %s\n\n", $title, scalar localtime $start_time);
403 elsif ( ( $command eq "stop") || ($command eq "off" ) )
411 my $stop_time = parse_arguments
(STOP
);
413 my $current = get_current_id
();
416 printf("No project is currently tracked. To stop, please start first\n");
419 my $title = get_track_name
( $current );
421 my $activity = get_current_id
($current);
424 printf("An active subtask is running: '%s'. Closing it.\n", get_track_name
( $activity, $current ));
425 close_track
($stop_time, $current);
427 close_track
($stop_time);
429 printf("Stopped tracking of '%s' at %s\n\n", $title, scalar localtime $stop_time);
431 elsif ( ( $command eq "activity") || ($command eq "task" ) )
438 my ( $start_time, $title ) = parse_arguments
(START
);
440 my $trk_id = get_current_id
();
443 printf("Starting a task/activity requires an active main track.\n");
449 my $current = get_current_id
( $trk_id );
452 $current = start_track
( $start_time, $title, $trk_id );
456 printf("Something weird happened.\n");
462 printf("A task/activity is being tracked: %s\n", get_track_name
( $current, $trk_id ) );
463 close_track
($start_time, $trk_id);
464 $current = start_track
( $start_time, $title, $trk_id );
467 printf("Started tracking of '%s' at %s\n\n", $title, scalar localtime $start_time);
473 elsif ( $command eq "main" )
482 my $stop_time = parse_arguments
(STOP
);
484 my $trk_id = get_current_id
();
487 printf("Stopping a task/activity requires an active main track.\n");
492 my $current = get_current_id
( $trk_id );
495 printf("No activity/task is currently tracked. To stop, please start first\n");
498 my $title = get_track_name
( $current, $trk_id );
499 close_track
($stop_time, $trk_id);
501 printf("Stopped tracking of '%s' at %s\n\n", $title, scalar localtime $stop_time);
504 elsif ( ( $command eq "projects" ) || ( $command eq "list" ) )
506 # Todo/future extensions:
507 # TODO: Sort list of names alphabetically
508 # TODO: Get total-hours for projects
510 my $tracks = get_tracks
();
511 printf("Currently tracked project names:\n\n");
512 my $current = get_current_id
();
514 foreach my $id ( keys %$tracks )
516 printf(" %s %s\n", ($id eq $current ?
">" : " " ),$tracks->{$id} );
520 elsif ( $command eq "report" )
523 my ( undef, $title ) = parse_arguments
(START
);
529 $track = get_track_id
( $title );
533 $track = get_last_id
();
538 printf ("Unable to get info for that track\n");
543 my $activities = get_tracks
( $track );
544 if ( keys %$activities )
546 printf("# Reporting for sub-task/activities:\n\n");
547 foreach my $id ( keys %$activities )
549 report
( $id, $track );
550 printf("# --------------------------------------------------------------\n");
555 printf("# Reporting for main track/project/task\n");
557 printf("\n# ==============================================================\n\n");
560 print("# End of report\n");
564 elsif ( $command eq "edit" )
567 my ( undef, $title ) = parse_arguments
(EDIT
);
568 my $id = get_last_id
();
572 $id = get_track_id
($title);
575 printf("No project by that name. Try 'list'\n");
580 system( "/usr/bin/editor " . $trk_dir . "/" . $id . "/tracking" );