gemterms 0.1.0

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