bibliothecary 4.0.4 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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