tlog 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,144 @@
1
+
2
+ class Tlog::Command::Display < Tlog::Command
3
+
4
+ def name
5
+ "display"
6
+ end
7
+
8
+ def execute(input, output)
9
+ raise Tlog::Error::CommandInvalid, "Logging invalid" unless display(input.args[0], input.options[:length], output)
10
+ end
11
+
12
+ def options(parser, options)
13
+ parser.banner = "usage: tlog log <log_name>"
14
+
15
+ parser.on("-l", "--length <length_threshold>") do |length|
16
+ options[:length] = length
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def display(log_name, length_threshold, output)
23
+ storage.in_branch do |wd|
24
+ if log_name
25
+ display_log(log_name, length_threshold, output)
26
+ else
27
+ display_all(length_threshold, output)
28
+ end
29
+ end
30
+ end
31
+
32
+ def display_log(log_name, length_threshold, output)
33
+ log = storage.require_log(log_name)
34
+ log_length = log.goal_length
35
+ entries = log.entries
36
+ if storage.start_time_string && is_current_log_name?(log_name)
37
+ start_time = Time.parse(storage.start_time_string)
38
+ end
39
+ return if length_exceeds_threshold?(log_length, length_threshold)
40
+ print_log_name(log_name, output)
41
+ print_header(output)
42
+ print_current(log_name, log_length, start_time, output)
43
+ display_entries(entries, output) if entries
44
+ print_footer(log, log_length, output)
45
+ end
46
+
47
+ def display_all(length_threshold, output)
48
+ storage.all_log_dirs.each do |log_path|
49
+ log_basename = log_path.basename.to_s
50
+ display_log(log_basename, length_threshold, output)
51
+ end
52
+ end
53
+
54
+ def display_entries(entries, output)
55
+ if entries.size > 0
56
+ entries.each do |entry|
57
+ out_str = "\t%-4s %16s %14s %14s %s" % [
58
+ date_time_format.timestamp(entry.time[:start]),
59
+ date_time_format.timestamp(entry.time[:end]),
60
+ seconds_format.duration(entry.length.to_s),
61
+ entry.owner,
62
+ entry.description,
63
+ ]
64
+ output.line(out_str)
65
+ end
66
+ end
67
+ end
68
+
69
+ def print_footer(log, log_length, output)
70
+ output.line "-" * 100
71
+ print_total(log, output)
72
+ print_time_left(log, output)
73
+ end
74
+
75
+ def print_header(output)
76
+ output.line("\tStart End Duration Owner Description")
77
+ end
78
+
79
+ def print_total(log, output)
80
+ #output.line("-") * 52
81
+ duration = log.duration
82
+ if storage.current_log_name == log.name
83
+ duration += storage.time_since_start
84
+ end
85
+ output.line("\tTotal%45s " % seconds_format.duration(duration))
86
+ end
87
+
88
+ def print_log_name(log_name, output)
89
+ output.line_yellow("Log: #{log_name}")
90
+ end
91
+
92
+ def print_time_left(log, output)
93
+ if log.goal
94
+ log_goal = log.goal
95
+ if (storage.current_log_name == log.name)
96
+ current_time = Time.now - storage.cur_start_time
97
+ log_goal -= current_time.to_i
98
+ end
99
+ log_goal = 0 if log_goal < 0
100
+ output.line_red("\tTime left: %39s" % seconds_format.duration(log_goal))
101
+ end
102
+ end
103
+
104
+ #should be added to entries array, not its own seperate thing
105
+ def print_current(log_name, log_length, current_start_time, output)
106
+ if is_current_log_name?(log_name)
107
+ formatted_length = seconds_format.duration storage.time_since_start
108
+ out_str = out_str = "\t%-4s %16s %14s %14s %s" % [
109
+ date_time_format.timestamp(current_start_time),
110
+ nil,
111
+ formatted_length,
112
+ storage.cur_entry_owner,
113
+ storage.cur_entry_description,
114
+ ]
115
+ output.line(out_str)
116
+ storage.time_since_start
117
+ end
118
+ end
119
+
120
+ def length_exceeds_threshold?(log_length, length_threshold)
121
+ if length_threshold and log_length
122
+ length_threshold = ChronicDuration.parse(length_threshold)
123
+ if log_length - length_threshold > 0
124
+ true
125
+ else
126
+ false
127
+ end
128
+ else
129
+ false
130
+ end
131
+ end
132
+
133
+ def update_log_length(log_length)
134
+ log_length - storage.time_since_start if log_length
135
+ end
136
+
137
+ def is_current_log_name?(log_name)
138
+ if storage.current_log_name == log_name
139
+ true
140
+ else
141
+ false
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,34 @@
1
+
2
+ class Tlog::Command::Init < Tlog::Command
3
+
4
+ def name
5
+ "init"
6
+ end
7
+
8
+ def execute(input,output)
9
+ if input.args[0].nil?
10
+ raise Tlog::Error::CommandInvalid, "Project already initialized" unless @storage.init_project
11
+ else
12
+ raise Tlog::Error::CommandInvalid, "Command invalid"
13
+ end
14
+ #elsif input.args[1].nil?
15
+ # arg1 = input.args.shift
16
+ # #output.line("arg at 0 was #{arg1}")
17
+ #else
18
+ # arg1 = input.args.shift
19
+ # arg2 = input.args.shift
20
+ # #output.line("arg at 0 was #{arg1}")
21
+ # #output.line("arg at 1 was #{arg2}")
22
+ # raise Tlog::Error::CommandInvalid, "Command invalid"
23
+ #end
24
+
25
+ #@storage.init_project
26
+ end
27
+
28
+ def options(parser, options)
29
+ parser.banner = "usage: tlog init"
30
+ end
31
+
32
+ private
33
+
34
+ end
@@ -0,0 +1,31 @@
1
+
2
+ class Tlog::Command::Start < Tlog::Command
3
+
4
+ def name
5
+ "start"
6
+ end
7
+
8
+ def execute(input, output)
9
+ raise Tlog::Error::CommandInvalid, "Must specify log name" unless input.args[0]
10
+ start(input.args[0], input.options[:description])
11
+ end
12
+
13
+ def options(parser, options)
14
+ parser.banner = "usage: tlog start <log_name>"
15
+
16
+ parser.on("-d", "--description <description>") do |description|
17
+ options[:description] = description
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def start(log_name, entry_description)
24
+ storage.in_branch do |wd|
25
+ log = storage.require_log(log_name)
26
+ raise Tlog::Error::CommandNotFound, "Time log '#{log_name}' does not exist" unless log
27
+ current_owner = storage.cur_entry_owner
28
+ storage.start_log(log, entry_description)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ class Tlog::Command::Stop < Tlog::Command
2
+
3
+ def name
4
+ "stop"
5
+ end
6
+
7
+ def execute(input, output)
8
+ raise Tlog::Error::CommandInvalid, "Must specify log name" unless input.args[0]
9
+ stop(input.args[0])
10
+ end
11
+
12
+ def options(parser, options)
13
+ parser.banner = "usage: tlog stop <log_name>"
14
+ end
15
+
16
+ private
17
+
18
+ def stop(log_name)
19
+ storage.in_branch do |wd|
20
+ log = storage.require_log(log_name)
21
+ storage.stop_log(log)
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,32 @@
1
+
2
+ class Tlog::Command::Test < Tlog::Command
3
+
4
+ def name
5
+ "test"
6
+ end
7
+
8
+ def execute(input,output)
9
+ output.line("execute on test called")
10
+ if input.args[0].nil?
11
+ output.line("args at 0 was nil")
12
+ elsif input.args[1].nil?
13
+ arg1 = input.args.shift
14
+ output.line("arg at 0 was #{arg1}")
15
+ else
16
+ arg1 = input.args.shift
17
+ arg2 = input.args.shift
18
+ output.line("arg at 0 was #{arg1}")
19
+ output.line("arg at 1 was #{arg2}")
20
+ raise Tlog::Error::CommandInvalid, "Command invalid"
21
+ end
22
+ end
23
+
24
+ def options(parser, options)
25
+ parser.banner = "usage: tlog test <project>"
26
+ end
27
+
28
+ private
29
+
30
+
31
+
32
+ end
@@ -0,0 +1,14 @@
1
+ class Tlog::Command
2
+
3
+ attr_accessor :storage
4
+ attr_accessor :seconds_format
5
+ attr_accessor :date_time_format
6
+
7
+ def execute(input, output)
8
+ raise NotImplementedError
9
+ end
10
+
11
+ def options(parser, options)
12
+ end
13
+
14
+ end
@@ -0,0 +1,11 @@
1
+
2
+ # Helper class for printing out active time logs
3
+ class Tlog::Entity::Active_Log
4
+ attr_accessor :name
5
+ attr_accessor :current
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @current = false
10
+ end
11
+ end
@@ -0,0 +1,90 @@
1
+
2
+ class Tlog::Entity::Entry
3
+
4
+ attr_accessor :hex
5
+ attr_accessor :path
6
+
7
+ def initialize(path, hex)
8
+ @path = path
9
+ @hex = hex
10
+ end
11
+
12
+ def length
13
+ time_difference if time[:start] && time[:end]
14
+ end
15
+
16
+ def create(parent, current)
17
+ FileUtils.mkdir_p(path)
18
+ time_log = current[:start_time].to_s + " " + Time.now.to_s
19
+ write_file(parent_path, parent)
20
+ write_file(time_path, time_log.strip)
21
+ write_file(description_path, current[:description])
22
+ write_file(owner_path, current[:owner])
23
+ end
24
+
25
+ def parent_hex
26
+ read_file(parent_path)
27
+ end
28
+
29
+ def time
30
+ time_hash = {}
31
+ start_time_string = ""
32
+ end_time_string = ""
33
+ time_contents = read_file(time_path)
34
+ return time_hash unless time_contents
35
+ split_contents = time_contents.split(" ", 6)
36
+ for i in 0..2
37
+ start_time_string += split_contents[i] + " "
38
+ end
39
+ for i in 3..5
40
+ end_time_string += split_contents[i] + " "
41
+ end
42
+ time_hash[:start] = Time.parse(start_time_string)
43
+ time_hash[:end] = Time.parse(end_time_string)
44
+ return time_hash
45
+ end
46
+
47
+ def description
48
+ read_file(description_path)
49
+ end
50
+
51
+ def owner
52
+ read_file(owner_path)
53
+ end
54
+
55
+ private
56
+
57
+ def write_file(path, content)
58
+ File.open(path, 'w'){ |f| f.write(content)}
59
+ end
60
+
61
+ def read_file(path)
62
+ if File.exists?(path)
63
+ contents = File.read(path)
64
+ contents.strip
65
+ end
66
+ end
67
+
68
+ def time_difference
69
+ time_hash = time
70
+ difference = time_hash[:end] - time_hash[:start]
71
+ difference.to_i
72
+ end
73
+
74
+ def parent_path
75
+ File.join(@path, 'PARENT')
76
+ end
77
+
78
+ def time_path
79
+ File.join(@path, 'TIME')
80
+ end
81
+
82
+ def description_path
83
+ File.join(@path, 'DESCRIPTION')
84
+ end
85
+
86
+ def owner_path
87
+ File.join(@path, 'OWNER')
88
+ end
89
+
90
+ end
@@ -0,0 +1,102 @@
1
+
2
+ class Tlog::Entity::Log
3
+
4
+ attr_accessor :name
5
+ attr_accessor :goal
6
+ attr_accessor :entries
7
+ attr_accessor :path
8
+
9
+ def initialize(log_path = nil)
10
+ @entries = []
11
+ if log_path
12
+ @name = log_path.basename.to_s
13
+ @path = log_path
14
+ @goal = goal_length
15
+ end
16
+ end
17
+
18
+ def goal_length
19
+ if File.exists?(goal_path)
20
+ contents = File.read(goal_path)
21
+ contents.strip
22
+ contents.to_i
23
+ end
24
+ end
25
+
26
+
27
+ def entries
28
+ log_entries = []
29
+ hex_value = head_hex_value
30
+ return log_entries unless hex_value
31
+ begin
32
+ entry = Tlog::Entity::Entry.new(entry_path(hex_value), hex_value)
33
+ hex_value = entry.parent_hex
34
+ log_entries.push(entry)
35
+ end until hex_value == "none"
36
+ return log_entries
37
+ end
38
+
39
+ def duration
40
+ dur = 0
41
+ entries.each do |entry|
42
+ dur += entry.length
43
+ end
44
+ dur
45
+ end
46
+
47
+ def create
48
+ unless Dir.exists?(@path)
49
+ FileUtils.mkdir_p(@path)
50
+ File.open(goal_path, 'w'){|f| f.write(@goal)} if @goal
51
+ true
52
+ end
53
+ end
54
+
55
+ def add_entry(current)
56
+ entry_hex = generate_random_hex
57
+ new_entry = Tlog::Entity::Entry.new(entry_path(entry_hex), entry_hex)
58
+ head_hex_value ? parent_hex = head_hex_value : parent_hex = "none"
59
+
60
+ update_head(entry_hex)
61
+ new_entry.create(parent_hex, current)
62
+ update_goal(new_entry.length) if goal_length
63
+ end
64
+
65
+ def update_head(entry_hex)
66
+ File.open(head_path, 'w'){|f| f.write(entry_hex)}
67
+ end
68
+
69
+ def update_goal(entry_length)
70
+ new_length = goal_length - entry_length
71
+ File.open(goal_path, 'w'){|f| f.write(new_length)}
72
+ end
73
+
74
+ def delete
75
+ FileUtils.rm_rf(@path) if Dir.exists?(@path)
76
+ end
77
+
78
+ private
79
+
80
+ def head_hex_value
81
+ if File.exists?(head_path)
82
+ head_content = File.read(head_path)
83
+ head_content.strip if head_content
84
+ end
85
+ end
86
+
87
+ def goal_path
88
+ File.join(@path, 'GOAL')
89
+ end
90
+
91
+ def head_path
92
+ File.join(@path, 'HEAD')
93
+ end
94
+
95
+ def entry_path(hex)
96
+ File.join(@path, hex)
97
+ end
98
+
99
+ def generate_random_hex
100
+ SecureRandom.hex(13)
101
+ end
102
+ end
data/lib/tlog/error.rb ADDED
@@ -0,0 +1,6 @@
1
+
2
+ class Tlog::Error::CommandNotFound < StandardError
3
+ end
4
+
5
+ class Tlog::Error::CommandInvalid < StandardError
6
+ end
@@ -0,0 +1,7 @@
1
+ class Tlog::Format::DateTime
2
+
3
+ def self.timestamp(gmt_time)
4
+ gmt_time.strftime("%B %d, %I:%M%p")
5
+ end
6
+
7
+ end
@@ -0,0 +1,13 @@
1
+ class Tlog::Format::Seconds
2
+
3
+ def self.duration(total_seconds)
4
+ output = ""
5
+ total_seconds ||= 0
6
+ total_seconds = total_seconds.to_i
7
+ mm, ss = total_seconds.divmod(60)
8
+ hh, mm = mm.divmod(60)
9
+ output = "%2s:%02d:%02d" % [hh, mm, ss]
10
+ return output
11
+ end
12
+
13
+ end
data/lib/tlog/input.rb ADDED
@@ -0,0 +1,10 @@
1
+
2
+ class Tlog::Input
3
+ attr_accessor :args
4
+ attr_accessor :options
5
+
6
+ def initialize(args=[])
7
+ @args = args
8
+ @options = {}
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ require 'colorize'
2
+ class Tlog::Output
3
+
4
+ attr_accessor :stdout
5
+ attr_accessor :stderr
6
+
7
+ def initialize(stdout,stderr)
8
+ @stdout = stdout
9
+ @stderr = stderr
10
+ end
11
+
12
+ def error(err)
13
+ @stderr.puts err
14
+ end
15
+
16
+ def line(out)
17
+ @stdout.puts out
18
+ true
19
+ end
20
+
21
+ def line_yellow(out)
22
+ @stdout.puts out.yellow
23
+ end
24
+
25
+ def line_red(out)
26
+ @stdout.puts out.red
27
+ end
28
+
29
+ end