clockout 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/clock +73 -51
  2. data/lib/clockout.rb +80 -32
  3. metadata +2 -2
data/bin/clock CHANGED
@@ -3,16 +3,16 @@
3
3
  require 'clockout'
4
4
 
5
5
  HELP_BANNER = <<-EOS
6
- Clockout v0.1
6
+ Clockout v0.2
7
7
  Usage:
8
- $ clock [options]
8
+ $ clock [options]
9
9
 
10
10
  Options:
11
- --estimations, -e: Show estimations made for first commit of each block
12
- --condensed, -c: Condense output (don't show the timeline for each day)
13
- --generate-clock, -g: Generate .clock file
14
- --see-clock, -s: See options specified in .clock file
15
- --help, -h: Show this message
11
+ --estimations, -e: Show estimations made for first commit of each block
12
+ --condensed, -c: Condense output (don't show the timeline for each day)
13
+ --generate-clock, -g: Generate .clock file
14
+ --see-clock, -s: See options specified in .clock file
15
+ --help, -h: Show this message
16
16
  EOS
17
17
 
18
18
  TEMPLATE_CLOCKFILE = <<-EOF
@@ -41,7 +41,7 @@ TEMPLATE_CLOCKFILE = <<-EOF
41
41
  ; that you don't want to report as your own work.
42
42
  ; Below is an example regex that will only calculate changes made to files with those extensions
43
43
 
44
- ;my_files = /\.(m|h|rb|txt)$/
44
+ ;my_files = /\\.(m|h|rb|txt)$/
45
45
 
46
46
  ; Diffs of files matched by this regex will NOT be included in commit time estimation
47
47
  ; Type: Regex (Ruby)
@@ -50,7 +50,7 @@ TEMPLATE_CLOCKFILE = <<-EOF
50
50
  ; You also have the option of defining a negative regex match, to ignore certain files.
51
51
  ; For example, if you added an external library or something, you should ignore those additions
52
52
 
53
- ;not_my_files = /(ThisFile\.cpp | SomeOtherClass\.*)/
53
+ ;not_my_files = /(ThisFile\\.cpp | SomeOtherClass\\.*)/
54
54
 
55
55
  ; Completion time overrides for commit estimations
56
56
  ; Type: Int (in minutes)
@@ -76,8 +76,8 @@ def parse_options(args)
76
76
  opts[:condensed] = true
77
77
  elsif (arg == "-g" || arg == "--generate-clock")
78
78
  opts[:generate_clock] = true
79
- elsif (arg[0] == "-")
80
- puts "Error: invalid option '#{arg}'."
79
+ else
80
+ puts "#{colorize("Error:", RED)} invalid option '#{arg}'."
81
81
  puts "Try --help for help."
82
82
  exit
83
83
  end
@@ -86,51 +86,73 @@ def parse_options(args)
86
86
  opts
87
87
  end
88
88
 
89
+ def generate_clock_file(path)
90
+ clock_path = Clockout.clock_path(path)
91
+ if (File.exists?(clock_path))
92
+ false
93
+ else
94
+ File.open(clock_path, "w") do |file|
95
+ file.write(TEMPLATE_CLOCKFILE)
96
+ end
97
+ true
98
+ end
99
+ end
100
+
89
101
  path = Dir.pwd
90
102
 
91
- # Default options
92
- opts = {time_cutoff:120, my_files:"/.*/"}
93
- opts.merge!(parse_options(ARGV))
94
-
95
- if opts[:generate_clock]
96
- clock_path = path+"/.clock"
97
- if (File.exists?(clock_path))
98
- puts "#{colorize("Error:", RED)} .clock file already exists, ignoring --generate-clock option.\n"
99
- else
100
- File.open(clock_path, "w") do |file|
101
- file.write(TEMPLATE_CLOCKFILE)
102
- end
103
- puts "Generated .clock file at #{clock_path}.\n"
104
- end
105
- end
103
+ if (ARGV[0] == "in" || ARGV[0] == "out")
104
+ # Generate a clock file if one doesn't already exist
105
+ generate_clock_file(path)
106
106
 
107
- clock = Clockout.new(path, opts)
107
+ # Append "in <current date>" or "out <current date>" to the clockfile
108
+ File.open(Clockout.clock_path(path), "a") do |file|
109
+ file.puts ARGV[0] + " " + Time.new.to_s
110
+ end
111
+ else
112
+ opts = parse_options(ARGV)
113
+
114
+ if opts[:help]
115
+ puts HELP_BANNER
116
+ exit
117
+ end
108
118
 
109
- if opts[:see_clock]
110
- if !clock.clock_opts
111
- puts "No .clock file found. Run `clock -g` to generate one."
112
- else
113
- if clock.clock_opts.size == 0
114
- puts "No clock options."
115
- else
116
- puts "Clock options:"
117
- clock.clock_opts.each do |k, v|
118
- key = k[0..19]
119
- puts " #{key}:#{' '*(20-key.length)}#{v}"
120
- end
121
- end
119
+ if opts[:generate_clock]
120
+ if generate_clock_file(path)
121
+ puts "Generated .clock file at #{Clockout.clock_path(path)}.\n"
122
+ else
123
+ puts "#{colorize("Error:", RED)} .clock file already exists for this repo.\n"
124
+ end
125
+ exit
122
126
  end
123
- exit
124
- end
125
127
 
126
- if opts[:help]
127
- puts HELP_BANNER
128
- exit
129
- end
128
+ if opts[:see_clock]
129
+ clock_opts = Clockout.parse_clockfile(Clockout.clock_path(path))
130
+ if !clock_opts
131
+ puts "No .clock file found. Run `clock -g` to generate one."
132
+ else
133
+ if clock_opts.size == 0
134
+ puts "No clock options."
135
+ else
136
+ puts "Clock options:"
137
+ clock_opts.each do |k, v|
138
+ space = 23
139
+ width = space-6
140
+ key = k[0..width]
141
+ key += "..." if k.length > width
142
+ # For clockins/outs, display the number of them instead of all the dates
143
+ v = v.length if k == :clockins || k == :clockouts
144
+ puts " #{key}:#{' '*(space-key.length)}#{v}"
145
+ end
146
+ end
147
+ end
148
+ exit
149
+ end
130
150
 
131
- if (opts[:estimations])
132
- clock.print_estimations
133
- else
134
- clock.print_chart
135
- end
151
+ clock = Clockout.new(path)
136
152
 
153
+ if (opts[:estimations])
154
+ clock.print_estimations
155
+ else
156
+ clock.print_chart(opts[:condensed])
157
+ end
158
+ end
data/lib/clockout.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'grit'
2
+ require 'time'
2
3
 
3
4
  class Commit
4
5
  attr_accessor :message, :minutes, :date, :diffs, :sha
@@ -16,7 +17,7 @@ class Clockout
16
17
  COLS = 80
17
18
  DAY_FORMAT = '%B %e, %Y'
18
19
 
19
- attr_accessor :blocks, :time_per_day, :clock_opts
20
+ attr_accessor :blocks
20
21
 
21
22
  def diffs(commit)
22
23
  plus, minus = 0, 0
@@ -43,6 +44,7 @@ class Clockout
43
44
 
44
45
  total_diffs, total_mins = 0, 0
45
46
 
47
+ prev = nil
46
48
  commits.each do |commit|
47
49
 
48
50
  c = Commit.new
@@ -52,7 +54,17 @@ class Clockout
52
54
  c.sha = commit.id[0..7]
53
55
 
54
56
  if block.size > 0
55
- time_since_last = (block.last.date - commit.committed_date).abs/60
57
+ last_date = block.last.date
58
+
59
+ @clockins.each do |clockin|
60
+ if clockin > last_date && clockin < c.date
61
+ last_date = clockin
62
+ @clockins.delete(clockin)
63
+ break
64
+ end
65
+ end
66
+
67
+ time_since_last = (last_date - commit.committed_date).abs/60
56
68
 
57
69
  if (time_since_last > $opts[:time_cutoff])
58
70
  blocks << block
@@ -82,22 +94,21 @@ class Clockout
82
94
  elsif ($opts[:ignore_initial] && block == blocks.first) || total_diffs == 0
83
95
  first.minutes = 0
84
96
  else
85
- # Underestimate by a factor of 0.9
86
- first.minutes = 0.9*first.diffs*(1.0*total_mins/total_diffs)
97
+ first.minutes = $opts[:estimation_factor]*first.diffs*(1.0*total_mins/total_diffs)
87
98
  end
88
99
 
89
100
  @time_per_day[first.date.strftime(DAY_FORMAT)] += first.minutes
90
101
  end
91
102
  end
92
103
 
93
- def print_chart
94
- cols = ($opts[:condensed] ? 30 : COLS)
104
+ def print_chart(condensed)
105
+ cols = (condensed ? 30 : COLS)
95
106
  total_sum = 0
96
107
  current_day = nil
97
108
  @blocks.each do |block|
98
109
  date = block.first.date.strftime(DAY_FORMAT)
99
110
  if date != current_day
100
- puts if (!$opts[:condensed])
111
+ puts if (!condensed)
101
112
 
102
113
  current_day = date
103
114
 
@@ -111,7 +122,7 @@ class Clockout
111
122
  puts
112
123
  end
113
124
 
114
- print_timeline(block) if (!$opts[:condensed])
125
+ print_timeline(block) if (!condensed)
115
126
  end
116
127
 
117
128
  puts " "*(cols-10) + colorize("-"*10,MAGENTA)
@@ -184,15 +195,16 @@ class Clockout
184
195
  begin
185
196
  return Grit::Repo.new(path)
186
197
  rescue Exception => e
198
+ print colorize("Error: ", RED)
187
199
  if e.class == Grit::NoSuchPathError
188
- puts "Error: Path '#{path}' could not be found."
200
+ puts "Path '#{path}' could not be found."
189
201
  else
190
- puts "Error: '#{path}' is not a Git repository."
202
+ puts "'#{path}' is not a Git repository."
191
203
  end
192
204
  end
193
205
  end
194
206
 
195
- def parse_clockfile(file)
207
+ def self.parse_clockfile(file)
196
208
  return nil if !File.exists?(file)
197
209
 
198
210
  opts = {}
@@ -200,42 +212,78 @@ class Clockout
200
212
  line_num = 0
201
213
  File.foreach(file) do |line|
202
214
  line_num += 1
215
+ #Strip whitespace
203
216
  line.strip!
217
+ #Strip comments
218
+ line = line.split(";",2)[0]
204
219
 
205
- next if line[0] == ";" || line.length == 0
220
+ next if !line || line.length == 0
206
221
 
207
222
  sides = line.split("=",2)
208
223
 
209
- if sides.length != 2
210
- puts "Error: bad syntax on line #{line_num} of .clock file:"
211
- puts " #{line}"
212
- puts ""
213
- puts "Line must be of form:"
214
- puts " KEY = VALUE"
224
+ clock_split = sides[0].split(" ",2)
225
+ if (clock_split[0] == "in" || clock_split[0] == "out")
215
226
 
216
- exit
217
- end
227
+ begin
228
+ date = Time.parse(clock_split[1])
229
+ rescue Exception => e
230
+ puts "#{colorize("Error:", RED)} invalid date for '#{clock_split[0]}' on line #{line_num} of .clock file:"
231
+ puts " #{line}"
218
232
 
219
- left = sides[0].strip
220
- right = sides[1].strip
233
+ exit
234
+ end
221
235
 
222
- if left == "ignore_initial"
223
- right = (right != "0")
224
- elsif left == "time_cutoff"
225
- right = right.to_i
226
- end
236
+ key = (clock_split[0] == "out") ? :clockouts : :clockins
227
237
 
228
- opts[left.to_sym] = right
238
+ opts[key] ||= []
239
+ opts[key] << date
240
+ else
241
+ if sides.length != 2
242
+ puts "#{colorize("Error:", RED)} bad syntax on line #{line_num} of .clock file:"
243
+ puts " #{line}"
244
+ puts ""
245
+ puts "Line must be of form:"
246
+ puts " KEY = VALUE"
247
+
248
+ exit
249
+ end
250
+
251
+ left = sides[0].strip
252
+ right = sides[1].strip
253
+
254
+ if left == "ignore_initial"
255
+ right = (right != "0")
256
+ elsif left == "time_cutoff"
257
+ right = right.to_i
258
+ elsif left == "estimation_factor"
259
+ right = right.to_f
260
+ end
261
+
262
+ opts[left.to_sym] = right
263
+ end
229
264
  end
230
265
 
231
266
  opts
232
267
  end
233
268
 
234
- def initialize(path, options)
235
- $opts = options
269
+ def self.clock_path(path)
270
+ path+"/.clock"
271
+ end
272
+
273
+ def initialize(path)
274
+ # Default options
275
+ $opts = {time_cutoff:120, my_files:"/.*/", estimation_factor:0.9}
276
+
277
+ # Parse .clock options
278
+ clock_opts = Clockout.parse_clockfile(Clockout.clock_path(path))
236
279
 
237
- @clock_opts = parse_clockfile(path+"/.clock")
238
- $opts.merge!(@clock_opts) if @clock_opts
280
+ if clock_opts
281
+ @clockins = clock_opts[:clockins] || []
282
+ @clockouts = clock_opts[:clockouts] || []
283
+
284
+ # Merge with .clock override options
285
+ $opts.merge!(clock_opts)
286
+ end
239
287
 
240
288
  repo = get_repo(path) || exit
241
289
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clockout
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-04 00:00:00.000000000 Z
12
+ date: 2013-05-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: grit