logstash-core 1.5.0.rc2.snapshot-java → 1.5.0.rc3-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of logstash-core might be problematic. Click here for more details.

@@ -0,0 +1,38 @@
1
+ class LogStash::PluginManager::Command < Clamp::Command
2
+ def gemfile
3
+ @gemfile ||= LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, 'r+')).load
4
+ end
5
+
6
+ # If set in debug mode we will raise an exception and display the stacktrace
7
+ def report_exception(readable_message, exception)
8
+ if ENV["DEBUG"]
9
+ raise exception
10
+ else
11
+ signal_error("#{readable_message}, message: #{exception.message}")
12
+ end
13
+ end
14
+
15
+ def display_bundler_output(output)
16
+ if ENV['DEBUG'] && output
17
+ # Display what bundler did in the last run
18
+ $stderr.puts("Bundler output")
19
+ $stderr.puts(output)
20
+ end
21
+ end
22
+
23
+
24
+ # Each plugin install for a gemfile create a path with a unique id.
25
+ # we must clear what is not currently used in the
26
+ def remove_unused_locally_installed_gems!
27
+ used_path = gemfile.locally_installed_gems.collect { |gem| gem.options[:path] }
28
+
29
+ Dir.glob(File.join(LogStash::Environment::LOCAL_GEM_PATH, '*')) do |path|
30
+ FileUtils.rm_rf(relative_path(path)) if used_path.none? { |p| p.start_with?(relative_path(path)) }
31
+ end
32
+ end
33
+
34
+ def relative_path(path)
35
+ require "pathname"
36
+ ::Pathname.new(path).relative_path_from(::Pathname.new(LogStash::Environment::LOGSTASH_HOME)).to_s
37
+ end
38
+ end
@@ -1,16 +1,17 @@
1
- require 'clamp'
2
- require 'logstash/namespace'
3
- require 'logstash/environment'
4
- require 'logstash/pluginmanager/util'
5
- require 'jar-dependencies'
6
- require 'jar_install_post_install_hook'
7
- require 'file-dependencies/gem'
8
-
1
+ require "clamp"
2
+ require "logstash/namespace"
3
+ require "logstash/environment"
4
+ require "logstash/pluginmanager/util"
5
+ require "logstash/pluginmanager/command"
6
+ require "jar-dependencies"
7
+ require "jar_install_post_install_hook"
8
+ require "file-dependencies/gem"
9
9
  require "logstash/gemfile"
10
10
  require "logstash/bundler"
11
+ require "fileutils"
11
12
 
12
- class LogStash::PluginManager::Install < Clamp::Command
13
- parameter "[PLUGIN] ...", "plugin name(s) or file"
13
+ class LogStash::PluginManager::Install < LogStash::PluginManager::Command
14
+ parameter "[PLUGIN] ...", "plugin name(s) or file", :attribute_name => :plugins_arg
14
15
  option "--version", "VERSION", "version of the plugin to install"
15
16
  option "--[no-]verify", :flag, "verify plugin validity before installation", :default => true
16
17
  option "--development", :flag, "install all development dependencies of currently installed plugins", :default => false
@@ -18,95 +19,123 @@ class LogStash::PluginManager::Install < Clamp::Command
18
19
  # the install logic below support installing multiple plugins with each a version specification
19
20
  # but the argument parsing does not support it for now so currently if specifying --version only
20
21
  # one plugin name can be also specified.
21
- #
22
- # TODO: find right syntax to allow specifying list of plugins with optional version specification for each
23
-
24
22
  def execute
25
- if development?
26
- raise(LogStash::PluginManager::Error, "Cannot specify plugin(s) with --development, it will add the development dependencies of the currently installed plugins") unless plugin_list.empty?
23
+ validate_cli_options!
24
+
25
+ if local_gems?
26
+ gems = extract_local_gems_plugins
27
+ elsif development?
28
+ gems = plugins_development_gems
27
29
  else
28
- raise(LogStash::PluginManager::Error, "No plugin specified") if plugin_list.empty? && verify?
29
-
30
- # temporary until we fullfil TODO ^^
31
- raise(LogStash::PluginManager::Error, "Only 1 plugin name can be specified with --version") if version && plugin_list.size > 1
30
+ gems = plugins_gems
31
+ verify_remote!(gems) if verify?
32
32
  end
33
- raise(LogStash::PluginManager::Error, "File #{LogStash::Environment::GEMFILE_PATH} does not exist or is not writable, aborting") unless File.writable?(LogStash::Environment::GEMFILE_PATH)
34
-
35
- gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load
36
- # keep a copy of the gemset to revert on error
37
- original_gemset = gemfile.gemset.copy
38
33
 
39
- # force Rubygems sources to our Gemfile sources
40
- Gem.sources = gemfile.gemset.sources
41
-
42
- # install_list will be an array of [plugin name, version] tuples, version can be nil
43
- install_list = []
34
+ install_gems_list!(gems)
35
+ remove_unused_locally_installed_gems!
36
+ end
44
37
 
38
+ private
39
+ def validate_cli_options!
45
40
  if development?
46
- specs = LogStash::PluginManager.all_installed_plugins_gem_specs(gemfile)
47
- install_list = specs.inject([]) do |result, spec|
48
- result = result + spec.dependencies.select{|dep| dep.type == :development}.map{|dep| [dep.name] + dep.requirement.as_list + [{:group => :development}]}
49
- end
41
+ signal_usage_error("Cannot specify plugin(s) with --development, it will add the development dependencies of the currently installed plugins") unless plugins_arg.empty?
50
42
  else
51
- # at this point we know that plugin_list is not empty and if the --version is specified there is only one plugin in plugin_list
43
+ signal_usage_error("No plugin specified") if plugins_arg.empty? && verify?
44
+ # TODO: find right syntax to allow specifying list of plugins with optional version specification for each
45
+ signal_usage_error("Only 1 plugin name can be specified with --version") if version && plugins_arg.size > 1
46
+ end
47
+ signal_error("File #{LogStash::Environment::GEMFILE_PATH} does not exist or is not writable, aborting") unless ::File.writable?(LogStash::Environment::GEMFILE_PATH)
48
+ end
52
49
 
53
- install_list = version ? [plugin_list << version] : plugin_list.map{|plugin| [plugin, nil]}
50
+ # Check if the specified gems contains
51
+ # the logstash `metadata`
52
+ def verify_remote!(gems)
53
+ gems.each do |plugin, version|
54
+ puts("Validating #{[plugin, version].compact.join("-")}")
55
+ signal_error("Installation aborted, verification failed for #{plugin} #{version}") unless LogStash::PluginManager.logstash_plugin?(plugin, version)
56
+ end
57
+ end
54
58
 
55
- install_list.each do |plugin, version|
56
- puts("Validating #{[plugin, version].compact.join("-")}")
57
- raise(LogStash::PluginManager::Error, "Installation aborted") unless LogStash::PluginManager.logstash_plugin?(plugin, version)
58
- end if verify?
59
+ def plugins_development_gems
60
+ # Get currently defined gems and their dev dependencies
61
+ specs = []
59
62
 
60
- # at this point we know that we either have a valid gem name & version or a valid .gem file path
63
+ specs = LogStash::PluginManager.all_installed_plugins_gem_specs(gemfile)
61
64
 
62
- # if LogStash::PluginManager.plugin_file?(plugin)
63
- # raise(LogStash::PluginManager::Error) unless cache_gem_file(plugin)
64
- # spec = LogStash::PluginManager.plugin_file_spec(plugin)
65
- # gemfile.update(spec.name, spec.version.to_s)
66
- # else
67
- # plugins.each{|tuple| gemfile.update(*tuple)}
68
- # end
65
+ # Construct the list of dependencies to add to the current gemfile
66
+ specs.each_with_object([]) do |spec, install_list|
67
+ dependencies = spec.dependencies
68
+ .select { |dep| dep.type == :development }
69
+ .map { |dep| [dep.name] + dep.requirement.as_list }
70
+
71
+ install_list.concat(dependencies)
69
72
  end
73
+ end
70
74
 
75
+ def plugins_gems
76
+ version ? [plugins_arg << version] : plugins_arg.map { |plugin| [plugin, nil] }
77
+ end
71
78
 
79
+ # install_list will be an array of [plugin name, version, options] tuples, version it
80
+ # can be nil at this point we know that plugins_arg is not empty and if the
81
+ # --version is specified there is only one plugin in plugins_arg
82
+ #
83
+ def install_gems_list!(install_list)
84
+ # If something goes wrong during the installation `LogStash::Gemfile` will restore a backup version.
72
85
  install_list = LogStash::PluginManager.merge_duplicates(install_list)
73
- install_list.each{|plugin, version| gemfile.update(plugin, version)}
74
- gemfile.save
75
86
 
76
- puts("Installing" + (install_list.empty? ? "..." : " " + install_list.map{|plugin, version| plugin}.join(", ")))
87
+ # Add plugins/gems to the current gemfile
88
+ puts("Installing" + (install_list.empty? ? "..." : " " + install_list.collect(&:first).join(", ")))
89
+ install_list.each { |plugin, version, options| gemfile.update(plugin, version, options) }
90
+
91
+ # Sync gemfiles changes to disk to make them available to the `bundler install`'s API
92
+ gemfile.save
77
93
 
78
94
  bundler_options = {:install => true}
79
95
  bundler_options[:without] = [] if development?
96
+ bundler_options[:rubygems_source] = gemfile.gemset.sources
80
97
 
81
- # any errors will be logged to $stderr by invoke_bundler!
82
- output, exception = LogStash::Bundler.invoke_bundler!(bundler_options)
98
+ output = LogStash::Bundler.invoke_bundler!(bundler_options)
83
99
 
84
- if ENV["DEBUG"]
85
- $stderr.puts(output)
86
- $stderr.puts("Error: #{exception.class}, #{exception.message}") if exception
87
- end
100
+ puts("Installation successful")
101
+ rescue => exception
102
+ gemfile.restore!
103
+ report_exception("Installation Aborted", exception)
104
+ ensure
105
+ display_bundler_output(output)
106
+ end
88
107
 
89
- if exception
90
- # revert to original Gemfile content
91
- gemfile.gemset = original_gemset
92
- gemfile.save
93
- raise(LogStash::PluginManager::Error, "Installation aborted")
94
- end
108
+ # Extract the specified local gems in a predefined local path
109
+ # Update the gemfile to use a relative path to this plugin and run
110
+ # Bundler, this will mark the gem not updatable by `bin/plugin update`
111
+ # This is the most reliable way to make it work in bundler without
112
+ # hacking with `how bundler works`
113
+ #
114
+ # Bundler 2.0, will have support for plugins source we could create a .gem source
115
+ # to support it.
116
+ def extract_local_gems_plugins
117
+ plugins_arg.collect do |plugin|
118
+ # We do the verify before extracting the gem so we dont have to deal with unused path
119
+ if verify?
120
+ puts("Validating #{plugin}")
121
+ signal_error("Installation aborted, verification failed for #{plugin}") unless LogStash::PluginManager.logstash_plugin?(plugin, version)
122
+ end
95
123
 
96
- puts("Installation successful")
124
+ package, path = LogStash::Bundler.unpack(plugin, LogStash::Environment::LOCAL_GEM_PATH)
125
+ [package.spec.name, package.spec.version, { :path => relative_path(path) }]
126
+ end
97
127
  end
98
128
 
99
- # copy .gem file into bundler cache directory, log any error to $stderr
100
- # @param path [String] the source .gem file to copy
101
- # @return [Boolean] true if successful
102
- def cache_gem_file(path)
103
- dest = ::File.join(LogStash::Environment.logstash_gem_home, "cache")
104
- begin
105
- FileUtils.cp(path, dest)
106
- rescue => e
107
- $stderr.puts("Error copying #{plugin} to #{dest}, caused by #{e.class}")
108
- return false
129
+ # We cannot install both .gem and normal plugin in one call of `plugin install`
130
+ def local_gems?
131
+ return false if plugins_arg.empty?
132
+
133
+ local_gem = plugins_arg.collect { |plugin| ::File.extname(plugin) == ".gem" }.uniq
134
+
135
+ if local_gem.size == 1
136
+ return local_gem.first
137
+ else
138
+ signal_usage_error("Mixed source of plugins, you can't mix local `.gem` and remote gems")
109
139
  end
110
- true
111
140
  end
112
141
  end # class Logstash::PluginManager
@@ -1,9 +1,11 @@
1
1
  require 'clamp'
2
2
  require 'logstash/namespace'
3
3
  require 'logstash/pluginmanager/util'
4
+ require 'logstash/pluginmanager/command'
5
+ require "logstash/bundler"
4
6
  require 'rubygems/spec_fetcher'
5
7
 
6
- class LogStash::PluginManager::List < Clamp::Command
8
+ class LogStash::PluginManager::List < LogStash::PluginManager::Command
7
9
 
8
10
  parameter "[PLUGIN]", "Part of plugin name to search for, leave empty for all plugins"
9
11
 
@@ -15,27 +17,28 @@ class LogStash::PluginManager::List < Clamp::Command
15
17
  end
16
18
 
17
19
  def execute
18
- require 'logstash/environment'
19
- LogStash::Environment.bundler_setup!
20
+ LogStash::Bundler.setup!
20
21
 
21
- Gem.configuration.verbose = false
22
+ signal_error("No plugins found") if filtered_specs.empty?
22
23
 
23
- gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load
24
-
25
- # start with all locally installed plugin gems regardless of the Gemfile content
26
- specs = LogStash::PluginManager.find_plugins_gem_specs
27
-
28
- # apply filters
29
- specs = specs.select{|spec| gemfile.find(spec.name)} if installed?
30
- specs = specs.select{|spec| spec.name =~ /#{plugin}/i} if plugin
31
- specs = specs.select{|spec| spec.metadata['logstash_group'] == group} if group
32
-
33
- raise(LogStash::PluginManager::Error, "No plugins found") if specs.empty?
34
-
35
- specs.sort_by{|spec| spec.name}.each do |spec|
24
+ filtered_specs.sort_by{|spec| spec.name}.each do |spec|
36
25
  line = "#{spec.name}"
37
26
  line += " (#{spec.version})" if verbose?
38
27
  puts(line)
39
28
  end
40
29
  end
30
+
31
+ def filtered_specs
32
+ @filtered_specs ||= begin
33
+ # start with all locally installed plugin gems regardless of the Gemfile content
34
+ specs = LogStash::PluginManager.find_plugins_gem_specs
35
+
36
+ # apply filters
37
+ specs = specs.select{|spec| gemfile.find(spec.name)} if installed?
38
+ specs = specs.select{|spec| spec.name =~ /#{plugin}/i} if plugin
39
+ specs = specs.select{|spec| spec.metadata['logstash_group'] == group} if group
40
+
41
+ specs
42
+ end
43
+ end
41
44
  end # class Logstash::PluginManager
@@ -5,7 +5,6 @@ require "logstash/pluginmanager/uninstall"
5
5
  require "logstash/pluginmanager/list"
6
6
  require "logstash/pluginmanager/update"
7
7
  require "logstash/pluginmanager/util"
8
- require "logstash/pluginmanager/maven_tools_patch"
9
8
  require "clamp"
10
9
 
11
10
  module LogStash
@@ -3,25 +3,21 @@ require "logstash/logging"
3
3
  require "logstash/errors"
4
4
  require "logstash/environment"
5
5
  require "logstash/pluginmanager/util"
6
+ require "logstash/pluginmanager/command"
6
7
  require "clamp"
7
8
 
8
9
  require "logstash/gemfile"
9
10
  require "logstash/bundler"
10
11
 
11
- class LogStash::PluginManager::Uninstall < Clamp::Command
12
+ class LogStash::PluginManager::Uninstall < LogStash::PluginManager::Command
12
13
  parameter "PLUGIN", "plugin name"
13
14
 
14
-
15
15
  def execute
16
- raise(LogStash::PluginManager::Error, "File #{LogStash::Environment::GEMFILE_PATH} does not exist or is not writable, aborting") unless File.writable?(LogStash::Environment::GEMFILE_PATH)
17
-
18
- gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load
19
- # keep a copy of the gemset to revert on error
20
- original_gemset = gemfile.gemset.copy
16
+ signal_error("File #{LogStash::Environment::GEMFILE_PATH} does not exist or is not writable, aborting") unless File.writable?(LogStash::Environment::GEMFILE_PATH)
21
17
 
22
18
  # make sure this is an installed plugin and present in Gemfile.
23
19
  # it is not possible to uninstall a dependency not listed in the Gemfile, for example a dependent codec
24
- raise(LogStash::PluginManager::Error, "This plugin has not been previously installed, aborting") unless LogStash::PluginManager.installed_plugin?(plugin, gemfile)
20
+ signal_error("This plugin has not been previously installed, aborting") unless LogStash::PluginManager.installed_plugin?(plugin, gemfile)
25
21
 
26
22
  # since we previously did a gemfile.find(plugin) there is no reason why
27
23
  # remove would not work (return nil) here
@@ -31,19 +27,15 @@ class LogStash::PluginManager::Uninstall < Clamp::Command
31
27
  puts("Uninstalling #{plugin}")
32
28
 
33
29
  # any errors will be logged to $stderr by invoke_bundler!
34
- output, exception = LogStash::Bundler.invoke_bundler!(:install => true, :clean => true)
35
-
36
- if ENV["DEBUG"]
37
- $stderr.puts(output)
38
- $stderr.puts("Error: #{exception.class}, #{exception.message}") if exception
39
- end
40
-
41
- if exception
42
- # revert to original Gemfile content
43
- gemfile.gemset = original_gemset
44
- gemfile.save
45
- raise(LogStash::PluginManager::Error, "Uninstall aborted")
46
- end
30
+ # output, exception = LogStash::Bundler.invoke_bundler!(:install => true, :clean => true)
31
+ output = LogStash::Bundler.invoke_bundler!(:install => true, :clean => true)
32
+
33
+ remove_unused_locally_installed_gems!
47
34
  end
35
+ rescue => exception
36
+ gemfile.restore!
37
+ report_exception("Uninstall Aborted", exception)
38
+ ensure
39
+ display_bundler_output(output)
48
40
  end
49
41
  end
@@ -1,51 +1,80 @@
1
- require 'clamp'
2
- require 'logstash/namespace'
3
- require 'logstash/pluginmanager/util'
4
- require 'jar-dependencies'
5
- require 'jar_install_post_install_hook'
6
- require 'file-dependencies/gem'
7
-
1
+ require "clamp"
2
+ require "logstash/namespace"
3
+ require "logstash/pluginmanager/util"
4
+ require "logstash/pluginmanager/command"
5
+ require "jar-dependencies"
6
+ require "jar_install_post_install_hook"
7
+ require "file-dependencies/gem"
8
8
  require "logstash/gemfile"
9
9
  require "logstash/bundler"
10
10
 
11
- class LogStash::PluginManager::Update < Clamp::Command
12
- parameter "[PLUGIN] ...", "Plugin name(s) to upgrade to latest version"
11
+ class LogStash::PluginManager::Update < LogStash::PluginManager::Command
12
+ parameter "[PLUGIN] ...", "Plugin name(s) to upgrade to latest version", :attribute_name => :plugins_arg
13
13
 
14
14
  def execute
15
- gemfile = LogStash::Gemfile.new(File.new(LogStash::Environment::GEMFILE_PATH, "r+")).load
16
- # keep a copy of the gemset to revert on error
17
- original_gemset = gemfile.gemset.copy
18
-
19
- previous_gem_specs_map = find_latest_gem_specs
15
+ local_gems = gemfile.locally_installed_gems
20
16
 
21
- # create list of plugins to update
22
- plugins = unless plugin_list.empty?
23
- not_installed = plugin_list.select{|plugin| !previous_gem_specs_map.has_key?(plugin.downcase)}
24
- raise(LogStash::PluginManager::Error, "Plugin #{not_installed.join(', ')} is not installed so it cannot be updated, aborting") unless not_installed.empty?
25
- plugin_list
17
+ if update_all? && !local_gems.empty?
18
+ error_plugin_that_use_path!(local_gems)
26
19
  else
27
- previous_gem_specs_map.values.map{|spec| spec.name}
20
+ plugins_with_path = plugins_arg & local_gems
21
+ error_plugin_that_use_path!(plugins_with_path) if plugins_with_path.size > 0
28
22
  end
29
23
 
24
+ update_gems!
25
+ end
26
+
27
+ private
28
+ def error_plugin_that_use_path!(plugins)
29
+ signal_error("Update is not supported for manually defined plugins or local .gem plugin installations: #{plugins.collect(&:name).join(",")}")
30
+ end
31
+
32
+ def update_all?
33
+ plugins_arg.size == 0
34
+ end
35
+
36
+ def update_gems!
37
+ # If any error is raise inside the block the Gemfile will restore a backup of the Gemfile
38
+ previous_gem_specs_map = find_latest_gem_specs
39
+
30
40
  # remove any version constrain from the Gemfile so the plugin(s) can be updated to latest version
31
41
  # calling update without requiremend will remove any previous requirements
32
- plugins.select{|plugin| gemfile.find(plugin)}.each{|plugin| gemfile.update(plugin)}
42
+ plugins = plugins_to_update(previous_gem_specs_map)
43
+ plugins
44
+ .select { |plugin| gemfile.find(plugin) }
45
+ .each { |plugin| gemfile.update(plugin) }
46
+
47
+ # force a disk sync before running bundler
33
48
  gemfile.save
34
49
 
35
50
  puts("Updating " + plugins.join(", "))
36
51
 
37
52
  # any errors will be logged to $stderr by invoke_bundler!
38
- output, exception = LogStash::Bundler.invoke_bundler!(:update => plugins)
39
- output, exception = LogStash::Bundler.invoke_bundler!(:clean => true) unless exception
53
+ # Bundler cannot update and clean gems in one operation so we have to call the CLI twice.
54
+ output = LogStash::Bundler.invoke_bundler!(:update => plugins)
55
+ output = LogStash::Bundler.invoke_bundler!(:clean => true)
40
56
 
41
- if exception
42
- # revert to original Gemfile content
43
- gemfile.gemset = original_gemset
44
- gemfile.save
57
+ display_updated_plugins(previous_gem_specs_map)
58
+ rescue => exception
59
+ gemfile.restore!
60
+ report_exception("Updated Aborted", exception)
61
+ ensure
62
+ display_bundler_output(output)
63
+ end
45
64
 
46
- report_exception(output, exception)
65
+ # create list of plugins to update
66
+ def plugins_to_update(previous_gem_specs_map)
67
+ if update_all?
68
+ previous_gem_specs_map.values.map{|spec| spec.name}
69
+ else
70
+ not_installed = plugins_arg.select{|plugin| !previous_gem_specs_map.has_key?(plugin.downcase)}
71
+ signal_error("Plugin #{not_installed.join(', ')} is not installed so it cannot be updated, aborting") unless not_installed.empty?
72
+ plugins_arg
47
73
  end
74
+ end
48
75
 
76
+ # We compare the before the update and after the update
77
+ def display_updated_plugins(previous_gem_specs_map)
49
78
  update_count = 0
50
79
  find_latest_gem_specs.values.each do |spec|
51
80
  name = spec.name.downcase
@@ -59,11 +88,10 @@ class LogStash::PluginManager::Update < Clamp::Command
59
88
  update_count += 1
60
89
  end
61
90
  end
91
+
62
92
  puts("No plugin updated") if update_count.zero?
63
93
  end
64
94
 
65
- private
66
-
67
95
  # retrieve only the latest spec for all locally installed plugins
68
96
  # @return [Hash] result hash {plugin_name.downcase => plugin_spec}
69
97
  def find_latest_gem_specs
@@ -73,13 +101,4 @@ class LogStash::PluginManager::Update < Clamp::Command
73
101
  result
74
102
  end
75
103
  end
76
-
77
- def report_exception(output, exception)
78
- if ENV["DEBUG"]
79
- $stderr.puts(output)
80
- $stderr.puts("Error: #{exception.class}, #{exception.message}") if exception
81
- end
82
-
83
- raise(LogStash::PluginManager::Error, "Update aborted")
84
- end
85
104
  end