mirror of
https://github.com/elastic/logstash.git
synced 2025-04-23 14:17:58 -04:00
Enables the following cops: * Layout/SpaceBeforeBlockBraces * Layout/SpaceBeforeBrackets * Layout/SpaceBeforeComma * Layout/SpaceBeforeComment * Layout/SpaceBeforeFirstArg * Layout/SpaceBeforeSemicolon
249 lines
7 KiB
Ruby
249 lines
7 KiB
Ruby
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
# license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright
|
|
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
# the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
module LogStash
|
|
class GemfileError < StandardError; end
|
|
|
|
class Gemfile
|
|
attr_accessor :gemset
|
|
|
|
HEADER = \
|
|
"# This is a Logstash generated Gemfile.\n" + \
|
|
"# If you modify this file manually all comments and formatting will be lost.\n\n"
|
|
|
|
# @params io [IO] any IO object that supports read, write, truncate, rewind
|
|
def initialize(io)
|
|
@io = io
|
|
@gemset = nil
|
|
end
|
|
|
|
def load(with_backup = true)
|
|
# encoding must be set to UTF-8 here to avoid ending up with Windows-1252 encoding on Windows
|
|
# which will break the DSL instance_eval of that string
|
|
@io.set_encoding(Encoding::UTF_8)
|
|
@gemset ||= DSL.parse(@io.read)
|
|
backup if with_backup
|
|
self
|
|
end
|
|
|
|
def save
|
|
raise(GemfileError, "a Gemfile must first be loaded") unless @gemset
|
|
@io.truncate(0)
|
|
@io.rewind
|
|
@io.write(generate)
|
|
@io.flush
|
|
end
|
|
|
|
def generate
|
|
"#{HEADER}#{gemset.to_s}"
|
|
end
|
|
|
|
def find(name)
|
|
@gemset.find_gem(name)
|
|
end
|
|
|
|
# @param name [String] gem name
|
|
# @param *requirements params following name use the same notation as the Gemfile gem DSL statement
|
|
# @raise GemfileError if gem already exists in Gemfile
|
|
def add(name, *requirements)
|
|
@gemset.add_gem(Gem.parse(name, *requirements))
|
|
end
|
|
|
|
# update existing or add new and merge passed options with current gem options if it exists
|
|
# @param name [String] gem name
|
|
# @param *requirements params following name use the same notation as the Gemfile gem DSL statement
|
|
def update(name, *requirements)
|
|
@gemset.update_gem(Gem.parse(name, *requirements))
|
|
end
|
|
|
|
# overwrite existing or add new
|
|
# @param name [String] gem name
|
|
# @param *requirements params following name use the same notation as the Gemfile gem DSL statement
|
|
def overwrite(name, *requirements)
|
|
@gemset.overwrite_gem(Gem.parse(name, *requirements))
|
|
end
|
|
|
|
# @return [Gem] removed gem or nil if not found
|
|
def remove(name)
|
|
@gemset.remove_gem(name)
|
|
end
|
|
|
|
def backup
|
|
@original_backup = @gemset.copy
|
|
end
|
|
|
|
def restore
|
|
@gemset = @original_backup
|
|
end
|
|
|
|
def defined_in_gemfile?(name)
|
|
@gemset.find_gem(name)
|
|
end
|
|
|
|
def restore!
|
|
restore
|
|
save
|
|
end
|
|
|
|
def locally_installed_gems
|
|
@gemset.gems.select { |gem| gem.options.include?(:path) }
|
|
end
|
|
end
|
|
|
|
class Gemset
|
|
attr_accessor :sources, :gems, :gemspec
|
|
|
|
def initialize
|
|
@sources = [] # list of urls
|
|
@gems = [] # list of Gem class
|
|
@gems_by_name = {} # hash of name => Gem
|
|
@gemspec = {} # gemspec is a options hash
|
|
end
|
|
|
|
def to_s
|
|
[sources_to_s, gemspec_to_s, gems_to_s].select {|s| !s.empty?}.join("\n") + "\n"
|
|
end
|
|
|
|
# @return [Gem] found gem or nil if not found
|
|
def find_gem(name)
|
|
@gems_by_name[name.downcase]
|
|
end
|
|
|
|
# @raise GemfileError if gem already exists
|
|
def add_gem(_gem)
|
|
raise(GemfileError, "duplicate gem #{_gem.name}") if find_gem(_gem.name)
|
|
@gems << _gem
|
|
@gems_by_name[_gem.name.downcase] = _gem
|
|
end
|
|
|
|
# update existing or add new
|
|
def update_gem(_gem)
|
|
if old = find_gem(_gem.name)
|
|
# always overwrite requirements if specified
|
|
old.requirements = _gem.requirements unless no_constrains?(_gem.requirements)
|
|
# but merge options
|
|
old.options = old.options.merge(_gem.options)
|
|
else
|
|
@gems << _gem
|
|
@gems_by_name[_gem.name.downcase] = _gem
|
|
end
|
|
end
|
|
|
|
# update existing or add new
|
|
def overwrite_gem(_gem)
|
|
if old = find_gem(_gem.name)
|
|
@gems[@gems.index(old)] = _gem
|
|
else
|
|
@gems << _gem
|
|
end
|
|
@gems_by_name[_gem.name.downcase] = _gem
|
|
end
|
|
|
|
# @return [Gem] removed gem or nil if not found
|
|
def remove_gem(name)
|
|
if _gem = @gems_by_name.delete(name.downcase)
|
|
@gems.delete_at(@gems.index(_gem))
|
|
end
|
|
_gem
|
|
end
|
|
|
|
# deep clone self
|
|
def copy
|
|
Marshal.load(Marshal.dump(self))
|
|
end
|
|
|
|
private
|
|
|
|
def no_constrains?(requirements)
|
|
return true if requirements.nil? || requirements.empty?
|
|
|
|
# check for the dummy ">= 0" version constrain or any variations thereof
|
|
# which is in fact a "no constrain" constrain which we should discard
|
|
return true if requirements.size == 1 && requirements.first.to_s.gsub(/\s+/, "") == ">=0"
|
|
|
|
false
|
|
end
|
|
|
|
def sources_to_s
|
|
return "" if @sources.empty?
|
|
@sources.map {|source| "source #{source.inspect}"}.join("\n")
|
|
end
|
|
|
|
def gems_to_s
|
|
return "" if @gems.empty?
|
|
@gems.map do |gem|
|
|
requirements = gem.requirements.empty? ? nil : gem.requirements.map {|r| r.inspect}.join(", ")
|
|
options = gem.options.empty? ? nil : gem.options.map {|k, v| "#{k.inspect} => #{v.inspect}"}.join(", ")
|
|
"gem " + [gem.name.inspect, requirements, options].compact.join(", ")
|
|
end.join("\n")
|
|
end
|
|
|
|
def gemspec_to_s
|
|
return "" if @gemspec.empty?
|
|
options = @gemspec.map {|k, v| "#{k.inspect} => #{v.inspect}"}.join(", ")
|
|
"gemspec #{options}"
|
|
end
|
|
end
|
|
|
|
# DSL is a minimal, incomplete Gemfile DSL subset parser, only what is currently required is implemented.
|
|
class DSL
|
|
attr_reader :gemset
|
|
|
|
def initialize
|
|
@gemset = Gemset.new
|
|
end
|
|
|
|
# @param gemfile_content [String] the Gemfile string content
|
|
# @return [Gemset] parsed Gemfile content as a Gemset
|
|
def self.parse(gemfile_content)
|
|
dsl = self.new
|
|
dsl.instance_eval(gemfile_content)
|
|
dsl.gemset
|
|
end
|
|
|
|
# DSL methods
|
|
|
|
def source(url)
|
|
@gemset.sources << url
|
|
end
|
|
|
|
def gem(name, *requirements)
|
|
parsed = Gem.parse(name, *requirements)
|
|
@gemset.add_gem(parsed)
|
|
end
|
|
|
|
def gemspec(options = {})
|
|
raise(GemfileError, "cannot declare multiple gemspec directives") unless @gemset.gemspec.empty?
|
|
@gemset.gemspec = options
|
|
end
|
|
end
|
|
|
|
class Gem
|
|
attr_accessor :name, :requirements, :options
|
|
|
|
def initialize(name, requirements = [], options = {})
|
|
@name = name
|
|
@requirements = requirements.map {|r| r.to_s.strip}.select {|r| !r.empty?}
|
|
@options = options
|
|
end
|
|
|
|
def self.parse(name, *requirements)
|
|
options = requirements.last.is_a?(Hash) ? requirements.pop : {}
|
|
self.new(name, requirements, options)
|
|
end
|
|
end
|
|
end
|