spandx 0.13.4 → 0.13.5

This diff has not been reviewed by any users.
Sign up to get free protection for your applications and to get access to all the features.
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