ttrack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ttrack +23 -0
- data/lib/ttrack/datastore.rb +137 -0
- data/lib/ttrack.rb +164 -0
- metadata +59 -0
data/bin/ttrack
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/Users/alex/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -w
|
2
|
+
require 'ttrack'
|
3
|
+
|
4
|
+
tt = TTrack.new
|
5
|
+
case ARGV[0]
|
6
|
+
when 'start' then
|
7
|
+
tt.start ARGV[1], ARGV[2]
|
8
|
+
when 'stop' then
|
9
|
+
tt.stop
|
10
|
+
when 'status' then
|
11
|
+
tt.status ARGV[1]
|
12
|
+
when 'init' then
|
13
|
+
tt.init
|
14
|
+
when 'report' then
|
15
|
+
tt.report ARGV[1]
|
16
|
+
when 'beguin' then
|
17
|
+
timestamp = ARGV[3] ? "%s %s" % ARGV[2..3] : ARGV[2]
|
18
|
+
tt.setstart ARGV[1], timestamp
|
19
|
+
when 'end' then
|
20
|
+
timestamp = ARGV[3] ? "%s %s" % ARGV[2..3] : ARGV[2]
|
21
|
+
tt.setstop ARGV[1], timestamp
|
22
|
+
else tt.usage
|
23
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
class TTrack::DataStore
|
5
|
+
|
6
|
+
def initialize dbname=".timetrackerdb", timezone="+02:00", version='v0.1.0', verbosity=0
|
7
|
+
@dbname = dbname
|
8
|
+
@timezone = timezone
|
9
|
+
@version = version
|
10
|
+
@verbosity = verbosity
|
11
|
+
|
12
|
+
if FileTest.zero?(dbname) or not FileTest.file?(dbname)
|
13
|
+
@db = SQLite3::Database.new( dbname )
|
14
|
+
createschema
|
15
|
+
init(timezone, version, verbosity)
|
16
|
+
else
|
17
|
+
@db = SQLite3::Database.open( dbname )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def createschema
|
23
|
+
@db.execute <<-SQL
|
24
|
+
CREATE TABLE system (
|
25
|
+
current,
|
26
|
+
latest,
|
27
|
+
timezone NOT NULL,
|
28
|
+
version INTEGER NOT NULL,
|
29
|
+
verbosity NOT NULL,
|
30
|
+
redmine
|
31
|
+
)
|
32
|
+
SQL
|
33
|
+
|
34
|
+
@db.execute <<-SQL
|
35
|
+
CREATE TABLE timesheet (
|
36
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
37
|
+
name,
|
38
|
+
tstart DEFAULT CURRENT_TIMESTAMP,
|
39
|
+
tstop,
|
40
|
+
synced DEFAULT 'false',
|
41
|
+
notes
|
42
|
+
)
|
43
|
+
SQL
|
44
|
+
end
|
45
|
+
|
46
|
+
def init timezone, version, verbosity
|
47
|
+
@db.execute 'INSERT INTO system ( timezone, version, verbosity ) VALUES ( "%s", "%s", "%s" )' %
|
48
|
+
[timezone, version, verbosity]
|
49
|
+
end
|
50
|
+
|
51
|
+
def droptables
|
52
|
+
for table in ['system', 'timesheet']
|
53
|
+
@db.execute 'DROP TABLE IF EXISTS %s' % table
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def setcurrent issueid
|
58
|
+
oldcurrent = @db.execute 'SELECT current, latest FROM system'
|
59
|
+
@db.execute "UPDATE system SET current = '%d', latest = '%s'" %
|
60
|
+
[issueid, oldcurrent[0][0] != '' ? oldcurrent[0][0] : oldcurrent[0][1]]
|
61
|
+
end
|
62
|
+
|
63
|
+
public
|
64
|
+
def getcurrent
|
65
|
+
current = @db.execute "SELECT current FROM system"
|
66
|
+
current[0][0] == "" ? nil : current[0][0]
|
67
|
+
end
|
68
|
+
|
69
|
+
def getstatus
|
70
|
+
current = getcurrent
|
71
|
+
if current
|
72
|
+
status = @db.execute "SELECT id,name FROM timesheet WHERE id=%d" % current
|
73
|
+
status[0]
|
74
|
+
else
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def startnew issuename, notes=''
|
80
|
+
@db.execute "INSERT INTO timesheet ( name, notes ) VALUES ( '%s', '%s' )" %
|
81
|
+
[issuename, notes]
|
82
|
+
latest = @db.execute "SELECT id FROM timesheet ORDER BY id DESC LIMIT 1"
|
83
|
+
setcurrent latest[0][0]
|
84
|
+
end
|
85
|
+
|
86
|
+
def stoprunning
|
87
|
+
current = getcurrent
|
88
|
+
if current
|
89
|
+
@db.execute "UPDATE timesheet set tstop = datetime('now') WHERE id = %d" % current
|
90
|
+
@db.execute "UPDATE system SET current = '', latest = '%d'" % current
|
91
|
+
else
|
92
|
+
p "Not tracking"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def gettime issueid=false
|
97
|
+
issueid = issueid ? issueid : getcurrent
|
98
|
+
if issueid
|
99
|
+
time = @db.execute "SELECT tstart,tstop FROM timesheet WHERE id=%d" % issueid
|
100
|
+
time[0]
|
101
|
+
else
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def gettimesbyissuename issuename
|
107
|
+
@db.execute "SELECT tstart,tstop FROM timesheet WHERE name='%s'" % issuename
|
108
|
+
end
|
109
|
+
|
110
|
+
def getissuesandtimesbyname issuename
|
111
|
+
@db.execute "SELECT tstart,tstop FROM timesheet WHERE name='%s'" % issuename
|
112
|
+
end
|
113
|
+
|
114
|
+
def getissuesidsbyname issuename
|
115
|
+
@db.execute "SELECT id,tstart,tstop,notes FROM timesheet WHERE name='%s'" % issuename
|
116
|
+
end
|
117
|
+
|
118
|
+
def settstart id, tstart
|
119
|
+
@db.execute "UPDATE timesheet SET tstart=datetime('%s') WHERE id=%d" % [tstart, id]
|
120
|
+
end
|
121
|
+
|
122
|
+
def settstop id, tstop
|
123
|
+
@db.execute "UPDATE timesheet SET tstop=datetime('%s') WHERE id=%d" % [tstop, id]
|
124
|
+
end
|
125
|
+
|
126
|
+
def isissue? id
|
127
|
+
r = @db.execute "SELECT id from timesheet WHERE id=%d" % id
|
128
|
+
r[0].nil? ? false : true
|
129
|
+
end
|
130
|
+
|
131
|
+
def cleanup
|
132
|
+
droptables
|
133
|
+
createschema
|
134
|
+
init(@timezone, @version, @verbosity)
|
135
|
+
end
|
136
|
+
|
137
|
+
end # End DataStore class
|
data/lib/ttrack.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class TTrack
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@db = DataStore.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def start issuename, notes
|
9
|
+
unless issuename.nil?
|
10
|
+
if @db.getcurrent
|
11
|
+
@db.stoprunning
|
12
|
+
end
|
13
|
+
@db.startnew issuename, notes
|
14
|
+
else
|
15
|
+
usage
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
@db.stoprunning
|
21
|
+
end
|
22
|
+
|
23
|
+
def status issuename
|
24
|
+
unless issuename
|
25
|
+
status = @db.getstatus
|
26
|
+
if status
|
27
|
+
delta = Time.now - gettstart(@db.getcurrent)
|
28
|
+
puts "Task '%s' run time: %d seconds (%.2f hours)" % [status[1], delta, delta / 3600]
|
29
|
+
else
|
30
|
+
puts "Not tracking"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
total = gettotalissueduration(issuename)
|
34
|
+
unless total == 0
|
35
|
+
puts "Total seconds for task %s: %d (%.2f hours)" %
|
36
|
+
[
|
37
|
+
issuename,
|
38
|
+
total,
|
39
|
+
total / 3600
|
40
|
+
]
|
41
|
+
else
|
42
|
+
puts "No entry for issue '%s'" % issuename
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def report issuename
|
48
|
+
r = @db.getissuesidsbyname issuename
|
49
|
+
unless r[0].nil?
|
50
|
+
puts "id | tstart | tstop | notes"
|
51
|
+
r.each do |x|
|
52
|
+
puts "%s | %s | %s | %s" % x
|
53
|
+
end
|
54
|
+
else
|
55
|
+
usage
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def setstart issueid, timestamp
|
60
|
+
if validateissueid issueid
|
61
|
+
t = validatetimestamp timestamp
|
62
|
+
@db.settstart issueid, t
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def setstop issueid, timestamp
|
67
|
+
if validateissueid issueid
|
68
|
+
t = validatetimestamp timestamp
|
69
|
+
@db.settstop issueid, t
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def init
|
74
|
+
@db.cleanup
|
75
|
+
end
|
76
|
+
|
77
|
+
def usage
|
78
|
+
puts "Usage: ttrack [start|stop|status|init|report|begin|end] issue_name"
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def gettimeobject timestamp
|
83
|
+
if timestamp
|
84
|
+
Time.utc(
|
85
|
+
timestamp[0..3],
|
86
|
+
timestamp[5..6],
|
87
|
+
timestamp[8..9],
|
88
|
+
timestamp[11..12],
|
89
|
+
timestamp[14..15],
|
90
|
+
timestamp[17..18]
|
91
|
+
)
|
92
|
+
else
|
93
|
+
Time.now
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def validatetimestamp timestamp
|
98
|
+
t = Time.utc(
|
99
|
+
timestamp[0..3],
|
100
|
+
timestamp[5..6],
|
101
|
+
timestamp[8..9],
|
102
|
+
timestamp[11..12],
|
103
|
+
timestamp[14..15],
|
104
|
+
timestamp[17..18]
|
105
|
+
)
|
106
|
+
"%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % [
|
107
|
+
t.year,
|
108
|
+
t.month,
|
109
|
+
t.day,
|
110
|
+
t.hour,
|
111
|
+
t.min,
|
112
|
+
t.sec
|
113
|
+
]
|
114
|
+
end
|
115
|
+
|
116
|
+
def validateissueid issueid
|
117
|
+
unless @db.isissue? issueid
|
118
|
+
puts "Issueid invalid"
|
119
|
+
false
|
120
|
+
else
|
121
|
+
true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def gettotalissueduration issuename
|
126
|
+
r = @db.getissuesandtimesbyname(issuename)
|
127
|
+
total = 0
|
128
|
+
r.each do |timestamps|
|
129
|
+
if timestamps[0]
|
130
|
+
t0, t1 = gettimeobject(timestamps[0]), gettimeobject(timestamps[1])
|
131
|
+
total = total + (t1 - t0)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
total
|
135
|
+
end
|
136
|
+
|
137
|
+
def getissueduration issueid
|
138
|
+
timestamps = @db.gettime issueid
|
139
|
+
if timestamps and timestamps[1]
|
140
|
+
t0, t1 = gettimeobject(timestamps[0]), gettimeobject(timestamps[1])
|
141
|
+
t1 - t0
|
142
|
+
else
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def gettstart issueid
|
148
|
+
timestamps = @db.gettime issueid
|
149
|
+
unless timestamps[0].nil?
|
150
|
+
gettimeobject timestamps[0]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def gettstop issueid
|
155
|
+
timestamps = @db.gettime issueid
|
156
|
+
unless timestamps[1].nil?
|
157
|
+
gettimeobject timestamps[1]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end # End TTrack class
|
162
|
+
|
163
|
+
require 'ttrack/datastore'
|
164
|
+
# TODO: add support for timezone
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ttrack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexander Fortin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sqlite3
|
16
|
+
requirement: &70137978508080 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.3.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70137978508080
|
25
|
+
description: A simple CLI time tracker
|
26
|
+
email: alexander.fortin@gmail.com
|
27
|
+
executables:
|
28
|
+
- ttrack
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/ttrack.rb
|
33
|
+
- lib/ttrack/datastore.rb
|
34
|
+
- bin/ttrack
|
35
|
+
homepage: https://rubygems.org/gems/ttrack
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.10
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Time Tracker
|
59
|
+
test_files: []
|