kpm 0.7.1 → 0.9.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.
Files changed (77) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +138 -0
  4. data/Gemfile +2 -0
  5. data/README.adoc +126 -109
  6. data/Rakefile +2 -1
  7. data/bin/kpm +4 -2
  8. data/kpm.gemspec +10 -8
  9. data/lib/kpm.rb +3 -0
  10. data/lib/kpm/account.rb +269 -337
  11. data/lib/kpm/base_artifact.rb +40 -36
  12. data/lib/kpm/base_installer.rb +71 -84
  13. data/lib/kpm/blob.rb +29 -0
  14. data/lib/kpm/cli.rb +3 -1
  15. data/lib/kpm/coordinates.rb +10 -12
  16. data/lib/kpm/database.rb +93 -103
  17. data/lib/kpm/diagnostic_file.rb +126 -146
  18. data/lib/kpm/formatter.rb +76 -48
  19. data/lib/kpm/inspector.rb +24 -34
  20. data/lib/kpm/installer.rb +53 -46
  21. data/lib/kpm/kaui_artifact.rb +4 -3
  22. data/lib/kpm/killbill_plugin_artifact.rb +10 -7
  23. data/lib/kpm/killbill_server_artifact.rb +24 -10
  24. data/lib/kpm/migrations.rb +26 -11
  25. data/lib/kpm/nexus_helper/actions.rb +45 -9
  26. data/lib/kpm/nexus_helper/github_api_calls.rb +70 -0
  27. data/lib/kpm/nexus_helper/nexus_api_calls_v2.rb +130 -108
  28. data/lib/kpm/nexus_helper/nexus_facade.rb +5 -3
  29. data/lib/kpm/plugins_directory.rb +14 -9
  30. data/lib/kpm/plugins_directory.yml +16 -175
  31. data/lib/kpm/plugins_manager.rb +29 -24
  32. data/lib/kpm/sha1_checker.rb +56 -15
  33. data/lib/kpm/system.rb +104 -135
  34. data/lib/kpm/system_helpers/cpu_information.rb +56 -55
  35. data/lib/kpm/system_helpers/disk_space_information.rb +60 -63
  36. data/lib/kpm/system_helpers/entropy_available.rb +37 -39
  37. data/lib/kpm/system_helpers/memory_information.rb +52 -51
  38. data/lib/kpm/system_helpers/os_information.rb +45 -47
  39. data/lib/kpm/system_helpers/system_proxy.rb +10 -10
  40. data/lib/kpm/tasks.rb +370 -443
  41. data/lib/kpm/tenant_config.rb +68 -83
  42. data/lib/kpm/tomcat_manager.rb +10 -8
  43. data/lib/kpm/trace_logger.rb +18 -16
  44. data/lib/kpm/uninstaller.rb +81 -14
  45. data/lib/kpm/utils.rb +13 -14
  46. data/lib/kpm/version.rb +3 -1
  47. data/packaging/Gemfile +2 -0
  48. data/pom.xml +1 -1
  49. data/spec/kpm/remote/base_artifact_spec.rb +33 -17
  50. data/spec/kpm/remote/base_installer_spec.rb +35 -34
  51. data/spec/kpm/remote/github_api_calls_spec.rb +40 -0
  52. data/spec/kpm/remote/installer_spec.rb +80 -78
  53. data/spec/kpm/remote/kaui_artifact_spec.rb +7 -6
  54. data/spec/kpm/remote/killbill_plugin_artifact_spec.rb +25 -30
  55. data/spec/kpm/remote/killbill_server_artifact_spec.rb +30 -13
  56. data/spec/kpm/remote/migrations_spec.rb +12 -11
  57. data/spec/kpm/remote/nexus_facade_spec.rb +32 -28
  58. data/spec/kpm/remote/tenant_config_spec.rb +30 -29
  59. data/spec/kpm/remote/tomcat_manager_spec.rb +4 -3
  60. data/spec/kpm/unit/actions_spec.rb +52 -0
  61. data/spec/kpm/unit/base_artifact_spec.rb +19 -18
  62. data/spec/kpm/unit/cpu_information_spec.rb +67 -0
  63. data/spec/kpm/unit/disk_space_information_spec.rb +47 -0
  64. data/spec/kpm/unit/entropy_information_spec.rb +36 -0
  65. data/spec/kpm/unit/formatter_spec.rb +163 -0
  66. data/spec/kpm/unit/inspector_spec.rb +34 -42
  67. data/spec/kpm/unit/installer_spec.rb +7 -6
  68. data/spec/kpm/unit/memory_information_spec.rb +102 -0
  69. data/spec/kpm/unit/os_information_spec.rb +38 -0
  70. data/spec/kpm/unit/plugins_directory_spec.rb +38 -22
  71. data/spec/kpm/unit/plugins_manager_spec.rb +62 -66
  72. data/spec/kpm/unit/sha1_checker_spec.rb +107 -60
  73. data/spec/kpm/unit/uninstaller_spec.rb +118 -72
  74. data/spec/kpm/unit_mysql/account_spec.rb +144 -143
  75. data/spec/spec_helper.rb +20 -18
  76. data/tasks/package.rake +18 -18
  77. metadata +26 -22
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'actions'
2
4
  module KPM
3
5
  module NexusFacade
@@ -11,10 +13,10 @@ module KPM
11
13
 
12
14
  class RemoteFactory
13
15
  class << self
14
- def create(overrides, ssl_verify=true, logger=nil)
15
- Actions.new(overrides, ssl_verify,logger || NexusFacade.logger)
16
+ def create(overrides, ssl_verify = true, logger = nil)
17
+ Actions.new(overrides, ssl_verify, logger || NexusFacade.logger)
16
18
  end
17
19
  end
18
20
  end
19
21
  end
20
- end
22
+ end
@@ -1,26 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open-uri'
2
4
  require 'yaml'
3
5
 
4
6
  module KPM
5
7
  class PluginsDirectory
6
- def self.all(latest=false)
8
+ def self.all(latest = false)
7
9
  if latest
8
10
  # Look at GitHub (source of truth)
9
- source = URI.parse('https://raw.githubusercontent.com/killbill/killbill-cloud/master/kpm/lib/kpm/plugins_directory.yml').read
11
+ begin
12
+ source = URI.parse('https://raw.githubusercontent.com/killbill/killbill-cloud/master/kpm/lib/kpm/plugins_directory.yml').read
13
+ rescue StandardError
14
+ # Default to built-in version if GitHub isn't accessible
15
+ return all(false)
16
+ end
10
17
  YAML.load(source)
11
18
  else
12
- source = File.join(File.expand_path(File.dirname(__FILE__)), 'plugins_directory.yml')
19
+ source = File.join(__dir__, 'plugins_directory.yml')
13
20
  YAML.load_file(source)
14
21
  end
15
22
  end
16
23
 
17
-
18
- def self.list_plugins(latest=false, kb_version)
19
- all(latest).inject({}) { |out, (key, val)| out[key]=val[:versions][kb_version.to_sym] if val[:versions].key?(kb_version.to_sym) ; out}
24
+ def self.list_plugins(latest = false, kb_version)
25
+ all(latest).each_with_object({}) { |(key, val), out| out[key] = val[:versions][kb_version.to_sym] if val[:versions].key?(kb_version.to_sym); }
20
26
  end
21
27
 
22
- # Note: this API is used in Docker images (see kpm_generator.rb, careful when changing it!)
23
- def self.lookup(raw_plugin_key, latest=false, raw_kb_version=nil)
28
+ def self.lookup(raw_plugin_key, latest = false, raw_kb_version = nil)
24
29
  plugin_key = raw_plugin_key.to_s.downcase
25
30
  plugin = all(latest)[plugin_key.to_sym]
26
31
  return nil if plugin.nil?
@@ -36,7 +41,7 @@ module KPM
36
41
  if raw_kb_version == 'LATEST'
37
42
  version = 'LATEST'
38
43
  else
39
- captures = raw_kb_version.nil? ? [] : raw_kb_version.scan(/(\d+\.\d+)(\.\d)?/)
44
+ captures = raw_kb_version.nil? ? [] : raw_kb_version.scan(/(\d+\.\d+)(\.\d+)?/)
40
45
  if captures.empty? || captures.first.nil? || captures.first.first.nil?
41
46
  version = 'LATEST'
42
47
  else
@@ -2,237 +2,78 @@
2
2
  :accertify:
3
3
  :type: :java
4
4
  :versions:
5
- :0.14: 0.1.0
6
- :0.16: 0.2.0
7
5
  :0.18: 0.3.0
8
- :require:
9
- - :org.killbill.billing.plugin.accertify.url
10
- - :org.killbill.billing.plugin.accertify.username
11
- - :org.killbill.billing.plugin.accertify.password
12
6
  :adyen:
13
7
  :type: :java
14
8
  :versions:
15
- :0.14: 0.1.0
16
- :0.15: 0.2.1
17
- :0.16: 0.3.2
18
- :0.17: 0.4.10
19
- :0.18: 0.5.10
20
- :0.19: 0.6.0
21
- :require:
22
- - :org.killbill.billing.plugin.adyen.merchantAccount
23
- - :org.killbill.billing.plugin.adyen.username
24
- - :org.killbill.billing.plugin.adyen.password
25
- - :org.killbill.billing.plugin.adyen.paymentUrl
9
+ :0.18: 0.5.26
10
+ :0.20: 0.7.0
26
11
  :analytics:
27
12
  :type: :java
28
13
  :versions:
29
- :0.14: 1.0.3
30
- :0.15: 2.0.1
31
- :0.16: 3.0.2
32
- :0.17: 4.0.5
33
14
  :0.18: 4.2.5
34
- :0.19: 5.1.4
35
- :0.20: 6.0.0
15
+ :0.20: 6.0.1
16
+ :0.22: 7.0.8
36
17
  :avatax:
37
18
  :type: :java
38
19
  :versions:
39
- :0.14: 0.1.0
40
- :0.15: 0.2.0
41
- :0.16: 0.3.0
42
20
  :0.18: 0.4.1
43
- :0.19: 0.5.1
44
- :0.20: 0.6.0
45
- :require:
46
- - :org.killbill.billing.plugin.avatax.url
47
- - :org.killbill.billing.plugin.avatax.accountNumber
48
- - :org.killbill.billing.plugin.avatax.licenseKey
49
- :braintree_blue:
50
- :type: :ruby
51
- :versions:
52
- :0.14: 0.0.1
53
- :0.16: 0.2.1
54
- :0.18: 0.3.1
55
- :require:
56
- - :merchant_id
57
- - :public_key
58
- - :private_key
59
- :currency:
60
- :type: :ruby
61
- :artifact_id: killbill-currency-plugin
62
- :versions:
63
- :0.16: 2.0.0
64
- :0.18: 3.0.0
21
+ :0.20: 0.6.1
22
+ :0.22: 0.7.0
65
23
  :cybersource:
66
24
  :type: :ruby
67
25
  :versions:
68
- :0.14: 1.0.0
69
- :0.15: 3.3.0
70
- :0.16: 4.0.12
71
26
  :0.18: 5.2.7
72
- :require:
73
- - :login
74
- - :password
75
27
  :dwolla:
76
28
  :type: :java
77
29
  :versions:
78
30
  :0.18: 0.1.0
79
- :require:
80
- - :org.killbill.billing.plugin.dwolla.baseUrl
81
- - :org.killbill.billing.plugin.dwolla.baseOAuthUrl
82
- - :org.killbill.billing.plugin.dwolla.scopes
83
- - :org.killbill.billing.plugin.dwolla.clientId
84
- - :org.killbill.billing.plugin.dwolla.clientSecret
85
- - :org.killbill.billing.plugin.dwolla.accountId
86
31
  :email-notifications:
87
32
  :type: :java
88
33
  :artifact_id: killbill-email-notifications-plugin
89
34
  :versions:
90
- :0.14: 0.1.0
91
- :0.16: 0.2.0
92
35
  :0.18: 0.3.1
93
- :0.19: 0.4.0
94
- :0.20: 0.5.0
95
- :firstdata_e4:
96
- :type: :ruby
97
- :artifact_id: firstdata-e4-plugin
98
- :versions:
99
- :0.16: 0.1.0
100
- :0.18: 0.2.0
101
- :require:
102
- - :login
103
- - :password
36
+ :0.20: 0.5.1
37
+ :0.22: 0.6.1
104
38
  :forte:
105
39
  :type: :java
106
40
  :versions:
107
- :0.14: 0.1.0
108
- :0.16: 0.2.0
109
41
  :0.18: 0.3.0
110
- :require:
111
- - :org.killbill.billing.plugin.forte.merchantId
112
- - :org.killbill.billing.plugin.forte.password
113
- - :org.killbill.billing.plugin.forte.host
114
- - :org.killbill.billing.plugin.forte.port
115
- - :org.killbill.billing.plugin.forte.apiLoginId
116
- - :org.killbill.billing.plugin.forte.secureTransactionKey
117
42
  :kpm:
118
43
  :type: :ruby
119
44
  :versions:
120
- :0.15: 0.0.2
121
- :0.16: 0.0.5
122
- :0.17: 1.0.0
123
45
  :0.18: 1.1.2
124
- :0.19: 1.2.4
125
46
  :0.20: 1.3.0
126
- :litle:
127
- :type: :ruby
128
- :versions:
129
- :0.14: 2.0.0
130
- :0.16: 3.0.0
131
- :0.18: 4.0.0
132
- :0.20: 5.0.0
133
- :require:
134
- - :account_id
135
- - :merchant_id
136
- - :username
137
- - :password
138
- - :secure_page_url
139
- - :paypage_id
140
- :logging:
141
- :type: :ruby
142
- :versions:
143
- :0.14: 1.7.0
144
- :0.15: 2.0.0
145
- :0.16: 3.0.0
146
- :0.18: 4.0.0
147
47
  :orbital:
148
48
  :type: :ruby
149
49
  :versions:
150
- :0.16: 0.0.2
151
- :0.18: 0.1.10
152
- :require:
153
- - :login
154
- - :password
155
- - :merchant_id
50
+ :0.18: 0.1.15
156
51
  :payment_bridge:
157
52
  :type: :java
158
53
  :artifact_id: bridge-plugin
159
54
  :versions:
160
- :0.19: 0.0.12
161
- :0.20: 0.1.0
162
- :payeezy:
163
- :type: :java
164
- :versions:
165
- :0.17: 0.1.0
166
- :require:
167
- - :org.killbill.billing.plugin.payeezy.apiKey
168
- - :org.killbill.billing.plugin.payeezy.token
169
- - :org.killbill.billing.plugin.payeezy.secret
170
- - :org.killbill.billing.plugin.payeezy.paymentUrl
55
+ :0.20: 0.1.2
56
+ :0.21: 0.2.1
171
57
  :payment-retries:
172
58
  :type: :java
173
59
  :versions:
174
- :0.16: 0.0.1
175
- :0.17: 0.1.0
176
60
  :0.18: 0.2.4
177
61
  :paypal:
178
62
  :type: :ruby
179
63
  :artifact_id: paypal-express-plugin
180
64
  :versions:
181
- :0.14: 2.0.0
182
- :0.15: 3.0.0
183
- :0.16: 4.1.7
184
- :0.18: 5.0.9
65
+ :0.18: 5.0.15
185
66
  :0.20: 6.0.0
186
- :require:
187
- - :signature
188
- - :login
189
- - :password
190
- :payu_latam:
191
- :type: :ruby
192
- :artifact_id: payu-latam-plugin
193
- :versions:
194
- :0.14: 0.1.0
195
- :0.16: 0.2.0
196
- :0.18: 0.3.0
197
- :require:
198
- - :api_login
199
- - :api_key
200
- - :country_account_id
201
- - :merchant_id
202
67
  :payment-test:
203
- :type: :ruby
68
+ :type: :java
204
69
  :artifact_id: payment-test-plugin
205
70
  :versions:
206
- :0.18: 4.2.0
207
- :0.19: 5.0.0
208
- :0.20: 6.0.0
71
+ :0.22: 7.0.4
209
72
  :securenet:
210
73
  :type: :ruby
211
74
  :versions:
212
- :0.16: 0.1.0
213
75
  :0.18: 0.2.0
214
- :require:
215
- - :login
216
- - :password
217
76
  :stripe:
218
- :type: :ruby
219
- :versions:
220
- :0.14: 1.0.0
221
- :0.15: 2.0.0
222
- :0.16: 3.0.3
223
- :0.17: 4.0.0
224
- :0.18: 4.1.1
225
- :0.19: 5.0.0
226
- :0.20: 6.0.0
227
- :require:
228
- - :api_secret_key
229
- :zendesk:
230
- :type: :ruby
77
+ :type: :java
231
78
  :versions:
232
- :0.14: 1.3.0
233
- :0.16: 2.0.0
234
- :0.18: 3.0.1
235
- :require:
236
- - :subdomain
237
- - :username
238
- - :password
79
+ :0.22: 7.0.4
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'json'
3
5
 
4
6
  module KPM
5
7
  class PluginsManager
6
-
7
8
  def initialize(plugins_dir, logger)
8
9
  @plugins_dir = Pathname.new(plugins_dir)
9
10
  @logger = logger
10
11
  end
11
12
 
12
- def set_active(plugin_name_or_path, plugin_version=nil)
13
+ def set_active(plugin_name_or_path, plugin_version = nil)
13
14
  if plugin_name_or_path.nil?
14
15
  @logger.warn('Unable to mark a plugin as active: no name or path specified')
15
16
  return
@@ -19,7 +20,7 @@ module KPM
19
20
  # Full path specified, with version
20
21
  link = Pathname.new(plugin_name_or_path).join('../SET_DEFAULT')
21
22
  FileUtils.rm_f(link)
22
- FileUtils.ln_s(plugin_name_or_path, link, :force => true)
23
+ FileUtils.ln_s(plugin_name_or_path, link, force: true)
23
24
  else
24
25
  # Plugin name (fs directory) specified
25
26
  plugin_dir_glob = @plugins_dir.join('*').join(plugin_name_or_path)
@@ -28,7 +29,7 @@ module KPM
28
29
  plugin_dir = Pathname.new(plugin_dir_path)
29
30
  link = plugin_dir.join('SET_DEFAULT')
30
31
  FileUtils.rm_f(link)
31
- FileUtils.ln_s(plugin_dir.join(plugin_version), link, :force => true)
32
+ FileUtils.ln_s(plugin_dir.join(plugin_version), link, force: true)
32
33
  end
33
34
  end
34
35
 
@@ -38,7 +39,7 @@ module KPM
38
39
  end
39
40
  end
40
41
 
41
- def uninstall(plugin_name_or_path, plugin_version=nil)
42
+ def uninstall(plugin_name_or_path, plugin_version = nil)
42
43
  update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
43
44
  FileUtils.rm_f(tmp_dir.join('restart.txt'))
44
45
  # Be safe, keep the code, just never start it
@@ -46,7 +47,7 @@ module KPM
46
47
  end
47
48
  end
48
49
 
49
- def restart(plugin_name_or_path, plugin_version=nil)
50
+ def restart(plugin_name_or_path, plugin_version = nil)
50
51
  update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
51
52
  # Remove disabled.txt so that the plugin is started if it was stopped
52
53
  FileUtils.rm_f(tmp_dir.join('disabled.txt'))
@@ -59,20 +60,19 @@ module KPM
59
60
  entry = identifiers[plugin_key]
60
61
  if entry
61
62
  coordinate_map.each_pair do |key, value|
62
- return false if !validate_plugin_identifier_key_value(plugin_key, key, entry[key.to_s], value)
63
+ return false unless validate_plugin_identifier_key_value(plugin_key, key, entry[key.to_s], value)
63
64
  end
64
65
  end
65
66
  true
66
67
  end
67
68
 
68
69
  def add_plugin_identifier_key(plugin_key, plugin_name, language, coordinate_map)
69
-
70
70
  identifiers = read_plugin_identifiers
71
71
  # If key does not already exists or if the version in the json is not the one we are currently installing we update the entry, if not nothing to do
72
- if !identifiers.has_key?(plugin_key) ||
72
+ if !identifiers.key?(plugin_key) ||
73
73
  (coordinate_map && identifiers[plugin_key]['version'] != coordinate_map[:version])
74
74
 
75
- entry = {'plugin_name' => plugin_name}
75
+ entry = { 'plugin_name' => plugin_name }
76
76
  entry['language'] = language
77
77
  if coordinate_map
78
78
  entry['group_id'] = coordinate_map[:group_id]
@@ -91,7 +91,7 @@ module KPM
91
91
  def remove_plugin_identifier_key(plugin_key)
92
92
  identifiers = read_plugin_identifiers
93
93
  # If key does not already exists we update it, if not nothing to do.
94
- if identifiers.has_key?(plugin_key)
94
+ if identifiers.key?(plugin_key)
95
95
  identifiers.delete(plugin_key)
96
96
  write_plugin_identifiers(identifiers)
97
97
  end
@@ -101,7 +101,7 @@ module KPM
101
101
 
102
102
  def get_plugin_key_and_name(plugin_name_or_key)
103
103
  identifiers = read_plugin_identifiers
104
- if identifiers.has_key?(plugin_name_or_key)
104
+ if identifiers.key?(plugin_name_or_key)
105
105
  # It's a plugin key
106
106
  [plugin_name_or_key, identifiers[plugin_name_or_key]['plugin_name']]
107
107
  else
@@ -121,19 +121,20 @@ module KPM
121
121
 
122
122
  def guess_plugin_name(artifact_id)
123
123
  return nil if artifact_id.nil?
124
+
124
125
  captures = artifact_id.scan(/(.*)-plugin/)
125
- if captures.empty? || captures.first.nil? || captures.first.first.nil?
126
- short_name = artifact_id
127
- else
128
- # 'analytics-plugin' or 'stripe-plugin' passed
129
- short_name = captures.first.first
130
- end
126
+ short_name = if captures.empty? || captures.first.nil? || captures.first.first.nil?
127
+ artifact_id
128
+ else
129
+ # 'analytics-plugin' or 'stripe-plugin' passed
130
+ captures.first.first
131
+ end
131
132
  Dir.glob(@plugins_dir.join('*').join('*')).each do |plugin_path|
132
133
  plugin_name = File.basename(plugin_path)
133
134
  if plugin_name == short_name ||
134
- plugin_name == artifact_id ||
135
- !plugin_name.scan(/-#{short_name}/).empty? ||
136
- !plugin_name.scan(/#{short_name}-/).empty?
135
+ plugin_name == artifact_id ||
136
+ !plugin_name.scan(/-#{short_name}/).empty? ||
137
+ !plugin_name.scan(/#{short_name}-/).empty?
137
138
  return plugin_name
138
139
  end
139
140
  end
@@ -148,6 +149,7 @@ module KPM
148
149
  JSON.parse(f.read)
149
150
  end
150
151
  rescue Errno::ENOENT
152
+ # Ignore
151
153
  end
152
154
  identifiers
153
155
  end
@@ -166,7 +168,6 @@ module KPM
166
168
  end
167
169
 
168
170
  def write_plugin_identifiers(identifiers)
169
-
170
171
  path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
171
172
  Dir.mktmpdir do |tmp_dir|
172
173
  tmp_path = Pathname.new(tmp_dir).join('plugin_identifiers.json')
@@ -179,13 +180,17 @@ module KPM
179
180
  end
180
181
 
181
182
  # Note: the plugin name here is the directory name on the filesystem
182
- def update_fs(plugin_name_or_path, plugin_version=nil, &block)
183
+ def update_fs(plugin_name_or_path, plugin_version = nil)
183
184
  if plugin_name_or_path.nil?
184
185
  @logger.warn('Unable to update the filesystem: no name or path specified')
185
186
  return
186
187
  end
187
188
 
188
- p = plugin_version.nil? ? plugin_name_or_path : @plugins_dir.join('*').join(plugin_name_or_path).join(plugin_version == :all ? '*' : plugin_version)
189
+ p = if plugin_version.nil?
190
+ plugin_name_or_path
191
+ else
192
+ @plugins_dir.join('*').join(plugin_name_or_path).join(plugin_version == :all ? '*' : plugin_version)
193
+ end
189
194
 
190
195
  modified = []
191
196
  Dir.glob(p).each do |plugin_dir_path|