gemterms 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jon Williams
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Gemterms
2
+ Checks the licensing of your Gemfile.
3
+
4
+ ## Status
5
+
6
+ This is an early release. It's functional, but I'll be adding more useful
7
+ utilities soon.
8
+
9
+ ## Installation and Usage
10
+
11
+ To install, simply grab the gem:
12
+
13
+ gem install gemterms
14
+
15
+ Change a project directory with a Gemfile (e.g. Your Rails v3+ project) and
16
+ type:
17
+
18
+ gemterms report
19
+
20
+ This will output a list (known) licenses for your gems. For more
21
+ information and options, run gemterms with the --help option:
22
+
23
+ gemterms --help
24
+
25
+ ## Use of this Software
26
+
27
+ This tool is based upon a number of heuristics and guesses. It should not
28
+ be treated as legal advice. The MIT-LICENSE.txt really applies here.
29
+
30
+ Help is more than welcome. Use the usual Fork, Pull Request approach to
31
+ contribute. In particular, it's good to get additional licenses and
32
+ compatabilities.
33
+
34
+ ## License
35
+ MIT Licensed. See MIT-LICENSE.txt for more information.
36
+
37
+ Thanks, [@jonathannen](http://twitter.com/jonathannen).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+ require 'bundler/gem_tasks'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
data/bin/gemterms ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gemterms'
3
+ require 'gemterms/gem_runner'
4
+ Gemterms::GemRunner.new(ARGV)
data/compatability.yml ADDED
@@ -0,0 +1,395 @@
1
+ licenses:
2
+ references:
3
+ A: "http://opensource.org/licenses/alphabetical"
4
+ B: "http://www.gnu.org/licenses/licenses.html"
5
+ 1: "http://www.ruby-lang.org/en/about/license.txt"
6
+ 2: "http://www.gnu.org/licenses/license-list.html#WTFPL"
7
+ 3: "http://www.gnu.org/licenses/license-list.html#apache2"
8
+ 4: "http://www.gnu.org/licenses/license-list.html#ArtisticLicense2"
9
+ 5: "http://www.gnu.org/licenses/license-list.html#ModifiedBSD"
10
+ 6: "http://www.gnu.org/licenses/license-list.html#FreeBSD"
11
+ 7: "http://www.gnu.org/licenses/license-list.html#boost"
12
+ 8: "http://www.gnu.org/licenses/license-list.html#Expat"
13
+
14
+ # Special cases
15
+ #*: "http://opensource.org/faq#public-domain"
16
+ "Public Domain":
17
+ name: "United States Public Domain"
18
+ unknown: true
19
+
20
+ # Top Level Classifications
21
+ "GNU Software":
22
+ name: "GNU Software Licenses"
23
+ unknown: true
24
+ uri: "http://www.gnu.org/licenses/licenses.html"
25
+
26
+ "OSI Approved":
27
+ name: "Open Source Initiative License"
28
+ unknown: true
29
+
30
+ "Proprietary":
31
+ name: "Proprietary License"
32
+ unknown: true
33
+
34
+ "Unknown":
35
+ name: "Not supplied, unknown or unclassified License"
36
+ unknown: true
37
+
38
+ # OSI Approved Licenses
39
+ "AFL-3.0":
40
+ A: "OSI Approved"
41
+ name: "Academic Free License 3.0"
42
+ uri: "http://opensource.org/licenses/AFL-3.0"
43
+ "AGPL-3.0":
44
+ A: "OSI Approved"
45
+ B: "GNU Software"
46
+ name: "Affero GNU Public License"
47
+ uri: "http://opensource.org/licenses/AGPL-3.0"
48
+ "APL-1.0":
49
+ A: "OSI Approved"
50
+ name: "Adaptive Public License"
51
+ uri: "http://opensource.org/licenses/APL-1.0"
52
+ "Apache-2.0":
53
+ A: "OSI Approved"
54
+ 3: "GPL-3.0"
55
+ name: "Apache License 2.0"
56
+ uri: "http://opensource.org/licenses/Apache-2.0"
57
+ "APSL-2.0":
58
+ A: "OSI Approved"
59
+ name: "Apple Public Source License"
60
+ uri: "http://opensource.org/licenses/APSL-2.0"
61
+ "Artistic-2.0":
62
+ A: "OSI Approved"
63
+ 4: ["GPL-2.0", "GPL-3.0"]
64
+ name: "Artistic license 2.0"
65
+ uri: "http://opensource.org/licenses/Artistic-2.0"
66
+ "AAL":
67
+ A: "OSI Approved"
68
+ name: "Attribution Assurance Licenses"
69
+ uri: "http://opensource.org/licenses/AAL"
70
+ "BSD-3-Clause":
71
+ A: "OSI Approved"
72
+ 5: ["GPL-2.0", "GPL-3.0"]
73
+ name: "BSD 3-Clause \"New\" or \"Revised\" License"
74
+ uri: "http://opensource.org/licenses/BSD-3-Clause"
75
+ "BSD-2-Clause":
76
+ A: "OSI Approved"
77
+ 6: ["GPL-2.0", "GPL-3.0"]
78
+ name: "BSD 2-Clause \"Simplified\" or \"FreeBSD\" License"
79
+ uri: "http://opensource.org/licenses/BSD-2-Clause"
80
+ "BSL-1.0":
81
+ A: "OSI Approved"
82
+ 7: ["GPL-2.0", "GPL-3.0"]
83
+ name: "Boost Software License"
84
+ uri: "http://opensource.org/licenses/BSL-1.0"
85
+ "CATOSL-1.1":
86
+ A: "OSI Approved"
87
+ name: "Computer Associates Trusted Open Source License 1.1"
88
+ uri: "http://opensource.org/licenses/CATOSL-1.1"
89
+ "CDDL-1.0":
90
+ A: "OSI Approved"
91
+ name: "Common Development and Distribution License 1.0"
92
+ uri: "http://opensource.org/licenses/CDDL-1.0"
93
+ "CPAL-1.0":
94
+ A: "OSI Approved"
95
+ name: "Common Public Attribution License 1.0"
96
+ uri: "http://opensource.org/licenses/CPAL-1.0"
97
+ "CUA-OPL-1.0":
98
+ A: "OSI Approved"
99
+ name: "CUA Office Public License Version 1.0"
100
+ uri: "http://opensource.org/licenses/CUA-OPL-1.0"
101
+ "EUDatagrid":
102
+ A: "OSI Approved"
103
+ name: "EU DataGrid Software License"
104
+ uri: "http://opensource.org/licenses/EUDatagrid"
105
+ "EPL-1.0":
106
+ A: "OSI Approved"
107
+ name: "Eclipse Public License 1.0"
108
+ uri: "http://opensource.org/licenses/EPL-1.0"
109
+ "ECL-2.0":
110
+ A: "OSI Approved"
111
+ name: "Educational Community License, Version 2.0"
112
+ uri: "http://opensource.org/licenses/ECL-2.0"
113
+ "EFL-2.0":
114
+ A: "OSI Approved"
115
+ name: "Eiffel Forum License V2.0"
116
+ uri: "http://opensource.org/licenses/EFL-2.0"
117
+ "Entessa":
118
+ A: "OSI Approved"
119
+ name: "Entessa Public License"
120
+ uri: "http://opensource.org/licenses/Entessa"
121
+ "EUPL-1.1":
122
+ A: "OSI Approved"
123
+ name: "European Union Public License, Version 1.1"
124
+ uri: "http://opensource.org/licenses/EUPL-1.1"
125
+ "Fair":
126
+ A: "OSI Approved"
127
+ name: "Fair License"
128
+ uri: "http://opensource.org/licenses/Fair"
129
+ "Frameworx-1.0":
130
+ A: "OSI Approved"
131
+ name: "Frameworx License"
132
+ uri: "http://opensource.org/licenses/Frameworx-1.0"
133
+ "AGPL-3.0":
134
+ A: "OSI Approved"
135
+ B: "GNU Software"
136
+ name: "GNU Affero General Public License v3"
137
+ uri: "http://opensource.org/licenses/AGPL-3.0"
138
+ "GPL-2.0":
139
+ A: "OSI Approved"
140
+ B: "GNU Software"
141
+ name: "GNU General Public License version 2.0"
142
+ uri: "http://opensource.org/licenses/GPL-2.0"
143
+ "GPL-3.0":
144
+ A: "OSI Approved"
145
+ B: "GNU Software"
146
+ name: "GNU General Public License version 3.0"
147
+ uri: "http://opensource.org/licenses/GPL-3.0"
148
+ "LGPL-2.1":
149
+ A: "OSI Approved"
150
+ B: "GNU Software"
151
+ name: "GNU Library or \"Lesser\" General Public License version 2.1"
152
+ uri: "http://opensource.org/licenses/LGPL-2.1"
153
+ "LGPL-3.0":
154
+ A: "OSI Approved"
155
+ B: "GNU Software"
156
+ name: "GNU Library or \"Lesser\" General Public License version 3.0"
157
+ uri: "http://opensource.org/licenses/LGPL-3.0"
158
+ "HPND":
159
+ A: "OSI Approved"
160
+ name: "Historical Permission Notice and Disclaimer"
161
+ uri: "http://opensource.org/licenses/HPND"
162
+ "IPL-1.0":
163
+ A: "OSI Approved"
164
+ name: "IBM Public License 1.0"
165
+ uri: "http://opensource.org/licenses/IPL-1.0"
166
+ "IPA":
167
+ A: "OSI Approved"
168
+ name: "IPA Font License"
169
+ uri: "http://opensource.org/licenses/IPA"
170
+ "ISC":
171
+ A: "OSI Approved"
172
+ name: "ISC License"
173
+ uri: "http://opensource.org/licenses/ISC"
174
+ "LPPL-1.3c":
175
+ A: "OSI Approved"
176
+ name: "LaTeX Project Public License 1.3c"
177
+ uri: "http://opensource.org/licenses/LPPL-1.3c"
178
+ "LPL-1.02":
179
+ A: "OSI Approved"
180
+ name: "Lucent Public License Version 1.02"
181
+ uri: "http://opensource.org/licenses/LPL-1.02"
182
+ "MirOS":
183
+ A: "OSI Approved"
184
+ name: "MirOS Licence"
185
+ uri: "http://opensource.org/licenses/MirOS"
186
+ "MS-PL":
187
+ A: "OSI Approved"
188
+ name: "Microsoft Public License"
189
+ uri: "http://opensource.org/licenses/MS-PL"
190
+ "MS-RL":
191
+ A: "OSI Approved"
192
+ name: "Microsoft Reciprocal License"
193
+ uri: "http://opensource.org/licenses/MS-RL"
194
+ "MIT":
195
+ A: "OSI Approved"
196
+ 8: ["GPL-2.0", "GPL-3.0"]
197
+ name: "MIT license"
198
+ uri: "http://opensource.org/licenses/MIT"
199
+ "Motosoto":
200
+ A: "OSI Approved"
201
+ name: "Motosoto License"
202
+ uri: "http://opensource.org/licenses/Motosoto"
203
+ "MPL-2.0":
204
+ A: "OSI Approved"
205
+ name: "Mozilla Public License 2.0"
206
+ uri: "http://opensource.org/licenses/MPL-2.0"
207
+ "Multics":
208
+ A: "OSI Approved"
209
+ name: "Multics License"
210
+ uri: "http://opensource.org/licenses/Multics"
211
+ "NASA-1.3":
212
+ A: "OSI Approved"
213
+ name: "NASA Open Source Agreement 1.3"
214
+ uri: "http://opensource.org/licenses/NASA-1.3"
215
+ "NTP":
216
+ A: "OSI Approved"
217
+ name: "NTP License"
218
+ uri: "http://opensource.org/licenses/NTP"
219
+ "Naumen":
220
+ A: "OSI Approved"
221
+ name: "Naumen Public License"
222
+ uri: "http://opensource.org/licenses/Naumen"
223
+ "NGPL":
224
+ A: "OSI Approved"
225
+ name: "Nethack General Public License"
226
+ uri: "http://opensource.org/licenses/NGPL"
227
+ "Nokia":
228
+ A: "OSI Approved"
229
+ name: "Nokia Open Source License"
230
+ uri: "http://opensource.org/licenses/Nokia"
231
+ "NPOSL-3.0":
232
+ A: "OSI Approved"
233
+ name: "Non-Profit Open Software License 3.0"
234
+ uri: "http://opensource.org/licenses/NPOSL-3.0"
235
+ "OCLC-2.0":
236
+ A: "OSI Approved"
237
+ name: "OCLC Research Public License 2.0"
238
+ uri: "http://opensource.org/licenses/OCLC-2.0"
239
+ "OFL-1.1":
240
+ A: "OSI Approved"
241
+ name: "Open Font License 1.1"
242
+ uri: "http://opensource.org/licenses/OFL-1.1"
243
+ "OGTSL":
244
+ A: "OSI Approved"
245
+ name: "Open Group Test Suite License"
246
+ uri: "http://opensource.org/licenses/OGTSL"
247
+ "OSL-3.0":
248
+ A: "OSI Approved"
249
+ name: "Open Software License 3.0"
250
+ uri: "http://opensource.org/licenses/OSL-3.0"
251
+ "PHP-3.0":
252
+ A: "OSI Approved"
253
+ name: "PHP License 3.0"
254
+ uri: "http://opensource.org/licenses/PHP-3.0"
255
+ "PostgreSQL":
256
+ A: "OSI Approved"
257
+ name: "The PostgreSQL License"
258
+ uri: "http://opensource.org/licenses/PostgreSQL"
259
+ "Python-2.0":
260
+ A: "OSI Approved"
261
+ name: "Python License"
262
+ uri: "http://opensource.org/licenses/Python-2.0"
263
+ "CNRI-Python":
264
+ A: "OSI Approved"
265
+ name: "CNRI Python license"
266
+ uri: "http://opensource.org/licenses/CNRI-Python"
267
+ "QPL-1.0":
268
+ A: "OSI Approved"
269
+ name: "Q Public License"
270
+ uri: "http://opensource.org/licenses/QPL-1.0"
271
+ "RPSL-1.0":
272
+ A: "OSI Approved"
273
+ name: "RealNetworks Public Source License V1.0"
274
+ uri: "http://opensource.org/licenses/RPSL-1.0"
275
+ "RPL-1.5":
276
+ A: "OSI Approved"
277
+ name: "Reciprocal Public License 1.5"
278
+ uri: "http://opensource.org/licenses/RPL-1.5"
279
+ "RSCPL":
280
+ A: "OSI Approved"
281
+ name: "Ricoh Source Code Public License"
282
+ uri: "http://opensource.org/licenses/RSCPL"
283
+ "SimPL-2.0":
284
+ A: "OSI Approved"
285
+ name: "Simple Public License 2.0"
286
+ uri: "http://opensource.org/licenses/SimPL-2.0"
287
+ "Sleepycat":
288
+ A: "OSI Approved"
289
+ name: "Sleepycat License"
290
+ uri: "http://opensource.org/licenses/Sleepycat"
291
+ "SPL-1.0":
292
+ A: "OSI Approved"
293
+ name: "Sun Public License 1.0"
294
+ uri: "http://opensource.org/licenses/SPL-1.0"
295
+ "Watcom-1.0":
296
+ A: "OSI Approved"
297
+ name: "Sybase Open Watcom Public License 1.0"
298
+ uri: "http://opensource.org/licenses/Watcom-1.0"
299
+ "NCSA":
300
+ A: "OSI Approved"
301
+ name: "University of Illinois/NCSA Open Source License"
302
+ uri: "http://opensource.org/licenses/NCSA"
303
+ "VSL-1.0":
304
+ A: "OSI Approved"
305
+ name: "Vovida Software License v. 1.0"
306
+ uri: "http://opensource.org/licenses/VSL-1.0"
307
+ "W3C":
308
+ A: "OSI Approved"
309
+ name: "W3C License"
310
+ uri: "http://opensource.org/licenses/W3C"
311
+ "WXwindows":
312
+ A: "OSI Approved"
313
+ name: "wxWindows Library License"
314
+ uri: "http://opensource.org/licenses/WXwindows"
315
+ "Xnet":
316
+ A: "OSI Approved"
317
+ name: "X.Net License"
318
+ uri: "http://opensource.org/licenses/Xnet"
319
+ "ZPL-2.0":
320
+ A: "OSI Approved"
321
+ name: "Zope Public License 2.0"
322
+ uri: "http://opensource.org/licenses/ZPL-2.0"
323
+ "Zlib":
324
+ A: "OSI Approved"
325
+ name: "zlib/libpng license"
326
+ uri: "http://opensource.org/licenses/Zlib"
327
+
328
+
329
+ # Other Licenses
330
+ "Ruby":
331
+ 1: "BSD-2-Clause"
332
+ name: "Ruby License"
333
+ uri: "http://www.ruby-lang.org/en/about/license.txt"
334
+
335
+ "WTFPL":
336
+ 2: ["!GPL-2.0", "GPL-3.0"]
337
+ #@todo "!Public Domain"
338
+ name: "Do What The Fuck You Want To Public License"
339
+ uri: "http://www.wtfpl.net/about/"
340
+
341
+ # References used in gem specifications of RubyGems. This is free-form, so
342
+ # tends to have a lot of variation. This maps directly to the "known"
343
+ # formats.
344
+ #
345
+ # Modifying these values:
346
+ # - If the mapping is ambiguous, choose the most restrictive form. For
347
+ # example, "BSD" maps to the 3-Clause BSD.
348
+ #
349
+ # - If the mapping is not completely clear, add a bang "!" on the beginning
350
+ # to generate a warning.
351
+ rubygems:
352
+ "MIT": "MIT"
353
+ "LGPLv2": "!LGPL-2.1"
354
+ "BSD": "BSD-3-Clause"
355
+ "Apache License 2.0": "Apache-2.0"
356
+ "BSD-2-Clause": "BSD-2-Clause"
357
+ "Ruby": "Ruby"
358
+ "APLv2": "!Apache-2.0"
359
+ "Apache-2.0": "Apache-2.0"
360
+ "GPL-3": "GPL-3.0"
361
+ "Apache License Version 2.0": "Apache-2.0"
362
+ "GPL-V2+": "GPL-3.0"
363
+ "Ruby's": "Ruby"
364
+ "Apache 2.0": "GPL-3.0"
365
+ "Artistic 2.0": "Artistic-2.0"
366
+ "LGPL-2": "!LGPL-2.1"
367
+ "GPLv3": "GPL-3.0"
368
+ "BSD + MPL 1.1/GPL 2.0/LGPL 2.1": ["BSD-3-Clause", "GPL-2.0", "LGPL-2.1"]
369
+ "WTFPL": "WTFPL"
370
+ "LGPL-3": "LGPL-3.0"
371
+ "GPL": "!GPL-3.0"
372
+ "Ruby or LGPLv3+": ["Ruby", "LGPL-3.0"]
373
+ "New BSD": "BSD-3-Clause"
374
+ "MIT-LICENSE": "MIT"
375
+ "Public Domain": "Public Domain"
376
+ "LGPLv2.1": "LGPL-2.1"
377
+ "GPL-2": "GPL-2.0"
378
+ "GPLv2+": "GPL-2.0"
379
+ "GPLv2": "GPL-2.0"
380
+ "Ruby 1.8": "Ruby"
381
+ "MIT License": "MIT"
382
+ "BSD-3-Clause": "BSD-2-Clause"
383
+ "Apache v2": "Apache-2.0"
384
+ "LGPL v2.1": "LGPL-2.1"
385
+ "GPL-2 or later": "GPLv2"
386
+ "2-clause BSD-style license": "BSD-2-Clause"
387
+ "Apache Software License 2.0": "Apache-2.0"
388
+ "Ruby License": "Ruby"
389
+ "LGPL-2.0+": "LGPL-2.1"
390
+ "GNU GPL v2": "GPL-2.0"
391
+ "LGPLv3": "LGPL-3.0"
392
+ "BSD-3": "BSD-3-Clause"
393
+ "LGPLv2.1 or later": "LGPL-2.1"
394
+ "Ruby's and PSFL (lib/test/unit/diff.rb)": ["Ruby", "!Python-2.0"]
395
+ "2-clause BSDL": "BSD-2-Clause"
data/gemterms.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'gemterms'
3
+ s.version = '0.1.0'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = ['Jon Williams']
6
+ s.email = ['jon@jonathannen.com']
7
+ s.homepage = 'https://github.com/jonathannen/gemterms'
8
+ s.summary = 'Checks the licensing of your Gemfile.'
9
+ s.description = 'Scans Gemfiles to see what licenses are in use.'
10
+
11
+ s.license = "MIT"
12
+
13
+ s.files = `git ls-files`.split($/)
14
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_runtime_dependency 'bundler', '>= 1.0.10'
19
+ end
data/lib/gemterms.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Gemterms
2
+ end
3
+
4
+ require 'gemterms/license'
5
+ require 'gemterms/project'
@@ -0,0 +1,143 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'time'
4
+ require 'gemterms/ruby_gems'
5
+
6
+ module Gemterms
7
+
8
+ # Accepts a Gemfile and Gemfile.lock to produce a <tt>Gemterm::Project</tt>
9
+ # based upon the rubygems defined. Can output statistics on that basis.
10
+ class GemFiler
11
+ attr_accessor :disable_api, :use_remotes
12
+ attr_reader :bundle, :project
13
+
14
+ def initialize(licenser)
15
+ @licenser = licenser
16
+ @use_remotes = @disable_api = false
17
+ end
18
+
19
+ def read_bundle
20
+ # Read the Bundle from the Gem and Lockfiles
21
+ Bundler.settings[:frozen] = true
22
+ @bundle = Bundler::Dsl.evaluate(@gemfile, @lockfile, {})
23
+ end
24
+
25
+ def read_bundle_specs
26
+ read_bundle
27
+ missing = []
28
+ @specs = bundle.resolve.materialize(bundle.dependencies, missing)
29
+
30
+ # Happy path - all the specs are available locally.
31
+ if missing.length == 0
32
+ # Use requested specs instead. This is due to the fact that
33
+ # bundler cleverly excludes itself. However, if it's an explicit
34
+ # spec we want to evaluate it's licence too (ps. It's MIT)
35
+ @specs = bundle.requested_specs
36
+ return true
37
+ end
38
+
39
+ # If we can, try and get the additional gem data from RubyGem sources
40
+ # (typically https://rubygems.org). Otherwise give the user a warning.
41
+ if use_remotes
42
+ puts "Sourcing gem information from gem sources. This may take some time."
43
+ read_bundle
44
+ @specs = bundle.resolve_remotely!
45
+ else
46
+ # @todo This path will be missing bundler - if it was supplied.
47
+ puts missing.length == 1 ? "The following gem isn't installed:" : "The following gems aren't installed:"
48
+ puts <<-INST
49
+ #{missing.map { |s| s.full_name } * ', '}
50
+
51
+ We cannot report on uninstalled gems. You can use `bundle install` to install.
52
+ Alternatively, if you run with the `--use-remotes` option, gemterms will use
53
+ your RubyGem sources to load gem metadata (note, this will be slower).
54
+
55
+ INST
56
+ end
57
+ end
58
+
59
+ def process(gemfile, lockfile)
60
+ @gemfile = gemfile
61
+ @lockfile = lockfile
62
+ @project = Project.new
63
+
64
+ read_bundle_specs
65
+ load_specs
66
+ @project
67
+ end
68
+
69
+ protected
70
+
71
+ def load_specs
72
+ # @todo Do we include *all* dependencies of a given gem here? Technically
73
+ # they are not in use, but they are linked to the gem. Maybe one for
74
+ # --very-strict mode
75
+ @sources = {}
76
+ @specs.each do |spec|
77
+ spec = spec.__materialize__ if Bundler::LazySpecification == spec
78
+ @project << load_spec_as_component(spec)
79
+ end
80
+ puts "\n\n" if @sources.length > 0
81
+ @project
82
+ end
83
+
84
+ def load_spec_as_component(spec)
85
+ if spec.licenses.nil? || spec.licenses == []
86
+ licenses = []
87
+ if (spec.source.class == Bundler::Source::Rubygems) && !disable_api
88
+ puts "Getting missing license data from gem source (use --disable-api to skip) " if @sources.length == 0
89
+ STDOUT.print(".") & STDOUT.flush
90
+ licenses = rubygem_licences_from_spec(spec)
91
+ end
92
+ else
93
+ licenses = spec.licenses
94
+ end
95
+ component = Component.new(spec.name, spec.version, @licenser.rubygem_licenses(licenses))
96
+ end
97
+
98
+ # Iterates over the remotes in the spec, using the API to access rubygem
99
+ # data. If a particular remote ever fails, it's not tried again.
100
+ #
101
+ # @param [ Gem::Specification ] spec The specification to source
102
+ # @return [ Array<String> ] the array of license strings (can be empty)
103
+ def rubygem_licences_from_spec(spec)
104
+ # Try every remote until we (hopefully) get a result
105
+ licenses = spec.source.remotes.each do |remote|
106
+ begin
107
+ source = @sources[remote]
108
+ next if source == :unavailable
109
+ @sources[remote] = source = RubyGems.new(remote) if source.nil?
110
+ licenses = rubygem_licenses_from_versions(spec, source)
111
+ return licenses unless licenses.nil?
112
+ rescue SourceUnavailableError => sae
113
+ @sources[source] = :unavailable
114
+ nil
115
+ end
116
+ end
117
+ []
118
+ end
119
+
120
+ def rubygem_licenses_from_versions(spec, source)
121
+ versions = source.versions(spec.name)
122
+
123
+ # Try for an exact match. If this has license information, we'll use it.
124
+ version = versions.detect { |v| v["number"] == spec.version.to_s }
125
+ licenses = version.nil? ? nil : version["licenses"]
126
+
127
+ # Try for any later version. e.g. Rails 4 is marked as MIT licensed,
128
+ # but earlier versions aren't. We assume MIT for the earlier versions.
129
+ # @todo this should be disabled when a --strict mode is introduced.
130
+ if licenses.nil? || licenses == []
131
+ version = versions.detect do |v|
132
+ (Gem::Version.new(v["number"]) > spec.version) &&
133
+ !v["licenses"].nil? && v["licenses"].length > 0
134
+ end
135
+ licenses = version.nil? ? nil : version["licenses"]
136
+ end
137
+
138
+ licenses
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,96 @@
1
+ require 'gemterms/gem_filer'
2
+ require 'gemterms/runner'
3
+
4
+ module Gemterms
5
+
6
+ # Command line utility for running reports on Bundler (Gemfile) based
7
+ # projects. Think includes Rails v3+ projects.
8
+ class GemRunner < Runner
9
+ attr_reader :no_remote
10
+
11
+ def gemfiles(args)
12
+ @gemfile = args.shift || "./Gemfile"
13
+ @lockfile = args.shift || "./Gemfile.lock"
14
+ errors = []
15
+ errors << "Couldn't file '#{@gemfile}'." unless File.exists?(@gemfile)
16
+ errors << "Couldn't file '#{@lockfile}'." unless File.exists?(@lockfile)
17
+ if errors.length > 0
18
+ puts "#{errors * ' '} Run 'gemterms --help' if you need more information."
19
+ exit -1
20
+ end
21
+ end
22
+
23
+ def initialize(args)
24
+ super('gem', 'gems')
25
+ return if standard_commands(args)
26
+
27
+ filer = GemFiler.new(licenser)
28
+ filer.disable_api = @disable_api = !!args.delete("--disable-api")
29
+ filer.use_remotes = @use_remotes = !!args.delete("--use-remotes")
30
+
31
+ case (args.shift || 'report')
32
+ when 'report'
33
+ gemfiles(args)
34
+ @project = filer.process(@gemfile, @lockfile)
35
+ commentary = "This is from the #{counter(filer.bundle.dependencies.length)} listed in your Gemfile, plus any dependencies."
36
+ stats(commentary)
37
+ ruler && license_breakdown
38
+
39
+ unlicensed = @project.count_unlicensed
40
+ ruler && no_remote_instructions(unlicensed) if no_remote && (unlicensed > 0)
41
+ end
42
+ end
43
+
44
+ # Instructions when there is missing license information, but the user
45
+ # has specified --disable-api - preventing remote license sources being used.
46
+ def no_remote_instructions(unlicensed)
47
+ puts <<-INST
48
+ There is no license defined for #{counter(unlicensed)}. You are running with the `--disable-api`
49
+ option. If you remove this option, gemterms will attempt to use RubyGems and
50
+ other sources for license information.
51
+ INST
52
+ true
53
+ end
54
+
55
+ # Show usage instructions
56
+ def usage
57
+ puts <<-USAGE
58
+ Usage:
59
+
60
+ gemterms
61
+ Equivalent to `gemfile report` below.
62
+
63
+ gemterms --help
64
+ Outputs these usage instructions.
65
+
66
+ gemterms list-licenses
67
+ Outputs a list of licenses that are referenced by this tool. This list is
68
+ in the form "<name> [<code>]". You can use the code to look up licenses.
69
+
70
+ gemterms report [options] [GEMFILE] [LOCKFILE]
71
+ Produces a report on license usage.
72
+
73
+ gemterms show-license <code>
74
+ Shows the details for the license given the code. e.g. Try the code
75
+ Ruby for details of the ruby license. See also "list-licenses" above.
76
+
77
+ Options:
78
+ GEMFILE and LOCKFILE will default to your current directory. Generally you'll
79
+ run gemterms from your Rails (or similar project) directory and omit these
80
+ arguments.
81
+
82
+ --disable-api
83
+ If the gem metadata isn't complete, gemterms seeks additional information
84
+ from the source (e.g. RubyGems) API. This option disables that feature.
85
+
86
+ --use-remotes
87
+ If gem metadata is not available, gemterms will use the gem sources (e.g
88
+ https://rubygems.org).
89
+
90
+ USAGE
91
+ true
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,108 @@
1
+ require 'yaml'
2
+
3
+ module Gemterms
4
+
5
+ # An actual license in the system. For example an MIT License, or BSD
6
+ # 3-Clause License.
7
+ class License
8
+ attr_accessor :unknown
9
+ attr_reader :classified, :compatible, :code, :name, :uri
10
+ alias :unknown? :unknown
11
+
12
+ def initialize(code, data)
13
+ @code = code || "Unknown"
14
+ @name = data.delete("name")
15
+ @uri = data.delete("uri")
16
+
17
+ @classified = []
18
+ @compatible = []
19
+ @unknown = false
20
+ end
21
+
22
+ def inspect
23
+ "#<License code=#{code} name='#{name}' uri=#{uri} compat_count=#{@compatible.length}>"
24
+ end
25
+
26
+ def mark_classified(*args)
27
+ @classified << args
28
+ end
29
+
30
+ #license, fer, warning = false
31
+ def mark_compatible(*args)
32
+ @compatible << args
33
+ end
34
+
35
+ def to_s
36
+ "#{name} [#{code}]"
37
+ end
38
+
39
+ end
40
+
41
+ class Licensing
42
+ attr_reader :licenses, :references, :unknown_license
43
+
44
+ UNKNOWN_LICENSE_CODE = "Unknown"
45
+
46
+ def[](code)
47
+ licenses[code] || @unknown_license
48
+ end
49
+
50
+ def initialize(filename = nil)
51
+ filename ||= File.join(File.dirname(__FILE__), '..', '..', 'compatability.yml')
52
+ load(filename)
53
+ end
54
+
55
+ def inspect
56
+ "#<Licensing licence_count=#{@licenses.length}>"
57
+ end
58
+
59
+ # @param [ String, Array ] term_or_terms The terms provided in the license
60
+ # or licenses portion of the rubygem specification.
61
+ #
62
+ # @return [ Array<License> ] The given licenses.
63
+ def rubygem_licenses(term_or_terms)
64
+ return [unknown_license] if term_or_terms == []
65
+ values = term_or_terms.respond_to?(:map) ? term_or_terms : [term_or_terms.to_s]
66
+ values = values.map { |v| @rubygems[v.to_s] || "Unknown" }
67
+ values.map { |v| self[v] }
68
+ end
69
+
70
+ protected
71
+
72
+ def load(filename)
73
+ data = YAML.load(File.read(filename))["licenses"]
74
+
75
+ @references = data.delete("references")
76
+ @rubygems = data.delete("rubygems")
77
+
78
+ @licenses = data.inject({}) { |memo,(code, element)| memo[code] = License.new(code, element); memo }
79
+ @unknown_license = self[UNKNOWN_LICENSE_CODE]
80
+ @unknown_license.unknown = true
81
+
82
+ data.each do |code,element|
83
+ target = self[code]
84
+ element.each do |ref, value|
85
+ next unless ref.to_s[0] =~ /[A-Z0-9]/
86
+ names = value.respond_to?(:each) ? value : [value.to_s]
87
+ compat = ref.to_i.to_s == ref.to_s
88
+ names.each do |name|
89
+ name.strip!
90
+ warning = name[0] == "!"
91
+ name = name[1..-1] if warning
92
+ raise "Compatability file '#{filename}' lists a compatability with '#{UNKNOWN_LICENSE_CODE}'. This is not allowed." if name == UNKNOWN_LICENSE_CODE
93
+ peer = @licenses[name]
94
+ raise "Compatability file '#{filename}' references License coded '#{name}', but it is not specified elsewhere in the file." if peer.nil?
95
+
96
+ if compat
97
+ target.mark_compatible(peer, ref, warning)
98
+ else
99
+ target.mark_classified(peer, ref, warning)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,71 @@
1
+ module Gemterms
2
+
3
+ # A licenced component that is part of an overall project.
4
+ class Component
5
+ attr_reader :licenses, :name, :version
6
+
7
+ def initialize(name, version, licenses)
8
+ @name = name
9
+ @version = version
10
+ @licenses = licenses
11
+ end
12
+
13
+ # @return [ true, false ] if this component has at least one "known"
14
+ # license
15
+ def licensed?
16
+ !@licenses.nil? && @licenses.detect { |l| !l.unknown }
17
+ end
18
+
19
+ # @return [ true, false ] if this component has at least two "known"
20
+ # licenses.
21
+ def multiple?
22
+ !@licenses.nil? && (@licenses.count { |l| !l.unknown } > 1)
23
+ end
24
+
25
+ end
26
+
27
+ # A collection of components to be evaluated as a set.
28
+ class Project
29
+ attr_reader :components
30
+
31
+ def <<(component)
32
+ @components << component
33
+ end
34
+
35
+ # @return [ int ] number of components in the project
36
+ def count
37
+ @components.length
38
+ end
39
+
40
+ # @return [ int ] count of components in this projects that have "Unknown"
41
+ # licenses
42
+ def count_unlicensed
43
+ @components.count { |c| c.licensed? }
44
+ end
45
+
46
+ def components_for_license(license)
47
+ @components.select { |c| c.licenses.include?(license) }
48
+ end
49
+
50
+ def initialize
51
+ @components = []
52
+ end
53
+
54
+ def licenses(include_unknown = true)
55
+ result = @components.map { |c| c.licenses }.flatten
56
+ result.reject! { |l| l.unknown? } unless include_unknown
57
+ result
58
+ end
59
+
60
+ # @param [ true, false ] include_unknown If true, unknown licenses are
61
+ # included in the returned list. Defaults to true.
62
+ #
63
+ # @return [ Array<License> ] array of unique licenses in use by this
64
+ # project.
65
+ def unique_licenses(include_unknown = true)
66
+ self.licenses.uniq
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,49 @@
1
+ require 'net/http'
2
+ require 'yaml'
3
+
4
+ # Front for RubyGems
5
+ class SourceUnavailableError < StandardError; end
6
+ class RubyGems
7
+ attr_reader :uri
8
+
9
+ def data(name)
10
+ YAML.load(self.get("/api/v1/gems/#{name}.yaml"))
11
+ end
12
+
13
+ def initialize(uri)
14
+ @connection = nil
15
+ @uri = uri.kind_of?(URI::Generic) ? uri : URI(uri.to_s)
16
+ end
17
+
18
+ # May raise SourceUnavailableError if the source can't be accessed
19
+ def get(path, data={}, content_type='application/x-www-form-urlencoded')
20
+ begin
21
+ request = Net::HTTP::Get.new(path)
22
+ request.add_field 'Connection', 'keep-alive'
23
+ request.add_field 'Keep-Alive', '30'
24
+ request.add_field 'User-Agent', 'github.com/jonathannen/gemfresh'
25
+ response = connection.request request
26
+ response.body
27
+ rescue StandardError => se
28
+ # For now we assume this is an unavailable repo
29
+ raise SourceUnavailableError.new(se.message)
30
+ end
31
+ end
32
+
33
+ # @param [ String ] name The name of the gem to access.
34
+ #
35
+ # @return [ Hash ] version data for the given named gem
36
+ def versions(name)
37
+ YAML.load(self.get("/api/v1/versions/#{name}.yaml"))
38
+ end
39
+
40
+ private
41
+ # A persistent connection
42
+ def connection
43
+ return @connection unless @connection.nil?
44
+ @connection = Net::HTTP.new self.uri.host, self.uri.port
45
+ @connection.use_ssl = (uri.scheme == 'https')
46
+ @connection.start
47
+ @connection
48
+ end
49
+ end
@@ -0,0 +1,152 @@
1
+ require 'gemterms'
2
+
3
+ # Generic command-line runner for processing projects of licenced
4
+ # components. Generally you'll use a specialisation of this, such as
5
+ # the <tt>Gemterms::GemFiler</tt> class.
6
+ class Gemterms::Runner
7
+ attr_reader :component_name, :component_plural, :licenser, :project
8
+
9
+ def all_licenses
10
+ @licenser.licenses
11
+ end
12
+
13
+ def banner
14
+ puts <<-BANNER
15
+ Thanks for using gemterms. Please read the README.md and MIT-LICENCE.txt
16
+ available at https://github.com/jonathannen/gemterms. It contains important
17
+ information about the usage of this tool.
18
+ BANNER
19
+ true
20
+ end
21
+
22
+ def counter(count)
23
+ count == 1 ? "1 #{component_name}" : "#{count} #{component_plural}"
24
+ end
25
+
26
+ # component_name, component_plural
27
+ def initialize(*args)
28
+ @component_name, @component_plural = *args
29
+ @licenser = Gemterms::Licensing.new
30
+ @verbose = true
31
+ banner && ruler
32
+ end
33
+
34
+ def license_breakdown
35
+ puts <<-INST
36
+ Following are your #{component_plural} listed by license. Any #{component_plural} listed with a '*'
37
+ have multiple licenses.
38
+
39
+ INST
40
+ unknown_last(project.unique_licenses).each do |license|
41
+ puts "== #{license}"
42
+ components = project.components_for_license(license).sort_by { |c| c.name.downcase }
43
+ names = components.map do |c|
44
+ "#{c.multiple? ? '*' : ''}#{c.name}"
45
+ end
46
+ puts names * ', '
47
+ puts ""
48
+ end
49
+ # puts ls.inspect
50
+ # ls = projectall_licenses.
51
+ # puts "Break it on down"
52
+ true
53
+ end
54
+
55
+ def list_licenses
56
+ count = @licenser.licenses.values.count
57
+ ruler
58
+ unknown_last(all_licenses.values).each do |l|
59
+ puts "#{l.name} [#{l.code}]"
60
+ end
61
+ ruler
62
+ puts "#{count} licence#{count == 1 ? '' : 's'} defined."
63
+ true
64
+ end
65
+
66
+ def ruler
67
+ puts ""
68
+ true
69
+ end
70
+
71
+ def show_license(arg)
72
+ if arg.nil?
73
+ puts <<-INST
74
+ Please specify a licence code (e.g. GPL-2.0) when getting license details. You
75
+ can get a list of licenses and codes with the `list-licenses` command. Use
76
+ the --help command for more information.
77
+ INST
78
+ return true
79
+ end
80
+
81
+ l = @licenser[arg]
82
+ if l.unknown?
83
+ puts <<-INST
84
+ The given code '#{arg}' doesn't map to a known license. You can get a list of
85
+ licenses and codes with the `list-licenses` command. Use the --help command for
86
+ more information.
87
+ INST
88
+ return true
89
+ end
90
+
91
+ puts "#{l.name} [#{l.code}]"
92
+ puts l.uri
93
+ puts ""
94
+
95
+ if l.compatible.length > 0
96
+ puts "This license is compatiable with:"
97
+ l.compatible.group_by { |p, ref, warn| ref }.each do |ref, vals|
98
+ puts " Based on reference [#{ref}] #{@licenser.references[ref]}"
99
+ vals.each { |p, ref, warn| puts " - #{p.name} [#{p.code}]" }
100
+ end
101
+ else
102
+ puts <<-INST
103
+ This license is not listed as being compatible with any licenses. This doesn't
104
+ mean it's true, just that the are no mappings. See the site
105
+ https://github.com/jonathannen/gemterms for more details and how you can help.
106
+ INST
107
+ end
108
+
109
+ if l.classified.length > 0
110
+ puts "\nThis license is classified as:"
111
+ l.classified.group_by { |p, ref, warn| ref }.each do |ref, vals|
112
+ puts " Based on reference [#{ref}] #{@licenser.references[ref]}"
113
+ vals.each { |p, ref, warn| puts " - #{p.name} [#{p.code}]" }
114
+ end
115
+ end
116
+
117
+ puts ""
118
+ true
119
+ end
120
+
121
+
122
+ # Runs the standard commands if possible. This includes things like
123
+ # listing licenses and the such.
124
+ def standard_commands(args)
125
+ return usage if args.delete('--help')
126
+ case args.first
127
+ when "list-licenses" then list_licenses
128
+ when "show-license" then show_license(args[1])
129
+ else
130
+ false
131
+ end
132
+ end
133
+
134
+ def stats(commentary = nil)
135
+ ns = counter(project.count)
136
+ lg = counter(project.components.select { |c| c.licensed? }.count)
137
+ ul = project.unique_licenses(false).count
138
+ puts "Ok. Your project has #{ns} listed."
139
+ puts commentary unless commentary.nil?
140
+ puts "There is an explict license for #{lg}. There #{ul == 1 ? "is 1 unique license" : "#{ul} unique licenses"} referenced."
141
+ true
142
+ end
143
+
144
+ protected
145
+
146
+ # @param [ Array<License> ] list The list of licenses to process.
147
+ # @return [ Array<License> ] The list with unknown licenses at the end.
148
+ def unknown_last(list)
149
+ list.partition { |l| !l.unknown? }.flatten.each
150
+ end
151
+
152
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'gemterms'
3
+ require 'gemterms/gem_runner'
4
+
5
+ class CompatTest < Test::Unit::TestCase
6
+
7
+
8
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemterms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jon Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.10
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.10
30
+ description: Scans Gemfiles to see what licenses are in use.
31
+ email:
32
+ - jon@jonathannen.com
33
+ executables:
34
+ - gemterms
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - MIT-LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - bin/gemterms
44
+ - compatability.yml
45
+ - gemterms.gemspec
46
+ - lib/gemterms.rb
47
+ - lib/gemterms/gem_filer.rb
48
+ - lib/gemterms/gem_runner.rb
49
+ - lib/gemterms/license.rb
50
+ - lib/gemterms/project.rb
51
+ - lib/gemterms/ruby_gems.rb
52
+ - lib/gemterms/runner.rb
53
+ - test/test_compat.rb
54
+ homepage: https://github.com/jonathannen/gemterms
55
+ licenses:
56
+ - MIT
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.25
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Checks the licensing of your Gemfile.
79
+ test_files:
80
+ - test/test_compat.rb