kpm 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af4823a1ad26ca690e372df3596841ae7fa54ee9
4
- data.tar.gz: ade7725741e69b929bfa0fd9d47d6fa6326f4695
3
+ metadata.gz: 14627c006a8ca097ba3574e2a06329ee1c71b3d4
4
+ data.tar.gz: 790ba80f029ff28d86d0e91088a0327653cf39cc
5
5
  SHA512:
6
- metadata.gz: 92361d67b9abc0bd2da406fc460481aa8b74176cddf5d4b5b11381428750fe1b417ac0b5bb2796512e52e65963427793cd293dfbf56d53f02672f82b6b0430d2
7
- data.tar.gz: b9f1727cdd593dfb48fb4b5c6ef16e2caf272141253100b8566ee7a808b9c74577e652f5742863deb3804bfacb13ff793a37927f151b4bccbbaa895d0ca9f1b1
6
+ metadata.gz: 45c071a90801caf7a6ec2e8a83d6edd0d1567fc63a2017bf5b7f9be91ec8834ab4cf1b3cc345ddeb8d219281d5697c927367af88367d856b09d14c77aa8e2e1a
7
+ data.tar.gz: 94dffb5a06040e48f83f70f27cc8d509798848c30b76a5672dbdda12641a4e1fc72ed819b905a8735af44d107da5b72cb85627ddcc70ffea8e1fcba6da08bb9a
data/lib/kpm.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  module KPM
2
2
  autoload :Utils, 'kpm/utils'
3
3
  autoload :BaseArtifact, 'kpm/base_artifact'
4
+ autoload :Coordinates, 'kpm/coordinates'
5
+ autoload :Formatter, 'kpm/formatter'
6
+ autoload :Inspector, 'kpm/inspector'
4
7
  autoload :Sha1Checker, 'kpm/sha1_checker'
5
8
  autoload :TomcatManager, 'kpm/tomcat_manager'
6
9
  autoload :KillbillServerArtifact, 'kpm/killbill_server_artifact'
@@ -9,9 +12,11 @@ module KPM
9
12
  autoload :PluginsManager, 'kpm/plugins_manager'
10
13
  autoload :BaseInstaller, 'kpm/base_installer'
11
14
  autoload :Installer, 'kpm/installer'
15
+ autoload :Uninstaller, 'kpm/uninstaller'
12
16
  autoload :Tasks, 'kpm/tasks'
13
17
  autoload :Cli, 'kpm/cli'
14
18
  autoload :PluginsDirectory, 'kpm/plugins_directory'
19
+ autoload :Migrations, 'kpm/migrations'
15
20
 
16
21
  class << self
17
22
  def root
@@ -65,7 +65,7 @@ module KPM
65
65
 
66
66
  # Update with resolved version in case 'LATEST' was passed
67
67
  coordinate_map[:version] = artifact_info[:version]
68
- coordinates = build_coordinates(coordinate_map)
68
+ coordinates = KPM::Coordinates.build_coordinates(coordinate_map)
69
69
 
70
70
  # Return early if there's nothing to do
71
71
  if !force_download && skip_if_exists(artifact_info, coordinates, sha1_file)
@@ -178,7 +178,7 @@ module KPM
178
178
  :skipped => false
179
179
  }
180
180
 
181
- coordinates = build_coordinates(coordinate_map)
181
+ coordinates = KPM::Coordinates.build_coordinates(coordinate_map)
182
182
  begin
183
183
  nexus_info = nexus_remote(overrides, ssl_verify).get_artifact_info(coordinates)
184
184
  rescue NexusCli::ArtifactMalformedException => e
@@ -256,27 +256,6 @@ module KPM
256
256
  res
257
257
  end
258
258
 
259
- def build_coordinates(coordinate_map)
260
- group_id = coordinate_map[:group_id]
261
- artifact_id = coordinate_map[:artifact_id]
262
- packaging = coordinate_map[:packaging]
263
- classifier = coordinate_map[:classifier]
264
- version = coordinate_map[:version]
265
-
266
- if classifier.nil?
267
- if version.nil?
268
- "#{group_id}:#{artifact_id}:#{packaging}"
269
- else
270
- "#{group_id}:#{artifact_id}:#{packaging}:#{version}"
271
- end
272
- else
273
- if version.nil?
274
- "#{group_id}:#{artifact_id}:#{packaging}:#{classifier}"
275
- else
276
- "#{group_id}:#{artifact_id}:#{packaging}:#{classifier}:#{version}"
277
- end
278
- end
279
- end
280
259
 
281
260
  # Magic methods...
282
261
 
@@ -0,0 +1,40 @@
1
+ module KPM
2
+
3
+ class Coordinates
4
+
5
+ class << self
6
+
7
+ def build_coordinates(coordinate_map)
8
+ group_id = coordinate_map[:group_id]
9
+ artifact_id = coordinate_map[:artifact_id]
10
+ packaging = coordinate_map[:packaging]
11
+ classifier = coordinate_map[:classifier]
12
+ version = coordinate_map[:version]
13
+
14
+ if classifier.nil?
15
+ if version.nil?
16
+ "#{group_id}:#{artifact_id}:#{packaging}"
17
+ else
18
+ "#{group_id}:#{artifact_id}:#{packaging}:#{version}"
19
+ end
20
+ else
21
+ "#{group_id}:#{artifact_id}:#{packaging}:#{classifier}:#{version}"
22
+ end
23
+ end
24
+
25
+ def get_coordinate_map(entry)
26
+ parts = entry.split(':')
27
+ length = parts.size
28
+ if length == 3
29
+ {:group_id => parts[0], :artifact_id => parts[1], :packaging => parts[2]}
30
+ elsif length == 4
31
+ {:group_id => parts[0], :artifact_id => parts[1], :packaging => parts[2], :version => parts[3]}
32
+ elsif length == 5
33
+ {:group_id => parts[0], :artifact_id => parts[1], :packaging => parts[2], :classifier => parts[3], :version => parts[4]}
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,123 @@
1
+ # Extend String to be able to instantiate a object based on its classname
2
+ class String
3
+ def to_class
4
+ self.split('::').inject(Kernel) do |mod, class_name|
5
+ mod.const_get(class_name)
6
+ end
7
+ end
8
+ end
9
+
10
+ module KPM
11
+
12
+ class Formatter
13
+
14
+ def initialize
15
+ end
16
+
17
+ # Used for normal types where to_s is enough
18
+ class DefaultFormatter
19
+
20
+ def initialize(label, input)
21
+ @label = label
22
+ @input = input
23
+ end
24
+
25
+ def size
26
+ to_s.size
27
+ end
28
+
29
+ def to_s
30
+ @input.to_s
31
+ end
32
+
33
+ def label
34
+ @label.to_s.upcase.gsub(/_/, ' ')
35
+ end
36
+ end
37
+
38
+ # Used for the version map
39
+ class VersionFormatter
40
+
41
+ def initialize(label, versions)
42
+ @label = label
43
+ @versions = versions
44
+ end
45
+
46
+ def size
47
+ to_s.size
48
+ end
49
+
50
+ def to_s
51
+ @versions.map { |q| sha1=format_sha(q[:sha1]); disabled=""; disabled="(x)" if q[:is_disabled]; default=""; default="(*)" if q[:is_default]; "#{q[:version]}#{sha1}#{default}#{disabled}" }.join(", ")
52
+ end
53
+
54
+ def label
55
+ "#{@label.to_s.upcase.gsub(/_/, ' ')} sha1=[], def=(*), del=(x)"
56
+ end
57
+
58
+ def format_sha(sha)
59
+ return "[???]" if sha.nil?
60
+ "[#{sha[0..5]}..]"
61
+ end
62
+ end
63
+
64
+
65
+ def format(all_plugins)
66
+ if all_plugins.size == 0
67
+ return
68
+ end
69
+
70
+ # What we want to output
71
+ labels = [{:label => :plugin_name},
72
+ {:label => :plugin_key},
73
+ {:label => :type},
74
+ {:label => :group_id},
75
+ {:label => :artifact_id},
76
+ {:label => :packaging},
77
+ {:label => :versions, :formatter => VersionFormatter.name}]
78
+
79
+ # Compute label to print along with max size for each label
80
+ labels_format_argument = []
81
+ all_plugins.keys.each do |key|
82
+ v = all_plugins[key]
83
+ labels.each do |e|
84
+ # sanitize entry at the same time
85
+ v[e[:label]] = v[e[:label]] || "???"
86
+
87
+ formatter = e[:formatter].nil? ? DefaultFormatter.new(e[:label], v[e[:label]]) : e[:formatter].to_class.new(e[:label], v[e[:label]])
88
+ prev_size = e.key?(:size) ? e[:size] : formatter.label.size
89
+ cur_size = formatter.size
90
+ e[:size] = prev_size < cur_size ? cur_size : prev_size
91
+ labels_format_argument << formatter.label
92
+ end
93
+ end
94
+
95
+
96
+
97
+ border = "_"
98
+ border = (0...labels.size).inject(border) { |res, i| res="#{res}_"; res }
99
+ border = labels.inject(border) { |res, lbl| (0...lbl[:size] + 2).each { |s| res="#{res}_" }; res }
100
+ format = "|"
101
+ format = labels.inject(format) { |res, lbl| res="#{res} %#{lbl[:size]}s |"; res }
102
+
103
+
104
+
105
+ puts "\n#{border}\n"
106
+ puts "#{format}\n" % labels_format_argument
107
+ puts "#{border}\n"
108
+
109
+ all_plugins.keys.each do |key|
110
+ v = all_plugins[key]
111
+
112
+ arguments = []
113
+ labels.inject(arguments) do |res, e|
114
+ formatter = e[:formatter].nil? ? DefaultFormatter.new(e[:label], v[e[:label]]) : e[:formatter].to_class.new(e[:label], v[e[:label]])
115
+ res << formatter.to_s
116
+ end
117
+ puts "#{format}\n" % arguments
118
+ end
119
+ puts "#{border}\n\n"
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,108 @@
1
+ module KPM
2
+
3
+ class Inspector
4
+
5
+ def initialize
6
+ end
7
+
8
+ def inspect(bundles_dir)
9
+ bundles_dir = Pathname.new(bundles_dir || KPM::BaseInstaller::DEFAULT_BUNDLES_DIR).expand_path
10
+ plugins= bundles_dir.join('plugins')
11
+ ruby_plugins_path=bundles_dir.join('plugins/ruby')
12
+ java_plugins_path=bundles_dir.join('plugins/java')
13
+
14
+ all_plugins = {}
15
+ build_plugins_for_type(ruby_plugins_path, 'ruby', all_plugins)
16
+ build_plugins_for_type(java_plugins_path, 'java', all_plugins)
17
+
18
+ add_plugin_identifier_info(plugins, all_plugins)
19
+
20
+ add_sha1_info(bundles_dir, all_plugins)
21
+
22
+ all_plugins
23
+ end
24
+
25
+ def format(all_plugins)
26
+ formatter = KPM::Formatter.new
27
+ formatter.format(all_plugins)
28
+ end
29
+
30
+
31
+ private
32
+
33
+ def add_sha1_info(bundles_dir, all_plugins)
34
+
35
+ sha1_filename = KPM::BaseInstaller::SHA1_FILENAME
36
+ sha1_file = "#{bundles_dir}/#{sha1_filename}"
37
+ sha1_checker = Sha1Checker.from_file(sha1_file)
38
+
39
+ all_plugins.keys.each do |cur_plugin_name|
40
+ cur = all_plugins[cur_plugin_name]
41
+
42
+ sha1_checker.all_sha1.each do |e|
43
+ coord, sha1 = e
44
+ coordinate_map = KPM::Coordinates.get_coordinate_map(coord)
45
+
46
+ if coordinate_map[:group_id] == cur[:group_id] &&
47
+ coordinate_map[:artifact_id] == cur[:artifact_id] &&
48
+ coordinate_map[:packaging] == cur[:packaging]
49
+
50
+ found_version = cur[:versions].select { |v| v[:version] == coordinate_map[:version] }[0]
51
+ found_version[:sha1] = sha1 if found_version
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+
58
+ def add_plugin_identifier_info(plugins, all_plugins)
59
+ plugins_manager = PluginsManager.new(plugins, @logger)
60
+ all_plugins.keys.each do |cur|
61
+ plugin_key, entry = plugins_manager.get_identifier_key_and_entry(cur)
62
+ all_plugins[cur][:plugin_key] = plugin_key
63
+ all_plugins[cur][:group_id] = entry ? entry['group_id'] : nil
64
+ all_plugins[cur][:artifact_id] = entry ? entry['artifact_id'] : nil
65
+ all_plugins[cur][:packaging] = entry ? entry['packaging'] : nil
66
+ all_plugins[cur][:classifier] = entry ? entry['classifier'] : nil
67
+ end
68
+ end
69
+
70
+
71
+ def build_plugins_for_type(plugins_path, type, res)
72
+ if !File.exists?(plugins_path)
73
+ return []
74
+ end
75
+ get_entries(plugins_path).inject(res) do |out, e|
76
+ plugin_map = build_plugin_map(e, plugins_path.join(e), type)
77
+ out[e] = plugin_map
78
+ out
79
+ end
80
+ end
81
+
82
+ def build_plugin_map(plugin_name, plugin_path, type)
83
+
84
+ plugin_map = {:plugin_name => plugin_name, :plugin_path => plugin_path.to_s, :type => type}
85
+ entries = get_entries(plugin_path)
86
+ set_default = entries.select { |e| e == "SET_DEFAULT" }[0]
87
+ default_version = File.basename(File.readlink(plugin_path.join(set_default))) if set_default
88
+
89
+ versions = entries.select do |e|
90
+ e != "SET_DEFAULT"
91
+ end.inject([]) do |out, e|
92
+ is_disabled = File.exists?(plugin_path.join(e).join('tmp').join('disabled.txt'))
93
+ out << {:version => e, :is_default => default_version == e, :is_disabled => is_disabled, :sha1 => nil};
94
+ out
95
+ end
96
+
97
+ versions.sort! { |a, b| a[:version] <=> b[:version] }
98
+ plugin_map[:versions] = versions || []
99
+
100
+ plugin_map
101
+ end
102
+
103
+ def get_entries(path)
104
+ Dir.entries(path).select { |entry| entry != '.' && entry != '..' && File.directory?(File.join(path, entry)) }
105
+ end
106
+
107
+ end
108
+ end
data/lib/kpm/installer.rb CHANGED
@@ -39,6 +39,7 @@ module KPM
39
39
  unless @config['default_bundles'] == false
40
40
  install_default_bundles(@config['plugins_dir'], @config['default_bundles_version'], @config['version'], force_download, verify_sha1)
41
41
  end
42
+ clean_up_descriptors
42
43
  end
43
44
 
44
45
  unless @kaui_config.nil?
@@ -99,5 +100,43 @@ module KPM
99
100
 
100
101
  infos
101
102
  end
103
+
104
+ def clean_up_descriptors
105
+ removed_plugins = clean_up_plugin_identifiers
106
+ clean_up_sha1s(removed_plugins)
107
+ end
108
+
109
+ def clean_up_plugin_identifiers
110
+ inspector = KPM::Inspector.new
111
+ installed_plugins = inspector.inspect(@config['plugins_dir'])
112
+
113
+ plugins_installation_path = File.join(@config['plugins_dir'], 'plugins')
114
+ plugins_manager = KPM::PluginsManager.new(plugins_installation_path, @logger)
115
+
116
+ plugin_identifiers = plugins_manager.read_plugin_identifiers
117
+ removed_identifiers = []
118
+ plugin_identifiers.each do |plugin_key, plugin|
119
+ if !installed_plugins.has_key?(plugin['plugin_name'])
120
+ _, plugin_entry = plugins_manager.get_identifier_key_and_entry(plugin_key)
121
+ plugins_manager.remove_plugin_identifier_key(plugin_key)
122
+ removed_identifiers << plugin_entry
123
+ end
124
+ end
125
+
126
+ removed_identifiers
127
+ end
128
+
129
+ def clean_up_sha1s(removed_plugins)
130
+ sha1checker = KPM::Sha1Checker.from_file(File.join(@config['plugins_dir'], KPM::BaseInstaller::SHA1_FILENAME))
131
+ removed_plugins.each do |removed|
132
+ coordinates = KPM::Coordinates.build_coordinates(group_id: removed['group_id'],
133
+ artifact_id: removed['artifact_id'],
134
+ packaging: removed['packaging'],
135
+ classifier: removed['classifier'],
136
+ version: removed['version'])
137
+ sha1checker.remove_entry!(coordinates)
138
+ end
139
+ end
140
+
102
141
  end
103
142
  end
@@ -8,7 +8,7 @@ module KPM
8
8
 
9
9
  coordinate_map = {:group_id => KPM::BaseArtifact::KAUI_GROUP_ID, :artifact_id => KPM::BaseArtifact::KAUI_ARTIFACT_ID, :packaging => KPM::BaseArtifact::KAUI_PACKAGING, :classifier => KPM::BaseArtifact::KAUI_CLASSIFIER}
10
10
 
11
- coordinates = build_coordinates(coordinate_map)
11
+ coordinates = KPM::Coordinates.build_coordinates(coordinate_map)
12
12
  response = REXML::Document.new nexus_remote(overrides, ssl_verify).search_for_artifacts(coordinates)
13
13
  versions = SortedSet.new
14
14
  response.elements.each('search-results/data/artifact/version') { |element| versions << element.text }
@@ -6,7 +6,7 @@ module KPM
6
6
  class << self
7
7
  def versions(artifact_id, packaging=KPM::BaseArtifact::KILLBILL_PACKAGING, classifier=KPM::BaseArtifact::KILLBILL_CLASSIFIER, overrides={}, ssl_verify=true)
8
8
  coordinate_map = {:group_id => KPM::BaseArtifact::KILLBILL_GROUP_ID, :artifact_id => artifact_id, :packaging => packaging, :classifier => classifier}
9
- coordinates = build_coordinates(coordinate_map)
9
+ coordinates = KPM::Coordinates.build_coordinates(coordinate_map)
10
10
  response = REXML::Document.new nexus_remote(overrides, ssl_verify).search_for_artifacts(coordinates)
11
11
  versions = SortedSet.new
12
12
  response.elements.each('search-results/data/artifact/version') { |element| versions << element.text }
@@ -0,0 +1,94 @@
1
+ require 'base64'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'open-uri'
5
+ require 'pathname'
6
+
7
+ module KPM
8
+ class Migrations
9
+
10
+ KILLBILL_MIGRATION_PATH = /src\/main\/resources\/org\/killbill\/billing\/[a-z]+\/migration\/(V[0-9a-zA-Z_]+.sql)/
11
+ JAVA_PLUGIN_MIGRATION_PATH = /src\/main\/resources\/migration\/(V[0-9a-zA-Z_]+.sql)/
12
+ RUBY_PLUGIN_MIGRATION_PATH = /db\/migrate\/([0-9a-zA-Z_]+.rb)/
13
+
14
+ # Go to https://github.com/settings/tokens to generate a token
15
+ def initialize(from_version, to_version = nil, repository = 'killbill/killbill', oauth_token = nil, logger = Logger.new(STDOUT))
16
+ @from_version = from_version
17
+ @to_version = to_version
18
+ @repository = repository
19
+ @oauth_token = oauth_token
20
+ @logger = logger
21
+ end
22
+
23
+ def migrations
24
+ @migrations ||= begin
25
+ if @to_version.nil?
26
+ for_version(@from_version)
27
+ else
28
+ migrations_to_skip = Set.new
29
+ for_version(@from_version, true).each { |migration| migrations_to_skip << migration[:name] }
30
+
31
+ for_version(@to_version, false, migrations_to_skip)
32
+ end
33
+ end
34
+ end
35
+
36
+ def save(dir = nil)
37
+ return nil if migrations.size == 0
38
+
39
+ dir ||= Dir.mktmpdir
40
+ @logger.debug("Storing migrations to #{dir}")
41
+ migrations.each do |migration|
42
+ migration_path = Pathname.new(dir).join(migration[:name])
43
+ File.open(migration_path, 'w') do |file|
44
+ @logger.debug("Storing migration #{migration_path}")
45
+ file.write(migration[:sql])
46
+ end
47
+ end
48
+ dir
49
+ end
50
+
51
+ private
52
+
53
+ def for_version(version = @from_version, name_only = false, migrations_to_skip = Set.new)
54
+ @logger.info("Looking for migrations repository=#{@repository}, version=#{version}")
55
+ metadata = get_as_json("https://api.github.com/repos/#{@repository}/git/trees/#{version}?recursive=1&access_token=#{@oauth_token}")
56
+
57
+ migrations = []
58
+ metadata['tree'].each do |entry|
59
+ match_data = KILLBILL_MIGRATION_PATH.match(entry['path']) || JAVA_PLUGIN_MIGRATION_PATH.match(entry['path']) || RUBY_PLUGIN_MIGRATION_PATH.match(entry['path'])
60
+ next unless match_data
61
+
62
+ migration_name = match_data[1]
63
+ @logger.info("Found migration #{migration_name}")
64
+ next if migrations_to_skip.include?(migration_name)
65
+
66
+ sql = nil
67
+ unless name_only
68
+ blob_metadata = get_as_json("#{entry['url']}?access_token=#{@oauth_token}")
69
+ sql = decode(blob_metadata['content'], blob_metadata['encoding'])
70
+ end
71
+
72
+ migrations << {
73
+ :name => migration_name,
74
+ :sql => sql
75
+ }
76
+ end
77
+
78
+ migrations
79
+ end
80
+
81
+ def get_as_json(url)
82
+ raw = URI.parse(url).read
83
+ JSON.parse(raw)
84
+ end
85
+
86
+ def decode(content, encoding)
87
+ if encoding == 'base64'
88
+ Base64.decode64(content)
89
+ else
90
+ content
91
+ end
92
+ end
93
+ end
94
+ end
@@ -119,7 +119,7 @@
119
119
  :versions:
120
120
  :0.14: 2.0.0
121
121
  :0.15: 3.0.0
122
- :0.16: 4.1.0
122
+ :0.16: 4.1.1
123
123
  :stable_version: 2.0.0
124
124
  :require:
125
125
  - :signature
@@ -111,6 +111,14 @@ module KPM
111
111
  end
112
112
  end
113
113
 
114
+ def get_identifier_key_and_entry(plugin_name_or_key)
115
+ identifiers = read_plugin_identifiers
116
+ identifiers.each_pair do |key, value|
117
+ return [key, value] if key == plugin_name_or_key || value['plugin_name'] == plugin_name_or_key
118
+ end
119
+ nil
120
+ end
121
+
114
122
  def guess_plugin_name(artifact_id)
115
123
  return nil if artifact_id.nil?
116
124
  captures = artifact_id.scan(/(.*)-plugin/)
@@ -132,6 +140,18 @@ module KPM
132
140
  nil
133
141
  end
134
142
 
143
+ def read_plugin_identifiers
144
+ path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
145
+ identifiers = {}
146
+ begin
147
+ identifiers = File.open(path, 'r') do |f|
148
+ JSON.parse(f.read)
149
+ end
150
+ rescue Errno::ENOENT
151
+ end
152
+ identifiers
153
+ end
154
+
135
155
  private
136
156
 
137
157
  def validate_plugin_identifier_key_value(plugin_key, value_type, entry_value, coordinate_value)
@@ -145,18 +165,6 @@ module KPM
145
165
  true
146
166
  end
147
167
 
148
- def read_plugin_identifiers
149
- path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
150
- identifiers = {}
151
- begin
152
- identifiers = File.open(path, 'r') do |f|
153
- JSON.parse(f.read)
154
- end
155
- rescue Errno::ENOENT
156
- end
157
- identifiers
158
- end
159
-
160
168
  def write_plugin_identifiers(identifiers)
161
169
 
162
170
  path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
@@ -33,6 +33,11 @@ module KPM
33
33
  save!
34
34
  end
35
35
 
36
+ def remove_entry!(coordinates)
37
+ @sha1_config['sha1'].delete(coordinates)
38
+ save!
39
+ end
40
+
36
41
  private
37
42
 
38
43
  def save!
@@ -62,4 +67,4 @@ module KPM
62
67
  end
63
68
 
64
69
  end
65
- end
70
+ end
data/lib/kpm/tasks.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'highline'
2
2
  require 'logger'
3
3
  require 'thor'
4
+ require 'pathname'
4
5
 
5
6
  module KPM
6
7
  module Tasks
@@ -32,6 +33,19 @@ module KPM
32
33
  say help, :green unless help.nil?
33
34
  end
34
35
 
36
+ method_option :destination,
37
+ :type => :string,
38
+ :default => nil,
39
+ :desc => 'A different folder other than the default bundles directory.'
40
+ method_option :force,
41
+ :type => :boolean,
42
+ :default => nil,
43
+ :desc => 'Don\'t ask for confirmation while deleting multiple versions of a plugin.'
44
+ desc 'uninstall plugin', 'Uninstall the specified plugin, identified by its name or key, from current deployment'
45
+ def uninstall(plugin)
46
+ say 'Done!' if Uninstaller.new(options[:destination]).uninstall_plugin(plugin, options[:force])
47
+ end
48
+
35
49
  method_option :destination,
36
50
  :type => :string,
37
51
  :default => nil,
@@ -324,6 +338,33 @@ module KPM
324
338
  say "Known plugin for KB version #{options[:version]}\n " + (plugins_info.map {|k,v| "#{k} #{v}"}).join("\n "), :green
325
339
  end
326
340
 
341
+ method_option :destination,
342
+ :type => :string,
343
+ :default => nil,
344
+ :desc => 'Folder where to download migration files.'
345
+ method_option :token,
346
+ :type => :string,
347
+ :default => nil,
348
+ :desc => 'GitHub OAuth token.'
349
+ desc 'migrations repository from to', 'Download migration files for Kill Bill or a plugin'
350
+ def migrations(repository, from, to = nil)
351
+ full_repo = repository.include?('/') ? repository : "killbill/#{repository}"
352
+ dir = KPM::Migrations.new(from, to, full_repo, options[:token], logger).save(options[:destination])
353
+ say (dir.nil? ? 'No migration required' : "Migrations can be found at #{dir}"), :green
354
+ end
355
+
356
+ method_option :destination,
357
+ :type => :string,
358
+ :default => nil,
359
+ :desc => 'A different folder other than the default bundles directory.'
360
+ desc 'inspect', 'Inspect current deployment'
361
+ def inspect
362
+ inspector = KPM::Inspector.new
363
+ all_plugins = inspector.inspect(options[:destination])
364
+ #puts all_plugins.to_json
365
+ inspector.format(all_plugins)
366
+ end
367
+
327
368
  private
328
369
 
329
370
  def logger
@@ -0,0 +1,69 @@
1
+ module KPM
2
+ class Uninstaller
3
+ def initialize(destination, logger = nil)
4
+ @logger = logger
5
+ if @logger.nil?
6
+ @logger = Logger.new(STDOUT)
7
+ @logger.level = Logger::INFO
8
+ end
9
+
10
+ destination ||= KPM::BaseInstaller::DEFAULT_BUNDLES_DIR
11
+ @installed_plugins = Inspector.new.inspect(destination)
12
+
13
+ plugins_installation_path = File.join(destination, 'plugins')
14
+ @plugins_manager = PluginsManager.new(plugins_installation_path, @logger)
15
+
16
+ sha1_file_path = File.join(destination, KPM::BaseInstaller::SHA1_FILENAME)
17
+ @sha1checker = KPM::Sha1Checker.from_file(sha1_file_path, @logger)
18
+ end
19
+
20
+ def uninstall_plugin(plugin, force = false)
21
+ plugin_info = find_plugin(plugin)
22
+ raise "No plugin with key/name '#{plugin}' found installed. Try running 'kpm inspect' for more info" unless plugin_info
23
+
24
+ remove_all_plugin_versions(plugin_info, force)
25
+ end
26
+
27
+ private
28
+
29
+ def find_plugin(plugin)
30
+ plugin_info = @installed_plugins[plugin]
31
+ if plugin_info.nil?
32
+ @installed_plugins.each do |_, info|
33
+ if info[:plugin_key] == plugin
34
+ plugin_info = info
35
+ break
36
+ end
37
+ end
38
+ end
39
+
40
+ plugin_info
41
+ end
42
+
43
+ def remove_all_plugin_versions(plugin_info, force = false)
44
+ versions = plugin_info[:versions].map { |artifact| artifact[:version] }
45
+ KPM.ui.say "Removing the following versions of the #{plugin_info[:plugin_name]} plugin: #{versions.join(', ')}"
46
+ if !force && versions.length > 1
47
+ return false unless 'y' == KPM.ui.ask('Are you sure you want to continue?', limited_to: %w(y n))
48
+ end
49
+
50
+ FileUtils.rmtree(plugin_info[:plugin_path])
51
+
52
+ @plugins_manager.remove_plugin_identifier_key(plugin_info[:plugin_key])
53
+ versions.each do |version|
54
+ remove_sha1_entry(plugin_info, version)
55
+ end
56
+
57
+ true
58
+ end
59
+
60
+ def remove_sha1_entry(plugin_info, version)
61
+ coordinates = KPM::Coordinates.build_coordinates(group_id: plugin_info[:group_id],
62
+ artifact_id: plugin_info[:artifact_id],
63
+ packaging: plugin_info[:packaging],
64
+ classifier: plugin_info[:classifier],
65
+ version: version)
66
+ @sha1checker.remove_entry!(coordinates)
67
+ end
68
+ end
69
+ end
data/lib/kpm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module KPM
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe KPM::Migrations do
4
+
5
+ context 'plugins' do
6
+ it 'should be able to find migrations for a java plugin' do
7
+ migrations = KPM::Migrations.new('master', nil, 'killbill/killbill-analytics-plugin', ENV['TOKEN']).migrations
8
+ # No migration yet
9
+ migrations.size.should == 0
10
+ end
11
+
12
+ it 'should be able to find migrations for a ruby plugin' do
13
+ migrations = KPM::Migrations.new('master', nil, 'killbill/killbill-cybersource-plugin', ENV['TOKEN']).migrations
14
+ # No migration yet
15
+ migrations.size.should == 0
16
+ end
17
+ end
18
+
19
+ context 'killbill' do
20
+ it 'should be able to find migrations between two versions' do
21
+ migrations = KPM::Migrations.new('master', 'work-for-release-0.16.4', 'killbill/killbill', ENV['TOKEN']).migrations
22
+
23
+ migrations.size.should == 1
24
+ migrations.first[:name].should == 'V20160324060345__revisit_payment_methods_indexes_509.sql'
25
+ migrations.first[:sql].should == "drop index payment_methods_active_accnt on payment_methods;\n"
26
+
27
+ KPM::Migrations.new('master', 'master', 'killbill/killbill', ENV['TOKEN']).migrations.size.should == 0
28
+ end
29
+
30
+ it 'should be able to find migrations for a given version' do
31
+ migrations = KPM::Migrations.new('work-for-release-0.16.4', nil, 'killbill/killbill', ENV['TOKEN']).migrations
32
+
33
+ migrations.size.should == 1
34
+ migrations.first[:name].should == 'V20160324060345__revisit_payment_methods_indexes_509.sql'
35
+ migrations.first[:sql].should == "drop index payment_methods_active_accnt on payment_methods;\n"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ describe KPM::Inspector do
4
+
5
+ before(:each) do
6
+ @logger = Logger.new(STDOUT)
7
+ @logger.level = Logger::INFO
8
+
9
+ tmp_bundles_dir = Dir.mktmpdir
10
+ @bundles_dir = Pathname.new(tmp_bundles_dir).expand_path
11
+ @plugins_dir = @bundles_dir.join('plugins')
12
+
13
+ FileUtils.mkdir_p(@plugins_dir)
14
+
15
+ @ruby_plugins_dir = @plugins_dir.join('ruby')
16
+ FileUtils.mkdir_p(@ruby_plugins_dir)
17
+
18
+ @java_plugins_dir = @plugins_dir.join('java')
19
+ FileUtils.mkdir_p(@java_plugins_dir)
20
+
21
+ @manager = KPM::PluginsManager.new(@plugins_dir, @logger)
22
+
23
+ @sha1_file = @bundles_dir.join("sha1.yml")
24
+ @sha1_checker = KPM::Sha1Checker.from_file(@sha1_file)
25
+
26
+ end
27
+
28
+
29
+ it 'should parse a correctly setup env' do
30
+
31
+ add_plugin('foo', 'plugin_foo', ['1.2.3', '2.0.0', '2.0.1'], 'ruby', 'com.foo', 'foo', 'tar.gz', nil, ['12345', '23456', '34567'], '2.0.1', ['1.2.3'])
32
+ add_plugin('bar', 'plugin_bar', ['1.0.0'], 'java', 'com.bar', 'bar', 'jar', nil, ['98765'], nil, [])
33
+
34
+ inspector = KPM::Inspector.new
35
+ all_plugins = inspector.inspect(@bundles_dir)
36
+ all_plugins.size == 2
37
+
38
+ all_plugins['plugin_bar']['plugin_key'] == 'bar'
39
+ all_plugins['plugin_bar']['plugin_path'] == @java_plugins_dir.join('plugin_bar').to_s
40
+ all_plugins['plugin_bar'][:versions].size == 1
41
+ all_plugins['plugin_bar'][:versions][0][:version] == '1.0.0'
42
+ all_plugins['plugin_bar'][:versions][0][:is_default] == true
43
+ all_plugins['plugin_bar'][:versions][0][:is_disabled] == false
44
+ all_plugins['plugin_bar'][:versions][0][:sha1] == '98765'
45
+
46
+ all_plugins['plugin_foo']['plugin_key'] == 'foo'
47
+ all_plugins['plugin_foo']['plugin_path'] == @ruby_plugins_dir.join('plugin_foo').to_s
48
+ all_plugins['plugin_foo'][:versions].size == 3
49
+
50
+ all_plugins['plugin_foo'][:versions][0][:version] == '1.2.3'
51
+ all_plugins['plugin_foo'][:versions][0][:is_default] == false
52
+ all_plugins['plugin_foo'][:versions][0][:is_disabled] == true
53
+ all_plugins['plugin_foo'][:versions][0][:sha1] == '12345'
54
+
55
+ all_plugins['plugin_foo'][:versions][1][:version] == '2.0.0'
56
+ all_plugins['plugin_foo'][:versions][1][:is_default] == false
57
+ all_plugins['plugin_foo'][:versions][1][:is_disabled] == false
58
+ all_plugins['plugin_foo'][:versions][1][:sha1] == '23456'
59
+
60
+ all_plugins['plugin_foo'][:versions][2][:version] == '2.0.1'
61
+ all_plugins['plugin_foo'][:versions][2][:is_default] == true
62
+ all_plugins['plugin_foo'][:versions][2][:is_disabled] == false
63
+ all_plugins['plugin_foo'][:versions][2][:sha1] == '34567'
64
+
65
+ end
66
+
67
+
68
+ private
69
+
70
+ def add_plugin(plugin_key, plugin_name, versions, language, group_id, artifact_id, packaging, classifier, sha1, active_version, disabled_versions)
71
+
72
+ plugin_dir = language == 'ruby' ? @ruby_plugins_dir.join(plugin_name) : @java_plugins_dir.join(plugin_name)
73
+
74
+ versions.each_with_index do |v, idx|
75
+
76
+ coordinate_map = {:group_id => group_id, :artifact_id => artifact_id, :version => v, :packaging => packaging, :classifier => classifier}
77
+ coordinates = KPM::Coordinates.build_coordinates(coordinate_map)
78
+
79
+ @manager.add_plugin_identifier_key(plugin_key, plugin_name, language, coordinate_map)
80
+ @sha1_checker.add_or_modify_entry!(coordinates, sha1[idx])
81
+
82
+
83
+ plugin_dir_version = plugin_dir.join(v)
84
+
85
+ FileUtils.mkdir_p(plugin_dir_version)
86
+
87
+ # Create some entry to look real
88
+ some_file = 'ruby' ? 'ROOT' : '#{plugin_name}.jar'
89
+ FileUtils.touch(plugin_dir_version.join(some_file))
90
+ end
91
+
92
+ @manager.set_active(plugin_dir, active_version) if active_version
93
+
94
+ disabled_versions.each do |v|
95
+ @manager.uninstall(plugin_dir, v)
96
+ end
97
+ end
98
+
99
+ end
@@ -65,6 +65,22 @@ describe KPM::Sha1Checker do
65
65
  existing.should == 'bbb068c3fd5f95646ce0d09852f43ff67f06fccc'
66
66
  end
67
67
 
68
+ context 'when removing an entry' do
69
+ let(:identifier) { 'killbill-plugin-match-1.0.0.tar.gz' }
70
+ before do
71
+ @sha1_checker.remove_entry!(identifier)
72
+ end
73
+
74
+ it 'does not find the entry' do
75
+ @sha1_checker.sha1(identifier).should be_nil
76
+ end
77
+
78
+ let(:reloaded_checker) { KPM::Sha1Checker.from_file(@tmp_config) }
79
+ it 'does not find entry in file system' do
80
+ reloaded_checker.sha1(identifier).should be_nil
81
+ end
82
+ end
83
+
68
84
  it 'should work with empty config' do
69
85
 
70
86
  tmp_destination_dir = Dir.tmpdir()
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe KPM::Uninstaller do
4
+
5
+ let(:uninstaller) { KPM::Uninstaller.new(destination) }
6
+ let(:destination) { 'somedir' }
7
+
8
+ let(:plugins_manager_mock) { double(KPM::PluginsManager) }
9
+ let(:sha1_checker_mock) { double(KPM::Sha1Checker) }
10
+ before do
11
+ KPM::Inspector.stub_chain(:new, :inspect).and_return(installed_plugins)
12
+ KPM::PluginsManager.stub(:new).and_return(plugins_manager_mock)
13
+ KPM::Sha1Checker.stub(:from_file).and_return(sha1_checker_mock)
14
+ end
15
+
16
+ context 'when plugin is not installed' do
17
+ let(:installed_plugins) { {} }
18
+
19
+ it 'raises a plugin not found error' do
20
+ expect {
21
+ uninstaller.uninstall_plugin('adyen')
22
+ }.to raise_error(StandardError, "No plugin with key/name 'adyen' found installed. Try running 'kpm inspect' for more info")
23
+ end
24
+ end
25
+
26
+ context 'when plugin is installed' do
27
+ let(:installed_plugins) do
28
+ {
29
+ plugin_name => {
30
+ plugin_key: plugin_key,
31
+ plugin_path: plugin_path,
32
+ versions: [{version: version}],
33
+ group_id: 'group',
34
+ artifact_id: 'artifact',
35
+ packaging: 'jar'
36
+ }
37
+ }
38
+ end
39
+
40
+ let(:plugin_name) { 'plugin-name' }
41
+ let(:plugin_key) { 'plugin-key' }
42
+ let(:plugin_path) { 'plugin-path' }
43
+ let(:version) { '1.0' }
44
+
45
+ it 'uninstalls a plugin by name' do
46
+ FileUtils.should_receive(:rmtree).with(plugin_path)
47
+ plugins_manager_mock.should_receive(:remove_plugin_identifier_key).with(plugin_key)
48
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version}")
49
+
50
+ uninstaller.uninstall_plugin(plugin_name).should be_true
51
+ end
52
+
53
+ it 'uninstalls a plugin by key' do
54
+ FileUtils.should_receive(:rmtree).with(plugin_path)
55
+ plugins_manager_mock.should_receive(:remove_plugin_identifier_key).with(plugin_key)
56
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version}")
57
+
58
+ uninstaller.uninstall_plugin(plugin_key).should be_true
59
+ end
60
+ end
61
+
62
+ context 'when plugin is installed' do
63
+ let(:installed_plugins) do
64
+ {
65
+ plugin_name => {
66
+ plugin_key: plugin_key,
67
+ plugin_path: plugin_path,
68
+ versions: [{version: version1},{version: version2}],
69
+ group_id: 'group',
70
+ artifact_id: 'artifact',
71
+ packaging: 'jar'
72
+ }
73
+ }
74
+ end
75
+
76
+ let(:plugin_name) { 'plugin-name' }
77
+ let(:plugin_key) { 'plugin-key' }
78
+ let(:plugin_path) { 'plugin-path' }
79
+ let(:version1) { '1.0' }
80
+ let(:version2) { '2.0' }
81
+
82
+ it 'uninstalls if user confirms action' do
83
+ KPM.ui.should_receive(:ask).and_return('y')
84
+
85
+ FileUtils.should_receive(:rmtree).with(plugin_path)
86
+ plugins_manager_mock.should_receive(:remove_plugin_identifier_key).with(plugin_key)
87
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version1}")
88
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version2}")
89
+
90
+ uninstaller.uninstall_plugin(plugin_name).should be_true
91
+ end
92
+
93
+ it 'does nothing if user cancels' do
94
+ KPM.ui.should_receive(:ask).and_return('n')
95
+
96
+ uninstaller.uninstall_plugin(plugin_name).should be_false
97
+ end
98
+
99
+ it 'uninstalls without confirmation if the force option is given' do
100
+ FileUtils.should_receive(:rmtree).with(plugin_path)
101
+ plugins_manager_mock.should_receive(:remove_plugin_identifier_key).with(plugin_key)
102
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version1}")
103
+ sha1_checker_mock.should_receive(:remove_entry!).with("group:artifact:jar:#{version2}")
104
+
105
+ uninstaller.uninstall_plugin(plugin_name, true).should be_true
106
+ end
107
+ end
108
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'tmpdir'
2
+ require 'thor'
2
3
  require 'kpm'
3
4
  require 'logger'
4
5
  require 'rspec'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kill Bill core team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-26 00:00:00.000000000 Z
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: highline
@@ -119,16 +119,21 @@ files:
119
119
  - lib/kpm/base_artifact.rb
120
120
  - lib/kpm/base_installer.rb
121
121
  - lib/kpm/cli.rb
122
+ - lib/kpm/coordinates.rb
123
+ - lib/kpm/formatter.rb
124
+ - lib/kpm/inspector.rb
122
125
  - lib/kpm/installer.rb
123
126
  - lib/kpm/kaui_artifact.rb
124
127
  - lib/kpm/killbill_plugin_artifact.rb
125
128
  - lib/kpm/killbill_server_artifact.rb
129
+ - lib/kpm/migrations.rb
126
130
  - lib/kpm/plugins_directory.rb
127
131
  - lib/kpm/plugins_directory.yml
128
132
  - lib/kpm/plugins_manager.rb
129
133
  - lib/kpm/sha1_checker.rb
130
134
  - lib/kpm/tasks.rb
131
135
  - lib/kpm/tomcat_manager.rb
136
+ - lib/kpm/uninstaller.rb
132
137
  - lib/kpm/utils.rb
133
138
  - lib/kpm/version.rb
134
139
  - spec/kpm/remote/base_artifact_spec.rb
@@ -137,12 +142,15 @@ files:
137
142
  - spec/kpm/remote/kaui_artifact_spec.rb
138
143
  - spec/kpm/remote/killbill_plugin_artifact_spec.rb
139
144
  - spec/kpm/remote/killbill_server_artifact_spec.rb
145
+ - spec/kpm/remote/migrations_spec.rb
140
146
  - spec/kpm/remote/tomcat_manager_spec.rb
141
147
  - spec/kpm/unit/base_artifact_spec.rb
148
+ - spec/kpm/unit/inspector_spec.rb
142
149
  - spec/kpm/unit/plugins_directory_spec.rb
143
150
  - spec/kpm/unit/plugins_manager_spec.rb
144
151
  - spec/kpm/unit/sha1_checker_spec.rb
145
152
  - spec/kpm/unit/sha1_test.yml
153
+ - spec/kpm/unit/uninstaller_spec.rb
146
154
  - spec/spec_helper.rb
147
155
  homepage: http://kill-bill.org
148
156
  licenses:
@@ -177,10 +185,13 @@ test_files:
177
185
  - spec/kpm/remote/kaui_artifact_spec.rb
178
186
  - spec/kpm/remote/killbill_plugin_artifact_spec.rb
179
187
  - spec/kpm/remote/killbill_server_artifact_spec.rb
188
+ - spec/kpm/remote/migrations_spec.rb
180
189
  - spec/kpm/remote/tomcat_manager_spec.rb
181
190
  - spec/kpm/unit/base_artifact_spec.rb
191
+ - spec/kpm/unit/inspector_spec.rb
182
192
  - spec/kpm/unit/plugins_directory_spec.rb
183
193
  - spec/kpm/unit/plugins_manager_spec.rb
184
194
  - spec/kpm/unit/sha1_checker_spec.rb
185
195
  - spec/kpm/unit/sha1_test.yml
196
+ - spec/kpm/unit/uninstaller_spec.rb
186
197
  - spec/spec_helper.rb