licensee 8.5.0 → 8.6.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.
- 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
|
+
[](https://travis-ci.org/benbalter/licensee) [](http://badge.fury.io/rb/licensee) [](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
|