bibliothecary 12.0.0 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -1
  3. data/.rubocop.yml +10 -2
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +13 -0
  6. data/Gemfile +16 -1
  7. data/Rakefile +2 -0
  8. data/bibliothecary.gemspec +11 -13
  9. data/bin/bibliothecary +2 -1
  10. data/bin/console +1 -0
  11. data/lib/bibliothecary/analyser/analysis.rb +13 -8
  12. data/lib/bibliothecary/analyser/determinations.rb +2 -0
  13. data/lib/bibliothecary/analyser/matchers.rb +17 -17
  14. data/lib/bibliothecary/analyser.rb +11 -8
  15. data/lib/bibliothecary/cli.rb +3 -1
  16. data/lib/bibliothecary/configuration.rb +3 -8
  17. data/lib/bibliothecary/dependency.rb +17 -15
  18. data/lib/bibliothecary/exceptions.rb +6 -2
  19. data/lib/bibliothecary/file_info.rb +9 -11
  20. data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +13 -10
  21. data/lib/bibliothecary/multi_parsers/cyclonedx.rb +10 -8
  22. data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +11 -4
  23. data/lib/bibliothecary/multi_parsers/json_runtime.rb +5 -2
  24. data/lib/bibliothecary/multi_parsers/spdx.rb +24 -19
  25. data/lib/bibliothecary/parsers/bower.rb +5 -3
  26. data/lib/bibliothecary/parsers/cargo.rb +10 -4
  27. data/lib/bibliothecary/parsers/cocoapods.rb +15 -11
  28. data/lib/bibliothecary/parsers/conda.rb +20 -18
  29. data/lib/bibliothecary/parsers/cpan.rb +6 -4
  30. data/lib/bibliothecary/parsers/cran.rb +10 -6
  31. data/lib/bibliothecary/parsers/dub.rb +4 -2
  32. data/lib/bibliothecary/parsers/elm.rb +4 -1
  33. data/lib/bibliothecary/parsers/go.rb +51 -43
  34. data/lib/bibliothecary/parsers/haxelib.rb +2 -1
  35. data/lib/bibliothecary/parsers/julia.rb +5 -1
  36. data/lib/bibliothecary/parsers/maven.rb +93 -77
  37. data/lib/bibliothecary/parsers/meteor.rb +2 -0
  38. data/lib/bibliothecary/parsers/npm.rb +89 -75
  39. data/lib/bibliothecary/parsers/nuget.rb +37 -28
  40. data/lib/bibliothecary/parsers/packagist.rb +21 -11
  41. data/lib/bibliothecary/parsers/pub.rb +4 -2
  42. data/lib/bibliothecary/parsers/pypi.rb +48 -29
  43. data/lib/bibliothecary/parsers/rubygems.rb +16 -12
  44. data/lib/bibliothecary/parsers/shard.rb +10 -7
  45. data/lib/bibliothecary/purl_util.rb +2 -1
  46. data/lib/bibliothecary/related_files_info.rb +7 -8
  47. data/lib/bibliothecary/runner/multi_manifest_filter.rb +5 -4
  48. data/lib/bibliothecary/runner.rb +12 -10
  49. data/lib/bibliothecary/version.rb +3 -1
  50. data/lib/bibliothecary.rb +7 -4
  51. data/lib/sdl_parser.rb +11 -6
  52. metadata +18 -101
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12b592879fc7f4fbe3622f495e8ef989b541c81487915b693d02907cedeb62a0
4
- data.tar.gz: fd266f3924f202a864017c52ff1c2eb84fd68c4451b16b95e6aa44d80b850598
3
+ metadata.gz: a0dbcee666f0bade61cdab50c1adf3feccd919c961db92df409845b0d8930a8f
4
+ data.tar.gz: cff0b5d9c69db6d9438c7d976e503096d75f8ea8991f318e800fdbb8caccc323
5
5
  SHA512:
6
- metadata.gz: e4622e4be1424fd679fac201929bcdf77ed02f0f5782799cf506c93af1d21b803a7e8319e8f471b4747eb5d1a02dba3c0bf8914bae3c4a7a9c95c1b49c37c7b8
7
- data.tar.gz: 16950d0fdfcf98cbef1b0faeb61fe1e398816b5499a2fe7af02ea3380975fce4bf85e81a64bfc2d9bb382753f2bdd538e2a46896e8a7e08476716a777adc32aa
6
+ metadata.gz: 2e1299ec112f03c1322b7084c65e14685a74b778c11cd82c0bde376d7f3ca06be08a01f76139b4237d78671fcfd91779edf7f457e756c98f7344b3f4712594de
7
+ data.tar.gz: 82388cba64ac674b92b77d364c05787f4ab2effd2dcd244c860b06d2761be4ba30f42a70adf3b3e80cb2d48e11fa12deedac46323447bd887db4d703a8bd9467
data/.circleci/config.yml CHANGED
@@ -5,7 +5,7 @@ orbs:
5
5
  executors:
6
6
  bibliothecary:
7
7
  docker:
8
- - image: cimg/ruby:3.2.4
8
+ - image: cimg/ruby:3.2.6
9
9
  working_directory: ~/bibliothecary
10
10
 
11
11
 
@@ -20,6 +20,7 @@ commands:
20
20
  bundle lock --add-platform x86_64-linux
21
21
  - ruby/install-deps:
22
22
  bundler-version: "2.3"
23
+ key: gems-v3
23
24
 
24
25
 
25
26
  jobs:
data/.rubocop.yml CHANGED
@@ -1,8 +1,16 @@
1
1
  ---
2
2
 
3
+ # Without this, CI might pickup nested dep's rubocop files in vendor/
4
+ inherit_mode:
5
+ merge:
6
+ - Exclude
7
+
3
8
  AllCops:
4
- DisabledByDefault: true
5
- TargetRubyVersion: 3.0
9
+ NewCops: enable
10
+ TargetRubyVersion: 3.2.6
11
+ Exclude:
12
+ - spec/fixtures/**/*
13
+ - vendor/bundle/**/* # This is actually needed for CI, not for biblio itself
6
14
 
7
15
 
8
16
  Metrics/BlockLength:
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.4
1
+ 3.2.6
data/CHANGELOG.md CHANGED
@@ -13,6 +13,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Removed
15
15
 
16
+ ## [12.1.0] - 2025-01-30
17
+
18
+ ### Added
19
+
20
+ - Populate Bibliothecary::Dependency#source field in all parsers. This makes the source field useful when consuming
21
+ from Bibliothecary, and removes a step from consumers having to populate this field themselves.
22
+
23
+ ### Changed
24
+
25
+ - Improved Rubocop rules to make future spec changes easier via Rubocop auto-correcting formatting violations.
26
+
27
+ ### Removed
28
+
16
29
  ## [12.0.0] - 2025-01-27
17
30
 
18
31
  ### Removed
data/Gemfile CHANGED
@@ -1,9 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in bibliothecary.gemspec
4
6
  gemspec
5
7
 
8
+ group :development do
9
+ gem "pry"
10
+ end
11
+
12
+ group :development, :test do
13
+ gem "rake", "~> 12.0"
14
+ gem "rubocop", "~> 1.71"
15
+ gem "rubocop-rails"
16
+ gem "rubocop-rake" # This is needed by packageurl-ruby, until it reclassifies it as a dev dependency.
17
+ end
18
+
6
19
  group :test do
7
- gem "simplecov"
8
20
  gem "codeclimate-test-reporter", "~> 1.0.0"
21
+ gem "rspec", "~> 3.0"
22
+ gem "simplecov"
23
+ gem "webmock"
9
24
  end
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
@@ -1,9 +1,12 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require "bibliothecary/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
8
+ spec.required_ruby_version = ">= 3.2.0"
9
+
7
10
  spec.name = "bibliothecary"
8
11
  spec.version = Bibliothecary::VERSION
9
12
  spec.authors = ["Andrew Nesbitt"]
@@ -18,19 +21,14 @@ Gem::Specification.new do |spec|
18
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
22
  spec.require_paths = ["lib"]
20
23
 
21
- spec.add_dependency "tomlrb", "~> 2.0"
24
+ spec.add_dependency "commander"
25
+ spec.add_dependency "deb_control"
22
26
  spec.add_dependency "librariesio-gem-parser"
23
27
  spec.add_dependency "ox", ">= 2.8.1"
24
- spec.add_dependency "typhoeus"
25
- spec.add_dependency "deb_control"
26
- spec.add_dependency "sdl4r"
27
- spec.add_dependency "commander"
28
28
  spec.add_dependency "packageurl-ruby"
29
+ spec.add_dependency "sdl4r"
30
+ spec.add_dependency "tomlrb", "~> 2.0"
31
+ spec.add_dependency "typhoeus"
29
32
 
30
- spec.add_development_dependency "pry"
31
- spec.add_development_dependency "rake", "~> 12.0"
32
- spec.add_development_dependency "rspec", "~> 3.0"
33
- spec.add_development_dependency "webmock"
34
- spec.add_development_dependency "rubocop"
35
- spec.add_development_dependency "rubocop-rails"
33
+ spec.metadata["rubygems_mfa_required"] = "true"
36
34
  end
data/bin/bibliothecary CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- lib = File.expand_path("../../lib", __FILE__)
4
+ lib = File.expand_path("../lib", __dir__)
4
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
6
 
6
7
  require "bibliothecary/cli"
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "bibliothecary"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module Analyser
3
5
  module Analysis
@@ -42,25 +44,29 @@ module Bibliothecary
42
44
 
43
45
  dependencies_to_analysis(info, kind, dependencies)
44
46
  rescue Bibliothecary::FileParsingError => e
45
- Bibliothecary::Analyser::create_error_analysis(platform_name, info.relative_path, kind, e.message, e.location)
47
+ Bibliothecary::Analyser.create_error_analysis(platform_name, info.relative_path, kind, e.message, e.location)
46
48
  end
47
49
  alias analyze_contents_from_info analyse_contents_from_info
48
50
 
49
51
  def dependencies_to_analysis(info, kind, dependencies)
50
- dependencies = dependencies || [] # work around any legacy parsers that return nil
52
+ dependencies ||= [] # work around any legacy parsers that return nil
51
53
  if generic?
52
54
  grouped = dependencies.group_by { |dep| dep[:platform] }
53
55
  all_analyses = grouped.keys.map do |platform|
54
- deplatformed_dependencies = grouped[platform].map { |d| d.delete(:platform); d }
55
- Bibliothecary::Analyser::create_analysis(platform, info.relative_path, kind, deplatformed_dependencies)
56
+ deplatformed_dependencies = grouped[platform].map do |d|
57
+ d.delete(:platform)
58
+ d
59
+ end
60
+ Bibliothecary::Analyser.create_analysis(platform, info.relative_path, kind, deplatformed_dependencies)
56
61
  end
57
62
  # this is to avoid a larger refactor for the time being. The larger refactor
58
63
  # needs to make analyse_contents return multiple analysis, or add another
59
64
  # method that can return multiple and deprecate analyse_contents, perhaps.
60
65
  raise "File contains zero or multiple platforms, currently must have exactly one" if all_analyses.length != 1
66
+
61
67
  all_analyses.first
62
68
  else
63
- Bibliothecary::Analyser::create_analysis(platform_name, info.relative_path, kind, dependencies)
69
+ Bibliothecary::Analyser.create_analysis(platform_name, info.relative_path, kind, dependencies)
64
70
  end
65
71
  end
66
72
 
@@ -81,8 +87,7 @@ module Bibliothecary
81
87
  # this comment, some of the parsers return [] or nil to mean an error
82
88
  # which is confusing to users.
83
89
  send(details[:parser], contents, options: options.merge(filename: filename))
84
-
85
- rescue Exception => e # default is StandardError but C bindings throw Exceptions
90
+ rescue Exception => e # default is StandardError but C bindings throw Exceptions # rubocop:disable Lint/RescueException
86
91
  # the C xml parser also puts a newline at the end of the message
87
92
  location = e.backtrace_locations[0]
88
93
  .to_s
@@ -97,7 +102,7 @@ module Bibliothecary
97
102
 
98
103
  kind = determine_kind_from_info(info)
99
104
  relate_to_kind = first_matching_mapping_details(info)
100
- .fetch(:related_to, %w(manifest lockfile).reject { |k| k == kind })
105
+ .fetch(:related_to, %w[manifest lockfile].reject { |k| k == kind })
101
106
  dirname = File.dirname(info.relative_path)
102
107
 
103
108
  infos
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module Analyser
3
5
  module Determinations
@@ -1,42 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module Analyser
3
5
  module Matchers
4
6
  def match_filename(filename, case_insensitive: false)
5
7
  if case_insensitive
6
- lambda { |path| path.downcase == filename.downcase || path.downcase.end_with?("/" + filename.downcase) }
8
+ ->(path) { path.downcase == filename.downcase || path.downcase.end_with?("/#{filename.downcase}") }
7
9
  else
8
- lambda { |path| path == filename || path.end_with?("/" + filename) }
10
+ ->(path) { path == filename || path.end_with?("/#{filename}") }
9
11
  end
10
12
  end
11
13
 
12
14
  def match_filenames(*filenames)
13
15
  lambda do |path|
14
16
  filenames.any? { |f| path == f } ||
15
- filenames.any? { |f| path.end_with?("/" + f) }
17
+ filenames.any? { |f| path.end_with?("/#{f}") }
16
18
  end
17
19
  end
18
20
 
19
21
  def match_extension(filename, case_insensitive: false)
20
22
  if case_insensitive
21
- lambda { |path| path.downcase.end_with?(filename.downcase) }
23
+ ->(path) { path.downcase.end_with?(filename.downcase) }
22
24
  else
23
- lambda { |path| path.end_with?(filename) }
25
+ ->(path) { path.end_with?(filename) }
24
26
  end
25
27
  end
26
28
 
27
29
  def mapping_entry_match?(matcher, details, info)
28
- if matcher.call(info.relative_path)
29
- # we only want to load contents if we don't have them already
30
- # and there's a content_matcher method to use
31
- return true if details[:content_matcher].nil?
32
- # this is the libraries.io case where we won't load all .xml
33
- # files (for example) just to look at their contents, we'll
34
- # assume they are not manifests.
35
- return false if info.contents.nil?
36
- return send(details[:content_matcher], info.contents)
37
- else
38
- return false
39
- end
30
+ return false unless matcher.call(info.relative_path)
31
+ # we only want to load contents if we don't have them already
32
+ # and there's a content_matcher method to use
33
+ return true if details[:content_matcher].nil?
34
+ # this is the libraries.io case where we won't load all .xml
35
+ # files (for example) just to look at their contents, we'll
36
+ # assume they are not manifests.
37
+ return false if info.contents.nil?
38
+
39
+ send(details[:content_matcher], info.contents)
40
40
  end
41
41
 
42
42
  # this is broken with contents=nil because it can't look at file
@@ -1,10 +1,12 @@
1
- require_relative "./analyser/matchers.rb"
2
- require_relative "./analyser/determinations.rb"
3
- require_relative "./analyser/analysis.rb"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "analyser/matchers"
4
+ require_relative "analyser/determinations"
5
+ require_relative "analyser/analysis"
4
6
 
5
7
  module Bibliothecary
6
8
  module Analyser
7
- def self.create_error_analysis(platform_name, relative_path, kind, message, location=nil)
9
+ def self.create_error_analysis(platform_name, relative_path, kind, message, location = nil)
8
10
  {
9
11
  platform: platform_name,
10
12
  path: relative_path,
@@ -53,15 +55,16 @@ module Bibliothecary
53
55
  end
54
56
 
55
57
  def platform_name
56
- self.name.to_s.split("::").last.downcase
58
+ name.to_s.split("::").last.downcase
57
59
  end
58
60
 
59
- def map_dependencies(hash, key, type)
60
- hash.fetch(key,[]).map do |name, requirement|
61
+ def map_dependencies(hash, key, type, source = nil)
62
+ hash.fetch(key, []).map do |name, requirement|
61
63
  Dependency.new(
62
64
  name: name,
63
65
  requirement: requirement,
64
66
  type: type,
67
+ source: source
65
68
  )
66
69
  end
67
70
  end
@@ -75,7 +78,7 @@ module Bibliothecary
75
78
  def add_multi_parser(klass)
76
79
  raise "No mapping found! You should place the add_multi_parser call below def self.mapping." unless respond_to?(:mapping)
77
80
 
78
- original_mapping = self.mapping
81
+ original_mapping = mapping
79
82
 
80
83
  define_singleton_method(:mapping) do
81
84
  original_mapping.merge(klass.mapping)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bibliothecary/version"
2
4
  require "bibliothecary"
3
5
  require "commander"
@@ -20,7 +22,7 @@ module Bibliothecary
20
22
  output = Bibliothecary.analyse(options.path)
21
23
  output.each do |file_contents|
22
24
  puts "#{file_contents[:path]} (#{file_contents[:platform]})"
23
- file_contents[:dependencies].group_by{|d| d[:type] }.each do |type, deps|
25
+ file_contents[:dependencies].group_by { |d| d[:type] }.each do |type, deps|
24
26
  puts " #{type}"
25
27
  deps.each do |dep|
26
28
  puts " #{dep[:name]} #{dep[:requirement]}"
@@ -1,13 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  class Configuration
3
- attr_accessor :ignored_dirs
4
- attr_accessor :ignored_files
5
- attr_accessor :carthage_parser_host
6
- attr_accessor :clojars_parser_host
7
- attr_accessor :mix_parser_host
8
- attr_accessor :conda_parser_host
9
- attr_accessor :swift_parser_host
10
- attr_accessor :cabal_parser_host
5
+ attr_accessor :ignored_dirs, :ignored_files, :carthage_parser_host, :clojars_parser_host, :mix_parser_host, :conda_parser_host, :swift_parser_host, :cabal_parser_host
11
6
 
12
7
  def initialize
13
8
  @ignored_dirs = [".git", "node_modules", "bower_components", "vendor", "dist"]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  # Dependency represents a single unique dependency that was parsed out of a manifest.
3
5
  #
@@ -19,21 +21,21 @@ module Bibliothecary
19
21
  # @source [String] source An optional string to store the location of the manifest that contained this
20
22
  # dependency, e.g. "src/package.json".
21
23
  class Dependency
22
- FIELDS = [
23
- :name,
24
- :requirement,
25
- :original_requirement,
26
- :platform,
27
- :type,
28
- :direct,
29
- :deprecated,
30
- :local,
31
- :optional,
32
- :original_name,
33
- :source,
34
- ]
24
+ FIELDS = %i[
25
+ name
26
+ requirement
27
+ original_requirement
28
+ platform
29
+ type
30
+ direct
31
+ deprecated
32
+ local
33
+ optional
34
+ original_name
35
+ source
36
+ ].freeze
35
37
 
36
- attr_reader *FIELDS
38
+ attr_reader(*FIELDS)
37
39
 
38
40
  def initialize(
39
41
  name:,
@@ -64,7 +66,7 @@ module Bibliothecary
64
66
  def eql?(other)
65
67
  FIELDS.all? { |f| public_send(f) == other.public_send(f) }
66
68
  end
67
- alias :== :eql?
69
+ alias == eql?
68
70
 
69
71
  def [](key)
70
72
  public_send(key)
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  class RemoteParsingError < StandardError
3
5
  attr_accessor :code
6
+
4
7
  def initialize(msg, code)
5
8
  @code = code
6
9
  super(msg)
@@ -9,11 +12,12 @@ module Bibliothecary
9
12
 
10
13
  class FileParsingError < StandardError
11
14
  attr_accessor :filename, :location
12
- def initialize(msg, filename, location=nil)
15
+
16
+ def initialize(msg, filename, location = nil)
13
17
  @filename = filename
14
18
  @location = location # source code location of the error, e.g. "lib/hi.rb:34"
15
19
  msg = "#{filename}: #{msg}" unless msg.include?(filename)
16
- super("#{msg}")
20
+ super(msg.to_s)
17
21
  end
18
22
  end
19
23
  end
@@ -1,24 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pathname"
2
4
 
3
5
  module Bibliothecary
4
6
  # A representation of a file on the filesystem, with location information
5
7
  # and package manager information if needed.
6
8
  class FileInfo
7
- attr_reader :folder_path
8
- attr_reader :relative_path
9
- attr_reader :full_path
9
+ attr_reader :folder_path, :relative_path, :full_path
10
10
  attr_accessor :package_manager
11
11
 
12
12
  def contents
13
13
  @contents ||=
14
- begin
15
- if @folder_path.nil?
16
- # if we have no folder_path then we aren't dealing with a
17
- # file that's actually on the filesystem
18
- nil
19
- else
20
- Bibliothecary.utf8_string(File.open(@full_path).read)
21
- end
14
+ if @folder_path.nil?
15
+ # if we have no folder_path then we aren't dealing with a
16
+ # file that's actually on the filesystem
17
+ nil
18
+ else
19
+ Bibliothecary.utf8_string(File.read(@full_path))
22
20
  end
23
21
  end
24
22
 
@@ -1,20 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module MultiParsers
3
5
  module BundlerLikeManifest
4
6
  # this takes parsed Bundler and Bundler-like (CocoaPods)
5
7
  # manifests and turns them into a list of dependencies.
6
- def parse_ruby_manifest(manifest)
8
+ def parse_ruby_manifest(manifest, source = nil)
7
9
  manifest.dependencies.inject([]) do |deps, dep|
8
10
  deps.push(Dependency.new(
9
- name: dep.name,
10
- requirement: dep
11
- .requirement
12
- .requirements
13
- .sort_by(&:last)
14
- .map { |op, version| "#{op} #{version}" }
15
- .join(", "),
16
- type: dep.type.to_s,
17
- ))
11
+ name: dep.name,
12
+ requirement: dep
13
+ .requirement
14
+ .requirements
15
+ .sort_by(&:last)
16
+ .map { |op, version| "#{op} #{version}" }
17
+ .join(", "),
18
+ type: dep.type.to_s,
19
+ source: source
20
+ ))
18
21
  end.uniq
19
22
  end
20
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "json"
2
4
  require "ox"
3
5
 
@@ -28,23 +30,24 @@ module Bibliothecary
28
30
  @parse_queue = parse_queue.dup
29
31
  end
30
32
 
31
- def <<(purl)
33
+ def add(purl, source = nil)
32
34
  mapping = PurlUtil::PURL_TYPE_MAPPING[purl.type]
33
35
  return unless mapping
34
36
 
35
37
  @manifests[mapping] ||= Set.new
36
- @manifests[mapping] << Dependency.new(
38
+ @manifests[mapping] << Dependency.new(
37
39
  name: PurlUtil.full_name(purl),
38
40
  requirement: purl.version,
39
41
  type: "lockfile",
42
+ source: source
40
43
  )
41
44
  end
42
45
 
43
46
  # Iterates over each manifest entry in the parse_queue, and accepts a block which will
44
47
  # be called on each component. The block has two jobs: 1) add more sub-components
45
48
  # to parse (if they exist), and 2) return the components purl.
46
- def parse!(&block)
47
- while @parse_queue.length > 0
49
+ def parse!(source = nil, &block)
50
+ until @parse_queue.empty?
48
51
  component = @parse_queue.shift
49
52
 
50
53
  purl_text = block.call(component, @parse_queue)
@@ -53,7 +56,7 @@ module Bibliothecary
53
56
 
54
57
  purl = PackageURL.parse(purl_text)
55
58
 
56
- self << purl
59
+ add(purl, source)
57
60
  end
58
61
  end
59
62
 
@@ -88,7 +91,6 @@ module Bibliothecary
88
91
  end
89
92
 
90
93
  def parse_cyclonedx_json(file_contents, options: {})
91
-
92
94
  manifest = try_cache(options, options[:filename]) do
93
95
  JSON.parse(file_contents)
94
96
  end
@@ -97,7 +99,7 @@ module Bibliothecary
97
99
 
98
100
  entries = ManifestEntries.new(parse_queue: manifest["components"])
99
101
 
100
- entries.parse! do |component, parse_queue|
102
+ entries.parse!(options.fetch(:filename, nil)) do |component, parse_queue|
101
103
  parse_queue.concat(component["components"]) if component["components"]
102
104
 
103
105
  component["purl"]
@@ -120,7 +122,7 @@ module Bibliothecary
120
122
 
121
123
  entries = ManifestEntries.new(parse_queue: root.locate("components/*"))
122
124
 
123
- entries.parse! do |component, parse_queue|
125
+ entries.parse!(options.fetch(:filename, nil)) do |component, parse_queue|
124
126
  # #locate returns an empty array if nothing is found, so we can
125
127
  # always safely concatenate it to the parse queue.
126
128
  parse_queue.concat(component.locate("components/*"))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "csv"
2
4
 
3
5
  module Bibliothecary
@@ -55,7 +57,7 @@ module Bibliothecary
55
57
  /^(manifest |)type$/i,
56
58
  ],
57
59
  },
58
- }
60
+ }.freeze
59
61
 
60
62
  attr_reader :result
61
63
 
@@ -79,7 +81,7 @@ module Bibliothecary
79
81
  # some column have default data to fall back on
80
82
  if row_data
81
83
  obj[header.to_sym] = row_data
82
- elsif info.has_key?(:default)
84
+ elsif info.key?(:default)
83
85
  # if the default is nil, don't even add the key to the hash
84
86
  obj[header.to_sym] = info[:default] if info[:default]
85
87
  else
@@ -99,6 +101,7 @@ module Bibliothecary
99
101
  unless header_examination_results[:missing].empty?
100
102
  raise "Missing required headers #{header_examination_results[:missing].join(', ')} in CSV. Check to make sure header names are all lowercase."
101
103
  end
104
+
102
105
  @header_mappings = header_examination_results[:found]
103
106
 
104
107
  table
@@ -114,7 +117,7 @@ module Bibliothecary
114
117
 
115
118
  if results.empty?
116
119
  # if a header has a default value it's optional
117
- obj[:missing] << header unless info.has_key?(:default)
120
+ obj[:missing] << header unless info.key?(:default)
118
121
  else
119
122
  # select the highest priority header possible
120
123
  obj[:found][header] ||= nil
@@ -139,7 +142,11 @@ module Bibliothecary
139
142
  csv_file
140
143
  .result
141
144
  .find_all { |dependency| dependency[:platform] == platform_name.to_s }
142
- .map { |dep_kvs| Dependency.new(**dep_kvs) }
145
+ .map do |dep_kvs|
146
+ Dependency.new(
147
+ **dep_kvs, source: options.fetch(:filename, nil)
148
+ )
149
+ end
143
150
  end
144
151
  end
145
152
  end
@@ -1,13 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module MultiParsers
3
5
  # Provide JSON Runtime Manifest parsing
4
6
  module JSONRuntime
5
- def parse_json_runtime_manifest(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
6
- JSON.parse(file_contents).fetch("dependencies",[]).map do |name, requirement|
7
+ def parse_json_runtime_manifest(file_contents, options: {})
8
+ JSON.parse(file_contents).fetch("dependencies", []).map do |name, requirement|
7
9
  Dependency.new(
8
10
  name: name,
9
11
  requirement: requirement,
10
12
  type: "runtime",
13
+ source: options.fetch(:filename, nil)
11
14
  )
12
15
  end
13
16
  end