bibliothecary 4.0.4 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +25 -0
- data/.github/CONTRIBUTING.md +165 -0
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +4 -1
- data/Gemfile +5 -0
- data/README.md +7 -1
- data/bibliothecary.gemspec +1 -1
- data/lib/bibliothecary.rb +16 -2
- data/lib/bibliothecary/analyser.rb +28 -4
- data/lib/bibliothecary/parsers/bower.rb +7 -10
- data/lib/bibliothecary/parsers/cargo.rb +9 -31
- data/lib/bibliothecary/parsers/carthage.rb +13 -34
- data/lib/bibliothecary/parsers/clojars.rb +4 -7
- data/lib/bibliothecary/parsers/cocoapods.rb +19 -30
- data/lib/bibliothecary/parsers/cpan.rb +10 -15
- data/lib/bibliothecary/parsers/cran.rb +7 -10
- data/lib/bibliothecary/parsers/dub.rb +7 -12
- data/lib/bibliothecary/parsers/elm.rb +7 -47
- data/lib/bibliothecary/parsers/go.rb +47 -52
- data/lib/bibliothecary/parsers/hex.rb +5 -14
- data/lib/bibliothecary/parsers/julia.rb +4 -7
- data/lib/bibliothecary/parsers/maven.rb +12 -18
- data/lib/bibliothecary/parsers/meteor.rb +6 -9
- data/lib/bibliothecary/parsers/npm.rb +15 -14
- data/lib/bibliothecary/parsers/nuget.rb +18 -28
- data/lib/bibliothecary/parsers/packagist.rb +9 -14
- data/lib/bibliothecary/parsers/pub.rb +9 -14
- data/lib/bibliothecary/parsers/pypi.rb +8 -10
- data/lib/bibliothecary/parsers/rubygems.rb +16 -23
- data/lib/bibliothecary/parsers/shard.rb +9 -14
- data/lib/bibliothecary/parsers/swift_pm.rb +4 -7
- data/lib/bibliothecary/version.rb +1 -1
- data/lib/sdl_parser.rb +0 -4
- metadata +9 -5
- data/CONTRIBUTING.md +0 -10
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Bibliothecary
|
2
2
|
|
3
|
-
Dependency manifest parsing
|
3
|
+
Dependency manifest parsing library for https://libraries.io
|
4
|
+
|
5
|
+
[![Build Status](https://travis-ci.org/librariesio/bibliothecary.svg?branch=master)](https://travis-ci.org/librariesio/bibliothecary)
|
6
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/librariesio/bibliothecary.svg?style=flat)](https://codeclimate.com/github/librariesio/bibliothecary)
|
7
|
+
[![Test Coverage](https://img.shields.io/codeclimate/coverage/github/librariesio/bibliothecary.svg?style=flat)](https://codeclimate.com/github/librariesio/bibliothecary)
|
8
|
+
[![Code Climate](https://img.shields.io/codeclimate/issues/github/librariesio/bibliothecary.svg)](https://codeclimate.com/github/librariesio/bibliothecary/issues)
|
9
|
+
[![license](https://img.shields.io/github/license/librariesio/bibliothecary.svg)](https://github.com/librariesio/bibliothecary/blob/master/LICENSE.txt)
|
4
10
|
|
5
11
|
## Installation
|
6
12
|
|
data/bibliothecary.gemspec
CHANGED
@@ -26,6 +26,6 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_dependency "sdl4r"
|
27
27
|
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.11"
|
29
|
-
spec.add_development_dependency "rake", "~>
|
29
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
30
30
|
spec.add_development_dependency "rspec", "~> 3.0"
|
31
31
|
end
|
data/lib/bibliothecary.rb
CHANGED
@@ -8,15 +8,29 @@ end
|
|
8
8
|
module Bibliothecary
|
9
9
|
def self.analyse(path)
|
10
10
|
cmd = `find #{path} -type f | grep -vE "#{ignored_files}"`
|
11
|
-
file_list = cmd.split("\n")
|
11
|
+
file_list = cmd.split("\n").sort
|
12
12
|
package_managers.map{|pm| pm.analyse(path, file_list) }.flatten.compact
|
13
13
|
end
|
14
14
|
|
15
|
+
def self.analyse_file(file_path, contents)
|
16
|
+
package_managers.map do |pm|
|
17
|
+
pm.analyse_contents(file_path, contents)
|
18
|
+
end.flatten.uniq.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.identify_manifests(file_list)
|
22
|
+
package_managers.map do |pm|
|
23
|
+
file_list.select do |file_path|
|
24
|
+
pm.match?(file_path)
|
25
|
+
end
|
26
|
+
end.flatten.uniq.compact
|
27
|
+
end
|
28
|
+
|
15
29
|
def self.package_managers
|
16
30
|
Bibliothecary::Parsers.constants.map{|c| Bibliothecary::Parsers.const_get(c) }.sort_by{|c| c.to_s.downcase }
|
17
31
|
end
|
18
32
|
|
19
33
|
def self.ignored_files
|
20
|
-
['.git', 'node_modules', 'bower_components'].join('|')
|
34
|
+
['.git', 'node_modules', 'bower_components', 'spec/fixtures', 'vendor/bundle'].join('|')
|
21
35
|
end
|
22
36
|
end
|
@@ -4,6 +4,19 @@ module Bibliothecary
|
|
4
4
|
base.extend(ClassMethods)
|
5
5
|
end
|
6
6
|
module ClassMethods
|
7
|
+
def parse_file(filename, contents)
|
8
|
+
mapping.each do |regex, method_name|
|
9
|
+
if filename.match(regex)
|
10
|
+
return send(method_name, contents)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
return []
|
14
|
+
end
|
15
|
+
|
16
|
+
def match?(filename)
|
17
|
+
mapping.keys.any?{|regex| filename.match(regex) }
|
18
|
+
end
|
19
|
+
|
7
20
|
def platform_name
|
8
21
|
self.name.to_s.split('::').last.downcase
|
9
22
|
end
|
@@ -11,17 +24,18 @@ module Bibliothecary
|
|
11
24
|
def analyse(folder_path, file_list)
|
12
25
|
file_list.map do |path|
|
13
26
|
filename = path.gsub(folder_path, '').gsub(/^\//, '')
|
14
|
-
|
27
|
+
contents = File.open(path).read
|
28
|
+
analyse_contents(filename, contents)
|
15
29
|
end.compact
|
16
30
|
end
|
17
31
|
|
18
|
-
def
|
32
|
+
def analyse_contents(filename, contents)
|
19
33
|
begin
|
20
|
-
dependencies =
|
34
|
+
dependencies = parse_file(filename, contents)
|
21
35
|
if dependencies.any?
|
22
36
|
{
|
23
37
|
platform: platform_name,
|
24
|
-
path:
|
38
|
+
path: filename,
|
25
39
|
dependencies: dependencies
|
26
40
|
}
|
27
41
|
else
|
@@ -31,6 +45,16 @@ module Bibliothecary
|
|
31
45
|
nil
|
32
46
|
end
|
33
47
|
end
|
48
|
+
|
49
|
+
def parse_ruby_manifest(manifest)
|
50
|
+
manifest.dependencies.inject([]) do |deps, dep|
|
51
|
+
deps.push({
|
52
|
+
name: dep.name,
|
53
|
+
requirement: dep.requirement.to_s,
|
54
|
+
type: dep.type
|
55
|
+
})
|
56
|
+
end.uniq
|
57
|
+
end
|
34
58
|
end
|
35
59
|
end
|
36
60
|
end
|
@@ -5,19 +5,16 @@ module Bibliothecary
|
|
5
5
|
class Bower
|
6
6
|
include Bibliothecary::Analyser
|
7
7
|
|
8
|
-
def self.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
parse_manifest(json)
|
13
|
-
else
|
14
|
-
[]
|
15
|
-
end
|
8
|
+
def self.mapping
|
9
|
+
{
|
10
|
+
/^bower\.json$/ => :parse_manifest
|
11
|
+
}
|
16
12
|
end
|
17
13
|
|
18
14
|
def self.parse_manifest(manifest)
|
19
|
-
|
20
|
-
map_dependencies(
|
15
|
+
json = JSON.parse(manifest)
|
16
|
+
map_dependencies(json, 'dependencies', 'runtime') +
|
17
|
+
map_dependencies(json, 'devDependencies', 'development')
|
21
18
|
end
|
22
19
|
|
23
20
|
def self.map_dependencies(hash, key, type)
|
@@ -5,21 +5,15 @@ module Bibliothecary
|
|
5
5
|
class Cargo
|
6
6
|
include Bibliothecary::Analyser
|
7
7
|
|
8
|
-
def self.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
elsif filename.match(/Cargo\.lock$/)
|
14
|
-
file_contents = File.open(path).read
|
15
|
-
toml = TOML.parse(file_contents)
|
16
|
-
parse_lockfile(toml)
|
17
|
-
else
|
18
|
-
[]
|
19
|
-
end
|
8
|
+
def self.mapping
|
9
|
+
{
|
10
|
+
/Cargo\.toml$/ => :parse_manifest,
|
11
|
+
/Cargo\.lock$/ => :parse_lockfile
|
12
|
+
}
|
20
13
|
end
|
21
14
|
|
22
|
-
def self.parse_manifest(
|
15
|
+
def self.parse_manifest(file_contents)
|
16
|
+
manifest = TOML.parse(file_contents)
|
23
17
|
manifest.fetch('dependencies', []).map do |name, requirement|
|
24
18
|
if requirement.respond_to?(:fetch)
|
25
19
|
requirement = requirement['version'] or next
|
@@ -33,24 +27,8 @@ module Bibliothecary
|
|
33
27
|
.compact
|
34
28
|
end
|
35
29
|
|
36
|
-
def self.
|
37
|
-
|
38
|
-
return unless paths.any?
|
39
|
-
|
40
|
-
paths.map do |path|
|
41
|
-
manifest = TOML.load_file(path)
|
42
|
-
|
43
|
-
{
|
44
|
-
platform: PLATFORM_NAME,
|
45
|
-
path: path,
|
46
|
-
dependencies: parse_lockfile(manifest)
|
47
|
-
}
|
48
|
-
end
|
49
|
-
rescue
|
50
|
-
[]
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.parse_lockfile(manifest)
|
30
|
+
def self.parse_lockfile(file_contents)
|
31
|
+
manifest = TOML.parse(file_contents)
|
54
32
|
manifest.fetch('package',[]).map do |dependency|
|
55
33
|
next if not dependency['source'] or not dependency['source'].start_with?('registry+')
|
56
34
|
{
|
@@ -3,49 +3,28 @@ module Bibliothecary
|
|
3
3
|
class Carthage
|
4
4
|
include Bibliothecary::Analyser
|
5
5
|
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
parse_cartfile_private(file_contents)
|
13
|
-
elsif filename.match(/^Cartfile\.resolved$/)
|
14
|
-
file_contents = File.open(path).read
|
15
|
-
parse_cartfile_resolved(file_contents)
|
16
|
-
else
|
17
|
-
[]
|
18
|
-
end
|
6
|
+
def self.mapping
|
7
|
+
{
|
8
|
+
/^Cartfile$/ => :parse_cartfile,
|
9
|
+
/^Cartfile\.private$/ => :parse_cartfile_private,
|
10
|
+
/^Cartfile\.resolved$/ => :parse_cartfile_resolved
|
11
|
+
}
|
19
12
|
end
|
20
13
|
|
21
14
|
def self.parse_cartfile(manifest)
|
22
|
-
|
23
|
-
json = JSON.parse(response.body)
|
24
|
-
|
25
|
-
json.map do |dependency|
|
26
|
-
{
|
27
|
-
name: dependency['name'],
|
28
|
-
version: dependency['version'],
|
29
|
-
type: dependency["type"]
|
30
|
-
}
|
31
|
-
end
|
15
|
+
map_dependencies(manifest, 'cartfile')
|
32
16
|
end
|
33
17
|
|
34
18
|
def self.parse_cartfile_private(manifest)
|
35
|
-
|
36
|
-
json = JSON.parse(response.body)
|
37
|
-
|
38
|
-
json.map do |dependency|
|
39
|
-
{
|
40
|
-
name: dependency['name'],
|
41
|
-
version: dependency['version'],
|
42
|
-
type: dependency["type"]
|
43
|
-
}
|
44
|
-
end
|
19
|
+
map_dependencies(manifest, 'cartfile.private')
|
45
20
|
end
|
46
21
|
|
47
22
|
def self.parse_cartfile_resolved(manifest)
|
48
|
-
|
23
|
+
map_dependencies(manifest, 'cartfile.resolved')
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.map_dependencies(manifest, path)
|
27
|
+
response = Typhoeus.post("https://carthageparser.herokuapp.com/#{path}", params: {body: manifest})
|
49
28
|
json = JSON.parse(response.body)
|
50
29
|
|
51
30
|
json.map do |dependency|
|
@@ -6,13 +6,10 @@ module Bibliothecary
|
|
6
6
|
class Clojars
|
7
7
|
include Bibliothecary::Analyser
|
8
8
|
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
[]
|
15
|
-
end
|
9
|
+
def self.mapping
|
10
|
+
{
|
11
|
+
/^project\.clj$/ => :parse_manifest
|
12
|
+
}
|
16
13
|
end
|
17
14
|
|
18
15
|
def self.parse_manifest(manifest)
|
@@ -9,29 +9,17 @@ module Bibliothecary
|
|
9
9
|
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'.freeze
|
10
10
|
NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
|
11
11
|
|
12
|
-
def self.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
manifest = Gemnasium::Parser.send(:podspec, file_contents)
|
20
|
-
parse_manifest(manifest)
|
21
|
-
elsif filename.match(/^Podfile\.lock$/)
|
22
|
-
file_contents = File.open(path).read
|
23
|
-
manifest = YAML.load file_contents
|
24
|
-
parse_podfile_lock(manifest)
|
25
|
-
elsif filename.match(/^[A-Za-z0-9_-]+\.podspec.json$/)
|
26
|
-
file_contents = File.open(path).read
|
27
|
-
json = JSON.parse(file_contents)
|
28
|
-
parse_json_manifest(json)
|
29
|
-
else
|
30
|
-
[]
|
31
|
-
end
|
12
|
+
def self.mapping
|
13
|
+
{
|
14
|
+
/^Podfile$/ => :parse_podfile,
|
15
|
+
/^[A-Za-z0-9_-]+\.podspec$/ => :parse_podspec,
|
16
|
+
/^Podfile\.lock$/ => :parse_podfile_lock,
|
17
|
+
/^[A-Za-z0-9_-]+\.podspec.json$/ => :parse_json_manifest
|
18
|
+
}
|
32
19
|
end
|
33
20
|
|
34
|
-
def self.parse_podfile_lock(
|
21
|
+
def self.parse_podfile_lock(file_contents)
|
22
|
+
manifest = YAML.load file_contents
|
35
23
|
manifest['PODS'].map do |row|
|
36
24
|
pod = row.is_a?(String) ? row : row.keys.first
|
37
25
|
match = pod.match(/(.+?)\s\((.+?)\)/i)
|
@@ -43,17 +31,18 @@ module Bibliothecary
|
|
43
31
|
end.compact
|
44
32
|
end
|
45
33
|
|
46
|
-
def self.
|
47
|
-
manifest.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
34
|
+
def self.parse_podspec(file_contents)
|
35
|
+
manifest = Gemnasium::Parser.send(:podspec, file_contents)
|
36
|
+
parse_ruby_manifest(manifest)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.parse_podfile(file_contents)
|
40
|
+
manifest = Gemnasium::Parser.send(:podfile, file_contents)
|
41
|
+
parse_ruby_manifest(manifest)
|
54
42
|
end
|
55
43
|
|
56
|
-
def self.parse_json_manifest(
|
44
|
+
def self.parse_json_manifest(file_contents)
|
45
|
+
manifest = JSON.parse(file_contents)
|
57
46
|
manifest['dependencies'].inject([]) do |deps, dep|
|
58
47
|
deps.push({
|
59
48
|
name: dep[0],
|
@@ -6,27 +6,22 @@ module Bibliothecary
|
|
6
6
|
class CPAN
|
7
7
|
include Bibliothecary::Analyser
|
8
8
|
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
elsif filename.match(/^META\.yml$/i)
|
15
|
-
file_contents = File.open(path).read
|
16
|
-
yaml = YAML.load file_contents
|
17
|
-
parse_yaml_manifest(yaml)
|
18
|
-
else
|
19
|
-
[]
|
20
|
-
end
|
9
|
+
def self.mapping
|
10
|
+
{
|
11
|
+
/^META\.json$/i => :parse_json_manifest,
|
12
|
+
/^META\.yml$/i => :parse_yaml_manifest
|
13
|
+
}
|
21
14
|
end
|
22
15
|
|
23
|
-
def self.parse_json_manifest(
|
24
|
-
manifest
|
16
|
+
def self.parse_json_manifest(file_contents)
|
17
|
+
manifest = JSON.parse file_contents
|
18
|
+
manifest['prereqs'].map do |_group, deps|
|
25
19
|
map_dependencies(deps, 'requires', 'runtime')
|
26
20
|
end.flatten
|
27
21
|
end
|
28
22
|
|
29
|
-
def self.parse_yaml_manifest(
|
23
|
+
def self.parse_yaml_manifest(file_contents)
|
24
|
+
manifest = YAML.load file_contents
|
30
25
|
map_dependencies(manifest, 'requires', 'runtime')
|
31
26
|
end
|
32
27
|
|
@@ -7,17 +7,14 @@ module Bibliothecary
|
|
7
7
|
|
8
8
|
REQUIRE_REGEXP = /([a-zA-Z0-9\-_\.]+)\s?\(?([><=\s\d\.,]+)?\)?/
|
9
9
|
|
10
|
-
def self.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
parse_description(control)
|
15
|
-
else
|
16
|
-
[]
|
17
|
-
end
|
10
|
+
def self.mapping
|
11
|
+
{
|
12
|
+
/^DESCRIPTION$/i => :parse_description
|
13
|
+
}
|
18
14
|
end
|
19
15
|
|
20
|
-
def self.parse_description(
|
16
|
+
def self.parse_description(file_contents)
|
17
|
+
manifest = DebControl::ControlFileBase.parse(file_contents)
|
21
18
|
parse_section(manifest, 'Depends') +
|
22
19
|
parse_section(manifest, 'Imports') +
|
23
20
|
parse_section(manifest, 'Suggests') +
|
@@ -26,7 +23,7 @@ module Bibliothecary
|
|
26
23
|
|
27
24
|
def self.parse_section(manifest, name)
|
28
25
|
return [] unless manifest.first[name]
|
29
|
-
deps = manifest.first[name].
|
26
|
+
deps = manifest.first[name].delete("\n").split(',').map(&:strip)
|
30
27
|
deps.map do |dependency|
|
31
28
|
dep = dependency.match(REQUIRE_REGEXP)
|
32
29
|
{
|
@@ -6,20 +6,15 @@ module Bibliothecary
|
|
6
6
|
class Dub
|
7
7
|
include Bibliothecary::Analyser
|
8
8
|
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
elsif filename.match(/^dub\.sdl$/)
|
15
|
-
file_contents = File.open(path).read
|
16
|
-
parse_sdl_manifest(file_contents)
|
17
|
-
else
|
18
|
-
[]
|
19
|
-
end
|
9
|
+
def self.mapping
|
10
|
+
{
|
11
|
+
/^dub\.json$/ => :parse_manifest,
|
12
|
+
/^dub\.sdl$/ => :parse_sdl_manifest
|
13
|
+
}
|
20
14
|
end
|
21
15
|
|
22
|
-
def self.parse_manifest(
|
16
|
+
def self.parse_manifest(file_contents)
|
17
|
+
manifest = JSON.parse(file_contents)
|
23
18
|
map_dependencies(manifest, 'dependencies', 'runtime')
|
24
19
|
end
|
25
20
|
|