doing 2.1.10 → 2.1.11
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 +4 -4
- data/CHANGELOG.md +20 -0
- data/Dockerfile +9 -0
- data/Dockerfile-2.6 +9 -0
- data/Dockerfile-2.7 +8 -0
- data/Dockerfile-3.0 +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +39 -5
- data/bin/doing +2106 -1979
- data/lib/doing/configuration.rb +18 -8
- data/lib/doing/hooks.rb +10 -5
- data/lib/doing/items.rb +16 -1
- data/lib/doing/pager.rb +2 -20
- data/lib/doing/plugins/import/calendar_import.rb +5 -0
- data/lib/doing/plugins/import/doing_import.rb +2 -0
- data/lib/doing/plugins/import/timing_import.rb +5 -0
- data/lib/doing/util_backup.rb +16 -5
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +147 -66
- data/lib/doing.rb +1 -0
- data/lib/examples/plugins/hooks.rb +31 -0
- data/scripts/sort_commands.rb +59 -0
- metadata +7 -2
data/lib/doing/configuration.rb
CHANGED
@@ -152,17 +152,23 @@ module Doing
|
|
152
152
|
##
|
153
153
|
## @return [String] file path
|
154
154
|
##
|
155
|
-
def choose_config
|
155
|
+
def choose_config(create: false)
|
156
156
|
return @config_file if @force_answer
|
157
157
|
|
158
|
-
if @additional_configs.count.positive?
|
158
|
+
if @additional_configs.count.positive? || create
|
159
159
|
choices = [@config_file].concat(@additional_configs)
|
160
|
+
choices.push('Create a new .doingrc in the current directory') if create && !File.exist?('.doingrc')
|
160
161
|
res = Doing::Prompt.choose_from(choices.uniq.sort.reverse,
|
161
162
|
sorted: false,
|
162
163
|
prompt: 'Local configs found, select which to update > ')
|
163
164
|
|
164
165
|
raise UserCancelled, 'Cancelled' unless res
|
165
166
|
|
167
|
+
if res =~ /^Create a new/
|
168
|
+
res = File.expand_path('.doingrc')
|
169
|
+
FileUtils.touch(res)
|
170
|
+
end
|
171
|
+
|
166
172
|
res.strip || @config_file
|
167
173
|
else
|
168
174
|
@config_file
|
@@ -249,7 +255,8 @@ module Doing
|
|
249
255
|
# defaults.
|
250
256
|
#
|
251
257
|
def from(user_config)
|
252
|
-
Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
|
258
|
+
# Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
|
259
|
+
Configuration[user_config].stringify_keys.deep_merge(DEFAULTS, { extend_existing_arrays: true, sort_merged_arrays: true })
|
253
260
|
end
|
254
261
|
|
255
262
|
##
|
@@ -320,8 +327,8 @@ module Doing
|
|
320
327
|
|
321
328
|
Hooks.trigger :post_config, self
|
322
329
|
|
323
|
-
|
324
|
-
config = Util.deep_merge_hashes(config, local_config) unless @ignore_local
|
330
|
+
config = local_config.deep_merge(config, { extend_existing_arrays: true, sort_merged_arrays: true }) unless @ignore_local
|
331
|
+
# config = Util.deep_merge_hashes(config, local_config) unless @ignore_local
|
325
332
|
|
326
333
|
Hooks.trigger :post_local_config, self
|
327
334
|
|
@@ -397,7 +404,7 @@ module Doing
|
|
397
404
|
|
398
405
|
begin
|
399
406
|
additional_configs.each do |cfg|
|
400
|
-
local_configs.deep_merge(Util.safe_load_file(cfg))
|
407
|
+
local_configs.deep_merge(Util.safe_load_file(cfg), { extend_existing_arrays: true, sort_merged_arrays: true })
|
401
408
|
end
|
402
409
|
rescue StandardError
|
403
410
|
Doing.logger.error('Config:', 'Error reading local configuration(s)')
|
@@ -416,15 +423,18 @@ module Doing
|
|
416
423
|
end
|
417
424
|
|
418
425
|
begin
|
426
|
+
|
419
427
|
user_config = Util.safe_load_file(config_file)
|
428
|
+
raise StandardError, 'Invalid config file format' unless user_config.is_a?(Hash)
|
429
|
+
|
420
430
|
if user_config.key?('html_template')
|
421
431
|
user_config['export_templates'] ||= {}
|
422
|
-
user_config['export_templates'].deep_merge(user_config.delete('html_template'))
|
432
|
+
user_config['export_templates'].deep_merge(user_config.delete('html_template'), { extend_existing_arrays: true, sort_merged_arrays: true })
|
423
433
|
end
|
424
434
|
|
425
435
|
user_config['include_notes'] = user_config.delete(':include_notes') if user_config.key?(':include_notes')
|
426
436
|
|
427
|
-
user_config.deep_merge(DEFAULTS)
|
437
|
+
user_config.deep_merge(DEFAULTS, { extend_existing_arrays: true, sort_merged_arrays: true })
|
428
438
|
rescue StandardError => e
|
429
439
|
Doing.logger.error('Config:', 'Error reading default configuration')
|
430
440
|
Doing.logger.error('Error:', e.message)
|
data/lib/doing/hooks.rb
CHANGED
@@ -6,11 +6,16 @@ module Doing
|
|
6
6
|
DEFAULT_PRIORITY = 20
|
7
7
|
|
8
8
|
@registry = {
|
9
|
-
post_config: [],
|
10
|
-
post_local_config: [],
|
11
|
-
post_read: [],
|
12
|
-
|
13
|
-
|
9
|
+
post_config: [], # wwid
|
10
|
+
post_local_config: [], # wwid
|
11
|
+
post_read: [], # wwid
|
12
|
+
pre_entry_add: [], # wwid, new_entry
|
13
|
+
post_entry_added: [], # wwid, new_entry.dup
|
14
|
+
post_entry_updated: [], # wwid, entry
|
15
|
+
post_entry_removed: [], # wwid, entry.dup
|
16
|
+
pre_export: [], # wwid, format, entries
|
17
|
+
pre_write: [], # wwid, file
|
18
|
+
post_write: [] # wwid, file
|
14
19
|
}
|
15
20
|
|
16
21
|
# map of all hooks and their priorities
|
data/lib/doing/items.rb
CHANGED
@@ -69,7 +69,7 @@ module Doing
|
|
69
69
|
if section =~ /^all$/i
|
70
70
|
dup
|
71
71
|
else
|
72
|
-
items = Items.new.concat(select { |item| item.section == section })
|
72
|
+
items = Items.new.concat(select { |item| !item.nil? && item.section == section })
|
73
73
|
items.add_section(section, log: false)
|
74
74
|
items
|
75
75
|
end
|
@@ -84,6 +84,7 @@ module Doing
|
|
84
84
|
deleted = delete(item)
|
85
85
|
Doing.logger.count(:deleted)
|
86
86
|
Doing.logger.info('Entry deleted:', deleted.title) if single
|
87
|
+
deleted
|
87
88
|
end
|
88
89
|
|
89
90
|
##
|
@@ -111,6 +112,20 @@ module Doing
|
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
115
|
+
##
|
116
|
+
## Return Items containing items that don't exist in receiver
|
117
|
+
##
|
118
|
+
## @param items [Items] Receiver
|
119
|
+
##
|
120
|
+
def diff(items)
|
121
|
+
diff = Items.new
|
122
|
+
each do |item|
|
123
|
+
res = items.select { |i| i.equal?(item) }
|
124
|
+
diff.push(item) unless res.count.positive?
|
125
|
+
end
|
126
|
+
diff
|
127
|
+
end
|
128
|
+
|
114
129
|
# Output sections and items in Doing file format
|
115
130
|
def to_s
|
116
131
|
out = []
|
data/lib/doing/pager.rb
CHANGED
@@ -64,22 +64,8 @@ module Doing
|
|
64
64
|
|
65
65
|
private
|
66
66
|
|
67
|
-
def command_exist?(command)
|
68
|
-
exts = ENV.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR)
|
69
|
-
if Pathname.new(command).absolute?
|
70
|
-
::File.exist?(command) ||
|
71
|
-
exts.any? { |ext| ::File.exist?("#{command}#{ext}")}
|
72
|
-
else
|
73
|
-
ENV.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir|
|
74
|
-
file = ::File.join(dir, command)
|
75
|
-
::File.exist?(file) ||
|
76
|
-
exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
67
|
def git_pager
|
82
|
-
|
68
|
+
TTY::Which.exist?('git') ? `#{TTY::Which.which('git')} config --get-all core.pager` : nil
|
83
69
|
end
|
84
70
|
|
85
71
|
def pagers
|
@@ -91,11 +77,7 @@ module Doing
|
|
91
77
|
execs = commands.empty? ? pagers : commands
|
92
78
|
execs
|
93
79
|
.compact.map(&:strip).reject(&:empty?).uniq
|
94
|
-
.find { |cmd|
|
95
|
-
end
|
96
|
-
|
97
|
-
def exec_available?(*commands)
|
98
|
-
!find_executable(*commands).nil?
|
80
|
+
.find { |cmd| TTY::Which.exist?(cmd.split.first) }
|
99
81
|
end
|
100
82
|
|
101
83
|
def which_pager
|
@@ -73,7 +73,12 @@ module Doing
|
|
73
73
|
dups = filtered - new_items.count
|
74
74
|
Doing.logger.info(%(Skipped #{dups} items with overlapping times)) if dups.positive?
|
75
75
|
|
76
|
+
new_items.map { |item| Hooks.trigger :pre_entry_add, self, item }
|
77
|
+
|
76
78
|
wwid.content.concat(new_items)
|
79
|
+
|
80
|
+
new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
|
81
|
+
|
77
82
|
Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
|
78
83
|
end
|
79
84
|
|
@@ -80,7 +80,9 @@ module Doing
|
|
80
80
|
|
81
81
|
imported.each do |item|
|
82
82
|
wwid.content.add_section(item.section) unless wwid.content.section?(item.section)
|
83
|
+
Hooks.trigger :pre_entry_add, self, item
|
83
84
|
wwid.content.push(item)
|
85
|
+
Hooks.trigger :post_entry_added, self, item.dup
|
84
86
|
end
|
85
87
|
|
86
88
|
Doing.logger.info('Imported:', "#{imported.count} items")
|
@@ -77,7 +77,12 @@ module Doing
|
|
77
77
|
dups = filtered - new_items.count
|
78
78
|
Doing.logger.debug('Skipped:' , %(#{dups} items with overlapping times)) if dups.positive?
|
79
79
|
|
80
|
+
new_items.map { |item| Hooks.trigger :pre_entry_add, self, item }
|
81
|
+
|
80
82
|
wwid.content.concat(new_items)
|
83
|
+
|
84
|
+
new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
|
85
|
+
|
81
86
|
Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
|
82
87
|
end
|
83
88
|
|
data/lib/doing/util_backup.rb
CHANGED
@@ -37,6 +37,19 @@ module Doing
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
##
|
41
|
+
## Retrieve the most recent backup
|
42
|
+
##
|
43
|
+
## @param filename The filename
|
44
|
+
## @return [String] filename
|
45
|
+
##
|
46
|
+
def last_backup(filename = nil, count: 1)
|
47
|
+
filename ||= Doing.config.settings['doing_file']
|
48
|
+
|
49
|
+
backup = get_backups(filename).slice(count - 1)
|
50
|
+
backup.nil? ? nil : File.join(backup_dir, backup)
|
51
|
+
end
|
52
|
+
|
40
53
|
##
|
41
54
|
## Restore the most recent backup. If a filename is
|
42
55
|
## provided, only backups of that filename will be used.
|
@@ -48,15 +61,13 @@ module Doing
|
|
48
61
|
Doing.logger.benchmark(:restore_backup, :start)
|
49
62
|
filename ||= Doing.config.settings['doing_file']
|
50
63
|
|
51
|
-
|
52
|
-
raise DoingRuntimeError, 'End of undo history' if
|
53
|
-
|
54
|
-
backup_file = File.join(backup_dir, result)
|
64
|
+
backup_file = last_backup(filename, count: count)
|
65
|
+
raise DoingRuntimeError, 'End of undo history' if backup_file.nil?
|
55
66
|
|
56
67
|
save_undone(filename)
|
57
68
|
FileUtils.mv(backup_file, filename)
|
58
69
|
prune_backups_after(File.basename(backup_file))
|
59
|
-
Doing.logger.warn('File update:', "restored from #{
|
70
|
+
Doing.logger.warn('File update:', "restored from #{backup_file}")
|
60
71
|
Doing.logger.benchmark(:restore_backup, :finish)
|
61
72
|
end
|
62
73
|
|
data/lib/doing/version.rb
CHANGED