licenserec 1.0.2
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 +7 -0
- data/.idea/.gitignore +8 -0
- data/.idea/licenserec.iml +50 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +21 -0
- data/README.md +88 -0
- data/Rakefile +4 -0
- data/bin/licenserec.rb +56 -0
- data/exe/licenserec.rb +56 -0
- data/lib/compatibility_63.csv +64 -0
- data/lib/github_license_usage.csv +40 -0
- data/lib/license_readability.csv +65 -0
- data/lib/licensecompare.rb +30 -0
- data/lib/licensecompatibility.rb +296 -0
- data/lib/licenserec/version.rb +5 -0
- data/lib/licenserec.rb +13 -0
- data/lib/licenses_terms_63.csv +64 -0
- data/lib/licensesort.rb +59 -0
- data/lib/licensetermchoice.rb +352 -0
- data/lib/licensetypeguide.rb +106 -0
- data/licenserec-1.0.0.gem +0 -0
- data/licenserec-1.0.1.gem +0 -0
- data/sig/licenserec.rbs +4 -0
- metadata +71 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "licenserec/version"
|
|
4
|
+
require 'set'
|
|
5
|
+
require 'open3'
|
|
6
|
+
require 'csv'
|
|
7
|
+
|
|
8
|
+
module Licenserec
|
|
9
|
+
class CompatibilityFilter
|
|
10
|
+
def initialize()
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# 次级兼容、组合兼容和不兼容的含义
|
|
14
|
+
def self.compatibility_meaning()
|
|
15
|
+
compatibility_meaning_hash = Hash.new
|
|
16
|
+
compatibility_meaning_hash.store("次级兼容","开源许可证A授权的作品(无论是否经过修改)与开源许可证B授权的作品组合,所产生的衍生作品整体可合法地使用开源许可证B重新授权时,则认为开源许可证A次级兼容开源许可证B。本知识库中使用‘1’表示次级兼容。")
|
|
17
|
+
compatibility_meaning_hash.store("组合兼容","开源许可证A授权的作品(无论是否经过修改)可以与开源许可证B授权的作品可以合法地组合而不违反任一开源许可证时,可以认为开源许可证A组合兼容开源许可证B。本知识库中使用‘2’表示组合兼容。")
|
|
18
|
+
compatibility_meaning_hash.store("不兼容","不满足次级兼容或组合兼容的条件,则不兼容。本知识库中使用‘0’表示不兼容。")
|
|
19
|
+
return compatibility_meaning_hash
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# 遍历文件夹,返回所有文件的路径列表
|
|
23
|
+
def self.show_files(f_path,repofiles_pathlist)
|
|
24
|
+
if File.directory? f_path
|
|
25
|
+
Dir.foreach(f_path) do |file|
|
|
26
|
+
if file != "." and file != ".."
|
|
27
|
+
show_files(f_path + "/" + file,repofiles_pathlist)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
repofiles_pathlist.push(f_path)
|
|
32
|
+
end
|
|
33
|
+
return repofiles_pathlist
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# 第三方工具Ninka识别文件许可证,一个文件可能包含多个许可证,输入1为文件的路径,输入2为ninka路径,输出为许可证列表。
|
|
37
|
+
def self.ninka_process(filepath,ninka_path)
|
|
38
|
+
io = IO.popen("perl " + ninka_path + " " + filepath)
|
|
39
|
+
io_stdout = io.gets.split(";")
|
|
40
|
+
file_license_list = io_stdout[1].split(",")
|
|
41
|
+
# puts "++++++++++++++"
|
|
42
|
+
# puts file_license_list
|
|
43
|
+
return file_license_list
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# 识别项目所包含的许可证,输入1为项目路径,输入2为ninka路径,输出1为文件路径及对应许可证信息的哈希表,输出2为项目包含的许可证集合
|
|
47
|
+
def self.license_detection(repo_path,ninka_path)
|
|
48
|
+
# 遍历项目文件夹,获取项目中所有文件路径
|
|
49
|
+
repofiles_pathlist = []
|
|
50
|
+
repofiles_pathlist = show_files(repo_path,repofiles_pathlist)
|
|
51
|
+
# 创建子进程,获取每个文件的许可证信息
|
|
52
|
+
other_licenses = ["SeeFile", "UNKNOWN"]
|
|
53
|
+
licenses_set = Set.new
|
|
54
|
+
file_licenses_hash = {}
|
|
55
|
+
repofiles_pathlist.each do |filepath|
|
|
56
|
+
# 异常处理
|
|
57
|
+
begin
|
|
58
|
+
file_licenses = CompatibilityFilter.ninka_process(filepath,ninka_path)
|
|
59
|
+
dual_licenses = Set.new
|
|
60
|
+
dual_licenses_str = ""
|
|
61
|
+
if file_licenses.length <= 1
|
|
62
|
+
if other_licenses.include? file_licenses[0]
|
|
63
|
+
licenses_set.add("Other")
|
|
64
|
+
file_licenses_hash.store(filepath,"Other")
|
|
65
|
+
elsif file_licenses[0].include? "NONE"
|
|
66
|
+
licenses_set.add("")
|
|
67
|
+
file_licenses_hash.store(filepath,"NONE")
|
|
68
|
+
elsif file_licenses[0].nil?
|
|
69
|
+
licenses_set.add("")
|
|
70
|
+
file_licenses_hash.store(filepath,"NONE")
|
|
71
|
+
else
|
|
72
|
+
licenses_set.add(file_licenses[0])
|
|
73
|
+
file_licenses_hash.store(filepath,file_licenses[0])
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
file_licenses.each do |license_in_onefile|
|
|
77
|
+
if dual_licenses.include? license_in_onefile == false
|
|
78
|
+
dual_licenses_str = dual_licenses_str + license_in_onefile + ' or '
|
|
79
|
+
dual_licenses.add(license_in_onefile)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
licenses_set.add(dual_licenses_str[0,dual_licenses_str.length-4])
|
|
83
|
+
file_licenses_hash.store(filepath,dual_licenses_str[0,dual_licenses_str.length-4])
|
|
84
|
+
end
|
|
85
|
+
licenses_set.delete("")
|
|
86
|
+
rescue
|
|
87
|
+
puts $!
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
licenses_set.delete(nil)
|
|
91
|
+
return file_licenses_hash,licenses_set
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# 兼容性查询,输入1为许可证A(通常指项目中第三方组件的许可证),输入2为许可证B(通常指项目许可证),输出为"0"(不兼容)、"1"(次级兼容)、"2"(组合兼容)、"1,2"(次级兼容或组合兼容)。
|
|
95
|
+
def self.compatibility_lookup(licenseA,licenseB)
|
|
96
|
+
compatibility_AB = '1,2'
|
|
97
|
+
c_table = CSV.read("lib\\compatibility_63.csv",headers:true)
|
|
98
|
+
CSV.foreach("lib\\compatibility_63.csv") do |row|
|
|
99
|
+
if row[0]==licenseA
|
|
100
|
+
no_row = $.
|
|
101
|
+
compatibility_AB = c_table[no_row-2][licenseB]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
return compatibility_AB
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# 兼容许可证筛选,输入1为项目路径,输入2为ninka路径,输入3为许可证推荐范围,其中默认值“popular”包含MIT等20种常见开源许可证,“all”包含本知识库支持的6种开源许可证。输出1为仅满足次级兼容的许可证列表,输出2为仅满足组合兼容的许可证列表,输出3为既满足次级兼容又满足组合兼容的许可证列表。
|
|
108
|
+
def self.compatibility_filter(repo_path,ninka_path,recommand_scale="popular")
|
|
109
|
+
filelicense_hash,licenseA_set = CompatibilityFilter.license_detection(repo_path,ninka_path)
|
|
110
|
+
c_table = CSV.read("lib\\compatibility_63.csv",headers:true)
|
|
111
|
+
all_license = c_table['license']
|
|
112
|
+
if recommand_scale == "popular"
|
|
113
|
+
licenseB_list = %w[MIT Apache-2.0 GPL-3.0 BSD-3-Clause GPL-2.0 AGPL-3.0 MPL-2.0 LGPL-3.0 BSD-2-Clause Unlicense ISC EPL-1.0 CC0-1.0 LGPL-2.1 WTFPL Zlib EPL-2.0 Artistic-2.0 MulanPSL-2.0 MulanPubL-2.0]
|
|
114
|
+
elsif recommand_scale == "all"
|
|
115
|
+
licenseB_list = all_license.dup
|
|
116
|
+
else
|
|
117
|
+
puts "范围错误,请输入'popular'或'all'。"
|
|
118
|
+
end
|
|
119
|
+
checked_license = []
|
|
120
|
+
recommend_licenses_1 = licenseB_list.dup
|
|
121
|
+
recommend_licenses_2 = licenseB_list.dup
|
|
122
|
+
recommend_licenses_12 = licenseB_list.dup
|
|
123
|
+
licenseA_set.each { |licenseA|
|
|
124
|
+
if licenseA.include? " or "
|
|
125
|
+
dual_checked = 0
|
|
126
|
+
licenseB_list.each { |licenseB|
|
|
127
|
+
licenseAs = licenseA.split(" or ")
|
|
128
|
+
is_remove_secondary = 1
|
|
129
|
+
is_remove_combine = 1
|
|
130
|
+
is_remove_both = 1
|
|
131
|
+
licenseAs.each{ |lA|
|
|
132
|
+
if all_license.include? lA
|
|
133
|
+
compatibilityAB = CompatibilityFilter.compatibility_lookup(lA,licenseB)
|
|
134
|
+
dual_checked = 1
|
|
135
|
+
if compatibilityAB == "1" or compatibilityAB == '1,2'
|
|
136
|
+
is_remove_secondary = 0
|
|
137
|
+
end
|
|
138
|
+
if compatibilityAB == "2" or compatibilityAB == '1,2'
|
|
139
|
+
is_remove_combine = 0
|
|
140
|
+
end
|
|
141
|
+
if compatibilityAB == "1,2"
|
|
142
|
+
is_remove_both = 0
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
}
|
|
146
|
+
if is_remove_secondary and dual_checked ==1
|
|
147
|
+
recommend_licenses_1.delete(licenseB)
|
|
148
|
+
end
|
|
149
|
+
if is_remove_combine and dual_checked ==1
|
|
150
|
+
recommend_licenses_2.delete(licenseB)
|
|
151
|
+
end
|
|
152
|
+
if is_remove_both and dual_checked ==1
|
|
153
|
+
recommend_licenses_12.delete(licenseB)
|
|
154
|
+
end
|
|
155
|
+
}
|
|
156
|
+
if dual_checked == 1
|
|
157
|
+
checked_license.push(licenseA)
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
if all_license.include? licenseA
|
|
161
|
+
checked_license.push(licenseA)
|
|
162
|
+
licenseB_list.each { |licenseB|
|
|
163
|
+
compatibilityAB = CompatibilityFilter.compatibility_lookup(licenseA,licenseB)
|
|
164
|
+
if compatibilityAB != "1" and compatibilityAB != '1,2'
|
|
165
|
+
recommend_licenses_1.delete(licenseB)
|
|
166
|
+
end
|
|
167
|
+
if compatibilityAB != "2" and compatibilityAB != '1,2'
|
|
168
|
+
recommend_licenses_2.delete(licenseB)
|
|
169
|
+
end
|
|
170
|
+
if compatibilityAB != "1,2"
|
|
171
|
+
recommend_licenses_12.delete(licenseB)
|
|
172
|
+
end
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
}
|
|
177
|
+
return recommend_licenses_1,recommend_licenses_2,recommend_licenses_12,checked_license
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
class CompatibilityCheck
|
|
183
|
+
def initialize()
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# 兼容性检查,输入1为项目路径,输入2为ninka路径,输出为“OK”,或项目种包含互不兼容许可证的提示信息的集合、对应文件路径的列表
|
|
187
|
+
def self.compatibilitycheck(repo_path,ninka_path)
|
|
188
|
+
file_licenses_hash,licenses_set = CompatibilityFilter.license_detection(repo_path,ninka_path)
|
|
189
|
+
c_table = CSV.read("lib\\compatibility_63.csv",headers:true)
|
|
190
|
+
check_license_list = c_table["license"]
|
|
191
|
+
conflict_copyleft_infoset = Set.new
|
|
192
|
+
conflict_licenses = Set.new
|
|
193
|
+
licenses_set.each do |licenseA|
|
|
194
|
+
licenses_set.each do |licenseB|
|
|
195
|
+
if (licenseA.include? " or ") == false
|
|
196
|
+
iscompatibility = 0
|
|
197
|
+
ischeck = 0
|
|
198
|
+
if (licenseB.include? " or ") == false
|
|
199
|
+
ischeck = 1
|
|
200
|
+
compatibility_result_ab = CompatibilityFilter.compatibility_lookup(licenseA, licenseB)
|
|
201
|
+
compatibility_result_ba = CompatibilityFilter.compatibility_lookup(licenseB, licenseA)
|
|
202
|
+
if compatibility_result_ab != '0' or compatibility_result_ba != '0'
|
|
203
|
+
iscompatibility = 1
|
|
204
|
+
end
|
|
205
|
+
if iscompatibility == 0 and ischeck == 1
|
|
206
|
+
if (conflict_copyleft_infoset.include? licenseA+ "和" + licenseB + "互不兼容。") == false and (conflict_copyleft_infoset.include? licenseB+ "和" + licenseA + "互不兼容。") == false
|
|
207
|
+
conflict_copyleft_infoset.add(licenseA + "和" + licenseB + "互不兼容。")
|
|
208
|
+
conflict_licenses.add(licenseA)
|
|
209
|
+
conflict_licenses.add(licenseB)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
else
|
|
213
|
+
licenseBs = licenseB.split(' or ')
|
|
214
|
+
licenseBs.each do |lB|
|
|
215
|
+
if check_license_list.include? lB
|
|
216
|
+
ischeck = 1
|
|
217
|
+
compatibility_result_ab = CompatibilityFilter.compatibility_lookup(licenseA, lB)
|
|
218
|
+
compatibility_result_ba = CompatibilityFilter.compatibility_lookup(lB, licenseA)
|
|
219
|
+
if compatibility_result_ab != '0' or compatibility_result_ba != '0'
|
|
220
|
+
iscompatibility = 1
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
if iscompatibility == 0 and ischeck == 1
|
|
225
|
+
if (conflict_copyleft_infoset.include? licenseA+ "和" + licenseB + "互不兼容。") == false and (conflict_copyleft_infoset.include? licenseB+ "和" + licenseA + "互不兼容。") == false
|
|
226
|
+
conflict_copyleft_infoset.add(licenseA + "和" + licenseB + "互不兼容。")
|
|
227
|
+
conflict_licenses.add(licenseA)
|
|
228
|
+
conflict_licenses.add(licenseB)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
else
|
|
233
|
+
iscompatibility = 0
|
|
234
|
+
ischeck = 0
|
|
235
|
+
licenseAs = licenseA.split(' or ')
|
|
236
|
+
if (licenseB.include? " or ") == false
|
|
237
|
+
licenseAs.each do |lA|
|
|
238
|
+
if check_license_list.include? lA
|
|
239
|
+
ischeck = 1
|
|
240
|
+
compatibility_result_ab = CompatibilityFilter.compatibility_lookup(lA, licenseB)
|
|
241
|
+
compatibility_result_ba = CompatibilityFilter.compatibility_lookup(licenseB, lA)
|
|
242
|
+
if compatibility_result_ab != '0' or compatibility_result_ba != '0'
|
|
243
|
+
iscompatibility = 1
|
|
244
|
+
if iscompatibility == 0 and ischeck == 1
|
|
245
|
+
if (conflict_copyleft_infoset.include? licenseA+ "和" + licenseB + "互不兼容。") == false and (conflict_copyleft_infoset.include? licenseB+ "和" + licenseA + "互不兼容。") == false
|
|
246
|
+
conflict_copyleft_infoset.add(licenseA + "和" + licenseB + "互不兼容。")
|
|
247
|
+
conflict_licenses.add(licenseA)
|
|
248
|
+
conflict_licenses.add(licenseB)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
else
|
|
255
|
+
licenseBs = licenseB.split(' or ')
|
|
256
|
+
licenseAs.each do |lA|
|
|
257
|
+
licenseBs.each do |lB|
|
|
258
|
+
if check_license_list.include? lA and check_license_list.include? lB
|
|
259
|
+
ischeck = 1
|
|
260
|
+
compatibility_result_ab = CompatibilityFilter.compatibility_lookup(lA, lB)
|
|
261
|
+
compatibility_result_ba = CompatibilityFilter.compatibility_lookup(lB, lA)
|
|
262
|
+
if compatibility_result_ab != '0' or compatibility_result_ba != '0'
|
|
263
|
+
iscompatibility = 1
|
|
264
|
+
end
|
|
265
|
+
if iscompatibility == 0 and ischeck == 1
|
|
266
|
+
if (conflict_copyleft_infoset.include? licenseA+ "和" + licenseB + "互不兼容。") == false and (conflict_copyleft_infoset.include? licenseB+ "和" + licenseA + "互不兼容。") == false
|
|
267
|
+
conflict_copyleft_infoset.add(licenseA + "和" + licenseB + "互不兼容。")
|
|
268
|
+
conflict_licenses.add(licenseA)
|
|
269
|
+
conflict_licenses.add(licenseB)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
conflict_filepath = []
|
|
280
|
+
if conflict_copyleft_infoset.nil?
|
|
281
|
+
return "OK",nil
|
|
282
|
+
else
|
|
283
|
+
conflict_licenses.each do |one_license|
|
|
284
|
+
file_licenses_hash.each do |file_path,file_license|
|
|
285
|
+
if file_license == one_license
|
|
286
|
+
conflict_filepath.push(file_path + "----------" + file_license)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
return conflict_copyleft_infoset,conflict_filepath
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
data/lib/licenserec.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "licenserec/version"
|
|
4
|
+
|
|
5
|
+
module Licenserec
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
# Your code goes here...
|
|
8
|
+
require 'licensecompatibility'
|
|
9
|
+
require 'licensetypeguide'
|
|
10
|
+
require 'licensetermchoice'
|
|
11
|
+
require 'licensecompare'
|
|
12
|
+
require 'licensesort'
|
|
13
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
license,info,preamble,define,copyright,patent,trademark,copyleft,interaction,modification,retain_attr,enhance_attr,acceptance,patent_term,vio_term,disclaimer,law,instruction,compatible_version,secondary_license,gpl_combine
|
|
2
|
+
CC0-1.0,1,1,0,-1,-1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0
|
|
3
|
+
Unlicense,1,0,0,-1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0
|
|
4
|
+
WTFPL,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
5
|
+
0BSD,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0
|
|
6
|
+
MIT-0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0
|
|
7
|
+
Fair,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
8
|
+
MIT,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
9
|
+
ISC,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
10
|
+
FSFAP,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
11
|
+
Imlib2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
12
|
+
BSD-1-Clause,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
13
|
+
BSD-2-Clause,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
14
|
+
BSD-2-Clause-Patent,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,"GPL-2.0,GPL-2.0+",0
|
|
15
|
+
BSD-3-Clause,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
16
|
+
BSD-3-Clause-Clear,1,0,0,0,-1,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
17
|
+
NCSA,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
18
|
+
BSL-1.0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
19
|
+
NTP,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
20
|
+
Ruby,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
21
|
+
UPL-1.0,1,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
22
|
+
EFL-2.0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
23
|
+
MirOS,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0
|
|
24
|
+
CC-BY-4.0,1,1,1,1,-1,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0
|
|
25
|
+
ClArtistic,1,1,1,0,0,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0
|
|
26
|
+
Zlib,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0
|
|
27
|
+
LiLiQ-P-1.1,1,1,1,1,0,1,0,0,1,1,0,0,0,1,1,Québec,0,0,0,0
|
|
28
|
+
MulanPSL-2.0,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,0,1,0,"Apache-2.0,GPL-2.0,GPL-2.0+",0
|
|
29
|
+
Apache-2.0,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,0
|
|
30
|
+
Artistic-2.0,1,1,1,0,1,1,0,0,1,1,0,0,1,0,1,0,0,0,"AGPL-3.0,AGPL-3.0+,CC-BY-SA-4.0,CECILL-2.1,EPL-1.0,EUPL-1.1,EUPL-1.2,GPL-2.0,GPL-2.0+,GPL-3.0,GPL-3.0+,LiLiQ-Rplus-1.1,MulanPubL-2.0,NPOSL-3.0,OSL-3.0,RPL-1.5,SimPL-2.0",0
|
|
31
|
+
ECL-2.0,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,0
|
|
32
|
+
AFL-3.0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,0,0,0
|
|
33
|
+
BSD-4-Clause,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0
|
|
34
|
+
AAL,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0
|
|
35
|
+
CDDL-1.0,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0
|
|
36
|
+
CPAL-1.0,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,California,1,0,0,0
|
|
37
|
+
EPL-2.0,1,0,1,1,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0
|
|
38
|
+
LiLiQ-R-1.1,1,1,1,1,0,1,1,0,1,1,0,0,0,1,1,Québec,0,0,"CDDL-1.0,CPL-1.0,CECILL-2.1,CECILL-C,EPL-1.0,EUPL-1.1,LiLiQ-Rplus-1.1,GPL-2.0,GPL-3.0,LGPL-2.1,LGPL-3.0,MPL-2.0,GPL-2.0+,GPL-3.0+,LGPL-2.1+,LGPL-3.0+",0
|
|
39
|
+
MPL-2.0,1,0,1,1,1,1,1,0,0,1,0,0,1,1,1,0,1,0,"GPL-2.0,GPL-3.0,LGPL-2.1,LGPL-3.0,AGPL-3.0,GPL-2.0+,GPL-3.0+,LGPL-2.1+,LGPL-3.0+,AGPL-3.0+",0
|
|
40
|
+
MS-RL,1,0,1,1,1,1,1,0,0,1,0,0,1,0,1,0,0,0,0,0
|
|
41
|
+
NOSL,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,Victoria,0,0,0,0
|
|
42
|
+
OGTSL,1,1,1,0,0,1,2,0,1,1,0,0,0,0,1,0,0,0,0,0
|
|
43
|
+
MS-PL,1,0,1,1,1,1,3,0,0,1,0,0,1,0,1,0,0,0,0,0
|
|
44
|
+
CC-BY-SA-4.0,1,1,1,1,-1,1,3,0,1,1,0,0,0,1,1,0,0,0,0,0
|
|
45
|
+
CECILL-2.1,1,1,1,1,1,0,3,0,1,1,0,0,0,1,1,French,0,0,"GPL-2.0,GPL-3.0,AGPL-3.0,EUPL-1.1,EUPL-1.2,GPL-2.0+,GPL-3.0+,AGPL-3.0+",0
|
|
46
|
+
EPL-1.0,1,0,1,1,1,0,3,0,1,1,0,0,1,1,1,New York,0,EPL-2.0,0,0
|
|
47
|
+
EUPL-1.1,1,0,1,1,1,1,3,0,1,1,0,0,0,1,1, European Union,0,EUPL-1.2,"GPL-2.0,OSL-2.1,OSL-3.0,CPL-1.0,EPL-1.0,CECILL-2.0,GPL-2.0+",0
|
|
48
|
+
EUPL-1.2,1,0,1,1,1,1,3,0,1,1,0,0,0,1,1, European Union,0,0,"GPL-2.0,GPL-3.0,AGPL-3.0,OSL-2.1,OSL-3.0,EPL-1.0,CECILL-2.0,CECILL-2.1,MPL-2.0,LGPL-2.1,LGPL-3.0,CC-BY-SA-3.0,EUPL-1.1,EUPL-1.2,LiLiQ-R,LiLiQ-R+,GPL-2.0+,GPL-3.0+,AGPL-3.0+,LGPL-2.1+,LGPL-3.0+",0
|
|
49
|
+
LGPL-2.1+,1,1,1,0,0,0,2,0,1,1,0,0,0,1,1,0,1,"LGPL-3.0,LGPL-2.1,LGPL-3.0+","GPL-2.0,GPL-2.0+,GPL-3.0,GPL-3.0+","GPL-2.0,GPL-2.0+,GPL-3.0,GPL-3.0+,LGPL-2.1,LGPL-2.1+,LGPL-3.0,LGPL-3.0+"
|
|
50
|
+
LGPL-2.1,1,1,1,0,0,0,2,0,1,1,0,0,0,1,1,0,1,LGPL-2.1+,"GPL-2.0,GPL-2.0+,GPL-3.0,GPL-3.0+","GPL-2.0,GPL-2.0+,GPL-3.0,GPL-3.0+,LGPL-2.1,LGPL-2.1+,LGPL-3.0,LGPL-3.0+"
|
|
51
|
+
LGPL-3.0+,1,1,1,1,1,0,2,0,1,1,0,0,1,1,1,0,1,LGPL-3.0,"GPL-3.0,GPL-3.0+","GPL-3.0,GPL-3.0+,LGPL-2.1,LGPL-2.1+,LGPL-3.0,LGPL-3.0+"
|
|
52
|
+
LGPL-3.0,1,1,1,1,1,0,2,0,1,1,0,0,1,1,1,0,1,LGPL-3.0+,"GPL-3.0,GPL-3.0+","GPL-3.0,GPL-3.0+,LGPL-2.1,LGPL-2.1+,LGPL-3.0,LGPL-3.0+"
|
|
53
|
+
GPL-2.0+,1,1,1,0,0,0,3,0,1,1,0,0,0,1,1,0,1,"GPL-3.0,GPL-2.0,GPL-3.0+",0,"AGPL-3.0,AGPL-3.0+,GPL-2.0"
|
|
54
|
+
GPL-2.0,1,1,1,0,0,0,3,0,1,1,0,0,0,1,1,0,1,GPL-2.0+,0,GPL-2.0+
|
|
55
|
+
GPL-3.0+,1,1,1,1,1,0,3,0,1,1,0,0,1,1,1,0,1,GPL-3.0,0,"AGPL-3.0,AGPL-3.0+,GPL-3.0"
|
|
56
|
+
GPL-3.0,1,1,1,1,1,0,3,0,1,1,0,0,1,1,1,0,1,GPL-3.0+,0,"AGPL-3.0,AGPL-3.0+,GPL-3.0+"
|
|
57
|
+
AGPL-3.0+,1,1,1,1,1,0,3,1,1,1,0,0,1,1,1,0,1,AGPL-3.0,0,AGPL-3.0
|
|
58
|
+
AGPL-3.0,1,1,1,1,1,0,3,1,1,1,0,0,1,1,1,0,1,AGPL-3.0+,0,AGPL-3.0+
|
|
59
|
+
SimPL-2.0,1,0,0,1,0,0,3,0,1,1,0,0,0,1,1,0,0,0,"GPL-2.0,GPL-2.0+",0
|
|
60
|
+
LiLiQ-Rplus-1.1,1,1,1,1,0,1,3,0,1,1,0,0,0,1,1,Québec,0,0,"CPL-1.0,CECILL-2.1,EPL-1.0,EUPL-1.1,GPL-2.0,GPL-3.0,GPL-2.0+,GPL-3.0+",0
|
|
61
|
+
RPL-1.5,1,1,1,1,1,1,3,1,1,1,0,0,1,1,1,Colorado,1,0,0,0
|
|
62
|
+
NPOSL-3.0,1,0,0,1,1,1,3,1,1,1,0,1,1,1,1,0,0,0,0,0
|
|
63
|
+
MulanPubL-2.0,1,0,1,1,1,1,3,1,0,1,0,0,1,1,1,0,1,0,"AGPL-3.0,AGPL-3.0+",0
|
|
64
|
+
OSL-3.0,1,0,1,1,1,1,3,1,1,1,0,1,1,1,1,0,0,0,0,0
|
data/lib/licensesort.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "licenserec/version"
|
|
4
|
+
require 'csv'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module Licenserec
|
|
8
|
+
class LicenseSort
|
|
9
|
+
def initialize()
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# 将csv转为哈希值。输入1为csv表,输入2为是否包含首行(默认包含),输入3为列数i(转为hash的key),输入4为列数j(转为hash的value);输出为哈希表。
|
|
13
|
+
def self.csv_to_hash(csv_table,header=true,i=0,j=1)
|
|
14
|
+
sort_hash = Hash.new
|
|
15
|
+
CSV.foreach(csv_table) do |row|
|
|
16
|
+
if header
|
|
17
|
+
if $. != 1
|
|
18
|
+
sort_hash.store(row[i],row[j])
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
sort_hash.store(row[i],row[j])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
return sort_hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# 从排序哈希表中查询排序值。输入1为许可证SPDX,输入2为参照排序哈希表;输出为该许可证的排序值。
|
|
28
|
+
def self.sortvalue_lookup(one_license,sort_hash)
|
|
29
|
+
sortvalue = -1
|
|
30
|
+
if sort_hash.has_key? one_license
|
|
31
|
+
sortvalue = sort_hash.values_at(one_license)
|
|
32
|
+
end
|
|
33
|
+
return Float(sortvalue[0])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# 对指定许可证列表进行排序。输入1为指定的许可证列表,输入2为升降序(默认降序),输入3为参照排序哈希表(key为许可证SPDX,value为参照值,默认按文本复杂度);输出排序后的许可证列表。
|
|
37
|
+
def self.license_sort(license_list,desc=true,sort_hash=LicenseSort.csv_to_hash("lib\\license_readability.csv",header=true,i=0,j=4))
|
|
38
|
+
sort_res=[]
|
|
39
|
+
license_initsort = Hash.new
|
|
40
|
+
for one_license in license_list do
|
|
41
|
+
license_initsort[one_license] = LicenseSort.sortvalue_lookup(one_license,sort_hash)
|
|
42
|
+
end
|
|
43
|
+
if desc
|
|
44
|
+
license_sort_desc = license_initsort.sort{|a, b| b[1]<=>a[1]}
|
|
45
|
+
for sort_value in license_sort_desc do
|
|
46
|
+
sort_res.push(sort_value[0]) # 降序结果
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
license_sort_asc = license_initsort.sort{|a, b| a[1]<=>b[1]}
|
|
50
|
+
for sort_value in license_sort_asc do
|
|
51
|
+
sort_res.push(sort_value[0]) # 升序结果
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
return sort_res
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|