rexer 0.12.0 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 236c94fc48362e83c23049edb3b1b21311385622a66793fa19240f42fb702388
4
- data.tar.gz: 7707f18ae6e414d9390080944292f8537a11b19f03ce93d6142dc106129f7e04
3
+ metadata.gz: 9226515e3b9599a9915d140c03d8153f1e562409b5c2d8d3f28501d547511ffc
4
+ data.tar.gz: 8aa2e357ea18131f0fdef8a00276a891f8dec119ad0c9171524384ac4a6119f7
5
5
  SHA512:
6
- metadata.gz: 12a8e53ccdb53e9da0bbd66787eb4377031353e51d3d3785d3242006cbfe7445acbd5f136664bc5e681d76333ea8e082f7b92b8f1c0fe4923fb41a8a947526bd
7
- data.tar.gz: f487865de3c6f4064f72e0dae4fca83c9a8c17a711d26e0fb1e2c78058db44b510930cc67d856a19d71059e9cf46f95aeb3d24821266157dfd3eb2e627bfae77
6
+ metadata.gz: 002633010dcb32959079688a3510edda19e93784145b47b5ca60cf48749348d36f63691c94df30568b8a1fbc3acf63940a832ffa9afc80b0325a430398e9b122
7
+ data.tar.gz: 236685fa7ad6d2760831d2a416b81a1e2e23efb588399e83134e81dbcf06fa3a6b83351f383eae4f59adf3e8aae7c772ed70b6fbe3066004fa92664fca88ecc3
data/README.md CHANGED
@@ -28,7 +28,7 @@ gem install rexer
28
28
 
29
29
  ## Supported Redmine
30
30
 
31
- Rexer is tested with Redmine v5.1 and trunk.
31
+ Rexer is tested with Redmine v6.0 and trunk.
32
32
 
33
33
  ## Usage
34
34
 
@@ -109,6 +109,99 @@ If the specified ENV is currently installed, it compares the current `.extension
109
109
 
110
110
  Loads `.extensions.lock` and updates the currently installed extensions to the latest version. `.extensions.rb` is NOT referenced in this command.
111
111
 
112
+ ### Short commands available
113
+
114
+ The command to execute is determined by a forward match, so you can use like the following short commands.
115
+
116
+ ```
117
+ rex ins # means install
118
+ rex st # maens state
119
+ rex sw # means switch
120
+ rex e # means envs
121
+ rex v # means version
122
+
123
+ and more...
124
+ ```
125
+
126
+ ## Syntax of .extensions.rb file
127
+
128
+ ### Plugin
129
+
130
+ ```ruby
131
+ plugin :plugin_name, <source>: { ... }
132
+ ```
133
+
134
+ ### Theme
135
+
136
+ ```ruby
137
+ theme :theme_name, <source>: { ... }
138
+ ```
139
+
140
+ ### Source
141
+
142
+ #### Git
143
+
144
+ ```ruby
145
+ plugin :redmine_issues_panel, git: { url: "https://github.com/redmica/redmine_issues_panel" }
146
+ ```
147
+ ```ruby
148
+ # Specify the branch
149
+ plugin :redmine_issues_panel, git: { url: "https://github.com/redmica/redmine_issues_panel", branch: "main" }
150
+ # Specify the tag
151
+ plugin :redmine_issues_panel, git: { url: "https://github.com/redmica/redmine_issues_panel", tag: "v1.0.0" }
152
+ # Specify the commit
153
+ plugin :redmine_issues_panel, git: { url: "https://github.com/redmica/redmine_issues_panel", ref: "5cfb8ccbabb2fad2c8f2273a4dda3f16ef2de124" }
154
+ ```
155
+
156
+ #### GitHub
157
+
158
+ ```ruby
159
+ plugin :redmine_issues_panel, github: { repo: "redmica/redmine_issues_panel", tag: "v1.0.0" }
160
+ ```
161
+
162
+ ### Env
163
+
164
+ ```ruby
165
+ plugin :redmine_issues_panel, github: { repo: "redmica/redmine_issues_panel" }
166
+
167
+ # This is the same as the above.
168
+ env :default do
169
+ plugin :redmine_issues_panel, github: { repo: "redmica/redmine_issues_panel" }
170
+ end
171
+
172
+ env :stable do
173
+ plugin :redmine_issues_panel, github: { repo: "redmica/redmine_issues_panel", tag: "v1.0.2" }
174
+ end
175
+
176
+ env :default, :stable do
177
+ theme :bleuclair, github: { repo: "farend/redmine_theme_farend_bleuclair" }
178
+ end
179
+ ```
180
+
181
+ ### Hooks
182
+
183
+ ```ruby
184
+ plugin :redmine_issues_panel, github: { repo: "redmica/redmine_issues_panel" } do
185
+ installed do
186
+ puts "The plugin has been installed."
187
+ end
188
+
189
+ uninstalled do
190
+ puts "The plugin has been uninstalled."
191
+ end
192
+ end
193
+
194
+ theme :bleuclair, github: { repo: "farend/redmine_theme_farend_bleuclair" } do
195
+ installed do
196
+ puts "The theme has been installed."
197
+ end
198
+
199
+ uninstalled do
200
+ puts "The theme has been uninstalled."
201
+ end
202
+ end
203
+ ```
204
+
112
205
  ## Advanced Usage
113
206
 
114
207
  ### Defining for each environment and extension
data/lib/rexer/cli.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "thor"
2
2
  require "dotenv"
3
3
  require "erb"
4
+ require "active_support/core_ext/object/blank"
4
5
 
5
6
  module Rexer
6
7
  class Cli < Thor
@@ -34,7 +35,7 @@ module Rexer
34
35
  Commands::Switch.new.call(env&.to_sym)
35
36
  end
36
37
 
37
- desc "update", "Update extensions for the currently installed environment to the latest version"
38
+ desc "update", "Update extensions for the currently installed environment to the latest version if extensions are updateable"
38
39
  def update
39
40
  Commands::Update.new.call
40
41
  end
@@ -63,7 +63,7 @@ module Rexer
63
63
  end
64
64
 
65
65
  def build_source(opts)
66
- type = opts.keys.find { Rexer::Source.names.include?(_1) }
66
+ type = (opts.keys & Rexer::Source::TYPE.keys).first
67
67
  Source.new(type, opts[type]) if type
68
68
  end
69
69
  end
@@ -0,0 +1,65 @@
1
+ require "open3"
2
+ require "wisper"
3
+
4
+ module Rexer
5
+ module Extension
6
+ module Plugin
7
+ class Action
8
+ include Wisper::Publisher
9
+
10
+ def initialize(definition)
11
+ @definition = definition
12
+ @name = definition.name
13
+ @hooks = definition.hooks || {}
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :name, :hooks, :definition
19
+
20
+ def plugin_root_dir
21
+ Pathname.new("plugins")
22
+ end
23
+
24
+ def plugin_dir
25
+ @plugin_dir ||= plugin_root_dir.join(name.to_s)
26
+ end
27
+
28
+ def plugin_exists?
29
+ plugin_dir.exist? && !plugin_dir.empty?
30
+ end
31
+
32
+ def needs_db_migration?
33
+ plugin_dir.join("db", "migrate").then {
34
+ _1.exist? && !_1.empty?
35
+ }
36
+ end
37
+
38
+ def run_db_migrate(extra_envs = {})
39
+ return unless needs_db_migration?
40
+
41
+ envs = {"NAME" => name.to_s}.merge(extra_envs)
42
+ cmds = build_cmd("bundle", "exec", "rake", Rexer.verbosity.debug? ? nil : "-q", "redmine:plugins:migrate", envs:)
43
+
44
+ broadcast(:processing, "Execute #{cmds}")
45
+
46
+ if Rexer.verbosity.debug?
47
+ system(cmds, exception: true)
48
+ else
49
+ _, error, status = Open3.capture3(cmds)
50
+ raise error unless status.success?
51
+ end
52
+ end
53
+
54
+ def source
55
+ @source ||= Source.from_definition(definition.source)
56
+ end
57
+
58
+ def build_cmd(*command, envs: {})
59
+ envs_str = envs.map { [_1, _2].join("=") }
60
+ [Rexer.config.command_prefix, *command, *envs_str].compact.join(" ")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ module Rexer
2
+ module Extension
3
+ module Plugin
4
+ class Install < Action
5
+ def call
6
+ broadcast(:started, "Install #{name}")
7
+
8
+ if plugin_exists?
9
+ broadcast(:skipped, "Already exists")
10
+ return
11
+ end
12
+
13
+ load_from_source
14
+ run_bundle_install
15
+ run_db_migrate
16
+ hooks[:installed]&.call
17
+
18
+ broadcast(:completed)
19
+ end
20
+
21
+ private
22
+
23
+ def load_from_source
24
+ source.load(plugin_dir.to_s)
25
+ end
26
+
27
+ def run_bundle_install
28
+ return unless plugin_dir.join("Gemfile").exist?
29
+
30
+ cmds = build_cmd("bundle", "install", Rexer.verbosity.debug? ? nil : "--quiet")
31
+
32
+ broadcast(:processing, "Execute #{cmds}")
33
+
34
+ system(cmds, exception: true)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module Rexer
2
+ module Extension
3
+ module Plugin
4
+ class ReloadSource < Action
5
+ def call
6
+ return unless plugin_exists?
7
+
8
+ broadcast(:started, "Reload #{name} source")
9
+
10
+ reload_source
11
+ run_db_migrate
12
+
13
+ broadcast(:completed)
14
+ end
15
+
16
+ private
17
+
18
+ def reload_source
19
+ plugin_dir.to_s.then { |dir|
20
+ FileUtils.rm_rf(dir)
21
+ source.load(dir)
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ module Rexer
2
+ module Extension
3
+ module Plugin
4
+ class Uninstall < Action
5
+ def call
6
+ broadcast(:started, "Uninstall #{name}")
7
+
8
+ unless plugin_exists?
9
+ broadcast(:skipped, "Not exists")
10
+ return
11
+ end
12
+
13
+ reset_db_migration
14
+ remove_plugin
15
+ hooks[:uninstalled]&.call
16
+
17
+ broadcast(:completed)
18
+ end
19
+
20
+ private
21
+
22
+ def reset_db_migration
23
+ run_db_migrate("VERSION" => "0")
24
+ end
25
+
26
+ def remove_plugin
27
+ plugin_dir.rmtree
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Rexer
2
+ module Extension
3
+ module Plugin
4
+ class Update < Action
5
+ def call
6
+ return unless plugin_exists?
7
+
8
+ broadcast(:started, "Update #{name}")
9
+
10
+ unless source.updatable?
11
+ broadcast(:skipped, "Not updatable")
12
+ return
13
+ end
14
+
15
+ update_source
16
+ run_db_migrate
17
+
18
+ broadcast(:completed)
19
+ end
20
+
21
+ private
22
+
23
+ def update_source
24
+ source.update(plugin_dir.to_s)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ require "wisper"
2
+
3
+ module Rexer
4
+ module Extension
5
+ module Theme
6
+ class Action
7
+ include Wisper::Publisher
8
+
9
+ def initialize(definition)
10
+ @definition = definition
11
+ @name = definition.name
12
+ @hooks = definition.hooks || {}
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :name, :hooks, :definition
18
+
19
+ def theme_root_dir
20
+ public_themes = Pathname.pwd.join("public", "themes")
21
+
22
+ if public_themes.exist?
23
+ # When Redmine version is v5.1 or older, public/themes is used.
24
+ public_themes
25
+ else
26
+ Pathname.new("themes")
27
+ end
28
+ end
29
+
30
+ def theme_dir
31
+ @theme_dir ||= theme_root_dir.join(name.to_s)
32
+ end
33
+
34
+ def theme_exists?
35
+ theme_dir.exist? && !theme_dir.empty?
36
+ end
37
+
38
+ def source
39
+ @source ||= Source.from_definition(definition.source)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ module Rexer
2
+ module Extension
3
+ module Theme
4
+ class Install < Action
5
+ def call
6
+ broadcast(:started, "Install #{name}")
7
+
8
+ if theme_exists?
9
+ broadcast(:skipped, "Already exists")
10
+ return
11
+ end
12
+
13
+ load_from_source
14
+ hooks[:installed]&.call
15
+
16
+ broadcast(:completed)
17
+ end
18
+
19
+ private
20
+
21
+ def load_from_source
22
+ source.load(theme_dir.to_s)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Rexer
2
+ module Extension
3
+ module Theme
4
+ class ReloadSource < Action
5
+ def call
6
+ return unless theme_exists?
7
+
8
+ broadcast(:started, "Reload #{name} source")
9
+
10
+ reload_source
11
+
12
+ broadcast(:completed)
13
+ end
14
+
15
+ private
16
+
17
+ def reload_source
18
+ theme_dir.to_s.then { |dir|
19
+ FileUtils.rm_rf(dir)
20
+ source.load(dir)
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ module Rexer
2
+ module Extension
3
+ module Theme
4
+ class Uninstall < Action
5
+ def call
6
+ broadcast(:started, "Uninstall #{name}")
7
+
8
+ unless theme_exists?
9
+ broadcast(:skipped, "Not exists")
10
+ return
11
+ end
12
+
13
+ remove_theme
14
+ hooks[:uninstalled]&.call
15
+
16
+ broadcast(:completed)
17
+ end
18
+
19
+ private
20
+
21
+ def remove_theme
22
+ theme_dir.rmtree
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Rexer
2
+ module Extension
3
+ module Theme
4
+ class Update < Action
5
+ def call
6
+ return unless theme_exists?
7
+
8
+ broadcast(:started, "Update #{name}")
9
+
10
+ update_source
11
+
12
+ broadcast(:completed)
13
+ end
14
+
15
+ private
16
+
17
+ def update_source
18
+ source.update(theme_dir.to_s)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,10 +1,6 @@
1
1
  module Rexer
2
2
  module Source
3
3
  class Base
4
- def self.inherited(subclass)
5
- Source.names << subclass.name.split("::").last.downcase.to_sym
6
- end
7
-
8
4
  # Load the source to the given path.
9
5
  def load(_path)
10
6
  raise "Not implemented"
@@ -1,4 +1,5 @@
1
1
  require "git"
2
+ require "uri"
2
3
 
3
4
  module Rexer
4
5
  module Source
@@ -8,6 +9,7 @@ module Rexer
8
9
  @branch = branch
9
10
  @tag = tag
10
11
  @ref = ref
12
+ @reference = branch || tag || ref
11
13
  end
12
14
 
13
15
  def load(path)
@@ -20,19 +22,30 @@ module Rexer
20
22
  end
21
23
 
22
24
  def updatable?
23
- !branch.nil?
25
+ branch || reference.nil?
24
26
  end
25
27
 
26
28
  def info
27
- branch || tag || ref || "master"
29
+ URI.parse(url).then do |uri|
30
+ "#{uri.host}#{uri.path}@#{reference_name}"
31
+ end
28
32
  end
29
33
 
30
34
  private
31
35
 
32
- attr_reader :url, :branch, :tag, :ref
36
+ attr_reader :url, :reference, :branch, :tag, :ref
33
37
 
34
38
  def checkout(git)
35
- (branch || tag || ref)&.then { git.checkout(_1) }
39
+ reference&.then { git.checkout(_1) }
40
+ end
41
+
42
+ def reference_name
43
+ branch || tag || ref || "main"
44
+ end
45
+
46
+ def short_ref
47
+ return unless ref
48
+ ref.match?(/^[a-z0-9]+$/) ? ref.slice(0, 7) : ref
36
49
  end
37
50
  end
38
51
  end
@@ -2,8 +2,13 @@ module Rexer
2
2
  module Source
3
3
  class Github < Git
4
4
  def initialize(repo:, branch: nil, tag: nil, ref: nil)
5
+ @repo = repo
5
6
  super(url: "https://github.com/#{repo}", branch: branch, tag: tag, ref: ref)
6
7
  end
8
+
9
+ def info
10
+ "#{@repo}@#{reference_name}"
11
+ end
7
12
  end
8
13
  end
9
14
  end
data/lib/rexer/source.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  module Rexer
2
2
  module Source
3
- def self.names = @names ||= []
3
+ TYPE = {
4
+ git: Git,
5
+ github: Github
6
+ }.freeze
4
7
 
5
8
  def self.from_definition(source)
6
- const_get(source.type.capitalize).new(**source.options)
9
+ TYPE[source.type].new(**source.options)
7
10
  end
8
11
  end
9
12
  end
data/lib/rexer/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rexer
2
- VERSION = "0.12.0"
2
+ VERSION = "0.14.0"
3
3
  end
data/lib/rexer.rb CHANGED
@@ -27,9 +27,9 @@ module Rexer
27
27
  end
28
28
  end
29
29
 
30
+ require "active_support"
30
31
  require "pathname"
31
32
  require "zeitwerk"
32
33
 
33
34
  loader = Zeitwerk::Loader.for_gem
34
35
  loader.setup
35
- loader.eager_load
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rexer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuya Hidaka
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-25 00:00:00.000000000 Z
11
+ date: 2024-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activesupport
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '7.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '7.0'
97
111
  description: Rexer is a command-line tool for managing Redmine Extension (Plugin and
98
112
  Themes). It allows you to define extensions in a Ruby DSL and install, uninstall,
99
113
  update, and switch between different sets of the extensions.
@@ -125,8 +139,16 @@ files:
125
139
  - lib/rexer/definition/diff.rb
126
140
  - lib/rexer/definition/dsl.rb
127
141
  - lib/rexer/definition/lock.rb
128
- - lib/rexer/extension/plugin.rb
129
- - lib/rexer/extension/theme.rb
142
+ - lib/rexer/extension/plugin/action.rb
143
+ - lib/rexer/extension/plugin/install.rb
144
+ - lib/rexer/extension/plugin/reload_source.rb
145
+ - lib/rexer/extension/plugin/uninstall.rb
146
+ - lib/rexer/extension/plugin/update.rb
147
+ - lib/rexer/extension/theme/action.rb
148
+ - lib/rexer/extension/theme/install.rb
149
+ - lib/rexer/extension/theme/reload_source.rb
150
+ - lib/rexer/extension/theme/uninstall.rb
151
+ - lib/rexer/extension/theme/update.rb
130
152
  - lib/rexer/source.rb
131
153
  - lib/rexer/source/base.rb
132
154
  - lib/rexer/source/git.rb
@@ -1,172 +0,0 @@
1
- require "open3"
2
- require "wisper"
3
-
4
- module Rexer
5
- module Extension
6
- module Plugin
7
- def self.dir
8
- Pathname.new("plugins")
9
- end
10
-
11
- class Base
12
- include Wisper::Publisher
13
-
14
- def initialize(definition)
15
- @definition = definition
16
- @name = definition.name
17
- @hooks = definition.hooks || {}
18
- end
19
-
20
- private
21
-
22
- attr_reader :name, :hooks, :definition
23
-
24
- def plugin_dir
25
- @plugin_dir ||= Plugin.dir.join(name.to_s)
26
- end
27
-
28
- def plugin_exists?
29
- plugin_dir.exist? && !plugin_dir.empty?
30
- end
31
-
32
- def needs_db_migration?
33
- plugin_dir.join("db", "migrate").then {
34
- _1.exist? && !_1.empty?
35
- }
36
- end
37
-
38
- def run_db_migrate(extra_envs = {})
39
- return unless needs_db_migration?
40
-
41
- envs = {"NAME" => name.to_s}.merge(extra_envs)
42
- cmds = build_cmd("bundle", "exec", "rake", Rexer.verbosity.debug? ? nil : "-q", "redmine:plugins:migrate", envs:)
43
-
44
- broadcast(:processing, "Execute #{cmds}")
45
-
46
- if Rexer.verbosity.debug?
47
- system(cmds, exception: true)
48
- else
49
- _, error, status = Open3.capture3(cmds)
50
- raise error unless status.success?
51
- end
52
- end
53
-
54
- def source
55
- @source ||= Source.from_definition(definition.source)
56
- end
57
-
58
- def build_cmd(*command, envs: {})
59
- envs_str = envs.map { [_1, _2].join("=") }
60
- [Rexer.config.command_prefix, *command, *envs_str].compact.join(" ")
61
- end
62
- end
63
-
64
- class Install < Base
65
- def call
66
- broadcast(:started, "Install #{name}")
67
-
68
- if plugin_exists?
69
- broadcast(:skipped, "Already exists")
70
- return
71
- end
72
-
73
- load_from_source
74
- run_bundle_install
75
- run_db_migrate
76
- hooks[:installed]&.call
77
-
78
- broadcast(:completed)
79
- end
80
-
81
- private
82
-
83
- def load_from_source
84
- source.load(plugin_dir.to_s)
85
- end
86
-
87
- def run_bundle_install
88
- return unless plugin_dir.join("Gemfile").exist?
89
-
90
- cmds = build_cmd("bundle", "install", Rexer.verbosity.debug? ? nil : "--quiet")
91
-
92
- broadcast(:processing, "Execute #{cmds}")
93
-
94
- system(cmds, exception: true)
95
- end
96
- end
97
-
98
- class Uninstall < Base
99
- def call
100
- broadcast(:started, "Uninstall #{name}")
101
-
102
- unless plugin_exists?
103
- broadcast(:skipped, "Not exists")
104
- return
105
- end
106
-
107
- reset_db_migration
108
- remove_plugin
109
- hooks[:uninstalled]&.call
110
-
111
- broadcast(:completed)
112
- end
113
-
114
- private
115
-
116
- def reset_db_migration
117
- run_db_migrate("VERSION" => "0")
118
- end
119
-
120
- def remove_plugin
121
- plugin_dir.rmtree
122
- end
123
- end
124
-
125
- class Update < Base
126
- def call
127
- return unless plugin_exists?
128
-
129
- broadcast(:started, "Update #{name}")
130
-
131
- unless source.updatable?
132
- broadcast(:skipped, "Not updatable")
133
- return
134
- end
135
-
136
- update_source
137
- run_db_migrate
138
-
139
- broadcast(:completed)
140
- end
141
-
142
- private
143
-
144
- def update_source
145
- source.update(plugin_dir.to_s)
146
- end
147
- end
148
-
149
- class ReloadSource < Base
150
- def call
151
- return unless plugin_exists?
152
-
153
- broadcast(:started, "Reload #{name} source")
154
-
155
- reload_source
156
- run_db_migrate
157
-
158
- broadcast(:completed)
159
- end
160
-
161
- private
162
-
163
- def reload_source
164
- plugin_dir.to_s.then { |dir|
165
- FileUtils.rm_rf(dir)
166
- source.load(dir)
167
- }
168
- end
169
- end
170
- end
171
- end
172
- end
@@ -1,127 +0,0 @@
1
- require "wisper"
2
-
3
- module Rexer
4
- module Extension
5
- module Theme
6
- def self.dir
7
- public_themes = Pathname.pwd.join("public", "themes")
8
-
9
- if public_themes.exist?
10
- # When Redmine version is v5.1 or older, public/themes is used.
11
- public_themes
12
- else
13
- Pathname.new("themes")
14
- end
15
- end
16
-
17
- class Base
18
- include Wisper::Publisher
19
-
20
- def initialize(definition)
21
- @definition = definition
22
- @name = definition.name
23
- @hooks = definition.hooks || {}
24
- end
25
-
26
- private
27
-
28
- attr_reader :name, :hooks, :definition
29
-
30
- def theme_dir
31
- @theme_dir ||= Theme.dir.join(name.to_s)
32
- end
33
-
34
- def theme_exists?
35
- theme_dir.exist? && !theme_dir.empty?
36
- end
37
-
38
- def source
39
- @source ||= Source.from_definition(definition.source)
40
- end
41
- end
42
-
43
- class Install < Base
44
- def call
45
- broadcast(:started, "Install #{name}")
46
-
47
- if theme_exists?
48
- broadcast(:skipped, "Already exists")
49
- return
50
- end
51
-
52
- load_from_source
53
- hooks[:installed]&.call
54
-
55
- broadcast(:completed)
56
- end
57
-
58
- private
59
-
60
- def load_from_source
61
- source.load(theme_dir.to_s)
62
- end
63
- end
64
-
65
- class Uninstall < Base
66
- def call
67
- broadcast(:started, "Uninstall #{name}")
68
-
69
- unless theme_exists?
70
- broadcast(:skipped, "Not exists")
71
- return
72
- end
73
-
74
- remove_theme
75
- hooks[:uninstalled]&.call
76
-
77
- broadcast(:completed)
78
- end
79
-
80
- private
81
-
82
- def remove_theme
83
- theme_dir.rmtree
84
- end
85
- end
86
-
87
- class Update < Base
88
- def call
89
- return unless theme_exists?
90
-
91
- broadcast(:started, "Update #{name}")
92
-
93
- update_source
94
-
95
- broadcast(:completed)
96
- end
97
-
98
- private
99
-
100
- def update_source
101
- source.update(theme_dir.to_s)
102
- end
103
- end
104
-
105
- class ReloadSource < Base
106
- def call
107
- return unless theme_exists?
108
-
109
- broadcast(:started, "Reload #{name} source")
110
-
111
- reload_source
112
-
113
- broadcast(:completed)
114
- end
115
-
116
- private
117
-
118
- def reload_source
119
- theme_dir.to_s.then { |dir|
120
- FileUtils.rm_rf(dir)
121
- source.load(dir)
122
- }
123
- end
124
- end
125
- end
126
- end
127
- end