licensee 8.5.0 → 8.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -104
- data/bin/licensee +26 -12
- data/lib/licensee.rb +1 -0
- data/lib/licensee/license.rb +6 -2
- data/lib/licensee/matchers/copyright_matcher.rb +2 -0
- data/lib/licensee/matchers/cran_matcher.rb +20 -0
- data/lib/licensee/matchers/exact_matcher.rb +2 -0
- data/lib/licensee/project.rb +2 -1
- data/lib/licensee/project_file.rb +8 -2
- data/lib/licensee/project_files/license_file.rb +27 -6
- data/lib/licensee/project_files/package_info.rb +6 -1
- data/lib/licensee/project_files/readme.rb +2 -2
- data/lib/licensee/projects/fs_project.rb +0 -1
- data/lib/licensee/version.rb +1 -1
- data/spec/bin_spec.rb +56 -0
- data/spec/fixtures/case-sensitive/LiCeNsE.TxT +0 -0
- data/spec/fixtures/gemspec/project.gemspec +1 -0
- data/spec/fixtures/lgpl/COPYING.lesser +165 -0
- data/spec/fixtures/lgpl/LICENSE +674 -0
- data/spec/fixtures/license-folder/README.md +0 -0
- data/{test/fixtures/mit-without-title/mit.txt → spec/fixtures/mit/LICENSE.txt} +3 -1
- data/{test/fixtures/mit-with-redundant-title/mit.txt → spec/fixtures/mit/README.md} +4 -2
- data/spec/fixtures/mpl-without-hrs/LICENSE +362 -0
- data/spec/fixtures/readme/README.md +23 -0
- data/spec/integration_spec.rb +121 -0
- data/spec/licensee/content_helper_spec.rb +77 -0
- data/spec/licensee/license_spec.rb +224 -0
- data/spec/licensee/matchers/copyright_matcher_spec.rb +47 -0
- data/spec/licensee/matchers/cran_matcher_spec.rb +18 -0
- data/spec/licensee/matchers/dice_matcher_spec.rb +43 -0
- data/spec/licensee/matchers/exact_matcher_spec.rb +26 -0
- data/spec/licensee/matchers/gemspec_matcher_spec.rb +29 -0
- data/spec/licensee/matchers/npm_bower_matcher_spec.rb +31 -0
- data/spec/licensee/matchers/package_matcher_spec.rb +15 -0
- data/spec/licensee/project_files/license_file_spec.rb +122 -0
- data/spec/licensee/project_files/package_info_spec.rb +51 -0
- data/spec/licensee/project_files/readme_spec.rb +77 -0
- data/spec/licensee/project_spec.rb +91 -0
- data/spec/licensee_spec.rb +41 -0
- data/spec/project_file_spec.rb +33 -0
- data/spec/spec_helper.rb +78 -0
- data/spec/vendored_license_spec.rb +75 -0
- data/vendor/choosealicense.com/_licenses/bsl-1.0.txt +48 -0
- data/vendor/choosealicense.com/_licenses/lgpl-3.0.txt +1 -1
- metadata +39 -111
- data/Rakefile +0 -12
- data/test/fixtures/apache-2.0/LICENSE +0 -201
- data/test/fixtures/bower-with-readme/README.md +0 -1
- data/test/fixtures/bower-with-readme/bower.json +0 -3
- data/test/fixtures/bower/bower.json +0 -3
- data/test/fixtures/bsd-2-clause-without-title/bsd-2-clause.txt +0 -23
- data/test/fixtures/bsd-3-clause-without-title/bsd-3-clause.txt +0 -27
- data/test/fixtures/case-sensitive.git/HEAD +0 -1
- data/test/fixtures/case-sensitive.git/config +0 -6
- data/test/fixtures/case-sensitive.git/objects/01/7b4f1eebd1dcb735e950b1d01093e3e2bf85e9 +0 -0
- data/test/fixtures/case-sensitive.git/objects/2c/b878e0851c5cf53d7455d9018baa6755a38bd7 +0 -0
- data/test/fixtures/case-sensitive.git/objects/fb/ddf40ba5f30225af7cd9841afe374ca5800cb9 +0 -0
- data/test/fixtures/case-sensitive.git/refs/heads/master +0 -1
- data/test/fixtures/isc-without-title/isc.txt +0 -13
- data/test/fixtures/lgpl.git/HEAD +0 -1
- data/test/fixtures/lgpl.git/config +0 -5
- data/test/fixtures/lgpl.git/objects/1a/cd060ebbbeac294200008657d9502130f93465 +0 -2
- data/test/fixtures/lgpl.git/objects/4b/1f98c1e95b6d4dae0b0a160f554be97e5afece +0 -2
- data/test/fixtures/lgpl.git/objects/a4/cfa42bc8e1d432fa851c5c4e3f294f01e05fd3 +0 -0
- data/test/fixtures/lgpl.git/objects/b7/de6e186bd02935030f5d42867ea7043fb1c27c +0 -0
- data/test/fixtures/lgpl.git/objects/dd/d0e017b1bf39218a6ea4f2fadd29a7ea8ebe03 +0 -0
- data/test/fixtures/lgpl.git/objects/eb/d853e83a2d317422c52f3922f4c9c5bb4a10b7 +0 -0
- data/test/fixtures/lgpl.git/refs/heads/master +0 -1
- data/test/fixtures/licence.git/HEAD +0 -1
- data/test/fixtures/licence.git/config +0 -6
- data/test/fixtures/licence.git/objects/66/0c086dc25f9f3b96e7afd9dee8a11b4e614543 +0 -0
- data/test/fixtures/licence.git/objects/68/804815597f79aa323de3257a8fd7b76449943c +0 -0
- data/test/fixtures/licence.git/objects/dd/59aed84c5aa4dff7ceda11a1c045f831194067 +0 -0
- data/test/fixtures/licence.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/licence.git/refs/heads/master +0 -1
- data/test/fixtures/license-folder.git/HEAD +0 -1
- data/test/fixtures/license-folder.git/config +0 -6
- data/test/fixtures/license-folder.git/objects/32/6d0761f0c54d54327ea9e127e02d9bae14d2c8 +0 -2
- data/test/fixtures/license-folder.git/objects/93/109217bbe2937fc3a8d8933fddd80ed6292481 +0 -0
- data/test/fixtures/license-folder.git/objects/c6/6e45436e4f3fda934dc7268bccbc59c37a67b4 +0 -0
- data/test/fixtures/license-folder.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/license-folder.git/refs/heads/master +0 -1
- data/test/fixtures/licenses.git/HEAD +0 -1
- data/test/fixtures/licenses.git/config +0 -4
- data/test/fixtures/licenses.git/objects/51/a11d50f29a14774ded8f7b90ba9938dce78a92 +0 -3
- data/test/fixtures/licenses.git/objects/5e/df454e6517673d5e64a33cf284308b9c6b1075 +0 -0
- data/test/fixtures/licenses.git/objects/e1/b4dc13f4bf683ce8f2943e051c3e91e778d043 +0 -0
- data/test/fixtures/licenses.git/objects/info/packs +0 -2
- data/test/fixtures/licenses.git/objects/pack/pack-4a7088171ae3ca900f010a4be6f1c2c96490c338.idx +0 -0
- data/test/fixtures/licenses.git/objects/pack/pack-4a7088171ae3ca900f010a4be6f1c2c96490c338.pack +0 -0
- data/test/fixtures/licenses.git/packed-refs +0 -4
- data/test/fixtures/licenses.git/refs/heads/master +0 -1
- data/test/fixtures/mit-without-title-rewrapped/mit.txt +0 -19
- data/test/fixtures/mpl-without-hrs.git/HEAD +0 -1
- data/test/fixtures/mpl-without-hrs.git/config +0 -5
- data/test/fixtures/mpl-without-hrs.git/objects/45/26aa2d1d78ea20fb0faf59f2360a68fa897774 +0 -0
- data/test/fixtures/mpl-without-hrs.git/objects/ba/f5649b61fac4ed64ec2949fe5cd616b85a8298 +0 -0
- data/test/fixtures/mpl-without-hrs.git/objects/be/2cc4dfb609fb6c38f6365ec345bded3350dd63 +0 -0
- data/test/fixtures/mpl-without-hrs.git/refs/heads/master +0 -1
- data/test/fixtures/named-license-file-prefix.git/HEAD +0 -1
- data/test/fixtures/named-license-file-prefix.git/config +0 -6
- data/test/fixtures/named-license-file-prefix.git/objects/64/3983d3f82ecc2a7d8e4227946220ebffd477d2 +0 -4
- data/test/fixtures/named-license-file-prefix.git/objects/c9/b229e500e529fdbd4f50746ba207e91d0677b6 +0 -7
- data/test/fixtures/named-license-file-prefix.git/objects/d1/9223f355283b3ce0c51a2c527f685d0f403157 +0 -0
- data/test/fixtures/named-license-file-prefix.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/named-license-file-prefix.git/refs/heads/master +0 -1
- data/test/fixtures/named-license-file-suffix.git/HEAD +0 -1
- data/test/fixtures/named-license-file-suffix.git/config +0 -6
- data/test/fixtures/named-license-file-suffix.git/objects/36/465372136f81a2089f486298ca77ef41611198 +0 -0
- data/test/fixtures/named-license-file-suffix.git/objects/4a/2a139e7fbd24eef5c5ef3d22f490e89405f6a3 +0 -3
- data/test/fixtures/named-license-file-suffix.git/objects/c9/b229e500e529fdbd4f50746ba207e91d0677b6 +0 -7
- data/test/fixtures/named-license-file-suffix.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/named-license-file-suffix.git/refs/heads/master +0 -1
- data/test/fixtures/no-license.git/HEAD +0 -1
- data/test/fixtures/no-license.git/config +0 -6
- data/test/fixtures/no-license.git/objects/82/0c999cf27a6f71431646c404274c578f7a2869 +0 -0
- data/test/fixtures/no-license.git/objects/e1/d9b2a3d41c2ea74a520e66da2b5c63b2f6202f +0 -0
- data/test/fixtures/no-license.git/objects/ff/1592f44259635df9feda5e02853964b26f9e4d +0 -0
- data/test/fixtures/no-license.git/refs/heads/master +0 -1
- data/test/fixtures/npm-non-spdx/package.json +0 -3
- data/test/fixtures/npm.git/HEAD +0 -1
- data/test/fixtures/npm.git/config +0 -4
- data/test/fixtures/npm.git/objects/info/packs +0 -2
- data/test/fixtures/npm.git/objects/pack/pack-03c0879445cabcc37f91d97c7955465adef26f4a.idx +0 -0
- data/test/fixtures/npm.git/objects/pack/pack-03c0879445cabcc37f91d97c7955465adef26f4a.pack +0 -0
- data/test/fixtures/npm.git/packed-refs +0 -2
- data/test/fixtures/npm/package.json +0 -3
- data/test/functions.rb +0 -73
- data/test/helper.rb +0 -16
- data/test/licensee/matchers/test_copyright_matcher.rb +0 -59
- data/test/licensee/matchers/test_dice_matcher.rb +0 -60
- data/test/licensee/matchers/test_exact_matcher.rb +0 -25
- data/test/licensee/matchers/test_gemspec_matcher.rb +0 -11
- data/test/licensee/matchers/test_npm_bower_matcher.rb +0 -27
- data/test/licensee/matchers/test_package_matcher.rb +0 -27
- data/test/licensee/project_files/test_license_file.rb +0 -73
- data/test/licensee/project_files/test_package_info.rb +0 -19
- data/test/licensee/project_files/test_readme.rb +0 -47
- data/test/licensee/test_content_helper.rb +0 -81
- data/test/licensee/test_license.rb +0 -182
- data/test/licensee/test_project.rb +0 -134
- data/test/licensee/test_project_file.rb +0 -24
- data/test/test_licensee.rb +0 -40
- data/test/test_licensee_bin.rb +0 -37
- data/test/test_licensee_vendor.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a09cefedc079e0510fbdae2de030984fc477a60b
|
4
|
+
data.tar.gz: 1648fed5fcbab4086f7f2d992ee9fea4b03fbe01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64bb0bb0ccbe7bb4df9d043182ab3b2a598544b2c42212b2489d448b821d170ce7c48aaf9213a56c407f72e061d81710be4b07b7de9efffd226e8940e4c98fd2
|
7
|
+
data.tar.gz: 42f5c17fdb81239632a12e41df5c4e66cb8b29600eb23a3674a75f9b51a0aec3961a400edff62430bea76ebd400deac50e344ca59ba7856504d52bc30b58cc50
|
data/README.md
CHANGED
@@ -1,24 +1,38 @@
|
|
1
1
|
# Licensee
|
2
|
-
_A Ruby Gem to detect under what license a project is distributed._
|
3
2
|
|
4
|
-
|
3
|
+
*A Ruby Gem to detect under what license a project is distributed.*
|
4
|
+
|
5
|
+
[![Build Status](https://travis-ci.org/benbalter/licensee.svg?branch=master)](https://travis-ci.org/benbalter/licensee) [![Gem Version](https://badge.fury.io/rb/licensee.svg)](http://badge.fury.io/rb/licensee) [![Coverage Status](https://coveralls.io/repos/github/benbalter/licensee/badge.svg?branch=rspec)](https://coveralls.io/github/benbalter/licensee?branch=rspec)
|
5
6
|
|
6
7
|
## The problem
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
* You've got an open source project. How do you know what you can and can't do with the software?
|
10
|
+
* You've got a bunch of open source projects, how do you know what their licenses are?
|
11
|
+
* You've got a project with a license file, but which license is it? Has it been modified?
|
10
12
|
|
11
13
|
## The solution
|
14
|
+
|
12
15
|
Licensee automates the process of reading `LICENSE` files and compares their contents to known licenses using a several strategies (which we call "Matchers"). It attempts to determine a project's license in the following order:
|
13
|
-
- If the license file has an explicit copyright notice, and nothing more (e.g., `Copyright (c) 2015 Ben Balter`), we'll assume the author intends to retain all rights, and thus the project isn't licensed.
|
14
|
-
- If the license is an exact match to a known license. If we strip away whitespace and copyright notice, we might get lucky, and direct string comparison in Ruby is cheap.
|
15
|
-
- If we still can't match the license, we use a fancy math thing called the [Sørensen–Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient), which is really good at calculating the similarity between two strings. By calculating the percent changed from the known license to the license file, you can tell, e.g., that a given license is 90% similar to the MIT license, that 10% likely representing the copyright line being properly adapted to the project.
|
16
16
|
|
17
|
-
|
17
|
+
* If the license file has an explicit copyright notice, and nothing more (e.g., `Copyright (c) 2015 Ben Balter`), we'll assume the author intends to retain all rights, and thus the project isn't licensed.
|
18
|
+
* If the license is an exact match to a known license. If we strip away whitespace and copyright notice, we might get lucky, and direct string comparison in Ruby is cheap.
|
19
|
+
* If we still can't match the license, we use a fancy math thing called the [Sørensen–Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient), which is really good at calculating the similarity between two strings. By calculating the percent changed from the known license to the license file, you can tell, e.g., that a given license is 95% similar to the MIT license, that 5% likely representing legally insignificant changes to the license text.
|
20
|
+
|
21
|
+
*Special thanks to [@vmg](https://github.com/vmg) for his Git and algorithmic prowess.*
|
18
22
|
|
19
23
|
## Installation
|
24
|
+
|
20
25
|
`gem install licensee` or add `gem 'licensee'` to your project's `Gemfile`.
|
21
26
|
|
27
|
+
## Documentation
|
28
|
+
|
29
|
+
See [the docs folder](/docs) for more information. You may be interested in:
|
30
|
+
|
31
|
+
* [Contributing to Licensee](CONTRIBUTING.md) (and development instructions)
|
32
|
+
* [Customizing Licensee's behavior](docs/customizing.md)
|
33
|
+
* [Instructions for using Licensee](docs/usage.md)
|
34
|
+
* More information about [what Licensee looks at](docs/what-we-look-at.md) (or doesn't, and why)
|
35
|
+
|
22
36
|
## Semantic Versioning
|
23
37
|
|
24
38
|
This project conforms to [semver](http://semver.org/). As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/) with two digits of precision. For example:
|
@@ -28,98 +42,3 @@ spec.add_dependency 'licensee', '~> 1.0'
|
|
28
42
|
This means your project is compatible with licensee 1.0 up until 2.0. You can also set a higher minimum version:
|
29
43
|
|
30
44
|
spec.add_dependency 'licensee', '~> 1.1'
|
31
|
-
|
32
|
-
## Command line usage
|
33
|
-
1. `cd` into a project directory
|
34
|
-
2. execute the `licensee` command
|
35
|
-
|
36
|
-
You'll get an output that looks like:
|
37
|
-
|
38
|
-
```
|
39
|
-
License: MIT
|
40
|
-
Confidence: 98.42%
|
41
|
-
Matcher: Licensee::GitMatcher
|
42
|
-
```
|
43
|
-
|
44
|
-
Alternately, `licensee <directory>` will treat the argument as the project directory, and `licensee <file>` will attempt to match the individual file specified, both with output that looks like the above.
|
45
|
-
|
46
|
-
## License API
|
47
|
-
|
48
|
-
```ruby
|
49
|
-
license = Licensee.license "/path/to/a/project"
|
50
|
-
=> #<Licensee::License name="MIT" match=0.9842154131847726>
|
51
|
-
|
52
|
-
license.key
|
53
|
-
=> "mit"
|
54
|
-
|
55
|
-
license.name
|
56
|
-
=> "MIT License"
|
57
|
-
|
58
|
-
license.meta["source"]
|
59
|
-
=> "http://opensource.org/licenses/MIT"
|
60
|
-
|
61
|
-
license.meta["description"]
|
62
|
-
=> "A permissive license that is short and to the point. It lets people do anything with your code with proper attribution and without warranty."
|
63
|
-
|
64
|
-
license.meta["permissions"]
|
65
|
-
=> ["commercial-use","modifications","distribution","private-use"]
|
66
|
-
```
|
67
|
-
|
68
|
-
## More API
|
69
|
-
You can gather more information by working with the project object, and the top level Licensee class.
|
70
|
-
|
71
|
-
```ruby
|
72
|
-
Licensee::VERSION # The Licensee version
|
73
|
-
Licensee.licenses # All the licenses Licensee knows about
|
74
|
-
|
75
|
-
project=Licensee.project "/path/to/a/project" # Get a Project (Git checkout or just local Filesystem) (post 6.0.0)
|
76
|
-
|
77
|
-
project.license # The matched license
|
78
|
-
project.matched_file # Object for the particular file containing the apparent license
|
79
|
-
project.matched_file.filename # Its filename
|
80
|
-
project.matched_file.confidence # The confidence level in the license matching
|
81
|
-
project.matched_file.content # The content of your license file
|
82
|
-
project.license.content # The Open Source License text it matched against
|
83
|
-
```
|
84
|
-
|
85
|
-
## What it looks at
|
86
|
-
- `LICENSE`, `LICENSE.txt`, `COPYING`, etc. files in the root of the project, comparing the body to known licenses
|
87
|
-
- Crowdsourced license content and metadata from [`choosealicense.com`](http://choosealicense.com)
|
88
|
-
|
89
|
-
## What it doesn't look at
|
90
|
-
- Dependency licensing
|
91
|
-
- References to licenses in `README`, `README.md`, etc.
|
92
|
-
- Every single possible license (just the most popular ones)
|
93
|
-
- Compliance (e.g., whitelisting certain licenses)
|
94
|
-
|
95
|
-
If you're looking for dependency license checking and compliance, take a look at [LicenseFinder](https://github.com/pivotal/LicenseFinder).
|
96
|
-
|
97
|
-
## Huh? Why don't you look at X?
|
98
|
-
Because reasons.
|
99
|
-
|
100
|
-
### Why not just look at the "license" field of [insert package manager here]?
|
101
|
-
Because it's not legally binding. A license is a legal contract. You give up certain rights (e.g., the right to sue the author) in exchange for the right to use the software.
|
102
|
-
|
103
|
-
Most popular licenses today _require_ that the license itself be distributed along side the software. Simply putting the letters "MIT" or "GPL" in a configuration file doesn't really meet that requirement.
|
104
|
-
|
105
|
-
Not to mention, it doesn't tell you much about your rights as a user. Is it GPLv2? GPLv2 or later? Those files are designed to be read by computers (who can't enter into contracts), not humans (who can). It's great metadata, but that's about it.
|
106
|
-
|
107
|
-
### What about looking to see if the author said something in the readme?
|
108
|
-
You could make an argument that, when linked or sufficiently identified, the terms of the license are incorporated by reference, or at least that the author's intent is there. There's a handful of reasons why this isn't ideal. For one, if you're using the MIT or BSD (ISC) license, along with a few others, there's templematic language, like the copyright notice, which would go unfilled.
|
109
|
-
|
110
|
-
### What about checking every single file for a copyright header?
|
111
|
-
Because that's silly in the context of how software is developed today. You wouldn't put a copyright notice on each page of a book. Besides, it's a lot of work, as there's no standardized, cross-platform way to describe a project's license within a comment.
|
112
|
-
|
113
|
-
Checking the actual text into version control is definitive, so that's what this project looks at.
|
114
|
-
|
115
|
-
## Bootstrapping a local development environment
|
116
|
-
`script/bootstrap`
|
117
|
-
|
118
|
-
## Running tests
|
119
|
-
`script/cibuild`
|
120
|
-
|
121
|
-
## Updating the licenses
|
122
|
-
License data is pulled from `choosealicense.com`. To update the license data, simple run `script/vendor-licenses`.
|
123
|
-
|
124
|
-
## Roadmap
|
125
|
-
See [proposed enhancements](https://github.com/benbalter/licensee/labels/enhancement).
|
data/bin/licensee
CHANGED
@@ -14,23 +14,37 @@ matched_file = project.matched_file
|
|
14
14
|
|
15
15
|
if license_file
|
16
16
|
puts "License file: #{license_file.filename}"
|
17
|
+
puts "License hash: #{license_file.hash}"
|
17
18
|
puts "Attribution: #{license_file.attribution}" if license_file.attribution
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
unless matched_file
|
22
|
+
puts 'License: Not detected'
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
if matched_file.license
|
27
|
+
puts "License: #{matched_file.license.meta['title']}"
|
28
|
+
|
29
|
+
if matched_file.confidence
|
30
|
+
puts "Confidence: #{format_percent(matched_file.confidence)}"
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Method: #{matched_file.matcher.class}" if matched_file.matcher
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
if matched_file.is_a?(Licensee::Project::LicenseFile)
|
38
|
+
matcher = Licensee::Matchers::Dice.new(matched_file)
|
39
|
+
licenses = matcher.licenses_by_similiarity
|
40
|
+
unless licenses.empty?
|
27
41
|
puts
|
28
42
|
puts "Here's the closest licenses:"
|
29
|
-
|
30
|
-
|
31
|
-
puts "* #{
|
43
|
+
licenses[0...3].each do |license, similarity|
|
44
|
+
spdx_id = license.meta['spdx-id']
|
45
|
+
puts "* #{spdx_id} similarity: #{format_percent(similarity)}"
|
32
46
|
end
|
33
47
|
end
|
34
|
-
else
|
35
|
-
puts 'Unknown'
|
36
48
|
end
|
49
|
+
|
50
|
+
exit 1
|
data/lib/licensee.rb
CHANGED
@@ -20,6 +20,7 @@ require_relative 'licensee/matchers/dice_matcher'
|
|
20
20
|
require_relative 'licensee/matchers/package_matcher'
|
21
21
|
require_relative 'licensee/matchers/gemspec_matcher'
|
22
22
|
require_relative 'licensee/matchers/npm_bower_matcher'
|
23
|
+
require_relative 'licensee/matchers/cran_matcher'
|
23
24
|
|
24
25
|
module Licensee
|
25
26
|
# Over which percent is a match considered a match by default
|
data/lib/licensee/license.rb
CHANGED
@@ -131,12 +131,16 @@ module Licensee
|
|
131
131
|
!other.nil? && key == other.key
|
132
132
|
end
|
133
133
|
|
134
|
-
private
|
135
|
-
|
136
134
|
def pseudo_license?
|
137
135
|
PSEUDO_LICENSES.include?(key)
|
138
136
|
end
|
139
137
|
|
138
|
+
def inspect
|
139
|
+
"#<Licensee::License key=#{key}>"
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
140
144
|
# Raw content of license file, including YAML front matter
|
141
145
|
def raw_content
|
142
146
|
return if pseudo_license?
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Licensee
|
2
|
+
module Matchers
|
3
|
+
class Cran < Package
|
4
|
+
attr_reader :file
|
5
|
+
|
6
|
+
# While we could parse the package.json or bower.json file, prefer
|
7
|
+
# a lenient regex for speed and security. Moar parsing moar problems.
|
8
|
+
LICENSE_REGEX = /
|
9
|
+
^license:\s*([a-z\-0-9\.]+)
|
10
|
+
/ix
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def license_property
|
15
|
+
match = @file.content.match LICENSE_REGEX
|
16
|
+
match[1].downcase if match && match[1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/licensee/project.rb
CHANGED
@@ -36,7 +36,7 @@ module Licensee
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
39
|
+
def readme_file
|
40
40
|
return unless detect_readme?
|
41
41
|
return @readme if defined? @readme
|
42
42
|
@readme = begin
|
@@ -45,6 +45,7 @@ module Licensee
|
|
45
45
|
Readme.new(content, name) if content && name
|
46
46
|
end
|
47
47
|
end
|
48
|
+
alias readme readme_file
|
48
49
|
|
49
50
|
def package_file
|
50
51
|
return unless detect_packages?
|
@@ -3,10 +3,16 @@ module Licensee
|
|
3
3
|
class File
|
4
4
|
attr_reader :content, :filename
|
5
5
|
|
6
|
+
ENCODING = Encoding::UTF_8
|
7
|
+
ENCODING_OPTIONS = {
|
8
|
+
invalid: :replace,
|
9
|
+
undef: :replace,
|
10
|
+
replace: ''
|
11
|
+
}.freeze
|
12
|
+
|
6
13
|
def initialize(content, filename = nil)
|
7
14
|
@content = content
|
8
|
-
|
9
|
-
@content.encode!(Encoding::UTF_8, options)
|
15
|
+
@content.encode!(ENCODING, ENCODING_OPTIONS)
|
10
16
|
@filename = filename
|
11
17
|
end
|
12
18
|
|
@@ -3,6 +3,32 @@ module Licensee
|
|
3
3
|
class LicenseFile < Licensee::Project::File
|
4
4
|
include Licensee::ContentHelper
|
5
5
|
|
6
|
+
# List of extensions to give preference to
|
7
|
+
PREFERRED_EXT = %w(md markdown txt).freeze
|
8
|
+
PREFERRED_EXT_REGEX = /\.#{Regexp.union(PREFERRED_EXT)}\z/
|
9
|
+
|
10
|
+
# Regex to match any extension
|
11
|
+
ANY_EXT_REGEX = %r{\.[^./]+\z}
|
12
|
+
|
13
|
+
# Regex to match, LICENSE, LICENCE, unlicense, etc.
|
14
|
+
LICENSE_REGEX = /(un)?licen[sc]e/i
|
15
|
+
|
16
|
+
# Regex to match COPYING, COPYRIGHT, etc.
|
17
|
+
COPYING_REGEX = /copy(ing|right)/i
|
18
|
+
|
19
|
+
# Hash of Regex => score with which to score potential license files
|
20
|
+
FILENAME_REGEXES = {
|
21
|
+
/\A#{LICENSE_REGEX}\z/ => 1.0, # LICENSE
|
22
|
+
/\A#{LICENSE_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.9, # LICENSE.md
|
23
|
+
/\A#{COPYING_REGEX}\z/ => 0.8, # COPYING
|
24
|
+
/\A#{COPYING_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.7, # COPYING.md
|
25
|
+
/\A#{LICENSE_REGEX}#{ANY_EXT_REGEX}\z/ => 0.6, # LICENSE.textile
|
26
|
+
/\A#{COPYING_REGEX}#{ANY_EXT_REGEX}\z/ => 0.5, # COPYING.textile
|
27
|
+
/#{LICENSE_REGEX}/ => 0.4, # LICENSE-MIT
|
28
|
+
/#{COPYING_REGEX}/ => 0.3, # COPYING-MIT
|
29
|
+
// => 0.0 # Catch all
|
30
|
+
}.freeze
|
31
|
+
|
6
32
|
def possible_matchers
|
7
33
|
[Matchers::Copyright, Matchers::Exact, Matchers::Dice]
|
8
34
|
end
|
@@ -13,12 +39,7 @@ module Licensee
|
|
13
39
|
end
|
14
40
|
|
15
41
|
def self.name_score(filename)
|
16
|
-
|
17
|
-
return 0.9 if filename =~ /\A(un)?licen[sc]e\.(md|markdown|txt)\z/i
|
18
|
-
return 0.8 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
|
19
|
-
return 0.7 if filename =~ /\A(un)?licen[sc]e\.[^.]+\z/i
|
20
|
-
return 0.5 if filename =~ /licen[sc]e/i
|
21
|
-
0.0
|
42
|
+
FILENAME_REGEXES.find { |regex, _| filename =~ regex }[1]
|
22
43
|
end
|
23
44
|
|
24
45
|
# case-insensitive block to determine if the given file is LICENSE.lesser
|
@@ -8,13 +8,18 @@ module Licensee
|
|
8
8
|
when '.json'
|
9
9
|
[Matchers::NpmBower]
|
10
10
|
else
|
11
|
-
|
11
|
+
if filename == 'DESCRIPTION' && content.start_with?('Package:')
|
12
|
+
[Matchers::Cran]
|
13
|
+
else
|
14
|
+
[]
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def self.name_score(filename)
|
16
20
|
return 1.0 if ::File.extname(filename) == '.gemspec'
|
17
21
|
return 1.0 if filename == 'package.json'
|
22
|
+
return 0.9 if filename == 'DESCRIPTION'
|
18
23
|
return 0.75 if filename == 'bower.json'
|
19
24
|
0.0
|
20
25
|
end
|
@@ -2,8 +2,8 @@ module Licensee
|
|
2
2
|
class Project
|
3
3
|
class Readme < LicenseFile
|
4
4
|
SCORES = {
|
5
|
-
/\AREADME\z/i
|
6
|
-
/\AREADME\.(md|markdown|txt)\z/i => 0.9
|
5
|
+
/\AREADME\z/i => 1.0,
|
6
|
+
/\AREADME\.(md|markdown|mdown|txt)\z/i => 0.9
|
7
7
|
}.freeze
|
8
8
|
|
9
9
|
CONTENT_REGEX = /^#+ Licen[sc]e$(.*?)(?=#+|\z)/im
|
data/lib/licensee/version.rb
CHANGED
data/spec/bin_spec.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
RSpec.describe 'command line invocation' do
|
2
|
+
let(:command) { ['ruby', 'bin/licensee'] }
|
3
|
+
let(:output) do
|
4
|
+
Dir.chdir project_root do
|
5
|
+
Open3.capture3(*[command, arguments].flatten)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
let(:stdout) { output[0] }
|
9
|
+
let(:stderr) { output[1] }
|
10
|
+
let(:status) { output[2] }
|
11
|
+
|
12
|
+
context 'without any arguments' do
|
13
|
+
let(:arguments) { [] }
|
14
|
+
|
15
|
+
it 'Returns a zero exit code' do
|
16
|
+
expect(status.exitstatus).to eql(0)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "detects the folder's license" do
|
20
|
+
expect(stdout).to match('License: MIT License')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'outputs the hash' do
|
24
|
+
expect(stdout).to match('750260c322080bab4c19fd55eb78bc73e1ae8f11')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'outputs the attribution' do
|
28
|
+
expect(stdout).to match('2014-2016 Ben Balter')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'outputs the confidence' do
|
32
|
+
expect(stdout).to match('Confidence: 100.00%')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'outputs the method' do
|
36
|
+
expect(stdout).to match('Method: Licensee::Matchers::Exact')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when given a folder path' do
|
41
|
+
let(:arguments) { [project_root] }
|
42
|
+
|
43
|
+
it "detects the folder's license" do
|
44
|
+
expect(stdout).to match('License: MIT License')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when given a license path' do
|
49
|
+
let(:license_path) { File.expand_path 'LICENSE.md', project_root }
|
50
|
+
let(:arguments) { [license_path] }
|
51
|
+
|
52
|
+
it "detects the file's license" do
|
53
|
+
expect(stdout).to match('License: MIT License')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|