bibliothecary 7.2.1 → 7.3.3

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: ba740dd30abb75fb073f3160d963a970ffa41099966e86a38558fc50c515c9bf
4
- data.tar.gz: 19de22f64f4390acd0c15781283d1089c85459aa989393485ab25337e246ef01
3
+ metadata.gz: bb1338bc28ebb3dde8a6bdb5037f000176b9d759aa391319e74cbc85a35bd0ad
4
+ data.tar.gz: 8acc8a5acddd673c79680cefe8f0af6e325fd21905eb82da8751a01df81dac2c
5
5
  SHA512:
6
- metadata.gz: 9f7f301227e79af9a7f3bafc5484e39426c9d5faee1ee1c6a97f4173d6b438def08cf36ea3a8eedaa06d9ce0741ee6bf012b7aba1a972680c79b397ac57a1ac9
7
- data.tar.gz: 11bbaf66d5dcb32b042923abf85be353d96a6d1f09c1e641e0c40df215d9f70347e56b4d7afe81b5bb27a685318667c7c53d2ba24a2961e2a4dad72ad1c90273
6
+ metadata.gz: b078d0d7b486f79911d2f4426c431fc61353d6f326e173faaa7b3a6154cbb8dd77f1d0e0e0ceca50e78ed646cded4490e22a2dc7f324d8d041276b41e430952d
7
+ data.tar.gz: e6bb42ee137c6e9a5eeeee0f375c2a6362e822af1011ad6f92d101d7f1b4d7c9ea8dee04925846e5efd3ea553d0e57f6fde4c1e678d7cb8aaa07eab458d00fed
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
@@ -25,6 +25,10 @@ module Bibliothecary
25
25
  base.extend(ClassMethods)
26
26
  end
27
27
  module ClassMethods
28
+ def generic?
29
+ platform_name == "generic"
30
+ end
31
+
28
32
  def mapping_entry_match?(matcher, details, info)
29
33
  if matcher.call(info.relative_path)
30
34
  # we only want to load contents if we don't have them already
@@ -119,13 +123,32 @@ module Bibliothecary
119
123
  end
120
124
  alias analyze_contents analyse_contents
121
125
 
126
+ def dependencies_to_analysis(info, kind, dependencies)
127
+ dependencies = dependencies || [] # work around any legacy parsers that return nil
128
+ if generic?
129
+ analyses = []
130
+ grouped = dependencies.group_by { |dep| dep[:platform] }
131
+ all_analyses = grouped.keys.map do |platform|
132
+ deplatformed_dependencies = grouped[platform].map { |d| d.delete(:platform); d }
133
+ Bibliothecary::Analyser::create_analysis(platform, info.relative_path, kind, deplatformed_dependencies)
134
+ end
135
+ # this is to avoid a larger refactor for the time being. The larger refactor
136
+ # needs to make analyse_contents return multiple analysis, or add another
137
+ # method that can return multiple and deprecate analyse_contents, perhaps.
138
+ raise "File contains zero or multiple platforms, currently must have exactly one" if all_analyses.length != 1
139
+ all_analyses.first
140
+ else
141
+ Bibliothecary::Analyser::create_analysis(platform_name, info.relative_path, kind, dependencies)
142
+ end
143
+ end
144
+
122
145
  def analyse_contents_from_info(info)
123
146
  # If your Parser needs to return multiple responses for one file, please override this method
124
147
  # For example see conda.rb
125
148
  kind = determine_kind_from_info(info)
126
149
  dependencies = parse_file(info.relative_path, info.contents)
127
150
 
128
- Bibliothecary::Analyser::create_analysis(platform_name, info.relative_path, kind, dependencies || [])
151
+ dependencies_to_analysis(info, kind, dependencies)
129
152
  rescue Bibliothecary::FileParsingError => e
130
153
  Bibliothecary::Analyser::create_error_analysis(platform_name, info.relative_path, kind, e.message)
131
154
  end
@@ -0,0 +1,39 @@
1
+ require 'csv'
2
+
3
+ module Bibliothecary
4
+ module Parsers
5
+ class Generic
6
+ include Bibliothecary::Analyser
7
+
8
+ def self.mapping
9
+ {
10
+ match_filename("dependencies.csv") => {
11
+ kind: 'lockfile',
12
+ parser: :parse_lockfile
13
+ }
14
+ }
15
+ end
16
+
17
+ def self.parse_lockfile(file_contents)
18
+ table = CSV.parse(file_contents, headers: true)
19
+
20
+ required_headers = ["platform", "name", "requirement"]
21
+ missing_headers = required_headers - table.headers
22
+ raise "Missing headers #{missing_headers} in CSV" unless missing_headers.empty?
23
+
24
+ table.map.with_index do |row, idx|
25
+ line = idx + 1
26
+ required_headers.each do |h|
27
+ raise "missing field '#{h}' on line #{line}" if row[h].empty?
28
+ end
29
+ {
30
+ platform: row['platform'],
31
+ name: row['name'],
32
+ requirement: row['requirement'],
33
+ type: row.fetch('type', 'runtime'),
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -127,10 +127,12 @@ module Bibliothecary
127
127
 
128
128
  split = gradle_dep_match.captures[0]
129
129
 
130
- # org.springframework.boot:spring-boot-starter-web:2.1.0.M3 (*)
131
- # Lines can end with (c), (n), or (*)
132
- # to indicate that something was a dependency constraint (c), not resolved (n), or resolved previously (*).
133
- dep = line.split(split)[1].sub(/(\((c|n|\*)\))$/, "").sub(" -> ", ":").strip.split(":")
130
+
131
+ dep = line
132
+ .split(split)[1].sub(/(\((c|n|\*)\))$/, "") # line ending legend: (c) means a dependency constraint, (n) means not resolved, or (*) means resolved previously, e.g. org.springframework.boot:spring-boot-starter-web:2.1.0.M3 (*)
133
+ .sub(/ FAILED$/, "") # dependency could not be resolved (but still may have a version)
134
+ .sub(" -> ", ":") # handle version arrow syntax
135
+ .strip.split(":")
134
136
 
135
137
  # A testImplementation line can look like this so just skip those
136
138
  # \--- org.springframework.security:spring-security-test (n)
@@ -5,6 +5,9 @@ module Bibliothecary
5
5
  class NPM
6
6
  include Bibliothecary::Analyser
7
7
 
8
+ # Max depth to recurse into the "dependencies" property of package-lock.json
9
+ PACKAGE_LOCK_JSON_MAX_DEPTH = 10
10
+
8
11
  def self.mapping
9
12
  {
10
13
  match_filename("package.json") => {
@@ -43,26 +46,25 @@ module Bibliothecary
43
46
 
44
47
  def self.parse_package_lock(file_contents)
45
48
  manifest = JSON.parse(file_contents)
46
- manifest.fetch('dependencies',[]).map do |name, requirement|
47
- if requirement.fetch("dev", false)
48
- type = 'development'
49
- else
50
- type = 'runtime'
51
- end
52
-
53
- version = nil
54
-
55
- if requirement.key?("from")
56
- version = requirement["from"][/#(?:semver:)?v?(.*)/, 1]
57
- end
49
+ parse_package_lock_deps_recursively(manifest.fetch('dependencies', []))
50
+ end
58
51
 
52
+ def self.parse_package_lock_deps_recursively(dependencies, depth=1)
53
+ dependencies.flat_map do |name, requirement|
54
+ type = requirement.fetch("dev", false) ? 'development' : 'runtime'
55
+ version = requirement.key?("from") ? requirement["from"][/#(?:semver:)?v?(.*)/, 1] : nil
59
56
  version ||= requirement["version"].split("#").last
57
+ child_dependencies = if depth >= PACKAGE_LOCK_JSON_MAX_DEPTH
58
+ []
59
+ else
60
+ parse_package_lock_deps_recursively(requirement.fetch('dependencies', []), depth + 1)
61
+ end
60
62
 
61
- {
63
+ [{
62
64
  name: name,
63
65
  requirement: version,
64
66
  type: type
65
- }
67
+ }] + child_dependencies
66
68
  end
67
69
  end
68
70
 
@@ -95,6 +97,18 @@ module Bibliothecary
95
97
  transform_tree_to_array(manifest.fetch('dependencies', {}))
96
98
  end
97
99
 
100
+ def self.lockfile_preference_order(file_infos)
101
+ files = file_infos.each_with_object({}) do |file_info, obj|
102
+ obj[File.basename(file_info.full_path)] = file_info
103
+ end
104
+
105
+ if files["npm-shrinkwrap.json"]
106
+ [files["npm-shrinkwrap.json"]] + files.values.reject { |fi| File.basename(fi.full_path) == "npm-shrinkwrap.json" }
107
+ else
108
+ files.values
109
+ end
110
+ end
111
+
98
112
  private_class_method def self.transform_tree_to_array(deps_by_name)
99
113
  deps_by_name.map do |name, metadata|
100
114
  [
@@ -19,6 +19,9 @@ module Bibliothecary
19
19
 
20
20
  def initialize(file_infos)
21
21
  package_manager = file_infos.first.package_manager
22
+ if package_manager.respond_to?(:lockfile_preference_order)
23
+ file_infos = package_manager.lockfile_preference_order(file_infos)
24
+ end
22
25
  @platform = package_manager.platform_name
23
26
  @path = Pathname.new(File.dirname(file_infos.first.relative_path)).cleanpath.to_path
24
27
  # `package_manager.determine_kind_from_info(info)` can be an Array, so use include? which also works for string
@@ -1,3 +1,3 @@
1
1
  module Bibliothecary
2
- VERSION = "7.2.1"
2
+ VERSION = "7.3.3"
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: 7.2.1
4
+ version: 7.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-15 00:00:00.000000000 Z
11
+ date: 2021-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tomlrb
@@ -251,6 +251,7 @@ files:
251
251
  - lib/bibliothecary/parsers/cran.rb
252
252
  - lib/bibliothecary/parsers/dub.rb
253
253
  - lib/bibliothecary/parsers/elm.rb
254
+ - lib/bibliothecary/parsers/generic.rb
254
255
  - lib/bibliothecary/parsers/go.rb
255
256
  - lib/bibliothecary/parsers/hackage.rb
256
257
  - lib/bibliothecary/parsers/haxelib.rb