ad_licenselint 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/ad_licenselint +4 -0
- data/lib/ad_licenselint.rb +23 -0
- data/lib/ad_licenselint/ad_logger.rb +33 -0
- data/lib/ad_licenselint/constant.rb +8 -0
- data/lib/ad_licenselint/license_entry.rb +31 -0
- data/lib/ad_licenselint/markdown_formatter.rb +46 -0
- data/lib/ad_licenselint/option_handler.rb +52 -0
- data/lib/ad_licenselint/report.rb +17 -0
- data/lib/ad_licenselint/runner.rb +97 -0
- data/lib/ad_licenselint/terminal_formatter.rb +21 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3865f9b58fea6e2da9af8009f08e8ad04b979c7c9b2b2974e3fba37aeb589509
|
4
|
+
data.tar.gz: 7f7555f6efbc66a8af23cb5d851c341211669b07a1cc7e5f3846b847f9e9f278
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 90ca6ecf7176ef3bbefc45fe10450916356aeb9d08b1d57fb5e0080026d5ba50fb1f742242ef29b59fde41a890b78a815992d81162f1c7ff8361041757737110
|
7
|
+
data.tar.gz: 76266a5595f2ed1482328a7c2a6c7be940eb48348a904486612e02e230ea7c6e4ed5ae4ec9e4f5cd5998b45fc9a56f82ef3ad8a6b16c6a4f838deeb617fc404e
|
data/bin/ad_licenselint
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'logger'
|
3
|
+
require 'colorize'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'json'
|
6
|
+
require 'terminal-table'
|
7
|
+
require 'cocoapods-core'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
require 'ad_licenselint/ad_logger'
|
11
|
+
require 'ad_licenselint/option_handler'
|
12
|
+
require 'ad_licenselint/runner'
|
13
|
+
require 'ad_licenselint/license_entry'
|
14
|
+
require 'ad_licenselint/constant'
|
15
|
+
require 'ad_licenselint/report'
|
16
|
+
require 'ad_licenselint/terminal_formatter'
|
17
|
+
require 'ad_licenselint/markdown_formatter'
|
18
|
+
|
19
|
+
module ADLicenseLint
|
20
|
+
class Error < StandardError; end
|
21
|
+
|
22
|
+
LOGGER = ADLogger.new
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ADLicenseLint
|
2
|
+
class ADLogger
|
3
|
+
SEVERITY = { debug: Logger::DEBUG , info: Logger::INFO, warn: Logger::WARN, error: Logger::ERROR, fatal: Logger::FATAL, unknown: Logger::UNKNOWN }
|
4
|
+
AUTHORIZED_COLORS = [:black, :yellow, :red, :blue, :green]
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@logger = Logger.new(STDOUT)
|
8
|
+
@logger.level = Logger::INFO
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(level, color, text)
|
12
|
+
exit unless text and level and color
|
13
|
+
|
14
|
+
level, color = [level, color].map(&:to_sym)
|
15
|
+
raise "Color not supported" unless AUTHORIZED_COLORS.include? color
|
16
|
+
raise "Invalid severity" unless SEVERITY.dig(level)
|
17
|
+
|
18
|
+
@logger.add(SEVERITY.dig(level), text.send(color))
|
19
|
+
end
|
20
|
+
|
21
|
+
def debug!
|
22
|
+
@logger.level = Logger::DEBUG
|
23
|
+
end
|
24
|
+
|
25
|
+
def debug?
|
26
|
+
@logger.debug?
|
27
|
+
end
|
28
|
+
|
29
|
+
def close
|
30
|
+
@logger.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class LicenseEntry
|
2
|
+
attr_reader :license_content, :license_name, :pod_name, :source_url
|
3
|
+
attr_writer :source_url
|
4
|
+
|
5
|
+
def initialize(hash)
|
6
|
+
@pod_name = hash["Title"] || ""
|
7
|
+
@license_name = hash["License"] || ""
|
8
|
+
@license_content = hash["FooterText"] || ""
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_valid
|
12
|
+
!pod_name.empty? && !license_name.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def is_accepted
|
16
|
+
ADLicenseLint::Constant::ACCEPTED_LICENSES.include?(license_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def copyright
|
20
|
+
(/Copyright(.*)$/.match license_content)[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_hash
|
24
|
+
{
|
25
|
+
pod_name: @pod_name,
|
26
|
+
license_content: @license_content,
|
27
|
+
license_name: @license_name,
|
28
|
+
source_url: @source_url
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ADLicenseLint
|
2
|
+
class MarkdownFormatter
|
3
|
+
def initialize(report)
|
4
|
+
@entries = report.entries.sort_by(&:pod_name)
|
5
|
+
end
|
6
|
+
|
7
|
+
def formatted_content
|
8
|
+
"#{table}\n\n#{foldable_content}"
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def table
|
14
|
+
rows = [
|
15
|
+
"| Pod | License | Source |",
|
16
|
+
"| --- | --- | --- |",
|
17
|
+
] + @entries.map { |entry|
|
18
|
+
"| #{entry.pod_name} | #{entry.license_name} | #{entry.source_url} |"
|
19
|
+
}
|
20
|
+
rows.join("\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
def foldable_content
|
24
|
+
[
|
25
|
+
"<details>",
|
26
|
+
"<summary>Licenses</summary>",
|
27
|
+
"",
|
28
|
+
licenses_content,
|
29
|
+
"</details>"
|
30
|
+
].join("\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
def licenses_content
|
34
|
+
@entries
|
35
|
+
.map { |entry|
|
36
|
+
[
|
37
|
+
"### #{entry.pod_name}",
|
38
|
+
"```",
|
39
|
+
entry.license_content,
|
40
|
+
"```",
|
41
|
+
].join("\n")
|
42
|
+
}
|
43
|
+
.join("\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ADLicenseLint
|
2
|
+
|
3
|
+
class OptionHandler
|
4
|
+
|
5
|
+
def self.parse
|
6
|
+
|
7
|
+
options = {
|
8
|
+
format: ADLicenseLint::Constant::TERMINAL_FORMAT_OPTION,
|
9
|
+
path: ".",
|
10
|
+
all: false
|
11
|
+
}
|
12
|
+
available_formats = ADLicenseLint::Constant::AVAILABLE_OPTIONS
|
13
|
+
|
14
|
+
parser = OptionParser.new do |p|
|
15
|
+
p.banner = "Usage: ad_licenselint -f [md|term]"
|
16
|
+
|
17
|
+
p.on("-f", "--format [FORMAT]", "[Optional] Select output format [#{available_formats.join(", ")}] (default to #{options[:format]})") do |arg|
|
18
|
+
options[:format] = arg
|
19
|
+
end
|
20
|
+
|
21
|
+
p.on("-p", "--path [PATH]", "[Optional] Sources directory (default to \"#{options[:path]}\")") do |arg|
|
22
|
+
options[:path] = arg
|
23
|
+
end
|
24
|
+
|
25
|
+
p.on("-a", "--all", "[Optional] Display all licenses (default to #{options[:all]})") do |arg|
|
26
|
+
options[:all] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
p.on("-h", "--help", "Prints this help") do
|
30
|
+
puts p
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
parser.parse!
|
37
|
+
raise OptionParser::InvalidArgument, "--format" unless available_formats.include?(options[:format])
|
38
|
+
rescue OptionParser::MissingArgument => e
|
39
|
+
LOGGER.log(:error, :red, "Missing argument for option #{e.args.join(",")}")
|
40
|
+
exit
|
41
|
+
rescue OptionParser::InvalidArgument => e
|
42
|
+
LOGGER.log(:error, :red, "Invalid argument for option #{e.args.join(",")}")
|
43
|
+
exit
|
44
|
+
rescue ArgumentError => e
|
45
|
+
LOGGER.log(:error, :red, e.message)
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
|
49
|
+
options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ADLicenseLint
|
2
|
+
|
3
|
+
class Runner
|
4
|
+
attr_accessor :options, :path
|
5
|
+
|
6
|
+
POD_SOURCE = Pod::Source.new("~/.cocoapods/repos/master")
|
7
|
+
|
8
|
+
def initialize(options = nil)
|
9
|
+
@options = options || OptionHandler.parse
|
10
|
+
@path = File.expand_path(@options[:path])
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_report
|
14
|
+
raise "Folder #{target_support_path} does not exist" if Dir[target_support_path].empty?
|
15
|
+
|
16
|
+
plist_files = Dir[acknowledgements_plist_path] # one plist for each target
|
17
|
+
json_contents = plist_files.map { |plist_file| acknowledgement_json(plist_file) }
|
18
|
+
entries = all_entries(json_contents)
|
19
|
+
warning_entries = entries.reject(&:is_accepted)
|
20
|
+
displayed_entries = options[:all] ? entries : warning_entries
|
21
|
+
|
22
|
+
Report.new(displayed_entries)
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
report = create_report
|
27
|
+
return "" if report.empty?
|
28
|
+
|
29
|
+
case options[:format]
|
30
|
+
when ADLicenseLint::Constant::MARKDOWN_FORMAT_OPTION
|
31
|
+
MarkdownFormatter.new(report).formatted_content
|
32
|
+
when ADLicenseLint::Constant::TERMINAL_FORMAT_OPTION
|
33
|
+
TerminalFormatter.new(report).formatted_content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def acknowledgement_json(plist_file)
|
40
|
+
tmp_file = Tempfile.new('license')
|
41
|
+
begin
|
42
|
+
system "plutil -convert json -o #{tmp_file.path} \"#{plist_file}\"" # convert plist to json
|
43
|
+
JSON.parse(File.read(tmp_file.path))
|
44
|
+
ensure
|
45
|
+
tmp_file.close
|
46
|
+
tmp_file.unlink # deletes the temp file
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def all_entries(json_contents)
|
51
|
+
pod_names = pod_names_from_podfile
|
52
|
+
entries = json_contents
|
53
|
+
.map { |json| json["PreferenceSpecifiers"].map { |hash| LicenseEntry.new hash } }
|
54
|
+
.flatten
|
55
|
+
.select(&:is_valid)
|
56
|
+
.select { |e| pod_names.include?(e.pod_name) }
|
57
|
+
.uniq(&:pod_name)
|
58
|
+
entries.each { |e| e.source_url = source_url(e.pod_name) }
|
59
|
+
entries
|
60
|
+
end
|
61
|
+
|
62
|
+
def source_url(pod_name)
|
63
|
+
url = git_url(pod_name)
|
64
|
+
url&.gsub(".git", "")
|
65
|
+
end
|
66
|
+
|
67
|
+
def git_url(pod_name)
|
68
|
+
spec = pod_specification(pod_name)
|
69
|
+
spec["source"]["git"] || spec["homepage"] unless spec.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def pod_specification(pod_name)
|
73
|
+
set = POD_SOURCE.set(pod_name)
|
74
|
+
return nil if set.highest_version.nil? # access to specification crashes if highest_version is nil
|
75
|
+
set.specification.to_hash
|
76
|
+
end
|
77
|
+
|
78
|
+
def pod_names_from_podfile
|
79
|
+
Pod::Podfile.from_file(podfile_path).dependencies
|
80
|
+
.map(&:name)
|
81
|
+
.map { |e| e.split("/").first } # ex: convert CocoaLumberjack/Swift to CocoaLumberjack
|
82
|
+
.uniq
|
83
|
+
end
|
84
|
+
|
85
|
+
def podfile_path
|
86
|
+
File.join(@path, 'Podfile')
|
87
|
+
end
|
88
|
+
|
89
|
+
def target_support_path
|
90
|
+
File.join(@path, 'Pods', 'Target\ Support\ Files')
|
91
|
+
end
|
92
|
+
|
93
|
+
def acknowledgements_plist_path
|
94
|
+
File.join(target_support_path, "Pods-*/*acknowledgements.plist")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ADLicenseLint
|
2
|
+
class TerminalFormatter
|
3
|
+
|
4
|
+
def initialize(report)
|
5
|
+
@report = report
|
6
|
+
end
|
7
|
+
|
8
|
+
def formatted_content
|
9
|
+
rows = @report
|
10
|
+
.entries
|
11
|
+
.sort_by(&:pod_name)
|
12
|
+
.map { |entry|
|
13
|
+
[entry.pod_name, entry.license_name, entry.source_url]
|
14
|
+
}
|
15
|
+
Terminal::Table.new({
|
16
|
+
headings: ['Pod', 'License', 'Source'],
|
17
|
+
rows: rows
|
18
|
+
}).to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ad_licenselint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pierre Felgines
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.12.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.0.0
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.12.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rake
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '12.3'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '12.3'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: minitest
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '5.11'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '5.11'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: byebug
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '11.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '11.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: minitest-reporters
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '1.3'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '1.3'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: minitest-hooks
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.5'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.5'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: cocoapods
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.9'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '1.9'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: colorize
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0.8'
|
124
|
+
type: :runtime
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.8'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: terminal-table
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '1.8'
|
138
|
+
type: :runtime
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '1.8'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: cocoapods-core
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '1.9'
|
152
|
+
type: :runtime
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '1.9'
|
159
|
+
description: Lint the licenses for iOS projects
|
160
|
+
email: pierre.felgines@fabernovel.com
|
161
|
+
executables:
|
162
|
+
- ad_licenselint
|
163
|
+
extensions: []
|
164
|
+
extra_rdoc_files: []
|
165
|
+
files:
|
166
|
+
- bin/ad_licenselint
|
167
|
+
- lib/ad_licenselint.rb
|
168
|
+
- lib/ad_licenselint/ad_logger.rb
|
169
|
+
- lib/ad_licenselint/constant.rb
|
170
|
+
- lib/ad_licenselint/license_entry.rb
|
171
|
+
- lib/ad_licenselint/markdown_formatter.rb
|
172
|
+
- lib/ad_licenselint/option_handler.rb
|
173
|
+
- lib/ad_licenselint/report.rb
|
174
|
+
- lib/ad_licenselint/runner.rb
|
175
|
+
- lib/ad_licenselint/terminal_formatter.rb
|
176
|
+
homepage: https://rubygems.org/gems/ad_licenselint
|
177
|
+
licenses:
|
178
|
+
- MIT
|
179
|
+
metadata: {}
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - "~>"
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '2.3'
|
189
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
requirements: []
|
195
|
+
rubygems_version: 3.0.3
|
196
|
+
signing_key:
|
197
|
+
specification_version: 4
|
198
|
+
summary: Lint the licenses for iOS projects
|
199
|
+
test_files: []
|