done_log 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []