diffend 0.2.29 → 0.2.34

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building packages information from local context
7
+ class Packages
8
+ # Definition of a local path, if it matches it means that we are the source
9
+ ME_PATH = '.'
10
+ # Sources that we expect to match ourselves too
11
+ ME_SOURCES = [
12
+ Bundler::Source::Gemspec,
13
+ Bundler::Source::Path
14
+ ].freeze
15
+ # List of dependency types
16
+ DEPENDENCIES_TYPES = {
17
+ direct: 0,
18
+ dependency: 1
19
+ }.freeze
20
+ # List of sources types
21
+ SOURCES_TYPES = {
22
+ valid: 0,
23
+ multiple_primary: 1
24
+ }.freeze
25
+ # List of gem sources types
26
+ GEM_SOURCES_TYPES = {
27
+ local: 0,
28
+ gemfile_source: 1,
29
+ gemfile_git: 2,
30
+ gemfile_path: 3
31
+ }.freeze
32
+
33
+ class << self
34
+ # @param command [String] command executed via bundler
35
+ # @param definition [Bundler::Definition] definition for your source
36
+ def call(command, definition)
37
+ Bundler.ui.silence { definition.resolve_remotely! }
38
+
39
+ instance = new(definition)
40
+
41
+ case command
42
+ when Commands::INSTALL, Commands::EXEC then instance.build_install
43
+ when Commands::UPDATE then instance.build_update
44
+ else
45
+ raise ArgumentError, "invalid command: #{command}"
46
+ end
47
+ end
48
+ end
49
+
50
+ # @param definition [Bundler::Definition] definition for your source
51
+ #
52
+ # @return [Hash] local dependencies
53
+ def initialize(definition)
54
+ @definition = definition
55
+ @direct_dependencies = Hash[definition.dependencies.map { |val| [val.name, val] }]
56
+ # Support case without Gemfile.lock
57
+ @locked_specs = @definition.locked_gems ? @definition.locked_gems.specs : []
58
+ end
59
+
60
+ # Build install specification
61
+ #
62
+ # @return [Hash]
63
+ def build_install
64
+ hash = build_main
65
+
66
+ @definition.specs.each do |spec|
67
+ next if skip?(spec.source)
68
+
69
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
70
+
71
+ hash['dependencies'][spec.name] = {
72
+ 'platform' => build_spec_platform(spec, locked_spec),
73
+ 'source' => build_spec_source(spec),
74
+ 'type' => build_dependency_type(spec.name),
75
+ 'versions' => build_versions(spec, locked_spec)
76
+ }
77
+ end
78
+
79
+ hash
80
+ end
81
+
82
+ # Build update specification
83
+ #
84
+ # @return [Hash]
85
+ def build_update
86
+ hash = build_main
87
+
88
+ @definition.specs.each do |spec|
89
+ next if skip?(spec.source)
90
+
91
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
92
+
93
+ hash['dependencies'][spec.name] = {
94
+ 'platform' => build_spec_platform(spec, locked_spec),
95
+ 'source' => build_spec_source(spec),
96
+ 'type' => build_dependency_type(spec.name),
97
+ 'versions' => build_versions(spec, locked_spec)
98
+ }
99
+ end
100
+
101
+ hash
102
+ end
103
+
104
+ private
105
+
106
+ # Build default specification
107
+ #
108
+ # @return [Hash]
109
+ def build_main
110
+ {
111
+ 'dependencies' => {},
112
+ 'sources' => build_sources,
113
+ 'plugins' => {},
114
+ 'platforms' => @definition.platforms.map(&:to_s)
115
+ }
116
+ end
117
+
118
+ # Build gem versions
119
+ #
120
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
121
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
122
+ #
123
+ # @return [Array<String>]
124
+ def build_versions(spec, locked_spec = nil)
125
+ if locked_spec && locked_spec.version.to_s != spec.version.to_s
126
+ [locked_spec.version.to_s, spec.version.to_s]
127
+ else
128
+ [spec.version.to_s]
129
+ end
130
+ end
131
+
132
+ # @param specs [Array] specs that are direct dependencies
133
+ # @param name [String] spec name
134
+ #
135
+ # @return [Boolean] dependency type
136
+ def build_dependency_type(name)
137
+ if @direct_dependencies.key?(name)
138
+ DEPENDENCIES_TYPES[:direct]
139
+ else
140
+ DEPENDENCIES_TYPES[:dependency]
141
+ end
142
+ end
143
+
144
+ # Build gem platform
145
+ #
146
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
147
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
148
+ #
149
+ # @return [String]
150
+ def build_spec_platform(spec, locked_spec)
151
+ parse_platform(
152
+ spec.platform || locked_spec&.platform || spec.send(:generic_local_platform)
153
+ )
154
+ end
155
+
156
+ # Parse gem platform
157
+ #
158
+ # @param platform [String, Gem::Platform]
159
+ #
160
+ # @return [String]
161
+ def parse_platform(platform)
162
+ case platform
163
+ when String then platform
164
+ when Gem::Platform then platform.to_s
165
+ end
166
+ end
167
+
168
+ # Build gem source type
169
+ #
170
+ # @param source [Bundler::Source] gem source type
171
+ #
172
+ # @return [Integer] internal gem source type
173
+ def build_spec_gem_source_type(source)
174
+ case source
175
+ when Bundler::Source::Metadata
176
+ GEM_SOURCES_TYPES[:local]
177
+ when Bundler::Source::Rubygems, Bundler::Source::Rubygems::Remote
178
+ GEM_SOURCES_TYPES[:gemfile_source]
179
+ when Bundler::Source::Git
180
+ GEM_SOURCES_TYPES[:gemfile_git]
181
+ when Bundler::Source::Path
182
+ GEM_SOURCES_TYPES[:gemfile_path]
183
+ else
184
+ raise ArgumentError, "unknown source #{source.class}"
185
+ end
186
+ end
187
+
188
+ # Build gem source
189
+ #
190
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
191
+ #
192
+ # @return [Hash]
193
+ def build_spec_source(spec)
194
+ source = source_for_spec(spec)
195
+
196
+ {
197
+ 'type' => build_spec_gem_source_type(source),
198
+ 'value' => source_name_from_source(source)
199
+ }
200
+ end
201
+
202
+ # Figure out source for gem
203
+ #
204
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
205
+ #
206
+ # @return [Bundler::Source] gem source type
207
+ def source_for_spec(spec)
208
+ return spec.remote if spec.remote
209
+
210
+ case spec.source
211
+ when Bundler::Source::Rubygems
212
+ spec
213
+ .source
214
+ .send(:remote_specs)
215
+ .search(Bundler::Dependency.new(spec.name, spec.version))
216
+ .last
217
+ .remote
218
+ when Bundler::Source::Metadata, Bundler::Source::Git, Bundler::Source::Path
219
+ spec.source
220
+ else
221
+ raise ArgumentError, "unknown source #{spec.source.class}"
222
+ end
223
+ end
224
+
225
+ # Build gem source name
226
+ #
227
+ # @param source [Bundler::Source] gem source type
228
+ #
229
+ # @return [String]
230
+ def source_name_from_source(source)
231
+ case source
232
+ when Bundler::Source::Metadata
233
+ ''
234
+ when Bundler::Source::Rubygems::Remote
235
+ source_name(source.anonymized_uri)
236
+ when Bundler::Source::Git
237
+ source.instance_variable_get(:@safe_uri)
238
+ when Bundler::Source::Path
239
+ source.path
240
+ else
241
+ raise ArgumentError, "unknown source #{source.class}"
242
+ end
243
+ end
244
+
245
+ # @param uri [Bundler::URI]
246
+ #
247
+ # @return [String]
248
+ def source_name(uri)
249
+ uri.to_s[0...-1]
250
+ end
251
+
252
+ # Build sources used in the Gemfile
253
+ #
254
+ # @return [Array<Hash>]
255
+ def build_sources
256
+ sources = @definition.send(:sources).rubygems_sources
257
+ hash = {}
258
+
259
+ sources.each do |source|
260
+ type = build_source_type(source.remotes)
261
+
262
+ source.remotes.each do |src|
263
+ hash[source_name(src)] = type
264
+ end
265
+ end
266
+
267
+ hash.map { |name, type| { 'name' => name, 'type' => type } }
268
+ end
269
+
270
+ # Build gem source type
271
+ #
272
+ # @param remotes [Array<Bundler::URI>]
273
+ #
274
+ # @return [Integer] internal source type
275
+ def build_source_type(remotes)
276
+ remotes.count > 1 ? SOURCES_TYPES[:multiple_primary] : SOURCES_TYPES[:valid]
277
+ end
278
+
279
+ # Checks if we should skip a source
280
+ #
281
+ # @param source [Bundler::Source] gem source type
282
+ #
283
+ # @return [Boolean] true if we should skip this source, false otherwise
284
+ def skip?(source)
285
+ return true if me?(source)
286
+
287
+ false
288
+ end
289
+
290
+ # Checks if it's a self source, this happens for repositories that are a gem
291
+ #
292
+ # @param source [Bundler::Source] gem source type
293
+ #
294
+ # @return [Boolean] true if it's a self source, false otherwise
295
+ def me?(source)
296
+ return false unless ME_SOURCES.include?(source.class)
297
+
298
+ source.path.to_s == ME_PATH
299
+ end
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building platform information from local context
7
+ module Platform
8
+ class << self
9
+ # Build platform information
10
+ #
11
+ # @return [Hash]
12
+ def call
13
+ {
14
+ 'bundler' => {
15
+ 'version' => Bundler::VERSION
16
+ },
17
+ 'environment' => environment,
18
+ 'ruby' => ruby_information,
19
+ 'rubygems' => {
20
+ 'specification_version' => Gem::Specification::CURRENT_SPECIFICATION_VERSION,
21
+ 'version' => Gem::VERSION
22
+ }
23
+ }.freeze
24
+ end
25
+
26
+ private
27
+
28
+ # Build platform ruby information
29
+ #
30
+ # @return [Hash]
31
+ def ruby_information
32
+ if defined?(JRUBY_VERSION)
33
+ revision = JRUBY_REVISION.to_s
34
+ version = JRUBY_VERSION
35
+ else
36
+ revision = RUBY_REVISION.to_s
37
+ version = RUBY_ENGINE_VERSION
38
+ end
39
+
40
+ {
41
+ 'engine' => RUBY_ENGINE,
42
+ 'patchlevel' => RUBY_PATCHLEVEL,
43
+ 'release_date' => RUBY_RELEASE_DATE,
44
+ 'revision' => revision,
45
+ 'version' => version
46
+ }
47
+ end
48
+
49
+ # Build platform environment information
50
+ #
51
+ # @return [String]
52
+ def environment
53
+ ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Diffend logging
5
+ class Logger
6
+ # Low-level information, mostly for developers.
7
+ DEBUG = 0
8
+ # Generic (useful) information about system operation.
9
+ INFO = 1
10
+ # A warning.
11
+ WARN = 2
12
+ # A handleable error condition.
13
+ ERROR = 3
14
+ # An unhandleable error that results in a program crash.
15
+ FATAL = 4
16
+ # An unknown message that should always be logged.
17
+ UNKNOWN = 5
18
+
19
+ # @param level [Integer] logging severity threshold
20
+ def initialize(level = INFO)
21
+ @level = level
22
+ end
23
+
24
+ # @param message [String]
25
+ def debug(message)
26
+ log(DEBUG, message)
27
+ end
28
+
29
+ # @param message [String]
30
+ def info(message)
31
+ log(INFO, message)
32
+ end
33
+
34
+ # @param message [String]
35
+ def warn(message)
36
+ log(WARN, message)
37
+ end
38
+
39
+ # @param message [String]
40
+ def error(message)
41
+ log(ERROR, message)
42
+ end
43
+
44
+ # @param message [String]
45
+ def fatal(message)
46
+ log(FATAL, message)
47
+ end
48
+
49
+ private
50
+
51
+ # @param severity [Integer]
52
+ # @param message [String]
53
+ def log(severity, message)
54
+ return if severity < @level
55
+
56
+ case severity
57
+ when INFO
58
+ Bundler.ui.confirm(message)
59
+ when WARN
60
+ Bundler.ui.warn(message)
61
+ when ERROR, FATAL
62
+ Bundler.ui.error(message)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,30 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  %w[
4
- build_bundler_definition
4
+ version
5
+ logger
5
6
  errors
6
- config/fetcher
7
- config/file_finder
8
- config/validator
7
+ build_bundler_definition
9
8
  commands
9
+ config
10
+ configs/fetcher
11
+ configs/validator
10
12
  handle_errors/messages
11
13
  handle_errors/build_exception_payload
12
14
  handle_errors/display_to_stdout
13
15
  handle_errors/report
14
16
  request_object
15
17
  request
16
- voting
18
+ local_context/diffend
19
+ local_context/host
20
+ local_context/packages
21
+ local_context/platform
22
+ local_context
23
+ request_verdict
24
+ execute
17
25
  track
18
26
  ].each { |file| require "diffend/#{file}" }
19
27
 
20
- %w[
21
- versions/local
22
- versions/remote
23
- ].each { |file| require "diffend/voting/#{file}" }
28
+ begin
29
+ config = Diffend::Config.new(
30
+ command: Diffend::Commands::EXEC,
31
+ severity: Diffend::Logger::FATAL
32
+ )
33
+ rescue Diffend::Errors::HandledException
34
+ # we silent exit here because we don't want to break client boot
35
+ return
36
+ end
37
+
38
+ return if %w[development test].include?(config.env)
24
39
 
25
- unless %w[development test].include?(ENV['DIFFEND_ENV'])
26
- Thread.new do
27
- track = Diffend::Track.new
28
- track.start
29
- end
40
+ Thread.new do
41
+ track = Diffend::Track.new(config)
42
+ track.start
30
43
  end