tlog 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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