kpm 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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