podfileDep 1.1.4 → 2.0.1

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,183 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+ require_relative '../podfilelock'
4
+ require_relative '../constants'
5
+ require_relative 'module'
6
+ require_relative 'item'
7
+ require_relative 'xcodeproj'
8
+
9
+ module Dep
10
+ class DepChecker
11
+
12
+ # 检查缺少的或着多的依赖
13
+ def self.dep_check
14
+ puts "\n依赖库关系检查中..."
15
+ start = (Time.now.to_f * 1000).to_i
16
+
17
+ podfile_lock_manager = PodfileLock::PodfileLockManager
18
+ module_manager = ModuleModule::ModuleManager.share_instance
19
+ project_manager = XCProject::XcodeprojManager.share_manager
20
+
21
+ # podfile.lock的内容
22
+ lock_content = podfile_lock_manager.podfile_lock_content
23
+
24
+ # 获取需要检查的模块名和路径
25
+ modules = project_manager.get_development_module
26
+
27
+ # 获取所有已安装的依赖库
28
+ installed_deps = module_manager.get_installed_deps(lock_content)
29
+
30
+ # 计数
31
+ check_count = 0
32
+
33
+ # 遍历需要被检查的模块
34
+ modules.each { |module_name, module_item|
35
+
36
+ #组件的的真实依赖包括间接依赖 依据podfile.lock递归读取
37
+ real_dependencies = module_manager.real_dependencies(module_name, lock_content)
38
+
39
+ substart = (Time.now.to_f * 1000).to_i
40
+ real_frameworks = self.module_frameworks(real_dependencies)
41
+ puts "#{module_name}打点0:#{((Time.now.to_f * 1000).to_i - substart).to_s}毫秒\n"
42
+ substart = (Time.now.to_f * 1000).to_i
43
+
44
+ #podspec写的直接依赖
45
+ podspec_dependencies = module_manager.podspec_dependencies(module_item.podspec_path)
46
+
47
+ # 某个模块从代码文件里读取的真实需要的依赖库 #import <XX/XX.h>
48
+ import_item_map = {}
49
+ module_item.source_files.each { |source_file|
50
+ self.update_import_item_map(source_file, module_name, import_item_map)
51
+ check_count += 1
52
+ }
53
+
54
+ if import_item_map.size == 0 and real_dependencies.size == 0
55
+ next
56
+ end
57
+
58
+ # real_dependencies指的是根据组件podspec的写法 解析出来的依赖库
59
+ # import_item_map指的是根据代码文件解析出来的依赖库
60
+ loss = []
61
+ import_item_map.each_key {|key|
62
+ if key != module_name
63
+ did_loss = true
64
+
65
+ real_frameworks.each { |dep, frameworks|
66
+ frameworks.each {|framework|
67
+ if key == framework
68
+ did_loss = false
69
+ break
70
+ end
71
+ }
72
+ }
73
+
74
+ if did_loss
75
+ loss << "#{key}"
76
+ end
77
+
78
+ end
79
+ }
80
+
81
+ puts "#{module_name}打点1:#{((Time.now.to_f * 1000).to_i - substart).to_s}毫秒\n"
82
+ substart = (Time.now.to_f * 1000).to_i
83
+
84
+ unused = []
85
+ real_frameworks.each { |dep, frameworks|
86
+ use = false
87
+ frameworks.each{|framework|
88
+ if import_item_map.keys.include?(framework)
89
+ use = true
90
+ break
91
+ end
92
+ }
93
+ if not use and podspec_dependencies.include?(dep)
94
+ unused << "# s.dependency '#{dep}'"
95
+ end
96
+ }
97
+
98
+ if loss.size >0
99
+ puts "⚠️ [#{module_name}] 请到#{module_name}.podspec文件中添加缺少的依赖库, 如下:"
100
+ puts loss
101
+ puts "\n"
102
+ end
103
+
104
+ if unused.size >0
105
+ puts "⚠️ [#{module_name}] 请到#{module_name}.podspec文件中移除未被引用的依赖库, 如下:"
106
+ puts unused
107
+ puts "\n"
108
+ end
109
+
110
+ puts "#{module_name}打点2:#{((Time.now.to_f * 1000).to_i - substart).to_s}毫秒\n"
111
+ }
112
+
113
+ duration = ((Time.now.to_f * 1000).to_i - start)*0.001
114
+ puts "依赖库关系检查完毕! 共检查#{modules.size.to_s}个组件(#{check_count}个文件) 耗时:#{duration.round(2)}秒"
115
+ end
116
+
117
+ # 将某个库的所有依赖转化为其对应的frameworks
118
+ def self.module_frameworks(dependencies)
119
+ project_manager = XCProject::XcodeprojManager.share_manager
120
+ result_map = {}
121
+ dependencies.each do |dependency|
122
+ frameworks = project_manager.frameworks_with_module_name(dependency)
123
+ result_map[dependency] = frameworks
124
+ end
125
+ result_map
126
+ end
127
+
128
+ # 获取某个文件内对应类型的import <XX/XX>
129
+ def self.update_import_item_map(file_path, module_name, import_item_map)
130
+ if File.directory?(file_path)
131
+ return
132
+ end
133
+
134
+ line_array = IO.readlines(file_path)
135
+ line_array.each_with_index { |line, index|
136
+ line = line.gsub(" ", "")
137
+ if not line.start_with?("#import<") and not line.start_with?("#include<")
138
+ next
139
+ end
140
+
141
+ line_split_array = line.split(">")
142
+ if line_split_array.size == 0
143
+ next
144
+ end
145
+
146
+ import_name = line_split_array[0]+">" # #import <XX/XX.h> 或者 #import <XX.h> 防止后边有其他的内容
147
+ if not import_name.include?(".h") and not import_name.include?(".H")
148
+ next
149
+ end
150
+ import_array = import_name.split("/")
151
+ if line_split_array.size == 0
152
+ next
153
+ end
154
+
155
+ pod = import_array[0].gsub("#import<", "").gsub("#include<", "")
156
+ pod = pod.gsub(".h>", "")
157
+ pod = pod.gsub(".H>", "")
158
+
159
+ # 已经包含
160
+ if import_item_map[pod]
161
+ next
162
+ end
163
+
164
+ # 系统级依赖库
165
+ if self.system_deps.include?(pod)
166
+ next
167
+ end
168
+
169
+ file_name = File.basename(file_path)
170
+ line_index = index+1
171
+
172
+ import_item_map[pod] = ImportItem.new(import_name, module_name, file_name, line_index, pod)
173
+
174
+ }
175
+ end
176
+
177
+ # 系统级的依赖库
178
+ def self.system_deps
179
+ return Constants::LIBLIBARYS + Constants::FRAMEWORKS
180
+ end
181
+
182
+ end
183
+ end
@@ -0,0 +1,159 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+ require_relative '../constants'
4
+ require_relative 'module'
5
+ require_relative 'item'
6
+ require_relative 'xcodeproj'
7
+
8
+ module Import
9
+ class ImportManager
10
+
11
+ # 检查import规范
12
+ def self.import_check
13
+ puts "\nimport规范检查中..."
14
+ start = (Time.now.to_f * 1000).to_i
15
+
16
+ project_manager = XCProject::XcodeprojManager.share_manager
17
+
18
+ # 获取需要检查的模块名和路径
19
+ modules = project_manager.get_development_module
20
+
21
+ # 获取Pods和本地依赖库的 组件名和包含的头文件列表 map类型
22
+ module_headers = project_manager.get_installed_headers_module
23
+
24
+ # 计数
25
+ check_count = 0
26
+
27
+ # 遍历需要被检查的模块
28
+ modules.each_value { |module_item|
29
+
30
+ # 某个模块从代码文件里读取的双引号依赖库 #import "XX/XX.h"
31
+ import_item_map = {}
32
+
33
+ #头文件的文件名
34
+ header_file_names = []
35
+
36
+ module_item.source_files.each { |source_file|
37
+
38
+ header_file_name = File.basename(source_file)
39
+ if header_file_name.end_with?(".h") or header_file_name.end_with?(".hpp") or header_file_name.end_with?(".pch")
40
+ header_file_names << header_file_name
41
+ end
42
+
43
+ self.update_import_dot_item_map(source_file, module_item, import_item_map)
44
+
45
+ check_count += 1
46
+ }
47
+
48
+ if import_item_map.size == 0 and header_file_names.size == 0
49
+ next
50
+ end
51
+
52
+ messages = []
53
+ import_item_map.each {|key, value| #key是 xxx.h value是{ImportItem:}
54
+
55
+ # 当前仓库的文件已包含
56
+ if header_file_names.include?(key)
57
+ next
58
+ end
59
+
60
+ # 是否是导入的系统lib
61
+ if self.check_sys_libary(key)
62
+ next
63
+ end
64
+
65
+ search_module_name = self.get_module_name(module_headers, key)
66
+
67
+ unless search_module_name
68
+ next
69
+ end
70
+
71
+ messages << "#{value.file_name} 第#{value.line_index}行 #{value.import_name} => #import <#{search_module_name}/#{value.pod}>"
72
+
73
+ }
74
+
75
+ if messages.size >0
76
+ puts "⚠️ 组件#{module_item.module_name}存在以下情况, 请检查:"
77
+ puts messages
78
+ puts "\n"
79
+ end
80
+
81
+ }
82
+
83
+ duration = ((Time.now.to_f * 1000).to_i - start)*0.001
84
+ puts "import规范检查完毕! 共检查#{modules.size.to_s}个组件(#{check_count}个文件) 耗时:#{duration.round(2)}秒"
85
+ end
86
+
87
+ # 获取某个文件内对应类型的import "XXX.h"
88
+ def self.update_import_dot_item_map(file_path, module_name, import_item_map)
89
+ if File.directory?(file_path)
90
+ return
91
+ end
92
+
93
+ line_array = IO.readlines(file_path)
94
+ line_array.each_with_index { |line, index|
95
+ line = line.gsub(" ", "")
96
+ unless line.start_with?("#import\"")
97
+ next
98
+ end
99
+
100
+ if line.start_with?("@implementation")
101
+ break
102
+ end
103
+
104
+ line_split_array = line.split("\"")
105
+ if line_split_array.size <= 1
106
+ next
107
+ end
108
+
109
+ import_name = "#{line_split_array[0]}\"#{line_split_array[1]}\"" # import"XXX.h" 或import"XXX.AAA.h" 防止后边有其他内容
110
+
111
+ # 特殊处理
112
+ if import_name == "#import\"NBSAppAgent.h\""
113
+ next
114
+ end
115
+
116
+ podfile = import_name
117
+ podfile = podfile.gsub("#import\"", "")
118
+ podfile = podfile.gsub("\"", "") # 变成 XX.h
119
+
120
+ # 已经包含
121
+ if import_item_map[podfile]
122
+ next
123
+ end
124
+ pre_index = index-1 < 0 ? 0 : index-1
125
+ pre_line = line_array[pre_index]
126
+ pre_line = pre_line.gsub(" ", "").gsub("\n", "")
127
+ if pre_line.start_with?("#if") or pre_line == "#else"
128
+ next
129
+ end
130
+
131
+ file_name = File.basename(file_path)
132
+ line_index = index+1
133
+
134
+ import_item_map[podfile] = ImportItem.new(import_name, module_name, file_name, line_index, podfile)
135
+
136
+ }
137
+ end
138
+
139
+ # 根据文件名反查出属于哪个组件
140
+ def self.get_module_name(module_headers, file_name)
141
+ module_headers.each do |module_name,module_item|
142
+ module_item.source_files.each {|source_file|
143
+ if source_file.basename.to_s == file_name
144
+ return module_name
145
+ end
146
+ }
147
+ end
148
+ return nil
149
+ end
150
+
151
+ # 获取某库是否是系统级的依赖库
152
+ def self.check_sys_libary(name)
153
+ name = name.gsub(".h", "")
154
+ libs = Constants::LIBLIBARYS
155
+ return libs.include?(name)
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,11 @@
1
+
2
+ class ImportItem
3
+ attr_reader :import_name, :module_item, :file_name, :line_index, :pod
4
+ def initialize(import_name, module_item, file_name, line_index, pod)
5
+ @import_name = import_name
6
+ @module_item = module_item
7
+ @file_name = file_name
8
+ @line_index = line_index
9
+ @pod = pod
10
+ end
11
+ end
@@ -0,0 +1,178 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+ require 'cocoapods'
4
+ require 'xcodeproj'
5
+ require_relative '../constants'
6
+
7
+ module ModuleModule
8
+
9
+ class ModuleDepObject
10
+ def initialize(module_name)
11
+ @module_name = module_name
12
+ @dependencies = []
13
+ @dependencies_expanded = false
14
+ end
15
+
16
+ # 组件名
17
+ attr_reader :module_name
18
+
19
+ # 组件所引用的依赖库
20
+ attr_reader :dependencies
21
+
22
+ # 组件的依赖是否被全部展开
23
+ attr_reader :dependencies_expanded
24
+
25
+
26
+ # 添加一个依赖库
27
+ def add_dependency(dependency)
28
+ self.dependencies << dependency
29
+ end
30
+
31
+ def did_expanded
32
+ @dependencies_expanded = true
33
+ end
34
+
35
+ end
36
+
37
+ class ModuleManager
38
+
39
+ # 缓存某个的依赖库
40
+ # {{"module_nameA":ModuleDepObject,{"module_nameB":ModuleDepObject}
41
+ attr_reader :all_module_dependencies
42
+
43
+ def initialize
44
+ @all_module_dependencies = {}
45
+ end
46
+ # 单例方法
47
+ @@instance = ModuleManager.new
48
+
49
+ # 获取单例
50
+ def self.share_instance
51
+ @@instance
52
+ end
53
+
54
+ private_class_method :new
55
+
56
+ def real_dependencies(module_name, lock_content)
57
+
58
+ lock_dependencies = lock_content["PODS"]
59
+
60
+ module_dep = ModuleDepObject.new(module_name)
61
+
62
+ # 可能是取的缓存 所以必须赋值
63
+ module_dep = self.get_module_dep(lock_dependencies, module_dep)
64
+
65
+ module_dep.dependencies
66
+
67
+ end
68
+
69
+ # 根据podfile.lock里内容递归获取某个库的依赖库
70
+ @private
71
+ def get_module_dep(lock_dependencies, module_dep)
72
+
73
+ module_dep_cache = self.all_module_dependencies[module_dep.module_name]
74
+ if module_dep_cache&.dependencies_expanded
75
+ return module_dep_cache
76
+ end
77
+
78
+ # 找出当前组件的依赖
79
+ lock_dependencies.each { |item|
80
+
81
+ item_name= item
82
+ if item.class == Hash
83
+ item_name = item.keys[0]
84
+ end
85
+
86
+ item_name = item_name.split(" (")[0]
87
+ item_name = item_name.split("/")[0] #解决子仓库的问题
88
+
89
+ # 非当前组件
90
+ if item_name != module_dep.module_name
91
+ next
92
+ end
93
+
94
+ # 当前组件无其他依赖
95
+ if item.class == String
96
+ break
97
+ end
98
+
99
+ # 当前组件有其他依赖
100
+ # item:{"A (99999)"=>["Masonry", "MJExtension"]
101
+ item.each {|name, child_names|
102
+ child_names.each { |child_name|
103
+ child_name = child_name.split(" (")[0]
104
+ child_name = child_name.split("/")[0] #解决子仓库的问题
105
+
106
+ if item_name == child_name #解决item_name = AFNetworking child_name=AFNetworking/NSURLSession
107
+ next
108
+ end
109
+
110
+ # 当前库的依赖加进去
111
+ unless module_dep.dependencies.include?(child_name)
112
+ module_dep.dependencies << child_name
113
+ end
114
+
115
+ # 当前库的依赖的子依赖
116
+ child = ModuleDepObject.new(child_name)
117
+ child_dep = self.get_module_dep(lock_dependencies, child)
118
+
119
+ child_dep.did_expanded
120
+ self.all_module_dependencies[child_dep.module_name] = child_dep
121
+
122
+ child_dep.dependencies.each { |sun_name|
123
+ # 孙子依赖加进去
124
+ unless module_dep.dependencies.include?(sun_name)
125
+ module_dep.dependencies << sun_name
126
+ end
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ module_dep.did_expanded
133
+ self.all_module_dependencies[module_dep.module_name] = module_dep
134
+ module_dep
135
+ end
136
+
137
+ # 获取某个库的podspec的直接依赖
138
+ def podspec_dependencies(podspec_path)
139
+
140
+ podspec_json_path = podspec_path.to_s.end_with?(".podspec.json") ? podspec_path : nil
141
+
142
+ podspec_content = nil
143
+ if podspec_json_path and File.exist?(podspec_json_path)
144
+ json = File.read(podspec_json_path)
145
+ podspec_content = JSON.parse(json)
146
+ elsif podspec_path and File.exist?(podspec_path)
147
+ json = self.get_podspec_content(podspec_path)
148
+ podspec_content = JSON.parse(json)
149
+ end
150
+
151
+ podspec_content["dependencies"] ? podspec_content["dependencies"].keys : []
152
+
153
+ end
154
+
155
+ # 获取已安装的依赖库
156
+ def get_installed_deps(lock_dependencies)
157
+ lock_dependencies["SPEC CHECKSUMS"] ? lock_dependencies["SPEC CHECKSUMS"].keys : {}
158
+ end
159
+
160
+ # 根据podspec路径把podspec转为json
161
+ @private
162
+ def get_podspec_content(podspec_path)
163
+
164
+ spec_contents = File.open(podspec_path, 'r:utf-8', &:read)
165
+
166
+ if spec_contents.respond_to?(:encoding) && spec_contents.encoding.name != 'UTF-8'
167
+ spec_contents.encode!('UTF-8')
168
+ end
169
+
170
+ path = Pathname.new(podspec_path)
171
+
172
+ spec = ::Pod._eval_podspec(spec_contents, path)
173
+
174
+ spec.to_json
175
+ end
176
+
177
+ end
178
+ end