bibliothecary 10.2.0 → 10.2.2

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: 593043fd2afa0c57546f1947d788d7d4882cc398b36ebcc5774cb89446ba07d1
4
- data.tar.gz: fcf4b7b67a9b0d6de622d6bf4390bf20b64f6c015e13253ffad21257bd142f81
3
+ metadata.gz: 8b6fe7d18802ded7298cac3401086635c59397905fceb05aecb3bc777a3e9457
4
+ data.tar.gz: 532ff9bb7bcb77a56648165ade6dc1110f43cc06cd1c79945c3ff8ecdde02e6d
5
5
  SHA512:
6
- metadata.gz: 9b6922980540f62a05e27a46c612937dc165c4815dab3ca8462ad137e1cb4905ac9a015a7a47777126336eefa5a50794027696d1be9340e88206b71885c6893a
7
- data.tar.gz: b283d69564bbd69f8684cd4ac530551c42c5ab1c174da3edaa84f9ca4ee9750abc26cd1d6a977ccf69709fe52cb8d821d7875f6821c456ac5727b1a196dbd060
6
+ metadata.gz: 61ec2054d0905c6f3cb448603bbecc44679e3b07425b8c18c0d5985cc1135788c36525f7567577f7f9c767b5744cf2db1e58c8cd445f35f0894354aacdad2049
7
+ data.tar.gz: 19e8740cefc0cb5098579f933813bdd5912ba5ff716097c69fac603572b9484b04cd4d60710f4048002ed85b5b40a586be10b114ca3a652eb34bbf3fc1354e39
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.7
1
+ 3.0.7
data/CHANGELOG.md CHANGED
@@ -13,11 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Removed
15
15
 
16
+ ## [10.2.2] - 2024-09-25
17
+
18
+ ### Added
19
+
20
+ - Support parsing *.spdx.json files
21
+
16
22
  ## [10.2.0] - 2024-08-27
17
23
 
18
24
  ### Changed
19
25
 
20
- - `Bibliothecary::Dependency#requirement` now defaults to all versions (`"*"`) instead of `nil` if no version range is specified for the dependency,
26
+ - `Bibliothecary::Dependency#requirement` now defaults to all versions (`"*"`) instead of `nil` if no version range is specified for the dependency.
21
27
 
22
28
  ## [10.1.0] - 2024-07-23
23
29
 
data/Gemfile CHANGED
@@ -1,8 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Temporarily pegging to HEAD until 0.2.1 is released: https://github.com/piotrmurach/strings-ansi/pull/2
4
- gem "strings-ansi", ref: "35d0c9430cf0a8022dc12bdab005bce296cb9f00", git: "git@github.com:piotrmurach/strings-ansi.git"
5
-
6
3
  # Specify your gem's dependencies in bibliothecary.gemspec
7
4
  gemspec
8
5
 
data/README.md CHANGED
@@ -97,6 +97,11 @@ All available config options are in: https://github.com/librariesio/bibliothecar
97
97
  - JSON as cyclonedx.json
98
98
  - Note that CycloneDX manifests can contain information on multiple
99
99
  package manager's packages!
100
+ - SPDX
101
+ - tag:value as *.spdx
102
+ - JSON as *.spdx.json
103
+ - Note that SPDX manifests can contain information on multiple
104
+ package manager's packages!
100
105
  - Bower
101
106
  - bower.json
102
107
  - CPAN
@@ -25,8 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency "deb_control"
26
26
  spec.add_dependency "sdl4r"
27
27
  spec.add_dependency "commander"
28
- spec.add_dependency "strings-ansi" # NB this is also pegged to a git sha in Gemfile temporarily.
29
- spec.add_dependency "strings"
30
28
  spec.add_dependency "packageurl-ruby"
31
29
 
32
30
  spec.add_development_dependency "pry"
@@ -29,12 +29,12 @@ module Bibliothecary
29
29
  end
30
30
 
31
31
  def <<(purl)
32
- mapping = Bibliothecary::PURL_TYPE_MAPPING[purl.type]
32
+ mapping = PurlUtil::PURL_TYPE_MAPPING[purl.type]
33
33
  return unless mapping
34
34
 
35
35
  @manifests[mapping] ||= Set.new
36
36
  @manifests[mapping] << Dependency.new(
37
- name: self.class.full_name_for_purl(purl),
37
+ name: PurlUtil.full_name(purl),
38
38
  requirement: purl.version,
39
39
  type: "lockfile",
40
40
  )
@@ -60,18 +60,6 @@ module Bibliothecary
60
60
  def [](key)
61
61
  @manifests[key]&.to_a
62
62
  end
63
-
64
- # @return [String] The properly namespaced package name
65
- def self.full_name_for_purl(purl)
66
- parts = [purl.namespace, purl.name].compact
67
-
68
- case purl.type
69
- when "maven"
70
- parts.join(":")
71
- else
72
- parts.join("/")
73
- end
74
- end
75
63
  end
76
64
 
77
65
  def self.mapping
@@ -18,7 +18,7 @@ module Bibliothecary
18
18
  PACKAGE_NAME_REGEXP = /^\s*PackageName:\s*(.*)/
19
19
 
20
20
  # e.g. 'PackageVersion:' (allowing for excessive whitespace)
21
- PACKAGE_VERSION_REGEXP =/^\s*PackageVersion:\s*(.*)/
21
+ PACKAGE_VERSION_REGEXP = /^\s*PackageVersion:\s*(.*)/
22
22
 
23
23
  # e.g. "ExternalRef: PACKAGE-MANAGER purl (allowing for excessive whitespace)
24
24
  PURL_REGEXP = /^\s*ExternalRef:\s*PACKAGE[-|_]MANAGER\s*purl\s*(.*)/
@@ -33,6 +33,11 @@ module Bibliothecary
33
33
  parser: :parse_spdx_tag_value,
34
34
  ungroupable: true,
35
35
  },
36
+ match_extension(".spdx.json") => {
37
+ kind: "lockfile",
38
+ parser: :parse_spdx_json,
39
+ ungroupable: true,
40
+ },
36
41
  }
37
42
  end
38
43
 
@@ -46,53 +51,93 @@ module Bibliothecary
46
51
  entries[platform_name.to_sym]
47
52
  end
48
53
 
49
- def get_platform(purl_string)
50
- platform = PackageURL.parse(purl_string).type
51
-
52
- Bibliothecary::PURL_TYPE_MAPPING[platform]
53
- end
54
-
55
54
  def parse_spdx_tag_value_file_contents(file_contents)
56
55
  entries = {}
56
+ spdx_name = spdx_version = platform = purl_name = purl_version = nil
57
57
 
58
- package_name = nil
59
- package_version = nil
60
- platform = nil
61
-
62
- file_contents.split("\n").each do |line|
58
+ file_contents.each_line do |line|
63
59
  stripped_line = line.strip
60
+ next if skip_tag_value_line?(stripped_line)
64
61
 
65
- next if skip_line?(stripped_line)
66
-
67
- raise MalformedFile unless stripped_line.match(WELLFORMED_LINE_REGEXP)
62
+ raise MalformedFile unless stripped_line.match?(WELLFORMED_LINE_REGEXP)
68
63
 
69
64
  if (match = stripped_line.match(PACKAGE_NAME_REGEXP))
70
- package_name = match[1]
65
+ # Per the spec:
66
+ # > A new package Information section is denoted by the package name (7.1) field.
67
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
68
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
69
+
70
+ # reset for this new package
71
+ spdx_name = spdx_version = platform = purl_name = purl_version = nil
72
+
73
+ # capture the new package's name
74
+ spdx_package_name = match[1]
71
75
  elsif (match = stripped_line.match(PACKAGE_VERSION_REGEXP))
72
- package_version = match[1]
76
+ spdx_version = match[1]
73
77
  elsif (match = stripped_line.match(PURL_REGEXP))
74
- platform ||= get_platform(match[1])
78
+ purl = PackageURL.parse(match[1])
79
+ platform ||= purl.type
80
+ purl_name ||= PurlUtil.full_name(purl)
81
+ purl_version ||= purl.version
75
82
  end
83
+ end
76
84
 
77
- unless package_name.nil? || package_version.nil? || platform.nil?
78
- entries[platform.to_sym] ||= []
79
- entries[platform.to_sym] << Dependency.new(
80
- name: package_name,
81
- requirement: package_version,
82
- type: "lockfile",
83
- )
85
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
86
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
84
87
 
85
- package_name = package_version = platform = nil
86
- end
88
+ entries
89
+ end
90
+
91
+ def skip_tag_value_line?(stripped_line)
92
+ # Ignore blank lines and comments
93
+ stripped_line.empty? || stripped_line.start_with?("#")
94
+ end
95
+
96
+ def parse_spdx_json(file_contents, options: {})
97
+ entries = try_cache(options, options[:filename]) do
98
+ parse_spdx_json_file_contents(file_contents)
99
+ end
100
+
101
+ raise NoEntries if entries.empty?
102
+
103
+ entries[platform_name.to_sym]
104
+ end
105
+
106
+ def parse_spdx_json_file_contents(file_contents)
107
+ entries = {}
108
+ manifest = JSON.parse(file_contents)
109
+
110
+ manifest["packages"]&.each do |package|
111
+ spdx_name = package["name"]
112
+ spdx_version = package["versionInfo"]
113
+
114
+ first_purl_string = package.dig("externalRefs")&.find { |ref| ref["referenceType"] == "purl" }&.dig("referenceLocator")
115
+ purl = first_purl_string && PackageURL.parse(first_purl_string)
116
+ platform = purl&.type
117
+ purl_name = PurlUtil.full_name(purl)
118
+ purl_version = purl&.version
119
+
120
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
121
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version)
87
122
  end
88
123
 
89
124
  entries
90
125
  end
91
126
 
92
- def skip_line?(stripped_line)
93
- # Ignore blank lines and comments
94
- stripped_line == "" || stripped_line[0] == "#"
127
+ def add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:)
128
+ package_name = purl_name || spdx_name
129
+ package_version = purl_version || spdx_version
130
+
131
+ if platform && package_name && package_version
132
+ entries[platform.to_sym] ||= []
133
+ entries[platform.to_sym] << Dependency.new(
134
+ name: package_name,
135
+ requirement: package_version,
136
+ type: "lockfile"
137
+ )
138
+ end
95
139
  end
140
+
96
141
  end
97
142
  end
98
143
  end
@@ -1,5 +1,4 @@
1
1
  require "ox"
2
- require "strings-ansi"
3
2
 
4
3
  # Known shortcomings and unimplemented Maven features:
5
4
  # pom.xml
@@ -57,6 +56,27 @@ module Bibliothecary
57
56
  # e.g. "[info] "
58
57
  SBT_IGNORE_REGEXP = /^\[info\]\s*$/
59
58
 
59
+
60
+ # Copied from the "strings-ansi" gem, because it seems abandoned: https://github.com/piotrmurach/strings-ansi/pull/2
61
+ # From: https://github.com/piotrmurach/strings-ansi/blob/35d0c9430cf0a8022dc12bdab005bce296cb9f00/lib/strings/ansi.rb#L14-L29
62
+ # License: MIT
63
+ # The regex to match ANSI codes
64
+ ANSI_MATCHER = %r{
65
+ (?>\033(
66
+ \[[\[?>!]?\d*(;\d+)*[ ]?[a-zA-Z~@$^\]_\{\\] # graphics
67
+ |
68
+ \#?\d # cursor modes
69
+ |
70
+ [)(%+\-*/. ](\d|[a-zA-Z@=%]|) # character sets
71
+ |
72
+ O[p-xA-Z] # special keys
73
+ |
74
+ [a-zA-Z=><~\}|] # cursor movement
75
+ |
76
+ \]8;[^;]*;.*?(\033\\|\07) # hyperlink
77
+ ))
78
+ }x.freeze
79
+
60
80
  def self.mapping
61
81
  {
62
82
  match_filename("ivy.xml", case_insensitive: true) => {
@@ -218,7 +238,8 @@ module Bibliothecary
218
238
  end
219
239
 
220
240
  def self.parse_maven_resolved(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
221
- Strings::ANSI.sanitize(file_contents)
241
+ file_contents
242
+ .gsub(ANSI_MATCHER, "")
222
243
  .split("\n")
223
244
  .map(&method(:parse_resolved_dep_line))
224
245
  .compact
@@ -226,7 +247,8 @@ module Bibliothecary
226
247
  end
227
248
 
228
249
  def self.parse_maven_tree(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
229
- captures = Strings::ANSI.sanitize(file_contents)
250
+ captures = file_contents
251
+ .gsub(ANSI_MATCHER, "")
230
252
  .gsub(/\r\n?/, "\n")
231
253
  .scan(/^\[INFO\](?:(?:\+-)|\||(?:\\-)|\s)+((?:[\w\.-]+:)+[\w\.\-${}]+)/)
232
254
  .flatten
@@ -1,21 +1,39 @@
1
1
  module Bibliothecary
2
- # If a purl type (key) exists, it will be used in a manifest for
3
- # the key's value. If not, it's ignored.
4
- #
5
- # https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst
6
- PURL_TYPE_MAPPING = {
7
- "golang" => :go,
8
- "maven" => :maven,
9
- "npm" => :npm,
10
- "cargo" => :cargo,
11
- "composer" => :packagist,
12
- "conda" => :conda,
13
- "cran" => :cran,
14
- "gem" => :rubygems,
15
- "hackage" => :hackage,
16
- "hex" => :hex,
17
- "nuget" => :nuget,
18
- "pypi" => :pypi,
19
- "swift" => :swift_pm,
20
- }.freeze
2
+ class PurlUtil
3
+ # If a purl type (key) exists, it will be used in a manifest for
4
+ # the key's value. If not, it's ignored.
5
+ #
6
+ # https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst
7
+ PURL_TYPE_MAPPING = {
8
+ "golang" => :go,
9
+ "maven" => :maven,
10
+ "npm" => :npm,
11
+ "cargo" => :cargo,
12
+ "composer" => :packagist,
13
+ "conda" => :conda,
14
+ "cran" => :cran,
15
+ "gem" => :rubygems,
16
+ "hackage" => :hackage,
17
+ "hex" => :hex,
18
+ "nuget" => :nuget,
19
+ "pypi" => :pypi,
20
+ "swift" => :swift_pm,
21
+ }.freeze
22
+
23
+
24
+ # @param purl [PackageURL]
25
+ # @return [String] The properly namespaced package name
26
+ def self.full_name(purl)
27
+ return nil if purl.nil?
28
+
29
+ parts = [purl.namespace, purl.name].compact
30
+
31
+ case purl.type
32
+ when "maven"
33
+ parts.join(":")
34
+ else
35
+ parts.join("/")
36
+ end
37
+ end
38
+ end
21
39
  end
@@ -1,3 +1,3 @@
1
1
  module Bibliothecary
2
- VERSION = "10.2.0"
2
+ VERSION = "10.2.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bibliothecary
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.2.0
4
+ version: 10.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-27 00:00:00.000000000 Z
11
+ date: 2024-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tomlrb
@@ -108,34 +108,6 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: strings-ansi
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :runtime
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: strings
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
111
  - !ruby/object:Gem::Dependency
140
112
  name: packageurl-ruby
141
113
  requirement: !ruby/object:Gem::Requirement
@@ -266,7 +238,6 @@ files:
266
238
  - ".rubocop.yml"
267
239
  - ".ruby-version"
268
240
  - ".tidelift.yml"
269
- - ".travis.yml"
270
241
  - CHANGELOG.md
271
242
  - CODE_OF_CONDUCT.md
272
243
  - Gemfile
@@ -277,7 +248,6 @@ files:
277
248
  - bin/bibliothecary
278
249
  - bin/console
279
250
  - bin/setup
280
- - dependencyci.yml
281
251
  - lib/bibliothecary.rb
282
252
  - lib/bibliothecary/analyser.rb
283
253
  - lib/bibliothecary/analyser/analysis.rb
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.6.6
4
- cache: bundler
5
- before_install:
6
- - gem update --system
7
- - gem install bundler
8
- script:
9
- - bundle exec rake spec && bundle exec codeclimate-test-reporter
10
- notifications:
11
- slack:
12
- secure: MkuDOE57uFrypxJGB7fy6Mq7uT77SzC3ApXVbdpx8k+4ihwLK+7Gyn0IzJ0f24B9PprH2RzmFoHk6XPjSjVCAEoCHvuv2ntHPX3FqxkBXdkb3NjKjOvV1+rRt9D+3sG6IEY5M5ak7j34W0FGgczNQs3+IOGCs3NIJP/h2mAL02w8oZFU2LMGYY6gX7LL+z4q65Ag5mDMwN9kslmWELO7k8xLPunlCh9jRWbZpxzFKwsHC4HtygejWwijNlSAt6Rk2XaPJ4jR8PO8uvWR1+iXxOVFErZ/nriybYMdThpLUdLWWHn6n+a3lu9vpo0KtnMrVq/E5KSaM1bilKxTuFR35AU9kbMv2L9cs65sRz1rSa2CnfN+788icesDyePh6ZjDOb+5zvxOViDvoEc9cIogf6JJT8hDpvF0zDqEuU+CTvh+3AqRGS7yjlsviQZofB8Fr/VMjZzuHL45T1+4O46eryO1PZpNYlq9svLRgpkdmu5A+SFwlM2K7Zc4ND5GSlCnWdGx1ThBp1u1lFYvw2IMeU5bylS+ak4xt+S2YH5Hmc0y7F0nvB54mmap8T7GGc7dFhLaLTaTTijHF70HJgsDKCnPsRqk5Bt2h7grBMT6t9AG+6Hg0QVFJ4ZSfnM2IBb57naVhUpMFjYT9fnLrjIAg9rY1GW6kkowFdoj6mvFhAM=
data/dependencyci.yml DELETED
@@ -1,9 +0,0 @@
1
- platforms:
2
- NPM:
3
- jade:
4
- tests:
5
- deprecated: skip
6
- NuGet:
7
- tests:
8
- unlicensed: skip
9
- removed: skip