bibliothecary 4.0.4 → 5.0.0

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +25 -0
  3. data/.github/CONTRIBUTING.md +165 -0
  4. data/.github/ISSUE_TEMPLATE.md +18 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  6. data/.rubocop.yml +1156 -0
  7. data/.travis.yml +4 -1
  8. data/Gemfile +5 -0
  9. data/README.md +7 -1
  10. data/bibliothecary.gemspec +1 -1
  11. data/lib/bibliothecary.rb +16 -2
  12. data/lib/bibliothecary/analyser.rb +28 -4
  13. data/lib/bibliothecary/parsers/bower.rb +7 -10
  14. data/lib/bibliothecary/parsers/cargo.rb +9 -31
  15. data/lib/bibliothecary/parsers/carthage.rb +13 -34
  16. data/lib/bibliothecary/parsers/clojars.rb +4 -7
  17. data/lib/bibliothecary/parsers/cocoapods.rb +19 -30
  18. data/lib/bibliothecary/parsers/cpan.rb +10 -15
  19. data/lib/bibliothecary/parsers/cran.rb +7 -10
  20. data/lib/bibliothecary/parsers/dub.rb +7 -12
  21. data/lib/bibliothecary/parsers/elm.rb +7 -47
  22. data/lib/bibliothecary/parsers/go.rb +47 -52
  23. data/lib/bibliothecary/parsers/hex.rb +5 -14
  24. data/lib/bibliothecary/parsers/julia.rb +4 -7
  25. data/lib/bibliothecary/parsers/maven.rb +12 -18
  26. data/lib/bibliothecary/parsers/meteor.rb +6 -9
  27. data/lib/bibliothecary/parsers/npm.rb +15 -14
  28. data/lib/bibliothecary/parsers/nuget.rb +18 -28
  29. data/lib/bibliothecary/parsers/packagist.rb +9 -14
  30. data/lib/bibliothecary/parsers/pub.rb +9 -14
  31. data/lib/bibliothecary/parsers/pypi.rb +8 -10
  32. data/lib/bibliothecary/parsers/rubygems.rb +16 -23
  33. data/lib/bibliothecary/parsers/shard.rb +9 -14
  34. data/lib/bibliothecary/parsers/swift_pm.rb +4 -7
  35. data/lib/bibliothecary/version.rb +1 -1
  36. data/lib/sdl_parser.rb +0 -4
  37. metadata +9 -5
  38. data/CONTRIBUTING.md +0 -10
data/.travis.yml CHANGED
@@ -1,4 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
3
+ - 2.3.3
4
+ - 2.4.0
4
5
  cache: bundler
6
+ script:
7
+ - bundle exec rake spec && bundle exec codeclimate-test-reporter
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bibliothecary.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "simplecov"
8
+ gem "codeclimate-test-reporter", "~> 1.0.0"
9
+ end
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Bibliothecary
2
2
 
3
- Dependency manifest parsing service for https://libraries.io in Ruby
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
 
@@ -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", "~> 11.0"
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
- analyse_file(filename, path)
27
+ contents = File.open(path).read
28
+ analyse_contents(filename, contents)
15
29
  end.compact
16
30
  end
17
31
 
18
- def analyse_file(filename, path)
32
+ def analyse_contents(filename, contents)
19
33
  begin
20
- dependencies = parse(filename, path)
34
+ dependencies = parse_file(filename, contents)
21
35
  if dependencies.any?
22
36
  {
23
37
  platform: platform_name,
24
- path: 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.parse(filename, path)
9
- if filename.match(/^bower\.json$/)
10
- file_contents = File.open(path).read
11
- json = JSON.parse(file_contents)
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
- map_dependencies(manifest, 'dependencies', 'runtime') +
20
- map_dependencies(manifest, 'devDependencies', 'development')
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.parse(filename, path)
9
- if filename.match(/Cargo\.toml$/)
10
- file_contents = File.open(path).read
11
- toml = TOML.parse(file_contents)
12
- parse_manifest(toml)
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(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.analyse_cargo_lock(folder_path, file_list)
37
- paths = file_list.select{|path| path.gsub(folder_path, '').gsub(/^\//, '').match(/Cargo\.lock$/) }
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.parse(filename, path)
7
- if filename.match(/^Cartfile$/)
8
- file_contents = File.open(path).read
9
- parse_cartfile(file_contents)
10
- elsif filename.match(/^Cartfile\.private$/)
11
- file_contents = File.open(path).read
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
- response = Typhoeus.post("https://carthageparser.herokuapp.com/cartfile", params: {body: manifest})
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
- response = Typhoeus.post("https://carthageparser.herokuapp.com/cartfile.private", params: {body: manifest})
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
- response = Typhoeus.post("https://carthageparser.herokuapp.com/cartfile.resolved", params: {body: manifest})
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.parse(filename, path)
10
- if filename.match(/^project\.clj$/)
11
- file_contents = File.open(path).read
12
- parse_manifest(file_contents)
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.parse(filename, path)
13
- if filename.match(/^Podfile$/)
14
- file_contents = File.open(path).read
15
- manifest = Gemnasium::Parser.send(:podfile, file_contents)
16
- parse_manifest(manifest)
17
- elsif filename.match(/^[A-Za-z0-9_-]+\.podspec$/)
18
- file_contents = File.open(path).read
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(manifest)
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.parse_manifest(manifest)
47
- manifest.dependencies.inject([]) do |deps, dep|
48
- deps.push({
49
- name: dep.name,
50
- requirement: dep.requirement.to_s,
51
- type: dep.type
52
- })
53
- end.uniq
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(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.parse(filename, path)
10
- if filename.match(/^META\.json$/i)
11
- file_contents = File.open(path).read
12
- json = JSON.parse file_contents
13
- parse_json_manifest(json)
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(manifest)
24
- manifest['prereqs'].map do |group, deps|
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(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.parse(filename, path)
11
- if filename.match(/^DESCRIPTION$/i)
12
- file_contents = File.open(path).read
13
- control = DebControl::ControlFileBase.parse(file_contents)
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(manifest)
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].gsub("\n", '').split(',').map(&:strip)
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.parse(filename, path)
10
- if filename.match(/^dub\.json$/)
11
- file_contents = File.open(path).read
12
- json = JSON.parse(file_contents)
13
- parse_manifest(json)
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(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