done_log 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fa9087eac5309de9a13842028ba9d4414a31019914c288a4f6708b20a77fe12e
4
+ data.tar.gz: c95a79c7b8a1ebc63f831829f387d509f3872004b78defc139e84f985cddacd0
5
+ SHA512:
6
+ metadata.gz: 50203c3aafcd8719de41afda937b5859bd6b27d730d9688b57dd291e03a411b351c975ec124fe6d415af707a4bf9702053b27a6d8218b282a99aa1a9afe0370a
7
+ data.tar.gz: a4471793fc7b925e611957c8b81c28c77771c4ac42377e2b21202d2096c7d9fe51272be5029bbd409affa00a153d17a9bea0f4f081b10b33fc08d08d3fc1ab13
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ ## Done
2
+
3
+ This is a dumb Ruby script to help manage daily work logs.
4
+
5
+ Keeps each day in a separate file.
6
+
7
+ Keeps the files in a Git repository.
8
+
9
+ Edits the logs via `vim`.
10
+
11
+ Trailing newlines stripped automatically from logs.
12
+
13
+ Optionally pushes to a remote Git repository.
14
+
15
+ ### Installing
16
+
17
+ This is a Ruby program, so you'll need [a Ruby](https://www.ruby-lang.org/) first.
18
+
19
+ Via RubyGems:
20
+
21
+ gem install done_log
22
+
23
+ From source:
24
+
25
+ git clone https://github.com/presidentbeef/done_log.git
26
+ gem build done_log.gemspec
27
+ gem install done_log*.gem
28
+
29
+ ### Configuration
30
+
31
+ Logs are kept in `~/.done/log/`.
32
+
33
+ This directory is created automatically.
34
+
35
+ Configuration is read from JSON file `~/.done/config`.
36
+
37
+ A default configuration file is created automatically.
38
+
39
+ Options are:
40
+
41
+ * `git_repo` which can be set to a remote Git repository.
42
+ * `date_color` which sets the color used for dates when viewing logs.
43
+
44
+ [Possible colors listed here](https://github.com/presidentbeef/done_log/blob/master/lib/done_log/ansi_colors.rb#L4-L12),
45
+ plus they can be prefixed by `bright_`.
46
+
47
+ ### Running
48
+
49
+ `done_log` edits the log for the current day.
50
+
51
+ `done_log -[N]` edits the log for the previous `N` day. `-1` is yesterday, `-2` is two days ago, etc.
52
+
53
+ `done_log -d DATE` edits the log for the specified date.
54
+
55
+ `done_log -s -d DATE` shows the specified log.
56
+
57
+ `done_log --sprint` shows the last 14 days of logs.
58
+
59
+ ### Logging
60
+
61
+ #### Start a Log
62
+
63
+ To enter a log for today, run `done_log`.
64
+
65
+ To enter a log for yesterday, run `done_log -1`
66
+
67
+ To enter a log for a specific date, run `done_log -d DATE`.
68
+
69
+ #### Edit a Log
70
+
71
+ When editing, `vim` is opened to a new/existing document. When `vim` exits, the log is committed and pushed to the Git repo.
72
+
73
+ To cancel a new log, delete _everything_ in the file and save.
74
+
75
+ To cancel edits to an existing log, close `vim` without saving.
76
+
77
+ #### Review a Log
78
+
79
+ To view an existing log, use `-s` or `--show`.
80
+
81
+ Examples:
82
+
83
+ * `done_log --show --date DATE`
84
+ * `done_log -s -d DATE`
85
+ * `done_log -s -1` (Show yesterday's log)
86
+
87
+ ### License
88
+
89
+ MIT
data/bin/done_log ADDED
@@ -0,0 +1,14 @@
1
+ #!/bin/env ruby
2
+ require 'date'
3
+ require_relative '../lib/done_log.rb'
4
+
5
+ options = Done::Options.parse!(ARGV)
6
+
7
+ case options[:action]
8
+ when :edit
9
+ Done::Log.edit_logs(options[:time_period])
10
+ when :show
11
+ Done::Log.show_logs(options[:time_period], options[:date_color])
12
+ else
13
+ abort "Need to either --edit or --show logs"
14
+ end
data/lib/done_log.rb ADDED
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'fileutils'
5
+ require 'json'
6
+ require_relative 'done_log/git_repo'
7
+ require_relative 'done_log/options'
8
+ require_relative 'done_log/ansi_colors'
9
+
10
+ module Done
11
+ class Log
12
+ attr_reader :date, :dir, :git, :log_file
13
+
14
+ def initialize date:, date_color: nil
15
+ @date = date
16
+ @dir = Done::Log.default_log_dir
17
+ year = date.year.to_s
18
+ month = date.month.to_s.rjust(2, "0")
19
+ @log_file = File.join(dir, year, month, date_string)
20
+
21
+ config = Done::Log.config
22
+ @git = GitRepo.new(config[:git_repo], dir, log_file)
23
+ @date_color = date_color || config[:date_color]
24
+ end
25
+
26
+ def log
27
+ ensure_directory
28
+ git.pull
29
+ create_log
30
+ vim_edit
31
+ strip_log
32
+ git.add
33
+ git.commit
34
+ git.push
35
+ end
36
+
37
+ def show pull = true
38
+ ensure_directory
39
+ git.pull if pull
40
+
41
+ if File.exist? log_file
42
+ log = File.read(log_file)
43
+ if $stdout.tty?
44
+ puts log.sub(/^(\d{4}-\d{2}-\d{2})$/) { |date| Done::ANSIColors.colorize(date, @date_color) }
45
+ else
46
+ puts log
47
+ end
48
+
49
+ puts
50
+ else
51
+ puts <<~LOG
52
+ #{Done::ANSIColors.colorize(date_string, @date_color)}
53
+
54
+ [No log]
55
+
56
+ LOG
57
+ end
58
+ end
59
+
60
+ def ensure_directory
61
+ FileUtils.mkdir_p(File.dirname(log_file))
62
+ git.init
63
+ end
64
+
65
+ def create_log
66
+ unless File.exist? log_file
67
+ File.open(log_file, "w") do |f|
68
+ f.puts <<~LOG
69
+ #{date_string}
70
+
71
+ LOG
72
+ end
73
+
74
+ git.add
75
+ end
76
+ end
77
+
78
+ def strip_log
79
+ log = File.read(log_file).strip
80
+
81
+ if log.empty?
82
+ File.delete(log_file)
83
+ else
84
+ File.open(log_file, "w") do |f|
85
+ f.puts log
86
+ end
87
+ end
88
+ end
89
+
90
+ def vim_edit
91
+ system 'vim',
92
+ '+ normal Go', # Move to end of file, start new line
93
+ '+startinsert', # Switch to insert mode
94
+ log_file
95
+ end
96
+
97
+ def date_string
98
+ date.iso8601.freeze
99
+ end
100
+
101
+ class << self
102
+ def default_dir
103
+ File.join(Dir.home, ".done").freeze
104
+ end
105
+
106
+ def default_log_dir
107
+ File.join(Dir.home, ".done", "log").freeze
108
+ end
109
+
110
+ def logs
111
+ Dir[self.default_dir].sort
112
+ end
113
+
114
+ def config config_file = default_config_file
115
+ if File.exist? config_file
116
+ begin
117
+ JSON.parse(File.read(config_file), symbolize_names: true)
118
+ rescue JSON::ParserError => e
119
+ warn "Unable to parse config file: #{e.inspect}"
120
+ {}
121
+ end
122
+ else
123
+ FileUtils.mkdir_p(default_dir)
124
+
125
+ config = default_config
126
+ puts "What Git URL (e.g. git@github.com:user_name/example_log.git) should we use?\nLeave blank to skip."
127
+ print "? "
128
+ url = gets.strip
129
+
130
+ unless url.empty?
131
+ config[:git_repo] = url
132
+ end
133
+
134
+ File.open(config_file, "w") do |f|
135
+ f.puts(JSON.pretty_generate(config))
136
+ end
137
+
138
+ config
139
+ end
140
+ end
141
+
142
+ def default_config
143
+ {
144
+ git_repo: nil,
145
+ date_color: :cyan
146
+ }
147
+ end
148
+
149
+ def default_config_file
150
+ File.join(default_dir, "config")
151
+ end
152
+
153
+ def edit_logs time_period
154
+ if time_period.is_a? Date
155
+ Done::Log.new(date: time_period).log
156
+ else
157
+ time_period.each do |d|
158
+ Done::Log.new(date: d).log
159
+ end
160
+ end
161
+ end
162
+
163
+ def show_logs time_period, date_color = nil
164
+ if time_period.is_a? Date
165
+ Done::Log.new(date: time_period, date_color: date_color).show
166
+ else
167
+ pull = true
168
+ time_period.each do |d|
169
+ Done::Log.new(date: d, date_color: date_color).show(pull)
170
+ pull = false
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,38 @@
1
+ module Done
2
+ module ANSIColors
3
+ Colors = {
4
+ none: 0,
5
+ black: 30,
6
+ red: 31,
7
+ green: 32,
8
+ yellow: 33,
9
+ blue: 34,
10
+ magenta: 35,
11
+ cyan: 36,
12
+ white: 37,
13
+ }.freeze
14
+
15
+ def self.colorize input, color
16
+ return input unless color
17
+
18
+ color = color.to_sym
19
+
20
+ if color == :none
21
+ return input
22
+ end
23
+
24
+ color_code = if color.start_with? 'bright'
25
+ code = Colors[color.to_s.split('_').last.to_sym]
26
+ "#{code};1"
27
+ else
28
+ Colors[color.to_sym]
29
+ end
30
+
31
+ "\e[#{color_code}m#{input}\e[0m"
32
+ end
33
+
34
+ def self.colors
35
+ @colors ||= Colors.keys.concat(Colors.keys.map { |c| "bright_#{c}".to_sym })
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Done
6
+ class GitRepo
7
+ attr_reader :git_url, :log_dir, :log_file
8
+
9
+ def initialize git_url, log_dir, log_file
10
+ @git_url = git_url
11
+ @log_dir = log_dir
12
+ @log_file = log_file
13
+ end
14
+
15
+ def add
16
+ unless File.empty? log_file
17
+ run "git add #{log_file}"
18
+ end
19
+ end
20
+
21
+ def commit
22
+ unless run "git diff --no-patch --cached --exit-code" # Check if there are any changes
23
+ unless run "git commit #{log_file} -m 'Update #{File.basename log_file}'"
24
+ raise 'Could not commit update to git'
25
+ end
26
+ end
27
+ end
28
+
29
+ def has_remote?
30
+ run "git remote -v | grep -q -F #{git_url.inspect}"
31
+ end
32
+
33
+ def init
34
+ if git_url and not Dir.exist? log_dir
35
+ run "git clone -q #{git_url} #{log_dir}"
36
+ else
37
+ run "git init -q #{log_dir}"
38
+ end
39
+ end
40
+
41
+ def pull
42
+ return unless git_url
43
+ return unless has_remote?
44
+
45
+ unless run 'git pull -q'
46
+ raise 'Could not pull from git'
47
+ end
48
+ end
49
+
50
+ def push
51
+ return unless git_url
52
+ return unless has_remote?
53
+
54
+ unless run 'git push'
55
+ raise 'Could not push to git'
56
+ end
57
+ end
58
+
59
+ def run cmd
60
+ FileUtils.cd(log_dir) do
61
+ system cmd
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'optparse/date'
5
+ require_relative 'ansi_colors'
6
+
7
+ module Done
8
+ class Options
9
+ def self.parse!(args)
10
+ options = {}
11
+
12
+ days = args.grep(/^-\d+$/)
13
+
14
+ unless days.empty?
15
+ if days.length > 1
16
+ raise "Expected only one day, got #{days.inspect}"
17
+ end
18
+
19
+ days = days.first
20
+ args.delete days
21
+ options[:time_period] = Date.today - days.to_i.abs
22
+ options[:action] ||= :edit
23
+ end
24
+
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: done_log [options]"
27
+
28
+ opts.on "-NUM", OptionParser::DecimalInteger, "Go back NUM days"
29
+
30
+ opts.on "-e", "--edit", "Edit log(s)" do
31
+ options[:action] = :edit
32
+ end
33
+
34
+ opts.on "-s", "--show", "Display log(s)" do
35
+ options[:action] = :show
36
+ end
37
+
38
+ opts.on "-d", "--date [DATE]", Date, "Select date" do |date|
39
+ options[:time_period] = date
40
+ end
41
+
42
+ opts.on "--sprint", "Last 14 days" do
43
+ options[:time_period] = (Date.today - 14)..Date.today
44
+ options[:action] ||= :show
45
+ end
46
+
47
+ opts.on "-c", "--color-date COLOR", Done::ANSIColors.colors, "Set color for dates" do |color|
48
+ options[:date_color] = color.to_sym
49
+ end
50
+
51
+ opts.on_tail "-h", "--help", "Show this message" do
52
+ puts opts
53
+ exit
54
+ end
55
+ end.parse(args)
56
+
57
+ default_options.merge(options)
58
+ end
59
+
60
+ def self.default_options
61
+ {
62
+ action: :edit,
63
+ time_period: Date.today
64
+ }
65
+ end
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: done_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Collins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Manage very simple daily work logs in text files.
14
+ email:
15
+ executables:
16
+ - done_log
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - bin/done_log
22
+ - lib/done_log.rb
23
+ - lib/done_log/ansi_colors.rb
24
+ - lib/done_log/git_repo.rb
25
+ - lib/done_log/options.rb
26
+ homepage: https://github.com/presidentbeef/done_log
27
+ licenses:
28
+ - MIT
29
+ metadata:
30
+ source_code_uri: https://github.com/presidentbeef/done_log
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 2.3.0
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.1.2
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Extremely simple daily log.
50
+ test_files: []