spandx 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -2
- data/README.md +59 -2
- data/exe/spandx +3 -4
- data/lib/spandx.rb +13 -32
- data/lib/spandx/cli.rb +1 -30
- data/lib/spandx/cli/commands/build.rb +41 -0
- data/lib/spandx/cli/commands/pull.rb +21 -0
- data/lib/spandx/cli/commands/scan.rb +17 -2
- data/lib/spandx/cli/main.rb +54 -0
- data/lib/spandx/core/cache.rb +3 -3
- data/lib/spandx/core/circuit.rb +34 -0
- data/lib/spandx/core/dependency.rb +32 -7
- data/lib/spandx/core/gateway.rb +19 -0
- data/lib/spandx/core/{database.rb → git.rb} +7 -2
- data/lib/spandx/core/guess.rb +42 -4
- data/lib/spandx/core/http.rb +30 -5
- data/lib/spandx/core/license_plugin.rb +54 -0
- data/lib/spandx/core/null_gateway.rb +11 -0
- data/lib/spandx/core/parser.rb +8 -25
- data/lib/spandx/core/plugin.rb +15 -0
- data/lib/spandx/core/registerable.rb +27 -0
- data/lib/spandx/core/report.rb +30 -6
- data/lib/spandx/core/table.rb +29 -0
- data/lib/spandx/dotnet/index.rb +10 -5
- data/lib/spandx/dotnet/nuget_gateway.rb +20 -31
- data/lib/spandx/dotnet/parsers/csproj.rb +3 -12
- data/lib/spandx/dotnet/parsers/packages_config.rb +2 -10
- data/lib/spandx/dotnet/parsers/sln.rb +2 -2
- data/lib/spandx/java/gateway.rb +37 -0
- data/lib/spandx/java/index.rb +84 -2
- data/lib/spandx/java/metadata.rb +6 -3
- data/lib/spandx/java/parsers/maven.rb +11 -21
- data/lib/spandx/js/parsers/npm.rb +39 -0
- data/lib/spandx/js/parsers/yarn.rb +30 -0
- data/lib/spandx/js/yarn_lock.rb +67 -0
- data/lib/spandx/js/yarn_pkg.rb +59 -0
- data/lib/spandx/php/packagist_gateway.rb +25 -0
- data/lib/spandx/php/parsers/composer.rb +33 -0
- data/lib/spandx/python/index.rb +78 -0
- data/lib/spandx/python/parsers/pipfile_lock.rb +12 -16
- data/lib/spandx/python/pypi.rb +91 -8
- data/lib/spandx/python/source.rb +5 -1
- data/lib/spandx/{rubygems → ruby}/gateway.rb +8 -9
- data/lib/spandx/{rubygems → ruby}/parsers/gemfile_lock.rb +14 -16
- data/lib/spandx/spdx/catalogue.rb +1 -1
- data/lib/spandx/spdx/license.rb +12 -2
- data/lib/spandx/version.rb +1 -1
- data/spandx.gemspec +4 -1
- metadata +66 -10
- data/lib/spandx/cli/command.rb +0 -65
- data/lib/spandx/cli/commands/index.rb +0 -36
- data/lib/spandx/cli/commands/index/build.rb +0 -32
- data/lib/spandx/cli/commands/index/update.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f54b3c9f0a58ce0038a5ad242c02d7aad3b11090bdecb9d84e67a9f74d5dfd6
|
4
|
+
data.tar.gz: b4ed659d450474bff291b4ee0f723f3342fe9369b690894c1731badb797a4b6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e94f49bff3619f876aa2157f15f8efde4b585720bd95417b1d4c6a48ce24208e18d836597604e4837ea37aee424124404825f8887311ab6697b2efee8474ea42
|
7
|
+
data.tar.gz: cc3553ebc60ff24667c0b182e9beb319bed075e837ef34b348b6b8c15ff16ebccfc56e4cb80c75743baa7862b07e7331e5c924ee2305e6008f5ff1f772e78a71
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Version 0.
|
1
|
+
Version 0.12.0
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
@@ -9,6 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
## [Unreleased]
|
11
11
|
|
12
|
+
## [0.12.0] - 2020-04-14
|
13
|
+
### Added
|
14
|
+
- Add `--format csv` option to scan command.
|
15
|
+
- Add `--format table` option to scan command.
|
16
|
+
- Add `--index` option to `build` command.
|
17
|
+
- Add pypi index.
|
18
|
+
- Add maven index.
|
19
|
+
- Add support for parsing `yarn.lock` files.
|
20
|
+
- Add support for parsing `package-lock.json` files.
|
21
|
+
- Add `--pull` option to fetch latest cache before scan.
|
22
|
+
- Add support for parsing `composer.lock` files.
|
23
|
+
- Add support for loading custom plugins via the `--require` option.
|
24
|
+
|
25
|
+
### Changed
|
26
|
+
- Change the default `--format` to `table` for the scan command.
|
27
|
+
|
12
28
|
## [0.11.0] - 2020-03-20
|
13
29
|
### Added
|
14
30
|
- Add `--format` option to scan command.
|
@@ -115,7 +131,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
115
131
|
### Added
|
116
132
|
- Provide ruby API to the latest SPDX catalogue.
|
117
133
|
|
118
|
-
[Unreleased]: https://github.com/mokhan/spandx/compare/v0.
|
134
|
+
[Unreleased]: https://github.com/mokhan/spandx/compare/v0.12.0...HEAD
|
135
|
+
[0.12.0]: https://github.com/mokhan/spandx/compare/v0.11.0...v0.12.0
|
136
|
+
[0.11.0]: https://github.com/mokhan/spandx/compare/v0.10.1...v0.11.0
|
119
137
|
[0.10.1]: https://github.com/mokhan/spandx/compare/v0.10.0...v0.10.1
|
120
138
|
[0.10.0]: https://github.com/mokhan/spandx/compare/v0.9.0...v0.10.0
|
121
139
|
[0.9.0]: https://github.com/mokhan/spandx/compare/v0.8.0...v0.9.0
|
data/README.md
CHANGED
@@ -1,8 +1,26 @@
|
|
1
|
-
# Spandx
|
1
|
+
# Spandx ![badge](https://github.com/mokhan/spandx/workflows/ci/badge.svg)
|
2
2
|
|
3
3
|
A ruby API for interacting with the https://spdx.org software license catalogue.
|
4
|
+
This gem includes a command line interface to scan a software project for the
|
5
|
+
software licenses that are associated with each dependency in the project.
|
6
|
+
`spandx` leverages an offline cache of software licenses for known dependencies.
|
7
|
+
The offline cache allows spandx to perform a truly airgap friendly scan of software
|
8
|
+
projects.
|
9
|
+
|
10
|
+
### Supported project types
|
11
|
+
|
12
|
+
Spandx can work with following language's package managers. It utilises lock files generated by package managers to find dependencies.
|
13
|
+
|
14
|
+
| Language | Package Manager | Tested in |
|
15
|
+
| ------------ | --------------- | -------: |
|
16
|
+
| Ruby | bundler | 1.17.3 |
|
17
|
+
| Js | Npm | 6.13.4 |
|
18
|
+
| Js | Yarn | 1.19.1 |
|
19
|
+
| Python | Pypi(pipenv) | v2018.11.26 |
|
20
|
+
| C# | nuget | <> |
|
21
|
+
| Java | Maven | 3.6.3 |
|
22
|
+
| Php | Composer | 1.10.5 |
|
4
23
|
|
5
|
-
![badge](https://github.com/mokhan/spandx/workflows/ci/badge.svg)
|
6
24
|
|
7
25
|
## Installation
|
8
26
|
|
@@ -22,6 +40,45 @@ Or install it yourself as:
|
|
22
40
|
|
23
41
|
## Usage
|
24
42
|
|
43
|
+
### Command line interface
|
44
|
+
|
45
|
+
The command line interface supports operations to build and fetch the latest offline index.
|
46
|
+
See the help for each subcommand for more information on how to use the command.
|
47
|
+
|
48
|
+
```bash
|
49
|
+
モ spandx
|
50
|
+
Commands:
|
51
|
+
spandx help [COMMAND] # Describe available commands or one specific command
|
52
|
+
spandx scan LOCKFILE # Scan a lockfile and list dependencies/licenses
|
53
|
+
spandx version # spandx version
|
54
|
+
```
|
55
|
+
|
56
|
+
To scan a specific project file use the `scan` command:
|
57
|
+
|
58
|
+
```bash
|
59
|
+
モ spandx scan dotnet/application.sln
|
60
|
+
モ spandx scan java/pom.xml
|
61
|
+
モ spandx scan python/Pipfile.lock
|
62
|
+
モ spandx scan ruby/Gemfile.lock
|
63
|
+
```
|
64
|
+
|
65
|
+
To activate airgap mode use the `--airgap` option:
|
66
|
+
|
67
|
+
```bash
|
68
|
+
モ spandx scan dotnet/application.sln --airgap
|
69
|
+
モ spandx scan ruby/Gemfile.lock --airgap
|
70
|
+
```
|
71
|
+
|
72
|
+
Airgap mode assumes that an offline cache has been placed in `$HOME/.local/share/`.
|
73
|
+
|
74
|
+
To fetch the latest offline cache:
|
75
|
+
|
76
|
+
```bash
|
77
|
+
モ spandx index update
|
78
|
+
```
|
79
|
+
|
80
|
+
### Ruby API
|
81
|
+
|
25
82
|
To fetch the latest version of the catalogue data from [SPDX](https://spdx.org/licenses/licenses.json).
|
26
83
|
|
27
84
|
```ruby
|
data/exe/spandx
CHANGED
@@ -2,8 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
lib_path = File.expand_path('../lib', __dir__)
|
5
|
-
|
6
|
-
require 'spandx/cli'
|
5
|
+
require "#{lib_path}/spandx"
|
7
6
|
|
8
7
|
Signal.trap('INT') do
|
9
8
|
warn("\n#{caller.join("\n")}: interrupted")
|
@@ -11,8 +10,8 @@ Signal.trap('INT') do
|
|
11
10
|
end
|
12
11
|
|
13
12
|
begin
|
14
|
-
Spandx::
|
15
|
-
rescue Spandx::
|
13
|
+
Spandx::Cli::Main.start
|
14
|
+
rescue Spandx::Cli::Error => error
|
16
15
|
puts "ERROR: #{error.message}"
|
17
16
|
exit 1
|
18
17
|
end
|
data/lib/spandx.rb
CHANGED
@@ -9,38 +9,15 @@ require 'logger'
|
|
9
9
|
require 'net/hippie'
|
10
10
|
require 'nokogiri'
|
11
11
|
require 'pathname'
|
12
|
+
require 'yaml'
|
13
|
+
require 'zeitwerk'
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
require 'spandx/core/database'
|
16
|
-
require 'spandx/core/dependency'
|
17
|
-
require 'spandx/core/guess'
|
18
|
-
require 'spandx/core/http'
|
19
|
-
require 'spandx/core/parser'
|
20
|
-
require 'spandx/core/report'
|
21
|
-
require 'spandx/core/score'
|
22
|
-
require 'spandx/dotnet/index'
|
23
|
-
require 'spandx/dotnet/nuget_gateway'
|
24
|
-
require 'spandx/dotnet/package_reference'
|
25
|
-
require 'spandx/dotnet/parsers/csproj'
|
26
|
-
require 'spandx/dotnet/parsers/packages_config'
|
27
|
-
require 'spandx/dotnet/parsers/sln'
|
28
|
-
require 'spandx/dotnet/project_file'
|
29
|
-
require 'spandx/java/index'
|
30
|
-
require 'spandx/java/metadata'
|
31
|
-
require 'spandx/java/parsers/maven'
|
32
|
-
require 'spandx/python/parsers/pipfile_lock'
|
33
|
-
require 'spandx/python/pypi'
|
34
|
-
require 'spandx/python/source'
|
35
|
-
require 'spandx/rubygems/gateway'
|
36
|
-
require 'spandx/rubygems/parsers/gemfile_lock'
|
37
|
-
require 'spandx/spdx/catalogue'
|
38
|
-
require 'spandx/spdx/gateway'
|
39
|
-
require 'spandx/spdx/license'
|
40
|
-
require 'spandx/version'
|
15
|
+
loader = Zeitwerk::Loader.for_gem
|
16
|
+
loader.setup # ready!
|
41
17
|
|
42
18
|
module Spandx
|
43
19
|
class Error < StandardError; end
|
20
|
+
Rubygems = Ruby
|
44
21
|
|
45
22
|
class << self
|
46
23
|
attr_writer :airgap, :logger
|
@@ -61,10 +38,14 @@ module Spandx
|
|
61
38
|
@logger ||= Logger.new('/dev/null')
|
62
39
|
end
|
63
40
|
|
64
|
-
def
|
65
|
-
@
|
66
|
-
.new(url: 'https://github.com/
|
67
|
-
.
|
41
|
+
def git
|
42
|
+
@git ||= {
|
43
|
+
cache: ::Spandx::Core::Git.new(url: 'https://github.com/mokhan/spandx-index.git'),
|
44
|
+
rubygems: ::Spandx::Core::Git.new(url: 'https://github.com/mokhan/spandx-rubygems.git'),
|
45
|
+
spdx: ::Spandx::Core::Git.new(url: 'https://github.com/spdx/license-list-data.git'),
|
46
|
+
}
|
68
47
|
end
|
69
48
|
end
|
70
49
|
end
|
50
|
+
|
51
|
+
loader.eager_load
|
data/lib/spandx/cli.rb
CHANGED
@@ -1,38 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
-
require 'spandx'
|
5
|
-
require 'spandx/cli/command'
|
6
|
-
require 'spandx/cli/commands/index'
|
7
|
-
require 'spandx/cli/commands/scan'
|
8
4
|
|
9
5
|
module Spandx
|
10
|
-
|
6
|
+
module Cli
|
11
7
|
Error = Class.new(StandardError)
|
12
|
-
|
13
|
-
desc 'version', 'spandx version'
|
14
|
-
def version
|
15
|
-
puts "v#{Spandx::VERSION}"
|
16
|
-
end
|
17
|
-
map %w[--version -v] => :version
|
18
|
-
|
19
|
-
register Spandx::Cli::Commands::Index, 'index', 'index [SUBCOMMAND]', 'Command description...'
|
20
|
-
|
21
|
-
desc 'scan LOCKFILE', 'Scan a lockfile and list dependencies/licenses'
|
22
|
-
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
23
|
-
method_option :recursive, aliases: '-r', type: :boolean, desc: 'Perform recursive scan', default: false
|
24
|
-
method_option :airgap, aliases: '-a', type: :boolean, desc: 'Disable network connections', default: false
|
25
|
-
method_option :logfile, aliases: '-l', type: :string, desc: 'Path to a logfile', default: '/dev/null'
|
26
|
-
method_option :format, aliases: '-f', type: :string, desc: 'Format of report', default: 'json'
|
27
|
-
def scan(lockfile)
|
28
|
-
Spandx.airgap = options[:airgap]
|
29
|
-
Spandx.logger = Logger.new(options[:logfile])
|
30
|
-
|
31
|
-
if options[:help]
|
32
|
-
invoke :help, ['scan']
|
33
|
-
else
|
34
|
-
Spandx::Cli::Commands::Scan.new(lockfile, options).execute
|
35
|
-
end
|
36
|
-
end
|
37
8
|
end
|
38
9
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
module Commands
|
6
|
+
class Build
|
7
|
+
INDEXES = {
|
8
|
+
maven: Spandx::Java::Index,
|
9
|
+
nuget: Spandx::Dotnet::Index,
|
10
|
+
dotnet: Spandx::Dotnet::Index,
|
11
|
+
pypi: Spandx::Python::Index,
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
def initialize(options)
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(output: $stdout)
|
19
|
+
catalogue = Spandx::Spdx::Catalogue.from_git
|
20
|
+
indexes.each do |index|
|
21
|
+
output.puts index.name
|
22
|
+
index.update!(catalogue: catalogue, output: output)
|
23
|
+
end
|
24
|
+
output.puts 'OK'
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def indexes
|
30
|
+
index = INDEXES[@options[:index]&.to_sym]
|
31
|
+
|
32
|
+
if index.nil?
|
33
|
+
INDEXES.values.uniq.map { |x| x.new(directory: @options[:directory]) }
|
34
|
+
else
|
35
|
+
[index.new(directory: @options[:directory])]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
module Commands
|
6
|
+
class Pull
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(output: $stdout)
|
12
|
+
Spandx.git.each_value do |db|
|
13
|
+
output.puts "Updating #{db.url}..."
|
14
|
+
db.update!
|
15
|
+
end
|
16
|
+
output.puts 'OK'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -3,12 +3,13 @@
|
|
3
3
|
module Spandx
|
4
4
|
module Cli
|
5
5
|
module Commands
|
6
|
-
class Scan
|
6
|
+
class Scan
|
7
7
|
attr_reader :scan_path
|
8
8
|
|
9
9
|
def initialize(scan_path, options)
|
10
10
|
@scan_path = ::Pathname.new(scan_path)
|
11
11
|
@options = options
|
12
|
+
require(options[:require]) if options[:require]
|
12
13
|
end
|
13
14
|
|
14
15
|
def execute(output: $stdout)
|
@@ -18,7 +19,7 @@ module Spandx
|
|
18
19
|
report.add(dependency)
|
19
20
|
end
|
20
21
|
end
|
21
|
-
output.puts
|
22
|
+
output.puts(format(report.to(@options[:format])))
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
@@ -33,6 +34,7 @@ module Spandx
|
|
33
34
|
if File.directory?(file)
|
34
35
|
each_file_in(file, &block) if recursive?
|
35
36
|
else
|
37
|
+
Spandx.logger.debug(file)
|
36
38
|
block.call(file)
|
37
39
|
end
|
38
40
|
end
|
@@ -42,7 +44,20 @@ module Spandx
|
|
42
44
|
::Spandx::Core::Parser
|
43
45
|
.for(file)
|
44
46
|
.parse(file)
|
47
|
+
.map { |dependency| enhance(dependency) }
|
45
48
|
.each { |dependency| yield dependency }
|
49
|
+
rescue StandardError => error
|
50
|
+
Spandx.logger.error(error)
|
51
|
+
end
|
52
|
+
|
53
|
+
def format(output)
|
54
|
+
Array(output).map(&:to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def enhance(dependency)
|
58
|
+
::Spandx::Core::Plugin
|
59
|
+
.all
|
60
|
+
.inject(dependency) { |memo, plugin| plugin.enhance(memo) }
|
46
61
|
end
|
47
62
|
end
|
48
63
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Cli
|
5
|
+
class Main < Thor
|
6
|
+
desc 'scan LOCKFILE', 'Scan a lockfile and list dependencies/licenses'
|
7
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
8
|
+
method_option :recursive, aliases: '-R', type: :boolean, desc: 'Perform recursive scan', default: false
|
9
|
+
method_option :airgap, aliases: '-a', type: :boolean, desc: 'Disable network connections', default: false
|
10
|
+
method_option :logfile, aliases: '-l', type: :string, desc: 'Path to a logfile', default: '/dev/null'
|
11
|
+
method_option :format, aliases: '-f', type: :string, desc: 'Format of report', default: 'table'
|
12
|
+
method_option :pull, aliases: '-p', type: :boolean, desc: 'Pull the latest cache before the scan', default: false
|
13
|
+
method_option :require, aliases: '-r', type: :string, desc: 'Causes spandx to load the library using require.', default: nil
|
14
|
+
def scan(lockfile)
|
15
|
+
if options[:help]
|
16
|
+
invoke :help, ['scan']
|
17
|
+
else
|
18
|
+
Spandx.airgap = options[:airgap]
|
19
|
+
Spandx.logger = Logger.new(options[:logfile])
|
20
|
+
pull if options[:pull]
|
21
|
+
Spandx::Cli::Commands::Scan.new(lockfile, options).execute
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'pull', 'Pull the latest offline cache'
|
26
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
27
|
+
def pull(*)
|
28
|
+
if options[:help]
|
29
|
+
invoke :help, ['pull']
|
30
|
+
else
|
31
|
+
Commands::Pull.new(options).execute
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'build', 'Build a package index'
|
36
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
37
|
+
method_option :directory, aliases: '-d', type: :string, desc: 'Directory to build index in', default: '.index'
|
38
|
+
method_option :index, aliases: '-i', type: :string, desc: 'The specific index to build', default: :all
|
39
|
+
def build(*)
|
40
|
+
if options[:help]
|
41
|
+
invoke :help, ['build']
|
42
|
+
else
|
43
|
+
Commands::Build.new(options).execute
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'version', 'spandx version'
|
48
|
+
def version
|
49
|
+
puts "v#{Spandx::VERSION}"
|
50
|
+
end
|
51
|
+
map %w[--version -v] => :version
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/spandx/core/cache.rb
CHANGED
@@ -5,14 +5,14 @@ module Spandx
|
|
5
5
|
class Cache
|
6
6
|
attr_reader :db, :package_manager
|
7
7
|
|
8
|
-
def initialize(package_manager,
|
8
|
+
def initialize(package_manager, db: Spandx.git[:cache])
|
9
9
|
@package_manager = package_manager
|
10
|
-
@db =
|
10
|
+
@db = db
|
11
11
|
@cache = {}
|
12
12
|
@lines = {}
|
13
13
|
end
|
14
14
|
|
15
|
-
def licenses_for(name
|
15
|
+
def licenses_for(name, version)
|
16
16
|
found = search(name: name, version: version)
|
17
17
|
Spandx.logger.debug("Cache miss: #{name}-#{version}") if found.nil?
|
18
18
|
found ? found[2].split('-|-') : []
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spandx
|
4
|
+
module Core
|
5
|
+
class Circuit
|
6
|
+
attr_reader :state
|
7
|
+
|
8
|
+
def initialize(state: :closed)
|
9
|
+
@state = state
|
10
|
+
end
|
11
|
+
|
12
|
+
def attempt
|
13
|
+
return if open?
|
14
|
+
|
15
|
+
open!
|
16
|
+
result = yield
|
17
|
+
close!
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def open!
|
22
|
+
@state = :open
|
23
|
+
end
|
24
|
+
|
25
|
+
def close!
|
26
|
+
@state = :closed
|
27
|
+
end
|
28
|
+
|
29
|
+
def open?
|
30
|
+
state == :open
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|