spandx 0.13.4 → 0.13.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef9e117562bb153d2bf7a7aa8561244f50f7dcbca8a81300e10279efec45c674
4
- data.tar.gz: '069f96ae764417f3b005ebd8e7fee919c66eee38a63649918f7dea3209a9bc34'
3
+ metadata.gz: 01abc42f6e315aee9f35bf60cdad7a4801ee95ae4a186ef3ee001f2617c9891e
4
+ data.tar.gz: 78248675cdddbcb197f347239c85016862254a113b17894e4d6ffe7ecd33cddd
5
5
  SHA512:
6
- metadata.gz: 67ec66d00236b0c4a98bc770e0b33698ecabb6e868b4e1b309c735a0d3cf5288a49393280f0cff2829d8ab5d1005920b16a877bdabdb2a0b63c88ac9f7af7df9
7
- data.tar.gz: 9260aeb08a495fb4f8bd1ba4c2b17fed8e34c2e60e96d5c826c79f7c51d83a8686b4194e060fa77e3b898f1beb17404006dd5370b727d2a7ce98d87ddce41507
6
+ metadata.gz: d6d4462c74dc412f9016ff576f55e67bdc9a6b341059d3b372b505f6e7ee730a92da53a4b5d0ab836df298b2cb527d0890c599fdc48f92a848b3d93c6c7d67ab
7
+ data.tar.gz: fdc618b97c619aa7d8a99b799dc5b1569d8396e9cfbbee5ee91cf7b994335e7fcbd9a5abac03b87a21615b23eef7913d5b59aabf277cacaa3eeac8497d795f38
@@ -1,4 +1,4 @@
1
- Version 0.13.4
1
+ Version 0.13.5
2
2
 
3
3
  # Changelog
4
4
 
@@ -8,6 +8,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
10
  ## [Unreleased]
11
+ ## [0.13.5] - 2020-05-26
12
+ ### Fixed
13
+ - Process PyPI package urls with single digit versions.
14
+ - Remove unsupported `hash` report from help text.
15
+
16
+ ### Changed
17
+ - Stream output to output stream as soon as results are available.
18
+ - Switch to `Oj` for JSON parsing.
19
+ - Run spinner on background thread.
11
20
 
12
21
  ## [0.13.4] - 2020-05-26
13
22
  ### Added
@@ -189,7 +198,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
189
198
  ### Added
190
199
  - Provide ruby API to the latest SPDX catalogue.
191
200
 
192
- [Unreleased]: https://github.com/spandx/spandx/compare/v0.13.3...HEAD
201
+ [Unreleased]: https://github.com/spandx/spandx/compare/v0.13.5...HEAD
202
+ [0.13.5]: https://github.com/spandx/spandx/compare/v0.13.4...v0.13.5
203
+ [0.13.4]: https://github.com/spandx/spandx/compare/v0.13.3...v0.13.4
193
204
  [0.13.3]: https://github.com/spandx/spandx/compare/v0.13.2...v0.13.3
194
205
  [0.13.2]: https://github.com/spandx/spandx/compare/v0.13.1...v0.13.2
195
206
  [0.13.1]: https://github.com/spandx/spandx/compare/v0.13.0...v0.13.1
data/exe/spandx CHANGED
@@ -4,7 +4,6 @@
4
4
  require 'spandx'
5
5
 
6
6
  Signal.trap('INT') do
7
- warn("\n#{caller.join("\n")}: interrupted")
8
7
  exit(1)
9
8
  end
10
9
 
@@ -8,11 +8,11 @@ require 'json'
8
8
  require 'logger'
9
9
  require 'net/hippie'
10
10
  require 'nokogiri'
11
+ require 'oj'
11
12
  require 'parslet'
12
13
  require 'pathname'
13
14
  require 'yaml'
14
15
  require 'zeitwerk'
15
- require 'terminal-table'
16
16
  require 'spandx/spandx'
17
17
 
18
18
  loader = Zeitwerk::Loader.for_gem
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'nanospinner'
4
3
  require 'thor'
5
- require 'tty-screen'
4
+ require 'tty-spinner'
5
+ require 'terminal-table'
6
6
 
7
7
  module Spandx
8
8
  module Cli
@@ -4,51 +4,49 @@ module Spandx
4
4
  module Cli
5
5
  module Commands
6
6
  class Scan
7
- attr_reader :scan_path, :spinner
7
+ include Spandx::Core
8
+ attr_reader :scan_path
8
9
 
9
10
  def initialize(scan_path, options)
10
11
  @scan_path = ::Pathname.new(scan_path)
11
12
  @options = options
12
- @spinner = options[:show_progress] ? ::Spandx::Core::Spinner.new : ::Spandx::Core::Spinner::NULL
13
13
  require(options[:require]) if options[:require]
14
14
  end
15
15
 
16
16
  def execute(output: $stdout)
17
- report = ::Spandx::Core::Report.new
18
- each_file do |file|
19
- spinner.spin(file)
20
- each_dependency_from(file) do |dependency|
21
- spinner.spin(file)
22
- report.add(dependency)
17
+ with_printer(output) do |printer|
18
+ each_dependency do |dependency|
19
+ printer.print_line(Plugin.enhance(dependency), output)
23
20
  end
24
21
  end
25
- spinner.stop
26
- output.puts(format(report.to(@options[:format])))
27
22
  end
28
23
 
29
24
  private
30
25
 
31
26
  def each_file
32
- Spandx::Core::PathTraversal
27
+ PathTraversal
33
28
  .new(scan_path, recursive: @options[:recursive])
34
29
  .each { |file| yield file }
35
30
  end
36
31
 
37
- def each_dependency_from(file)
38
- ::Spandx::Core::Parser
39
- .parse(file)
40
- .map { |x| enhance(x) }
41
- .each { |dependency| yield dependency }
32
+ def each_dependency
33
+ each_file do |file|
34
+ Parser.parse(file).each do |dependency|
35
+ yield dependency
36
+ end
37
+ end
42
38
  end
43
39
 
44
40
  def format(output)
45
41
  Array(output).map(&:to_s)
46
42
  end
47
43
 
48
- def enhance(dependency)
49
- ::Spandx::Core::Plugin
50
- .all
51
- .inject(dependency) { |memo, plugin| plugin.enhance(memo) }
44
+ def with_printer(output)
45
+ printer = ::Spandx::Cli::Printer.for(@options[:format])
46
+ printer.print_header(output)
47
+ yield printer
48
+ ensure
49
+ printer.print_footer(output)
52
50
  end
53
51
  end
54
52
  end
@@ -8,14 +8,14 @@ module Spandx
8
8
  method_option :recursive, aliases: '-R', type: :boolean, desc: 'Perform recursive scan', default: false
9
9
  method_option :airgap, aliases: '-a', type: :boolean, desc: 'Disable network connections', default: false
10
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. (table, csv, json, hash)', default: 'table'
11
+ method_option :format, aliases: '-f', type: :string, desc: 'Format of report. (table, csv, json)', default: 'table'
12
12
  method_option :pull, aliases: '-p', type: :boolean, desc: 'Pull the latest cache before the scan', default: false
13
13
  method_option :require, aliases: '-r', type: :string, desc: 'Causes spandx to load the library using require.', default: nil
14
- method_option :show_progress, aliases: '-sp', type: :boolean, desc: 'Shows a progress bar', default: true
15
14
  def scan(lockfile = Pathname.pwd)
16
15
  if options[:help]
17
16
  invoke :help, ['scan']
18
17
  else
18
+ Oj.default_options = { mode: :strict }
19
19
  Spandx.airgap = options[:airgap]
20
20
  Spandx.logger = Logger.new(options[:logfile])
21
21
  pull if options[:pull]
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Cli
5
+ class Printer
6
+ def match?(_format)
7
+ raise ::Spandx::Error, :match?
8
+ end
9
+
10
+ def print_header(io); end
11
+
12
+ def print_line(dependency, io)
13
+ io.puts(dependency.to_s)
14
+ end
15
+
16
+ def print_footer(io); end
17
+
18
+ class << self
19
+ include Core::Registerable
20
+
21
+ def for(format)
22
+ find { |x| x.match?(format) } || new
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Cli
5
+ module Printers
6
+ class Csv < Printer
7
+ def match?(format)
8
+ format.to_sym == :csv
9
+ end
10
+
11
+ def print_line(dependency, io)
12
+ io.puts(CSV.generate_line(dependency.to_a))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Cli
5
+ module Printers
6
+ class Json < Printer
7
+ def match?(format)
8
+ format.to_sym == :json
9
+ end
10
+
11
+ def print_line(dependency, io)
12
+ io.puts(Oj.dump(dependency.to_h))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Cli
5
+ module Printers
6
+ class Table < Printer
7
+ HEADINGS = ['Name', 'Version', 'Licenses', 'Location'].freeze
8
+
9
+ def initialize
10
+ @spinner = TTY::Spinner.new(output: $stderr)
11
+ end
12
+
13
+ def match?(format)
14
+ format.to_sym == :table
15
+ end
16
+
17
+ def print_header(_io)
18
+ @dependencies = SortedSet.new
19
+ @spinner.auto_spin
20
+ end
21
+
22
+ def print_line(dependency, _io)
23
+ @dependencies << dependency
24
+ end
25
+
26
+ def print_footer(io)
27
+ @spinner.stop
28
+ io.puts(to_table(@dependencies.map(&:to_a)))
29
+ end
30
+
31
+ private
32
+
33
+ def to_table(rows)
34
+ Terminal::Table.new(headings: HEADINGS) do |table|
35
+ rows.each { |row| table.add_row(row) }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -11,9 +11,8 @@ module Spandx
11
11
  end
12
12
 
13
13
  def read(path)
14
- full_path = File.join(root, path)
15
-
16
- IO.read(full_path) if File.exist?(full_path)
14
+ full_path = root.join(path)
15
+ full_path.read if full_path.exist?
17
16
  end
18
17
 
19
18
  def update!
@@ -25,15 +24,16 @@ module Spandx
25
24
  def path_for(url)
26
25
  uri = URI.parse(url)
27
26
  name = uri.path.gsub(/\.git$/, '')
28
- File.expand_path(File.join(Dir.home, '.local', 'share', name))
27
+ Pathname(File.expand_path(File.join(Dir.home, '.local', 'share', name)))
29
28
  end
30
29
 
31
30
  def dotgit?
32
- File.directory?(File.join(root, '.git'))
31
+ root.join('.git').directory?
33
32
  end
34
33
 
35
34
  def clone!
36
- system('git', 'clone', '--quiet', '--depth=1', '--single-branch', '--branch', 'master', url, root)
35
+ system('rm', '-rf', root.to_s) if root.exist?
36
+ system('git', 'clone', '--quiet', '--depth=1', '--single-branch', '--branch', 'master', url, root.to_s)
37
37
  end
38
38
 
39
39
  def pull!
@@ -9,6 +9,12 @@ module Spandx
9
9
 
10
10
  class << self
11
11
  include Registerable
12
+
13
+ def enhance(dependency)
14
+ Plugin.all.inject(dependency) do |memo, plugin|
15
+ plugin.enhance(memo)
16
+ end
17
+ end
12
18
  end
13
19
  end
14
20
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Core
5
+ class ThreadPool
6
+ def initialize(size: 1)
7
+ @size = size
8
+ @queue = Queue.new
9
+ @pool = size.times.map { start_worker_thread(@queue) }
10
+ end
11
+
12
+ def run(*args, &job)
13
+ @queue.enq([job, args])
14
+ end
15
+
16
+ def done?
17
+ @queue.empty?
18
+ end
19
+
20
+ def shutdown
21
+ @size.times do
22
+ run { throw :exit }
23
+ end
24
+
25
+ @pool.map(&:join)
26
+ end
27
+
28
+ def self.open(**args)
29
+ pool = new(**args)
30
+ yield pool
31
+ ensure
32
+ pool.shutdown
33
+ end
34
+
35
+ private
36
+
37
+ def start_worker_thread(queue)
38
+ Thread.new(queue) do |q|
39
+ catch(:exit) do
40
+ loop do
41
+ job, args = q.deq
42
+ job.call(args)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -69,7 +69,7 @@ module Spandx
69
69
 
70
70
  def fetch_json(url)
71
71
  response = http.get(url)
72
- http.ok?(response) ? JSON.parse(response.body) : {}
72
+ http.ok?(response) ? Oj.load(response.body) : {}
73
73
  end
74
74
 
75
75
  def fetch_xml(url)
@@ -18,8 +18,8 @@ module Spandx
18
18
 
19
19
  private
20
20
 
21
- def each_metadata(file_path)
22
- package_lock = JSON.parse(IO.read(file_path))
21
+ def each_metadata(path)
22
+ package_lock = Oj.load(path.read)
23
23
  package_lock['dependencies'].each do |name, metadata|
24
24
  yield metadata.merge('name' => name)
25
25
  end
@@ -27,7 +27,7 @@ module Spandx
27
27
  response = http.get(uri, escape: false)
28
28
 
29
29
  if http.ok?(response)
30
- json = JSON.parse(response.body)
30
+ json = Oj.load(response.body)
31
31
  json['versions'] ? json['versions'][dependency.version] : json
32
32
  else
33
33
  {}
@@ -17,7 +17,7 @@ module Spandx
17
17
  response = http.get("https://repo.packagist.org/p/#{dependency.name}.json")
18
18
  return [] unless http.ok?(response)
19
19
 
20
- json = JSON.parse(response.body)
20
+ json = Oj.load(response.body)
21
21
  json['packages'][dependency.name][dependency.version]['license']
22
22
  end
23
23
  end
@@ -10,7 +10,7 @@ module Spandx
10
10
 
11
11
  def parse(path)
12
12
  items = Set.new
13
- composer_lock = JSON.parse(path.read)
13
+ composer_lock = Oj.load(path.read)
14
14
  composer_lock['packages'].concat(composer_lock['packages-dev']).each do |dependency|
15
15
  items.add(map_from(path, dependency))
16
16
  end
@@ -19,7 +19,7 @@ module Spandx
19
19
  private
20
20
 
21
21
  def dependencies_from(lockfile)
22
- json = JSON.parse(lockfile.read)
22
+ json = Oj.load(lockfile.read)
23
23
  each_dependency(json) do |name, version|
24
24
  yield ::Spandx::Core::Dependency.new(
25
25
  path: lockfile,
@@ -49,19 +49,26 @@ module Spandx
49
49
  end
50
50
 
51
51
  def version_from(url)
52
- path = SUBSTITUTIONS.inject(URI.parse(url).path.split('/')[-1]) do |memo, item|
53
- memo.gsub(item, '')
54
- end
55
-
52
+ path = cleanup(url)
56
53
  return if path.rindex('-').nil?
57
54
 
58
- path.scan(/-\d+\..*/)[-1][1..-1]
55
+ section = path.scan(/-\d+\..*/)
56
+ section = path.scan(/-\d+\.?.*/) if section.empty?
57
+ section[-1][1..-1]
58
+ rescue StandardError => error
59
+ warn([url, error].inspect)
59
60
  end
60
61
 
61
62
  private
62
63
 
63
64
  attr_reader :http
64
65
 
66
+ def cleanup(url)
67
+ SUBSTITUTIONS.inject(URI.parse(url).path.split('/')[-1]) do |memo, item|
68
+ memo.gsub(item, '')
69
+ end
70
+ end
71
+
65
72
  def sources_for(dependency)
66
73
  return default_sources if dependency.meta.empty?
67
74
 
@@ -76,7 +83,7 @@ module Spandx
76
83
  sources.each do |source|
77
84
  html_from(source, '/simple/').css('a[href*="/simple"]').each do |node|
78
85
  each_version(source, node[:href]) do |dependency|
79
- definition = source.lookup(dependency[:name], dependency[:version])
86
+ definition = source.lookup(dependency[:name], dependency[:version], http: http)
80
87
  yield dependency.merge(license: definition['license'])
81
88
  end
82
89
  end
@@ -93,7 +100,12 @@ module Spandx
93
100
 
94
101
  def html_from(source, path)
95
102
  url = URI.join(source.uri.to_s, path).to_s
96
- Nokogiri::HTML(http.get(url).body)
103
+ response = http.get(url)
104
+ if http.ok?(response)
105
+ Nokogiri::HTML(response.body)
106
+ else
107
+ Nokogiri::HTML('<html><head></head><body></body></html>')
108
+ end
97
109
  end
98
110
  end
99
111
  end
@@ -22,7 +22,7 @@ module Spandx
22
22
  def lookup(name, version, http: Spandx.http)
23
23
  response = http.get(uri_for(name, version))
24
24
  if http.ok?(response)
25
- JSON.parse(response.body)
25
+ Oj.load(response.body)
26
26
  else
27
27
  {}
28
28
  end
@@ -27,7 +27,7 @@ module Spandx
27
27
  end
28
28
 
29
29
  def parse(json)
30
- JSON.parse(json)
30
+ Oj.load(json)
31
31
  end
32
32
  end
33
33
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Spandx
4
- VERSION = '0.13.4'
4
+ VERSION = '0.13.5'
5
5
  end
@@ -34,13 +34,13 @@ Gem::Specification.new do |spec|
34
34
 
35
35
  spec.add_dependency 'addressable', '~> 2.7'
36
36
  spec.add_dependency 'bundler', '>= 1.16', '< 3.0.0'
37
- spec.add_dependency 'nanospinner', '~> 1.0.0'
38
37
  spec.add_dependency 'net-hippie', '~> 0.3'
39
38
  spec.add_dependency 'nokogiri', '~> 1.10'
39
+ spec.add_dependency 'oj', '~> 3.10'
40
40
  spec.add_dependency 'parslet', '~> 2.0'
41
41
  spec.add_dependency 'terminal-table', '~> 1.8'
42
42
  spec.add_dependency 'thor'
43
- spec.add_dependency 'tty-screen', '~> 0.7'
43
+ spec.add_dependency 'tty-spinner', '~> 0.9'
44
44
  spec.add_dependency 'zeitwerk', '~> 2.3'
45
45
 
46
46
  spec.add_development_dependency 'benchmark-ips', '~> 2.8'
@@ -54,6 +54,6 @@ Gem::Specification.new do |spec|
54
54
  spec.add_development_dependency 'rubocop', '~> 0.52'
55
55
  spec.add_development_dependency 'rubocop-rspec', '~> 1.22'
56
56
  spec.add_development_dependency 'ruby-prof', '~> 1.3'
57
- spec.add_development_dependency 'vcr', '~> 5.0'
57
+ spec.add_development_dependency 'vcr', '~> 6.0'
58
58
  spec.add_development_dependency 'webmock', '~> 3.7'
59
59
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spandx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.4
4
+ version: 0.13.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Can Eldem
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-05-26 00:00:00.000000000 Z
12
+ date: 2020-06-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -46,47 +46,47 @@ dependencies:
46
46
  - !ruby/object:Gem::Version
47
47
  version: 3.0.0
48
48
  - !ruby/object:Gem::Dependency
49
- name: nanospinner
49
+ name: net-hippie
50
50
  requirement: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.0
54
+ version: '0.3'
55
55
  type: :runtime
56
56
  prerelease: false
57
57
  version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.0.0
61
+ version: '0.3'
62
62
  - !ruby/object:Gem::Dependency
63
- name: net-hippie
63
+ name: nokogiri
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.3'
68
+ version: '1.10'
69
69
  type: :runtime
70
70
  prerelease: false
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.3'
75
+ version: '1.10'
76
76
  - !ruby/object:Gem::Dependency
77
- name: nokogiri
77
+ name: oj
78
78
  requirement: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.10'
82
+ version: '3.10'
83
83
  type: :runtime
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.10'
89
+ version: '3.10'
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: parslet
92
92
  requirement: !ruby/object:Gem::Requirement
@@ -130,19 +130,19 @@ dependencies:
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  - !ruby/object:Gem::Dependency
133
- name: tty-screen
133
+ name: tty-spinner
134
134
  requirement: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '0.7'
138
+ version: '0.9'
139
139
  type: :runtime
140
140
  prerelease: false
141
141
  version_requirements: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.7'
145
+ version: '0.9'
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: zeitwerk
148
148
  requirement: !ruby/object:Gem::Requirement
@@ -317,14 +317,14 @@ dependencies:
317
317
  requirements:
318
318
  - - "~>"
319
319
  - !ruby/object:Gem::Version
320
- version: '5.0'
320
+ version: '6.0'
321
321
  type: :development
322
322
  prerelease: false
323
323
  version_requirements: !ruby/object:Gem::Requirement
324
324
  requirements:
325
325
  - - "~>"
326
326
  - !ruby/object:Gem::Version
327
- version: '5.0'
327
+ version: '6.0'
328
328
  - !ruby/object:Gem::Dependency
329
329
  name: webmock
330
330
  requirement: !ruby/object:Gem::Requirement
@@ -367,6 +367,10 @@ files:
367
367
  - lib/spandx/cli/commands/pull.rb
368
368
  - lib/spandx/cli/commands/scan.rb
369
369
  - lib/spandx/cli/main.rb
370
+ - lib/spandx/cli/printer.rb
371
+ - lib/spandx/cli/printers/csv.rb
372
+ - lib/spandx/cli/printers/json.rb
373
+ - lib/spandx/cli/printers/table.rb
370
374
  - lib/spandx/core/cache.rb
371
375
  - lib/spandx/core/circuit.rb
372
376
  - lib/spandx/core/content.rb
@@ -383,9 +387,8 @@ files:
383
387
  - lib/spandx/core/plugin.rb
384
388
  - lib/spandx/core/registerable.rb
385
389
  - lib/spandx/core/relation.rb
386
- - lib/spandx/core/report.rb
387
390
  - lib/spandx/core/score.rb
388
- - lib/spandx/core/spinner.rb
391
+ - lib/spandx/core/thread_pool.rb
389
392
  - lib/spandx/dotnet/index.rb
390
393
  - lib/spandx/dotnet/nuget_gateway.rb
391
394
  - lib/spandx/dotnet/package_reference.rb
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spandx
4
- module Core
5
- class Report
6
- attr_reader :dependencies
7
-
8
- FORMATS = {
9
- csv: :to_csv,
10
- hash: :to_h,
11
- json: :to_json,
12
- table: :to_table,
13
- }.freeze
14
-
15
- def initialize
16
- @dependencies = SortedSet.new
17
- end
18
-
19
- def add(dependency)
20
- @dependencies << dependency
21
- end
22
-
23
- def to(format, formats: FORMATS)
24
- public_send(formats.fetch(format&.to_sym, :to_json))
25
- end
26
-
27
- def to_table
28
- Terminal::Table.new(headings: ['Name', 'Version', 'Licenses', 'Location']) do |t|
29
- dependencies.each do |d|
30
- t.add_row d.to_a
31
- end
32
- end
33
- end
34
-
35
- def to_h
36
- { version: '1.0', dependencies: [] }.tap do |report|
37
- dependencies.each do |dependency|
38
- report[:dependencies].push(dependency.to_h)
39
- end
40
- end
41
- end
42
-
43
- def to_json(*_args)
44
- JSON.pretty_generate(to_h)
45
- end
46
-
47
- def to_csv
48
- dependencies.map do |dependency|
49
- CSV.generate_line(dependency.to_a)
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spandx
4
- module Core
5
- class Spinner
6
- NULL = Class.new do
7
- def self.spin(*args); end
8
-
9
- def self.stop(*args); end
10
- end
11
-
12
- attr_reader :columns, :spinner
13
-
14
- def initialize(columns: TTY::Screen.columns, output: $stderr)
15
- @columns = columns
16
- @spinner = Nanospinner.new(output)
17
- @queue = Queue.new
18
- @thread = Thread.new { work }
19
- end
20
-
21
- def spin(message)
22
- @queue.enq(justify(message))
23
- yield if block_given?
24
- end
25
-
26
- def stop
27
- @queue.clear
28
- @queue.enq(:stop)
29
- @thread.join
30
- end
31
-
32
- private
33
-
34
- def justify(message)
35
- message.to_s.ljust(columns - 3)
36
- end
37
-
38
- def work
39
- last_message = justify('')
40
- loop do
41
- message = @queue.empty? ? last_message : @queue.deq
42
- break if message == :stop
43
-
44
- spinner.spin(message)
45
- last_message = message
46
- sleep 0.1
47
- end
48
- end
49
- end
50
- end
51
- end