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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/lib/cocoapods_plugin.rb +44 -0
- data/lib/old/podfileDep.rb +1408 -0
- data/lib/podfileDep/check/dep.rb +183 -0
- data/lib/podfileDep/check/import.rb +159 -0
- data/lib/podfileDep/check/item.rb +11 -0
- data/lib/podfileDep/check/module.rb +178 -0
- data/lib/podfileDep/check/xcodeproj.rb +310 -0
- data/lib/podfileDep/constants.rb +13 -0
- data/lib/podfileDep/indirect/indirect.rb +37 -0
- data/lib/podfileDep/modify/modify_code.rb +52 -0
- data/lib/podfileDep/podfilelock.rb +17 -0
- data/lib/podfileDep/reference/project.rb +72 -0
- data/lib/podfileDep/reference/unused.rb +141 -0
- data/lib/podfileDep/version.rb +1 -1
- data/lib/podfileDep/yaml/yaml_dep.rb +449 -0
- data/lib/podfileDep.rb +14 -816
- data/podfileDep.gemspec +6 -5
- metadata +50 -10
- data/Gemfile.lock +0 -19
- data/sig/podfileDep.rbs +0 -4
@@ -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
|