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.
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ad_licenselint'
4
+ puts ADLicenseLint::Runner.new.run
@@ -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,8 @@
1
+ module ADLicenseLint
2
+ module Constant
3
+ MARKDOWN_FORMAT_OPTION = "md"
4
+ TERMINAL_FORMAT_OPTION = "term"
5
+ AVAILABLE_OPTIONS = [MARKDOWN_FORMAT_OPTION, TERMINAL_FORMAT_OPTION]
6
+ ACCEPTED_LICENSES = ["MIT", "Apache", "BSD"]
7
+ end
8
+ 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,17 @@
1
+ module ADLicenseLint
2
+ class Report
3
+ attr_reader :entries
4
+
5
+ def initialize(entries)
6
+ @entries = entries
7
+ end
8
+
9
+ def to_hash
10
+ { entries: @entries.map(&:to_hash) }
11
+ end
12
+
13
+ def empty?
14
+ @entries.empty?
15
+ end
16
+ end
17
+ 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: []