-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathartifact_plugin.rb
More file actions
179 lines (147 loc) · 5.06 KB
/
artifact_plugin.rb
File metadata and controls
179 lines (147 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# encoding: utf-8
require_relative 'embedded_plugin'
require_relative 'aliased_plugin'
require_relative 'plugin'
require_relative 'repository'
require 'set'
module LogstashDocket
##
# An {@link ArtifactPlugin} is an implementation of {@link Plugin} that
# is used to represent plugins that are directly available by name on
# rubygems.org.
#
# It can be used to represent self-contained plugins:
# - filter,
# - input,
# - output, OR
# - codec.
#
# It can also be used to represent top-level "integration" plugins that
# themselves contain multiple "embedded" plugins (e.g., {@link EmbeddedPlugin}).
#
# @api public
class ArtifactPlugin
include Plugin
##
# Attempts to instantiate an {@link ArtifactPlugin} from the named gem, using
# the optionally-provided version as a hint.
#
# @param gem_name [String]
# @param version [String, nil]: (optional: when omitted, source's main will
# be used with the latest-available published gem metadata)
#
# @yieldparam [Hash{String=>Object}]: gem metadata
# @yieldreturn [Source]
#
# @return [ArtifactPlugin,nil]
def self.from_rubygems(gem_name, version=nil, &source_generator)
repository = Repository.from_rubygems(gem_name, version, &source_generator)
repository && repository.released_plugin(version)
end
SUPPORTED_TYPES = Set.new(%w(input output filter codec integration).map(&:freeze)).freeze
EMPTY = Array.new.freeze
VALID_PLUGIN_CAPTURING_TYPE_AND_NAME = %r{\Alogstash-(?<type>[a-z]+)-(?<name>.\w+)}
##
# @see Plugin#repository
attr_reader :repository
##
# @see Plugin#version
attr_reader :version
##
# @see Plugin#initialize
#
# @param repository [Repository]
# @param version [String]
def initialize(repository:,version:)
if repository.name !~ VALID_PLUGIN_CAPTURING_TYPE_AND_NAME
fail(ArgumentError, "invalid plugin name `#{repository.name}`")
end
super(type: Regexp.last_match(:type), name: Regexp.last_match(:name))
fail("#{desc} plugin type #{type} not supported as a top-level plugin") unless SUPPORTED_TYPES.include?(type)
@repository = repository
@version = version && Gem::Version.new(version)
@embedded_plugins = Util::ThreadsafeDeferral.for(&method(:generate_embedded_plugins))
end
##
# @see Plugin#release_date
def release_date
version && repository.release_date(version)
end
##
# @see Plugin#documentation
def documentation
repository.read_file("docs/index.asciidoc", version)
end
##
# @see Plugin#changelog_url
def changelog_url
repository.web_url("CHANGELOG.md", version)
end
##
# @see Plugin#tag
def tag
version ? "v#{version}" : "main"
end
##
# @see Plugin#desc
def desc
@desc ||= "[plugin:#{canonical_name}@#{tag}]"
end
##
# Returns an {@link Enumerable[Plugin]} containing itself and any integrated plugins
#
# @return [Enumerable[Plugin]]
def with_embedded_plugins
return enum_for(:with_embedded_plugins) unless block_given?
yield self
embedded_plugins.each do |embedded_plugin|
yield embedded_plugin
end
end
##
# Returns an {@link Enumerable[Plugin]} containing itself and any wrapped plugins,
# including integration-wrapped plugins and aliases from the provided mappings
#
def with_wrapped_plugins(alias_definitions)
return enum_for(:with_wrapped_plugins, alias_definitions) unless block_given?
with_embedded_plugins do |plugin|
plugin.with_alias(alias_definitions) do |plugin_or_alias|
yield plugin_or_alias
end
end
end
##
# Returns zero or more {@link Plugin::Wrapped} provided by
# an "integration" plugin.
#
def embedded_plugins
@embedded_plugins.value
end
##
# @see Plugin#==
def ==(other)
return false unless super
return false unless other.kind_of?(ArtifactPlugin)
return false unless self.repository == other.repository
return true
end
private
##
# @api private
#
# @return [Array[EmbeddedPlugin]]: a frozen array of {@link EmbeddedPlugin}
def generate_embedded_plugins
gem_data_version = version || repository.rubygem_info.latest
gem_data_version || fail("No releases on rubygems")
rubygem_info = repository.rubygem_info.for_version(gem_data_version) || fail("[#{desc}]: no gem data available")
embedded_plugin_canonical_names_csv = rubygem_info.dig('metadata','integration_plugins')
return EMPTY if embedded_plugin_canonical_names_csv.nil?
embedded_plugin_canonical_names_csv.split(',').map(&:strip).map do |wrapped_canonical_name|
if wrapped_canonical_name !~ %r{\Alogstash-(?<type>[a-z]+)-(?<name>.*)}
fail(ArgumentError "unsupported plugin name `#{canonical_name}`")
end
EmbeddedPlugin.new(artifact_plugin: self, type: Regexp.last_match(:type), name: Regexp.last_match(:name))
end.freeze
end
end
end