dsu 1.2.1 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -21
- data/Gemfile.lock +7 -7
- data/README.md +28 -35
- data/bin/console +23 -1
- data/bin/dsu +3 -0
- data/bin/setup +14 -3
- data/exe/dsu +23 -1
- data/exe/dsu_migrate.rb +43 -0
- data/lib/core/ruby/color_theme_colors.rb +16 -0
- data/lib/core/ruby/color_theme_mode.rb +42 -0
- data/lib/core/ruby/not_today.rb +7 -0
- data/lib/core/ruby/wrap_and_join.rb +31 -0
- data/lib/dsu/base_cli.rb +19 -23
- data/lib/dsu/cli.rb +47 -37
- data/lib/dsu/command_services/add_entry_service.rb +10 -21
- data/lib/dsu/crud/json_file.rb +139 -0
- data/lib/dsu/crud/raw_json_file.rb +51 -0
- data/lib/dsu/env.rb +21 -0
- data/lib/dsu/migration/service.rb +196 -0
- data/lib/dsu/migration/version.rb +7 -0
- data/lib/dsu/models/color_theme.rb +270 -0
- data/lib/dsu/models/configuration.rb +160 -0
- data/lib/dsu/models/entry.rb +6 -2
- data/lib/dsu/models/entry_group.rb +143 -42
- data/lib/dsu/models/migration_version.rb +48 -0
- data/lib/dsu/presenters/base_presenter.rb +32 -0
- data/lib/dsu/presenters/color_theme_presenter.rb +50 -0
- data/lib/dsu/presenters/color_theme_show_presenter.rb +49 -0
- data/lib/dsu/presenters/configuration_presenter.rb +45 -0
- data/lib/dsu/presenters/entry_group_presenter.rb +35 -0
- data/lib/dsu/presenters/entry_presenter.rb +25 -0
- data/lib/dsu/services/color_theme/hydrator_service.rb +42 -0
- data/lib/dsu/services/configuration/hydrator_service.rb +42 -0
- data/lib/dsu/services/entry/hydrator_service.rb +33 -0
- data/lib/dsu/services/entry_group/editor_service.rb +107 -0
- data/lib/dsu/services/entry_group/hydrator_service.rb +37 -0
- data/lib/dsu/services/migration_version/hydrator_service.rb +36 -0
- data/lib/dsu/services/stderr_redirector_service.rb +27 -0
- data/lib/dsu/services/temp_file/reader_service.rb +33 -0
- data/lib/dsu/services/temp_file/writer_service.rb +35 -0
- data/lib/dsu/subcommands/base_subcommand.rb +14 -0
- data/lib/dsu/subcommands/config.rb +92 -32
- data/lib/dsu/subcommands/edit.rb +3 -3
- data/lib/dsu/subcommands/list.rb +70 -93
- data/lib/dsu/subcommands/theme.rb +159 -0
- data/lib/dsu/support/ask.rb +14 -19
- data/lib/dsu/support/color_themable.rb +34 -0
- data/lib/dsu/support/command_help_colorizeable.rb +27 -0
- data/lib/dsu/support/command_hookable.rb +60 -0
- data/lib/dsu/support/command_options/dsu_times.rb +32 -21
- data/lib/dsu/support/command_options/time.rb +7 -1
- data/lib/dsu/support/command_options/time_mneumonic.rb +7 -1
- data/lib/dsu/support/descriptable.rb +6 -4
- data/lib/dsu/support/entry_group_viewable.rb +28 -4
- data/lib/dsu/support/fileable.rb +94 -0
- data/lib/dsu/support/presentable.rb +11 -0
- data/lib/dsu/support/subcommand_help_colorizeable.rb +27 -0
- data/lib/dsu/support/time_comparable.rb +19 -0
- data/lib/dsu/support/time_formatable.rb +12 -0
- data/lib/dsu/support/times_sortable.rb +48 -14
- data/lib/dsu/support/utils.rb +11 -0
- data/lib/dsu/validators/color_theme_validator.rb +74 -0
- data/lib/dsu/validators/entries_validator.rb +4 -8
- data/lib/dsu/validators/version_validator.rb +29 -0
- data/lib/dsu/version.rb +2 -1
- data/lib/dsu/views/color_theme/index.rb +62 -0
- data/lib/dsu/views/color_theme/show.rb +106 -0
- data/lib/dsu/views/configuration/show.rb +41 -0
- data/lib/dsu/views/entry_group/edit.rb +3 -5
- data/lib/dsu/views/entry_group/shared/no_entries_to_display.rb +41 -0
- data/lib/dsu/views/entry_group/show.rb +16 -15
- data/lib/dsu/views/shared/error.rb +17 -0
- data/lib/dsu/views/shared/info.rb +17 -0
- data/lib/dsu/views/shared/message.rb +85 -0
- data/lib/dsu/views/shared/model_errors.rb +31 -0
- data/lib/dsu/views/shared/success.rb +17 -0
- data/lib/dsu/views/shared/warning.rb +17 -0
- data/lib/dsu.rb +22 -1
- data/lib/seed_data/themes/cherry.json +79 -0
- data/lib/seed_data/themes/default.json +79 -0
- data/lib/seed_data/themes/lemon.json +79 -0
- data/lib/seed_data/themes/matrix.json +79 -0
- data/lib/seed_data/themes/whiteout.json +79 -0
- metadata +68 -23
- data/lib/dsu/core/ruby/not_today.rb +0 -11
- data/lib/dsu/services/ai/tense_translator_service.rb +0 -63
- data/lib/dsu/services/configuration_loader_service.rb +0 -55
- data/lib/dsu/services/entry_group_deleter_service.rb +0 -31
- data/lib/dsu/services/entry_group_editor_service.rb +0 -96
- data/lib/dsu/services/entry_group_hydrator_service.rb +0 -43
- data/lib/dsu/services/entry_group_reader_service.rb +0 -36
- data/lib/dsu/services/entry_group_writer_service.rb +0 -46
- data/lib/dsu/services/entry_hydrator_service.rb +0 -35
- data/lib/dsu/services/temp_file_reader_service.rb +0 -31
- data/lib/dsu/services/temp_file_writer_service.rb +0 -33
- data/lib/dsu/support/colorable.rb +0 -14
- data/lib/dsu/support/configurable.rb +0 -15
- data/lib/dsu/support/configuration.rb +0 -112
- data/lib/dsu/support/entry_group_fileable.rb +0 -49
- data/lib/dsu/support/entry_group_loadable.rb +0 -49
- data/lib/dsu/support/folder_locations.rb +0 -21
- data/lib/dsu/support/say.rb +0 -40
- data/lib/dsu/views/edited_entries/shared/errors.rb +0 -39
- data/lib/dsu/views/shared/messages.rb +0 -56
data/lib/dsu/cli.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'fileutils'
|
|
3
4
|
require 'time'
|
|
4
5
|
require_relative 'base_cli'
|
|
5
6
|
require_relative 'subcommands/config'
|
|
6
7
|
require_relative 'subcommands/edit'
|
|
7
8
|
require_relative 'subcommands/list'
|
|
9
|
+
require_relative 'subcommands/theme'
|
|
8
10
|
|
|
9
11
|
module Dsu
|
|
10
12
|
# The `dsu` command.
|
|
@@ -13,44 +15,41 @@ module Dsu
|
|
|
13
15
|
map %w[c -c] => :config
|
|
14
16
|
map %w[e -e] => :edit
|
|
15
17
|
map %w[l -l] => :list
|
|
18
|
+
map %w[t -t] => :theme
|
|
19
|
+
map %w[v -i] => :info
|
|
16
20
|
map %w[v -v] => :version
|
|
17
21
|
|
|
18
22
|
desc 'add, -a [OPTIONS] DESCRIPTION',
|
|
19
23
|
'Adds a DSU entry having DESCRIPTION to the date associated with the given OPTION'
|
|
20
24
|
long_desc <<-LONG_DESC
|
|
21
25
|
NAME
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
|
|
27
|
+
$ dsu add, -a [OPTIONS] DESCRIPTION -- will add a DSU entry having DESCRIPTION to the date associated with the given OPTION.
|
|
24
28
|
|
|
25
29
|
SYNOPSIS
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
|
|
31
|
+
$ dsu add, -a [-d DATE|-n|-t|-y] DESCRIPTION
|
|
28
32
|
|
|
29
33
|
OPTIONS:
|
|
30
|
-
|
|
34
|
+
|
|
31
35
|
-d DATE: Adds a DSU entry having DESCRIPTION to the DATE.
|
|
32
36
|
|
|
33
|
-
\x5
|
|
34
37
|
#{date_option_description}
|
|
35
38
|
|
|
36
|
-
\x5
|
|
37
39
|
-n: Adds a DSU entry having DESCRIPTION to today's date (`Time.now`).
|
|
38
40
|
|
|
39
|
-
\x5
|
|
40
41
|
-t: Adds a DSU entry having DESCRIPTION to tomorrow's date (`Time.new.tomorrow`).
|
|
41
42
|
|
|
42
|
-
\x5
|
|
43
43
|
-y: Adds a DSU entry having DESCRIPTION to yesterday's date (`Time.new.yesterday`).
|
|
44
44
|
|
|
45
45
|
DESCRIPTION:
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
Must be be between 2 and 256 characters (inclusive) in length.
|
|
48
48
|
LONG_DESC
|
|
49
49
|
option :date, type: :string, aliases: '-d'
|
|
50
50
|
option :tomorrow, type: :boolean, aliases: '-t'
|
|
51
51
|
option :yesterday, type: :boolean, aliases: '-y'
|
|
52
52
|
option :today, type: :boolean, aliases: '-n', default: true
|
|
53
|
-
|
|
54
53
|
def add(description)
|
|
55
54
|
time = if options[:date].present?
|
|
56
55
|
Time.parse(options[:date])
|
|
@@ -66,30 +65,6 @@ module Dsu
|
|
|
66
65
|
view_entry_group(time: time)
|
|
67
66
|
end
|
|
68
67
|
|
|
69
|
-
# def add(description)
|
|
70
|
-
# times = if options[:date].present?
|
|
71
|
-
# time = Time.parse(options[:date])
|
|
72
|
-
# [time, time.yesterday]
|
|
73
|
-
# else
|
|
74
|
-
# time = Time.now
|
|
75
|
-
# if options[:tomorrow].present?
|
|
76
|
-
# [time.tomorrow, time.tomorrow.yesterday]
|
|
77
|
-
# elsif options[:yesterday].present?
|
|
78
|
-
# [time.yesterday, time.yesterday.yesterday]
|
|
79
|
-
# elsif options[:today].present?
|
|
80
|
-
# [time, time.yesterday]
|
|
81
|
-
# end
|
|
82
|
-
# end
|
|
83
|
-
# entry = Models::Entry.new(description: description)
|
|
84
|
-
# # NOTE: We need to add the Entry to the date that is the furthest in the future
|
|
85
|
-
# # (time.max) because this is the DSU entry that the user specified.
|
|
86
|
-
# CommandServices::AddEntryService.new(entry: entry, time: times.max).call
|
|
87
|
-
# sorted_dsu_times_for(times: times).each do |t|
|
|
88
|
-
# view_entry_group(time: t)
|
|
89
|
-
# puts
|
|
90
|
-
# end
|
|
91
|
-
# end
|
|
92
|
-
|
|
93
68
|
desc 'list, -l SUBCOMMAND',
|
|
94
69
|
'Displays DSU entries for the given SUBCOMMAND'
|
|
95
70
|
subcommand :list, Subcommands::List
|
|
@@ -102,10 +77,45 @@ module Dsu
|
|
|
102
77
|
'Edit DSU entries for the given SUBCOMMAND'
|
|
103
78
|
subcommand :edit, Subcommands::Edit
|
|
104
79
|
|
|
80
|
+
desc 'theme, -t SUBCOMMAND',
|
|
81
|
+
'Manage DSU themes'
|
|
82
|
+
subcommand :theme, Subcommands::Theme
|
|
83
|
+
|
|
84
|
+
desc 'info, -i',
|
|
85
|
+
'Displays information about this dsu release'
|
|
86
|
+
def info
|
|
87
|
+
configuration_version = Models::Configuration::VERSION
|
|
88
|
+
entry_group_version = Models::EntryGroup::VERSION
|
|
89
|
+
color_theme_version = Models::ColorTheme::VERSION
|
|
90
|
+
info = <<~INFO
|
|
91
|
+
Dsu version: #{dsu_version}
|
|
92
|
+
Configuration version: #{configuration_version}
|
|
93
|
+
Entry group version: #{entry_group_version}
|
|
94
|
+
Color theme version: #{color_theme_version}
|
|
95
|
+
|
|
96
|
+
Config path: #{Support::Fileable.config_path}
|
|
97
|
+
Root folder: #{Support::Fileable.root_folder}
|
|
98
|
+
Entries folder: #{Support::Fileable.entries_folder}
|
|
99
|
+
Themes folder: #{Support::Fileable.themes_folder}
|
|
100
|
+
Gem folder: #{Support::Fileable.gem_dir}
|
|
101
|
+
Temp folder: #{Support::Fileable.temp_folder}
|
|
102
|
+
|
|
103
|
+
Migration version folder: #{Support::Fileable.migration_version_folder}
|
|
104
|
+
Migration file path: #{Support::Fileable.migration_version_path}
|
|
105
|
+
INFO
|
|
106
|
+
puts apply_theme(info, theme_color: color_theme.body)
|
|
107
|
+
end
|
|
108
|
+
|
|
105
109
|
desc 'version, -v',
|
|
106
|
-
'Displays this gem
|
|
110
|
+
'Displays the version for this gem'
|
|
107
111
|
def version
|
|
108
|
-
|
|
112
|
+
puts apply_theme(dsu_version, theme_color: color_theme.body)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def dsu_version
|
|
118
|
+
"v#{VERSION}"
|
|
109
119
|
end
|
|
110
120
|
end
|
|
111
121
|
end
|
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../models/entry'
|
|
4
|
-
require_relative '../
|
|
5
|
-
require_relative '../support/colorable'
|
|
4
|
+
require_relative '../support/color_themable'
|
|
6
5
|
require_relative '../support/descriptable'
|
|
7
|
-
require_relative '../support/
|
|
8
|
-
require_relative '../
|
|
9
|
-
require_relative '../support/say'
|
|
10
|
-
require_relative '../views/shared/messages'
|
|
6
|
+
require_relative '../support/fileable'
|
|
7
|
+
require_relative '../views/shared/error'
|
|
11
8
|
|
|
12
9
|
module Dsu
|
|
13
10
|
module CommandServices
|
|
14
11
|
# This class adds (does NOT update) an entry to an entry group by
|
|
15
12
|
# writing it to the appropriate entry group json file.
|
|
16
13
|
class AddEntryService
|
|
17
|
-
include Support::
|
|
14
|
+
include Support::ColorThemable
|
|
18
15
|
include Support::Descriptable
|
|
19
|
-
include Support::
|
|
20
|
-
include Support::FolderLocations
|
|
21
|
-
include Support::Say
|
|
16
|
+
include Support::Fileable
|
|
22
17
|
|
|
23
18
|
attr_reader :entry, :entry_group, :time
|
|
24
19
|
|
|
@@ -34,28 +29,22 @@ module Dsu
|
|
|
34
29
|
|
|
35
30
|
@entry = entry
|
|
36
31
|
@time = time
|
|
37
|
-
@entry_group = Models::EntryGroup.
|
|
32
|
+
@entry_group = Models::EntryGroup.find_or_initialize(time: time)
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
def call
|
|
41
36
|
entry.validate!
|
|
42
|
-
|
|
37
|
+
entry_group.entries << entry
|
|
38
|
+
entry_group.save!
|
|
43
39
|
entry
|
|
44
40
|
rescue ActiveModel::ValidationError => e
|
|
45
|
-
header = 'An error was encountered; the entry could not be added
|
|
46
|
-
Views::Shared::
|
|
41
|
+
header = 'An error was encountered; the entry could not be added:'
|
|
42
|
+
Views::Shared::Error.new(messages: e.message, header: header).render
|
|
47
43
|
end
|
|
48
44
|
|
|
49
45
|
private
|
|
50
46
|
|
|
51
47
|
attr_writer :entry, :entry_group, :time
|
|
52
|
-
|
|
53
|
-
def save_entry_group!
|
|
54
|
-
entry_group.entries << entry
|
|
55
|
-
entry_group.validate!
|
|
56
|
-
|
|
57
|
-
Services::EntryGroupWriterService.new(entry_group: entry_group).call
|
|
58
|
-
end
|
|
59
48
|
end
|
|
60
49
|
end
|
|
61
50
|
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_model'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'raw_json_file'
|
|
6
|
+
|
|
7
|
+
module Dsu
|
|
8
|
+
module Crud
|
|
9
|
+
class JsonFile
|
|
10
|
+
include ActiveModel::Model
|
|
11
|
+
|
|
12
|
+
attr_reader :file_path
|
|
13
|
+
|
|
14
|
+
def initialize(file_path)
|
|
15
|
+
@file_path = file_path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def delete
|
|
19
|
+
self.class.delete(file_path: file_path)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete!
|
|
23
|
+
self.class.delete!(file_path: file_path)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def exist?
|
|
27
|
+
self.class.exist?(file_path: file_path)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def persisted?
|
|
31
|
+
exist?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Override this method to reload data from the file
|
|
35
|
+
def reload
|
|
36
|
+
@version = read_version
|
|
37
|
+
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_h
|
|
42
|
+
raise NotImplementedError, 'You must implement this method in a your subclass'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_model
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def version
|
|
50
|
+
@version ||= read_version
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def write
|
|
54
|
+
return false unless valid?
|
|
55
|
+
|
|
56
|
+
self.class.write(file_data: to_h, file_path: file_path)
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def write!
|
|
61
|
+
validate!
|
|
62
|
+
|
|
63
|
+
self.class.write(file_data: to_h, file_path: file_path)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
alias save write
|
|
67
|
+
alias save! write!
|
|
68
|
+
|
|
69
|
+
class << self
|
|
70
|
+
def exist?(file_path:)
|
|
71
|
+
RawJsonFile.exist?(file_path: file_path)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def delete(file_path:)
|
|
75
|
+
RawJsonFile.delete(file_path: file_path)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def delete!(file_path:)
|
|
79
|
+
RawJsonFile.delete!(file_path: file_path)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def parse(json)
|
|
83
|
+
return if json.nil?
|
|
84
|
+
|
|
85
|
+
JSON.parse(json, symbolize_names: true)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def read(file_path:)
|
|
89
|
+
hash = parse(RawJsonFile.read(file_path: file_path))
|
|
90
|
+
return yield hash if hash && block_given?
|
|
91
|
+
|
|
92
|
+
hash
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def read!(file_path:)
|
|
96
|
+
hash = parse(RawJsonFile.read!(file_path: file_path))
|
|
97
|
+
return yield hash if hash && block_given?
|
|
98
|
+
|
|
99
|
+
hash
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def write(file_data:, file_path:)
|
|
103
|
+
Crud::RawJsonFile.write(file_data: file_data, file_path: file_path)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def write!(file_data:, file_path:)
|
|
107
|
+
write(file_data: file_data, file_path: file_path)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def read
|
|
114
|
+
hash = self.class.parse(RawJsonFile.read(file_path: file_path))
|
|
115
|
+
return yield hash if block_given?
|
|
116
|
+
|
|
117
|
+
hash
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def read!
|
|
121
|
+
hash = self.class.parse(RawJsonFile.read!(file_path: file_path))
|
|
122
|
+
return yield hash if hash && block_given?
|
|
123
|
+
|
|
124
|
+
hash
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def read_version
|
|
128
|
+
return 0 unless exist?
|
|
129
|
+
|
|
130
|
+
hash = read
|
|
131
|
+
return 0 if hash.nil?
|
|
132
|
+
|
|
133
|
+
hash.fetch(:version, 0).to_i
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
attr_writer :file_path, :version
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Dsu
|
|
6
|
+
module Crud
|
|
7
|
+
module RawJsonFile
|
|
8
|
+
class << self
|
|
9
|
+
def delete(file_path:)
|
|
10
|
+
return false unless exist?(file_path: file_path)
|
|
11
|
+
|
|
12
|
+
File.delete(file_path)
|
|
13
|
+
|
|
14
|
+
true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def delete!(file_path:)
|
|
18
|
+
raise file_does_not_exist_message(file_path: file_path) unless delete(file_path: file_path)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def exist?(file_path:)
|
|
22
|
+
File.exist?(file_path)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def read(file_path:)
|
|
26
|
+
File.read(file_path) if exist?(file_path: file_path)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def read!(file_path:)
|
|
30
|
+
raise file_does_not_exist_message(file_path: file_path) unless exist?(file_path: file_path)
|
|
31
|
+
|
|
32
|
+
read(file_path: file_path)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def write(file_data:, file_path:)
|
|
36
|
+
raise ArgumentError, 'file_data is nil' if file_data.nil?
|
|
37
|
+
raise ArgumentError, "file_data is the wrong object type:\"#{file_data}\"" unless file_data.is_a?(Hash)
|
|
38
|
+
|
|
39
|
+
file_data = JSON.pretty_generate(file_data)
|
|
40
|
+
File.write(file_path, file_data)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def file_does_not_exist_message(file_path:)
|
|
46
|
+
"File \"#{file_path}\" does not exist"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/dsu/env.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dsu
|
|
4
|
+
class << self
|
|
5
|
+
def env
|
|
6
|
+
@env ||= Struct.new(:env) do
|
|
7
|
+
def test?
|
|
8
|
+
env.fetch('DSU_ENV', nil) == 'test'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def development?
|
|
12
|
+
env.fetch('DSU_ENV', nil) == 'development'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def production?
|
|
16
|
+
env.fetch('DSU_ENV', 'production') == 'production'
|
|
17
|
+
end
|
|
18
|
+
end.new(ENV)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative '../migration/version'
|
|
6
|
+
require_relative '../models/configuration'
|
|
7
|
+
require_relative '../models/migration_version'
|
|
8
|
+
require_relative '../support/fileable'
|
|
9
|
+
|
|
10
|
+
module Dsu
|
|
11
|
+
module Migration
|
|
12
|
+
MIGRATION_VERSION_REGEX = /(\A\d+)/
|
|
13
|
+
|
|
14
|
+
class Service
|
|
15
|
+
include Support::Fileable
|
|
16
|
+
|
|
17
|
+
def initialize(options: {})
|
|
18
|
+
@options = options || {}
|
|
19
|
+
@migration_version = Models::MigrationVersion.new(options: options)
|
|
20
|
+
@start_migration_version = @migration_version.version
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call
|
|
24
|
+
unless self.class.run_migrations?
|
|
25
|
+
puts 'Nothing to do.'
|
|
26
|
+
return
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
run_migrations!
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
def run_migrations?
|
|
34
|
+
Models::MigrationVersion.new.version < Dsu::Migration::VERSION
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
attr_reader :migration_version, :options, :start_migration_version
|
|
41
|
+
|
|
42
|
+
def run_migrations!
|
|
43
|
+
puts "dsu version: #{Dsu::VERSION}"
|
|
44
|
+
puts
|
|
45
|
+
|
|
46
|
+
puts 'Running migrations...'
|
|
47
|
+
puts
|
|
48
|
+
|
|
49
|
+
puts "Current migration version: #{start_migration_version}"
|
|
50
|
+
puts "Migrating to version: #{Dsu::Migration::VERSION}"
|
|
51
|
+
puts
|
|
52
|
+
|
|
53
|
+
backup!
|
|
54
|
+
cleanup!
|
|
55
|
+
migrate!
|
|
56
|
+
|
|
57
|
+
new_migration_version = Models::MigrationVersion.new(version: Dsu::Migration::VERSION).tap(&:save!).version
|
|
58
|
+
|
|
59
|
+
puts "Migration version after migration is: #{new_migration_version}"
|
|
60
|
+
puts 'Migration completed successfully.'
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
warn "Migration completed with errors: #{e.message}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def backup!
|
|
66
|
+
backup_config!
|
|
67
|
+
puts
|
|
68
|
+
|
|
69
|
+
backup_entry_groups!
|
|
70
|
+
puts
|
|
71
|
+
|
|
72
|
+
backup_themes!
|
|
73
|
+
puts
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def backup_config!
|
|
77
|
+
puts 'Backing up config...'
|
|
78
|
+
if File.exist?(config_path)
|
|
79
|
+
backup_path = File.join(current_backup_folder, config_file_name)
|
|
80
|
+
puts "Backing up #{config_path} to #{backup_path}..."
|
|
81
|
+
FileUtils.cp(config_path, backup_path)
|
|
82
|
+
else
|
|
83
|
+
puts 'No config to backup.'
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def backup_entry_groups!
|
|
88
|
+
puts 'Backing up entry groups...'
|
|
89
|
+
if Dir.exist?(entries_folder)
|
|
90
|
+
backup_folder = File.join(current_backup_folder, File.basename(entries_folder))
|
|
91
|
+
puts "Backing up #{entries_folder} to #{backup_folder}..."
|
|
92
|
+
FileUtils.mkdir_p(backup_folder)
|
|
93
|
+
FileUtils.cp_r("#{entries_folder}/.", backup_folder)
|
|
94
|
+
else
|
|
95
|
+
puts 'No entries to backup.'
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def backup_themes!
|
|
100
|
+
puts 'Backing up themes...'
|
|
101
|
+
if Dir.exist?(themes_folder)
|
|
102
|
+
backup_folder = File.join(current_backup_folder, File.basename(themes_folder))
|
|
103
|
+
puts "Backing up #{themes_folder} to #{backup_folder}..."
|
|
104
|
+
FileUtils.mkdir_p(backup_folder)
|
|
105
|
+
FileUtils.cp_r("#{themes_folder}/.", backup_folder)
|
|
106
|
+
else
|
|
107
|
+
puts 'No entries to backup.'
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def before_migration_version
|
|
112
|
+
@before_migration_version ||= migration_version_instance.version
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def cleanup!
|
|
116
|
+
puts 'Cleaning up old config file...'
|
|
117
|
+
File.delete(config_path) if File.file?(config_path)
|
|
118
|
+
puts 'Done.'
|
|
119
|
+
puts
|
|
120
|
+
|
|
121
|
+
puts 'Cleaning up old entries...'
|
|
122
|
+
entry_files = Dir.glob(File.join(entries_folder, '*'))
|
|
123
|
+
entry_files.each do |entry_file|
|
|
124
|
+
File.delete(entry_file) if File.file?(entry_file)
|
|
125
|
+
end
|
|
126
|
+
puts 'Done.'
|
|
127
|
+
puts
|
|
128
|
+
|
|
129
|
+
puts 'Cleaning up old themes...'
|
|
130
|
+
theme_files = Dir.glob(File.join(themes_folder, '*'))
|
|
131
|
+
theme_files.each do |theme_file|
|
|
132
|
+
File.delete(theme_file) if File.file?(theme_file)
|
|
133
|
+
end
|
|
134
|
+
puts 'Done.'
|
|
135
|
+
puts
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def create_backup_folder!
|
|
139
|
+
FileUtils.mkdir_p(backup_folder(version: current_migration_version))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def current_backup_folder
|
|
143
|
+
@current_backup_folder ||= begin
|
|
144
|
+
create_backup_folder!
|
|
145
|
+
backup_folder(version: current_migration_version)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def current_migration_version
|
|
150
|
+
migration_version_instance.version
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Migrate
|
|
154
|
+
|
|
155
|
+
def migrate!
|
|
156
|
+
FileUtils.mkdir_p(dsu_folder)
|
|
157
|
+
FileUtils.mkdir_p(themes_folder)
|
|
158
|
+
FileUtils.mkdir_p(entries_folder)
|
|
159
|
+
|
|
160
|
+
migrate_themes!
|
|
161
|
+
migrate_config!
|
|
162
|
+
migrate_entry_groups!
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def migrate_config!
|
|
166
|
+
puts 'Migrating config...'
|
|
167
|
+
Models::Configuration.new.save!
|
|
168
|
+
puts 'Done.'
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def migrate_entry_groups!
|
|
172
|
+
puts 'Migrating entry groups...'
|
|
173
|
+
# source_folder = File.join(seed_data_folder, 'entries')
|
|
174
|
+
# puts "Copying entries from #{source_folder} to #{entries_folder}..."
|
|
175
|
+
# FileUtils.cp_r("#{source_folder}/.", entries_folder)
|
|
176
|
+
# puts 'Done.'
|
|
177
|
+
description = "Migrated DSU to version #{Dsu::Migration::VERSION}"
|
|
178
|
+
entry = Models::Entry.new(description: description)
|
|
179
|
+
Models::EntryGroup.new(time: Time.now, entries: [entry]).save!
|
|
180
|
+
puts 'Done.'
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def migrate_themes!
|
|
184
|
+
puts 'Migrating themes...'
|
|
185
|
+
source_folder = File.join(seed_data_folder, 'themes')
|
|
186
|
+
puts "Copying themes from #{source_folder} to #{themes_folder}..."
|
|
187
|
+
FileUtils.cp_r("#{source_folder}/.", themes_folder)
|
|
188
|
+
puts 'Done.'
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def migration_version_instance
|
|
192
|
+
@migration_version_instance ||= Models::MigrationVersion.new
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|