spandx 0.1.1 → 0.1.2

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: 79b4eefa834b1649c1cced69cd4666bdabb22f42383cb177545042e3c643eac9
4
- data.tar.gz: e0c3e8836e82c3b34eed0c83d0cdca7212334e87030fb900ae8152e1fa13ffb5
3
+ metadata.gz: a8c7d63af4cdd331e0f9ab51eb895797567278365cc1029dbbe07744158cb5f4
4
+ data.tar.gz: d8cb97dfc05729a577a95c358d2a8397b43bd4628925bf3bcb55b282d6042ee8
5
5
  SHA512:
6
- metadata.gz: 492a1ed30bb41f77c748c6ad70aa258ae16e74d2ee2e8bb437def781d72389403c6a67baf90d728c13971e9a1cf47c5f9535a63f2b754870f936ccb81d73ff3c
7
- data.tar.gz: 6c4281a992017b9dc07e9837426f862a5daa7514f20fa01674896a502b5356c31ab9877ac2e8372fbf39d07f97b21bf1eb3eb50f294dcc88a68ec92e69599e48
6
+ metadata.gz: 252c70cd5862c795eede663242f22b4be188c35a950fa55f41f1b324f9e6ee73b8a1a4bebf3d875fbd68b640359db6e20d5c0bbdd42e90dc640470a5fa91d7ad
7
+ data.tar.gz: 14a5bc5fe4ad89de5288df9ea6425d234d25daced1c6429e17563809ec666109c9b8ba668881cf32b5528c480b44a0fa32b3f57c33bb2608f123c2fd3c62d498
@@ -0,0 +1,13 @@
1
+ name: ci
2
+ on: [push]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions/checkout@v1
8
+ - name: Set up Ruby 2.6
9
+ uses: actions/setup-ruby@v1
10
+ with:
11
+ ruby-version: 2.6.x
12
+ - name: Run cibuild
13
+ run: bin/cibuild
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ *.log
data/.rubocop.yml CHANGED
@@ -3,46 +3,24 @@ require:
3
3
 
4
4
  AllCops:
5
5
  Exclude:
6
- - 'coverage/**/*'
7
6
  - 'pkg/**/*'
8
7
  - 'spec/fixtures/**/*'
9
- - 'tmp/**/*'
10
- - 'vendor/**/*'
11
8
  TargetRubyVersion: 2.6
12
9
 
13
- Layout/AlignArguments:
10
+ Layout/ArgumentAlignment:
14
11
  EnforcedStyle: with_fixed_indentation
15
12
 
16
- Layout/AlignParameters:
13
+ Layout/ParameterAlignment:
17
14
  Enabled: true
18
15
  EnforcedStyle: with_fixed_indentation
19
16
  IndentationWidth: 2
20
17
 
21
- Layout/ClassStructure:
22
- Enabled: true
23
- Categories:
24
- module_inclusion:
25
- - include
26
- - prepend
27
- - extend
28
- ExpectedOrder:
29
- - module_inclusion
30
- - constants
31
- - public_class_methods
32
- - initializer
33
- - instance_methods
34
- - protected_methods
35
- - private_methods
36
-
37
18
  Layout/EndOfLine:
38
19
  EnforcedStyle: lf
39
20
 
40
- Layout/IndentFirstArrayElement:
21
+ Layout/FirstArrayElementIndentation:
41
22
  EnforcedStyle: consistent
42
23
 
43
- Layout/IndentHeredoc:
44
- EnforcedStyle: active_support
45
-
46
24
  Layout/MultilineMethodCallIndentation:
47
25
  Enabled: true
48
26
  EnforcedStyle: indented
@@ -51,14 +29,8 @@ Lint/AmbiguousBlockAssociation:
51
29
  Exclude:
52
30
  - 'spec/**/*.rb'
53
31
 
54
- Lint/InterpolationCheck:
55
- Exclude:
56
- - 'spec/**/*.rb'
57
-
58
32
  Metrics/BlockLength:
59
33
  Exclude:
60
- - '**/**/*.builder'
61
- - '**/*.rake'
62
34
  - '*.gemspec'
63
35
  - 'Rakefile'
64
36
  - 'spec/**/*.rb'
@@ -69,24 +41,16 @@ Metrics/ModuleLength:
69
41
 
70
42
  Metrics/LineLength:
71
43
  Exclude:
72
- - 'lib/saml/kit/builders/templates/*.builder'
73
44
  - 'spec/**/*.rb'
74
45
  IgnoredPatterns:
75
46
  - '^#*'
76
47
 
77
- Naming/FileName:
78
- Exclude:
79
- - 'lib/saml-kit.rb'
80
-
81
48
  Naming/RescuedExceptionsVariableName:
82
49
  PreferredName: error
83
50
 
84
51
  Style/Documentation:
85
52
  Enabled: false
86
53
 
87
- Style/EachWithObject:
88
- Enabled: false
89
-
90
54
  Style/StringLiterals:
91
55
  EnforcedStyle: 'single_quotes'
92
56
 
@@ -99,14 +63,12 @@ Style/TrailingCommaInHashLiteral:
99
63
  RSpec/ExampleLength:
100
64
  Max: 80
101
65
 
102
- RSpec/MultipleExpectations:
103
- Enabled: false
104
-
105
66
  RSpec/NamedSubject:
106
67
  Enabled: false
107
68
 
108
- RSpec/NestedGroups:
109
- Max: 7
110
-
111
- RSpec/SubjectStub:
69
+ RSpec/FilePath:
112
70
  Enabled: false
71
+
72
+ RSpec/DescribeClass:
73
+ Exclude:
74
+ - 'spec/integration/**/*'
data/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ Version 0.1.2
2
+
3
+ # Changelog
4
+ All notable changes to this project will be documented in this file.
5
+
6
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
7
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
+
9
+ ## [Unreleased]
10
+ - nil
11
+
12
+ ## [0.1.2] - 2020-01-16
13
+ ### Added
14
+ - Add CLI for `spandx scan <LOCKER>`
15
+ - Parse Gemfile.lock for dependencies.
16
+ - Parse Pipfile.lock for dependencies.
17
+ - Allow lookup for a specific license by id
18
+
19
+ ## [0.1.1] - 2019-10-05
20
+ ### Added
21
+ - Provide ruby API to the latest SPDX catalogue.
22
+
23
+ [Unreleased]: https://github.com/mokhan/spandx/compare/v0.1.2...HEAD
24
+ [0.1.2]: https://github.com/mokhan/spandx/compare/v0.1.1...v0.1.2
25
+ [0.1.1]: https://github.com/mokhan/spandx/compare/v0.1.0...v0.1.1
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spandx (0.1.1)
5
- net-hippie (~> 0.2)
4
+ spandx (0.1.2)
5
+ net-hippie (~> 0.3)
6
+ thor (~> 0.1)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -17,35 +18,35 @@ GEM
17
18
  safe_yaml (~> 1.0.0)
18
19
  diff-lcs (1.3)
19
20
  hashdiff (1.0.0)
20
- jaro_winkler (1.5.3)
21
- net-hippie (0.2.6)
22
- parallel (1.17.0)
23
- parser (2.6.5.0)
21
+ jaro_winkler (1.5.4)
22
+ net-hippie (0.3.1)
23
+ parallel (1.19.1)
24
+ parser (2.7.0.0)
24
25
  ast (~> 2.4.0)
25
- public_suffix (4.0.1)
26
+ public_suffix (4.0.2)
26
27
  rainbow (3.0.0)
27
- rake (10.5.0)
28
- rspec (3.8.0)
29
- rspec-core (~> 3.8.0)
30
- rspec-expectations (~> 3.8.0)
31
- rspec-mocks (~> 3.8.0)
32
- rspec-core (3.8.2)
33
- rspec-support (~> 3.8.0)
34
- rspec-expectations (3.8.5)
28
+ rake (13.0.1)
29
+ rspec (3.9.0)
30
+ rspec-core (~> 3.9.0)
31
+ rspec-expectations (~> 3.9.0)
32
+ rspec-mocks (~> 3.9.0)
33
+ rspec-core (3.9.0)
34
+ rspec-support (~> 3.9.0)
35
+ rspec-expectations (3.9.0)
35
36
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.8.0)
37
- rspec-mocks (3.8.2)
37
+ rspec-support (~> 3.9.0)
38
+ rspec-mocks (3.9.0)
38
39
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.8.0)
40
- rspec-support (3.8.3)
41
- rubocop (0.75.0)
40
+ rspec-support (~> 3.9.0)
41
+ rspec-support (3.9.0)
42
+ rubocop (0.78.0)
42
43
  jaro_winkler (~> 1.5.1)
43
44
  parallel (~> 1.10)
44
45
  parser (>= 2.6)
45
46
  rainbow (>= 2.2.2, < 4.0)
46
47
  ruby-progressbar (~> 1.7)
47
48
  unicode-display_width (>= 1.4.0, < 1.7)
48
- rubocop-rspec (1.36.0)
49
+ rubocop-rspec (1.37.1)
49
50
  rubocop (>= 0.68.1)
50
51
  ruby-progressbar (1.10.1)
51
52
  safe_yaml (1.0.5)
@@ -62,7 +63,7 @@ PLATFORMS
62
63
  DEPENDENCIES
63
64
  bundler (~> 2.0)
64
65
  bundler-audit (~> 0.6)
65
- rake (~> 10.0)
66
+ rake (~> 13.0)
66
67
  rspec (~> 3.0)
67
68
  rubocop (~> 0.52)
68
69
  rubocop-rspec (~> 1.22)
@@ -70,4 +71,4 @@ DEPENDENCIES
70
71
  webmock (~> 3.7)
71
72
 
72
73
  BUNDLED WITH
73
- 2.0.2
74
+ 2.1.2
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Spandx
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/spandx`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ A ruby API for interacting with the https://spdx.org software license catalogue.
4
4
 
5
+ ![badge](https://github.com/mokhan/spandx/workflows/ci/badge.svg)
5
6
 
6
7
  ## Installation
7
8
 
@@ -21,7 +22,7 @@ Or install it yourself as:
21
22
 
22
23
  ## Usage
23
24
 
24
- TODO: Write usage instructions here
25
+ To fetch the latest version of the catalogue data from [SPDX](https://spdx.org/licenses/licenses.json).
25
26
 
26
27
  ```ruby
27
28
  catalogue = Spandx::Catalogue.latest
@@ -30,6 +31,16 @@ catalogue.each do |license|
30
31
  end
31
32
  ```
32
33
 
34
+ To load an offline copy of the data.
35
+
36
+ ```ruby
37
+ path = File.join(Dir.pwd, 'licenses.json')
38
+ catalogue = Spandx::Catalogue.from_file(path)
39
+ catalogue.each do |license|
40
+ puts license.inspect
41
+ end
42
+ ```
43
+
33
44
  ## Development
34
45
 
35
46
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/cibuild` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -38,7 +49,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
38
49
 
39
50
  ## Contributing
40
51
 
41
- Bug reports and pull requests are welcome on GitLab at https://gitlab.com/xlgmokha/spandx.
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mokhan/spandx.
42
53
 
43
54
  ## License
44
55
 
data/exe/spandx CHANGED
@@ -1,4 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'spandx'
4
+ lib_path = File.expand_path('../lib', __dir__)
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
+ require 'spandx/cli'
7
+
8
+ Signal.trap('INT') do
9
+ warn("\n#{caller.join("\n")}: interrupted")
10
+ exit(1)
11
+ end
12
+
13
+ begin
14
+ Spandx::CLI.start
15
+ rescue Spandx::CLI::Error => error
16
+ puts "ERROR: #{error.message}"
17
+ exit 1
18
+ end
@@ -8,6 +8,10 @@ module Spandx
8
8
  @catalogue = catalogue
9
9
  end
10
10
 
11
+ def [](id)
12
+ identity_map[id]
13
+ end
14
+
11
15
  def version
12
16
  catalogue[:licenseListVersion]
13
17
  end
@@ -18,8 +22,18 @@ module Spandx
18
22
  end
19
23
  end
20
24
 
21
- def self.latest
22
- CatalogueGateway.new.fetch
25
+ class << self
26
+ def latest(gateway: ::Spandx::Gateways::Spdx.new)
27
+ gateway.fetch
28
+ end
29
+
30
+ def from_file(path)
31
+ new(JSON.parse(IO.read(path), symbolize_names: true))
32
+ end
33
+
34
+ def empty
35
+ @empty ||= new(licenses: [])
36
+ end
23
37
  end
24
38
 
25
39
  private
@@ -27,7 +41,7 @@ module Spandx
27
41
  attr_reader :catalogue
28
42
 
29
43
  def licenses
30
- @licenses ||= catalogue.fetch(:licenses, []).map { |x| map_from(x) }
44
+ @licenses ||= identity_map.values
31
45
  end
32
46
 
33
47
  def map_from(license_hash)
@@ -37,5 +51,13 @@ module Spandx
37
51
  def present?(item)
38
52
  item && !item.empty?
39
53
  end
54
+
55
+ def identity_map
56
+ @identity_map ||=
57
+ catalogue.fetch(:licenses, []).each_with_object({}) do |hash, memo|
58
+ license = map_from(hash)
59
+ memo[license.id] = license if present?(license.id)
60
+ end
61
+ end
40
62
  end
41
63
  end
data/lib/spandx/cli.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ require 'spandx'
6
+ require 'spandx/command'
7
+ require 'spandx/commands/scan'
8
+
9
+ module Spandx
10
+ class CLI < Thor
11
+ Error = Class.new(StandardError)
12
+
13
+ desc 'version', 'spandx version'
14
+ def version
15
+ puts "v#{Spandx::VERSION}"
16
+ end
17
+ map %w[--version -v] => :version
18
+
19
+ desc 'scan LOCKFILE', 'Command description...'
20
+ method_option :help, aliases: '-h', type: :boolean,
21
+ desc: 'Display usage information'
22
+ def scan(lockfile = nil)
23
+ if options[:help]
24
+ invoke :help, ['scan']
25
+ else
26
+ Spandx::Commands::Scan.new(lockfile, options).execute
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ class Command
5
+ extend Forwardable
6
+
7
+ def_delegators :command, :run
8
+
9
+ # Execute this command
10
+ #
11
+ # @api public
12
+ def execute(*)
13
+ raise(
14
+ NotImplementedError,
15
+ "#{self.class}##{__method__} must be implemented"
16
+ )
17
+ end
18
+
19
+ # The external commands runner
20
+ #
21
+ # @see http://www.rubydoc.info/gems/tty-command
22
+ #
23
+ # @api public
24
+ def command(**options)
25
+ require 'tty-command'
26
+ TTY::Command.new(options)
27
+ end
28
+
29
+ # The cursor movement
30
+ #
31
+ # @see http://www.rubydoc.info/gems/tty-cursor
32
+ #
33
+ # @api public
34
+ def cursor
35
+ require 'tty-cursor'
36
+ TTY::Cursor
37
+ end
38
+
39
+ # Open a file or text in the user's preferred editor
40
+ #
41
+ # @see http://www.rubydoc.info/gems/tty-editor
42
+ #
43
+ # @api public
44
+ def editor
45
+ require 'tty-editor'
46
+ TTY::Editor
47
+ end
48
+
49
+ # File manipulation utility methods
50
+ #
51
+ # @see http://www.rubydoc.info/gems/tty-file
52
+ #
53
+ # @api public
54
+ def generator
55
+ require 'tty-file'
56
+ TTY::File
57
+ end
58
+
59
+ # Terminal output paging
60
+ #
61
+ # @see http://www.rubydoc.info/gems/tty-pager
62
+ #
63
+ # @api public
64
+ def pager(**options)
65
+ require 'tty-pager'
66
+ TTY::Pager.new(options)
67
+ end
68
+
69
+ # Terminal platform and OS properties
70
+ #
71
+ # @see http://www.rubydoc.info/gems/tty-pager
72
+ #
73
+ # @api public
74
+ def platform
75
+ require 'tty-platform'
76
+ TTY::Platform.new
77
+ end
78
+
79
+ # The interactive prompt
80
+ #
81
+ # @see http://www.rubydoc.info/gems/tty-prompt
82
+ #
83
+ # @api public
84
+ def prompt(**options)
85
+ require 'tty-prompt'
86
+ TTY::Prompt.new(options)
87
+ end
88
+
89
+ # Get terminal screen properties
90
+ #
91
+ # @see http://www.rubydoc.info/gems/tty-screen
92
+ #
93
+ # @api public
94
+ def screen
95
+ require 'tty-screen'
96
+ TTY::Screen
97
+ end
98
+
99
+ # The unix which utility
100
+ #
101
+ # @see http://www.rubydoc.info/gems/tty-which
102
+ #
103
+ # @api public
104
+ def which(*args)
105
+ require 'tty-which'
106
+ TTY::Which.which(*args)
107
+ end
108
+
109
+ # Check if executable exists
110
+ #
111
+ # @see http://www.rubydoc.info/gems/tty-which
112
+ #
113
+ # @api public
114
+ def exec_exist?(*args)
115
+ require 'tty-which'
116
+ TTY::Which.exist?(*args)
117
+ end
118
+ end
119
+ end
File without changes
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Commands
5
+ class Scan < Spandx::Command
6
+ attr_reader :lockfile
7
+
8
+ def initialize(lockfile, options)
9
+ @lockfile = lockfile ? Pathname.new(File.expand_path(lockfile)) : nil
10
+ @options = options
11
+ end
12
+
13
+ def execute(output: $stdout)
14
+ if lockfile.nil?
15
+ output.puts 'OK'
16
+ else
17
+ report = Parsers.for(lockfile).parse(lockfile)
18
+ output.puts report.to_json
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Gateways
5
+ class Http
6
+ attr_reader :driver
7
+
8
+ def initialize(driver: Http.default_driver)
9
+ @driver = driver
10
+ end
11
+
12
+ def get(uri, default: nil)
13
+ driver.with_retry do |client|
14
+ client.get(uri)
15
+ end
16
+ rescue *Net::Hippie::CONNECTION_ERRORS
17
+ default
18
+ end
19
+
20
+ def ok?(response)
21
+ response.is_a?(Net::HTTPSuccess)
22
+ end
23
+
24
+ def self.default_driver
25
+ @default_driver ||= Net::Hippie::Client.new.tap do |client|
26
+ client.logger = ::Logger.new('http.log')
27
+ client.follow_redirects = 3
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Gateways
5
+ class PyPI
6
+ class Source
7
+ attr_reader :name, :uri, :verify_ssl
8
+
9
+ def initialize(source)
10
+ @name = source['name']
11
+ @uri = URI.parse(source['url'])
12
+ @verify_ssl = source['verify_ssl']
13
+ end
14
+
15
+ def host
16
+ @uri.host
17
+ end
18
+
19
+ def uri_for(name, version)
20
+ URI.parse("https://#{host}/pypi/#{name}/#{version}/json")
21
+ end
22
+
23
+ def lookup(name, version, http: Spandx.http)
24
+ response = http.get(uri_for(name, version))
25
+ response if http.ok?(response)
26
+ end
27
+
28
+ class << self
29
+ def sources_from(json)
30
+ meta = json['_meta']
31
+ meta['sources'].map do |hash|
32
+ Gateways::PyPI::Source.new(hash)
33
+ end
34
+ end
35
+
36
+ def default
37
+ new(
38
+ 'name' => 'pypi',
39
+ 'url' => 'https://pypi.org/simple',
40
+ 'verify_ssl' => true
41
+ )
42
+ end
43
+ end
44
+ end
45
+
46
+ def initialize(sources: [Source.default])
47
+ @sources = sources
48
+ end
49
+
50
+ def definition_for(name, version)
51
+ @sources.each do |source|
52
+ response = source.lookup(name, version)
53
+ return JSON.parse(response.body).fetch('info', {}) if response
54
+ end
55
+ {}
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Gateways
5
+ class Spdx
6
+ URL = 'https://spdx.org/licenses/licenses.json'
7
+
8
+ def fetch(url: URL, http: Spandx.http, default: Catalogue.empty)
9
+ response = http.get(url, default: default)
10
+ http.ok?(response) ? parse(response.body) : default
11
+ end
12
+
13
+ private
14
+
15
+ def parse(json)
16
+ Catalogue.new(JSON.parse(json, symbolize_names: true))
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Parsers
5
+ class Base
6
+ attr_reader :catalogue
7
+
8
+ def initialize(catalogue:)
9
+ @catalogue = catalogue
10
+ end
11
+
12
+ class << self
13
+ include Enumerable
14
+
15
+ def each(&block)
16
+ registry.each do |x|
17
+ block.call(x)
18
+ end
19
+ end
20
+
21
+ def inherited(subclass)
22
+ registry.push(subclass)
23
+ end
24
+
25
+ def registry
26
+ @registry ||= []
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Parsers
5
+ class GemfileLock < Base
6
+ def self.matches?(filename)
7
+ filename.match?(/Gemfile.*\.lock/)
8
+ end
9
+
10
+ def parse(lockfile)
11
+ report = Report.new
12
+ dependencies_from(lockfile) do |dependency|
13
+ spec = dependency.to_spec
14
+ report.add(
15
+ name: dependency.name,
16
+ version: spec.version.to_s,
17
+ licenses: [catalogue[spec.license]]
18
+ )
19
+ end
20
+ report
21
+ end
22
+
23
+ private
24
+
25
+ def dependencies_from(lockfile)
26
+ ::Bundler::LockfileParser
27
+ .new(IO.read(lockfile))
28
+ .dependencies.each do |_key, dependency|
29
+ yield dependency
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ module Parsers
5
+ class PipfileLock < Base
6
+ def self.matches?(filename)
7
+ filename.match?(/Pipfile.*\.lock/)
8
+ end
9
+
10
+ def parse(lockfile)
11
+ report = Report.new
12
+ dependencies_from(lockfile) do |x|
13
+ report.add(
14
+ name: x[:name],
15
+ version: x[:version],
16
+ licenses: x[:licenses]
17
+ )
18
+ end
19
+ report
20
+ end
21
+
22
+ private
23
+
24
+ def dependencies_from(lockfile)
25
+ json = JSON.parse(IO.read(lockfile))
26
+ each_dependency(pypi_for(json), json) do |name, version, definition|
27
+ yield({ name: name, version: version, licenses: [catalogue[definition['license']]] })
28
+ end
29
+ end
30
+
31
+ def each_dependency(pypi, json, groups: %w[default develop])
32
+ groups.each do |group|
33
+ json[group].each do |name, value|
34
+ version = canonicalize(value['version'])
35
+ yield name, version, pypi.definition_for(name, version)
36
+ end
37
+ end
38
+ end
39
+
40
+ def canonicalize(version)
41
+ version.gsub(/==/, '')
42
+ end
43
+
44
+ def pypi_for(json)
45
+ Gateways::PyPI.new(
46
+ sources: Gateways::PyPI::Source.sources_from(json)
47
+ )
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spandx/parsers/base'
4
+ require 'spandx/parsers/gemfile_lock'
5
+ require 'spandx/parsers/pipfile_lock'
6
+
7
+ module Spandx
8
+ module Parsers
9
+ class << self
10
+ def for(path, catalogue: Spandx::Catalogue.latest)
11
+ result = ::Spandx::Parsers::Base.find do |x|
12
+ x.matches?(File.basename(path))
13
+ end
14
+
15
+ result&.new(catalogue: catalogue)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spandx
4
+ class Report
5
+ def initialize(report: { version: '1.0', packages: [] })
6
+ @report = report
7
+ end
8
+
9
+ def add(name:, version:, licenses: [])
10
+ @report[:packages].push(
11
+ name: name,
12
+ version: version,
13
+ licenses: licenses.map(&:id)
14
+ )
15
+ end
16
+
17
+ def to_h
18
+ @report
19
+ end
20
+
21
+ def to_json(*_args)
22
+ JSON.pretty_generate(to_h)
23
+ end
24
+ end
25
+ end
File without changes
@@ -0,0 +1 @@
1
+ #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Spandx
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/spandx.rb CHANGED
@@ -1,11 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
4
+ require 'json'
3
5
  require 'net/hippie'
6
+
4
7
  require 'spandx/catalogue'
5
- require 'spandx/catalogue_gateway'
8
+ require 'spandx/gateways/http'
9
+ require 'spandx/gateways/pypi'
10
+ require 'spandx/gateways/spdx'
6
11
  require 'spandx/license'
12
+ require 'spandx/parsers'
13
+ require 'spandx/report'
7
14
  require 'spandx/version'
8
15
 
9
16
  module Spandx
10
17
  class Error < StandardError; end
18
+
19
+ class << self
20
+ def root
21
+ Pathname.new(File.dirname(__FILE__)).join('../..')
22
+ end
23
+
24
+ def http
25
+ @http ||= Spandx::Gateways::Http.new
26
+ end
27
+ end
11
28
  end
data/spandx.gemspec CHANGED
@@ -12,12 +12,12 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = 'A ruby interface to the SPDX catalogue.'
14
14
  spec.description = 'A ruby interface to the SPDX catalogue.'
15
- spec.homepage = 'https://gitlab.com/xlgmokha/spandx'
15
+ spec.homepage = 'https://github.com/mokhan/spandx'
16
16
  spec.license = 'MIT'
17
17
 
18
18
  spec.metadata['homepage_uri'] = spec.homepage
19
- spec.metadata['source_code_uri'] = 'https://gitlab.com/xlgmokha/spandx'
20
- spec.metadata['changelog_uri'] = 'https://gitlab.com/xlgmokha/spandx/blob/master/CHANGELOG.md'
19
+ spec.metadata['source_code_uri'] = 'https://github.com/mokhan/spandx'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/mokhan/spandx/blob/master/CHANGELOG.md'
21
21
 
22
22
  # Specify which files should be added to the gem when it is released.
23
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -28,10 +28,11 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
30
 
31
- spec.add_dependency 'net-hippie', '~> 0.2'
31
+ spec.add_dependency 'net-hippie', '~> 0.3'
32
+ spec.add_dependency 'thor', '~> 0.1'
32
33
  spec.add_development_dependency 'bundler', '~> 2.0'
33
34
  spec.add_development_dependency 'bundler-audit', '~> 0.6'
34
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rake', '~> 13.0'
35
36
  spec.add_development_dependency 'rspec', '~> 3.0'
36
37
  spec.add_development_dependency 'rubocop', '~> 0.52'
37
38
  spec.add_development_dependency 'rubocop-rspec', '~> 1.22'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spandx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-05 00:00:00.000000000 Z
11
+ date: 2020-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-hippie
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.2'
19
+ version: '0.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.2'
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +72,14 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '10.0'
75
+ version: '13.0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '10.0'
82
+ version: '13.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -130,11 +144,12 @@ executables:
130
144
  extensions: []
131
145
  extra_rdoc_files: []
132
146
  files:
147
+ - ".github/workflows/ci.yml"
133
148
  - ".gitignore"
134
149
  - ".gitlab-ci.yml"
135
150
  - ".rspec"
136
151
  - ".rubocop.yml"
137
- - ".travis.yml"
152
+ - CHANGELOG.md
138
153
  - Gemfile
139
154
  - Gemfile.lock
140
155
  - LICENSE.txt
@@ -149,17 +164,30 @@ files:
149
164
  - exe/spandx
150
165
  - lib/spandx.rb
151
166
  - lib/spandx/catalogue.rb
152
- - lib/spandx/catalogue_gateway.rb
167
+ - lib/spandx/cli.rb
168
+ - lib/spandx/command.rb
169
+ - lib/spandx/commands/.gitkeep
170
+ - lib/spandx/commands/scan.rb
171
+ - lib/spandx/gateways/http.rb
172
+ - lib/spandx/gateways/pypi.rb
173
+ - lib/spandx/gateways/spdx.rb
153
174
  - lib/spandx/license.rb
175
+ - lib/spandx/parsers.rb
176
+ - lib/spandx/parsers/base.rb
177
+ - lib/spandx/parsers/gemfile_lock.rb
178
+ - lib/spandx/parsers/pipfile_lock.rb
179
+ - lib/spandx/report.rb
180
+ - lib/spandx/templates/.gitkeep
181
+ - lib/spandx/templates/scan/.gitkeep
154
182
  - lib/spandx/version.rb
155
183
  - spandx.gemspec
156
- homepage: https://gitlab.com/xlgmokha/spandx
184
+ homepage: https://github.com/mokhan/spandx
157
185
  licenses:
158
186
  - MIT
159
187
  metadata:
160
- homepage_uri: https://gitlab.com/xlgmokha/spandx
161
- source_code_uri: https://gitlab.com/xlgmokha/spandx
162
- changelog_uri: https://gitlab.com/xlgmokha/spandx/blob/master/CHANGELOG.md
188
+ homepage_uri: https://github.com/mokhan/spandx
189
+ source_code_uri: https://github.com/mokhan/spandx
190
+ changelog_uri: https://github.com/mokhan/spandx/blob/master/CHANGELOG.md
163
191
  post_install_message:
164
192
  rdoc_options: []
165
193
  require_paths:
@@ -175,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
203
  - !ruby/object:Gem::Version
176
204
  version: '0'
177
205
  requirements: []
178
- rubygems_version: 3.0.3
206
+ rubygems_version: 3.1.2
179
207
  signing_key:
180
208
  specification_version: 4
181
209
  summary: A ruby interface to the SPDX catalogue.
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.4
7
- before_install: gem install bundler -v 2.0.2
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spandx
4
- class CatalogueGateway
5
- URL = 'https://spdx.org/licenses/licenses.json'
6
-
7
- def initialize(http: default_client)
8
- @http = http
9
- end
10
-
11
- def fetch(url: URL)
12
- response = http.get(url)
13
-
14
- if response.code == '200'
15
- parse(response.body)
16
- else
17
- empty_catalogue
18
- end
19
- rescue *::Net::Hippie::CONNECTION_ERRORS
20
- empty_catalogue
21
- end
22
-
23
- private
24
-
25
- attr_reader :http
26
-
27
- def parse(json)
28
- build_catalogue(JSON.parse(json, symbolize_names: true))
29
- end
30
-
31
- def empty_catalogue
32
- build_catalogue(licenses: [])
33
- end
34
-
35
- def build_catalogue(hash)
36
- Catalogue.new(hash)
37
- end
38
-
39
- def default_client
40
- Net::Hippie::Client.new
41
- end
42
- end
43
- end