pod-binary-pack 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/CHANGELOG.md +15 -0
- data/LICENSE.txt +21 -0
- data/README.md +147 -0
- data/exe/pod-binary-pack +6 -0
- data/lib/core/auto_build.rb +299 -0
- data/lib/core/build_item.rb +69 -0
- data/lib/core/cli.rb +442 -0
- data/lib/core/commit.rb +19 -0
- data/lib/core/config.rb +56 -0
- data/lib/core/cost.rb +68 -0
- data/lib/core/git_helper.rb +222 -0
- data/lib/core/github_fork.rb +425 -0
- data/lib/core/github_helper.rb +334 -0
- data/lib/core/hook_manager.rb +32 -0
- data/lib/core/hosting/gitee_client.rb +114 -0
- data/lib/core/hosting/gitee_provider.rb +312 -0
- data/lib/core/hosting/gitlab_provider.rb +342 -0
- data/lib/core/hosting/provider.rb +96 -0
- data/lib/core/hosting.rb +43 -0
- data/lib/core/logger.rb +66 -0
- data/lib/core/podspec.rb +126 -0
- data/lib/core/push.rb +80 -0
- data/lib/core/repo.rb +284 -0
- data/lib/core/repo_cocoapods.rb +64 -0
- data/lib/core/repo_module.rb +281 -0
- data/lib/core/repo_module_binary.rb +439 -0
- data/lib/core/repo_module_source.rb +506 -0
- data/lib/core/repo_xcode.rb +41 -0
- data/lib/core/repo_xcode_package.rb +713 -0
- data/lib/core/repo_xcode_shell.rb +170 -0
- data/lib/core/util/file_helper.rb +100 -0
- data/lib/core/util/string.rb +35 -0
- data/lib/pod/binary_pack/version.rb +7 -0
- data/lib/pod/binary_pack.rb +9 -0
- metadata +144 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'repo'
|
|
4
|
+
require_relative 'repo_module'
|
|
5
|
+
|
|
6
|
+
module Build
|
|
7
|
+
class RepoCocoapods < Repo
|
|
8
|
+
|
|
9
|
+
# @return [RepoModule]
|
|
10
|
+
attr_accessor :repo_module
|
|
11
|
+
|
|
12
|
+
#获取某个pod_name的所有版本号
|
|
13
|
+
# @return [Array] 返回数组或nil
|
|
14
|
+
def pod_name_versions(pod_name)
|
|
15
|
+
pod_name_path = "#{self.path}/#{pod_name}"
|
|
16
|
+
unless File.directory?(pod_name_path)
|
|
17
|
+
return nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
entries = Dir.entries(pod_name_path)
|
|
21
|
+
entries.select { |entry| entry != '.' && entry != '..' }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_podspec(repo_module)
|
|
25
|
+
@repo_module = repo_module
|
|
26
|
+
Build.log.step("拷贝podspec文件到cocoapods中(#{File.basename(self.path)}):")
|
|
27
|
+
|
|
28
|
+
# 判断文件夹是否存在
|
|
29
|
+
pod_name = repo_module.pod_name
|
|
30
|
+
pod_version_final = repo_module.pod_version_final
|
|
31
|
+
pod_name_path = "#{self.path}/#{pod_name}"
|
|
32
|
+
|
|
33
|
+
unless File.directory?(pod_name_path)
|
|
34
|
+
Dir.mkdir(pod_name_path)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
pod_version_path = "#{pod_name_path}/#{pod_version_final}"
|
|
38
|
+
if File.directory?(pod_version_path)
|
|
39
|
+
if not repo_module.build_item.snapshot and not repo_module.third
|
|
40
|
+
error = "#{pod_name}已发布相同版本#{pod_version_final},请更换更高的版本号"
|
|
41
|
+
pusher.push("❌ 打包失败", error)
|
|
42
|
+
Process.exit(-1)
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
Dir.mkdir(pod_version_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
FileUtils.cp(repo_module.podspec_json_path, pod_version_path)
|
|
49
|
+
|
|
50
|
+
# 移除掉已有的podspec文件
|
|
51
|
+
podspec_path = "#{pod_version_path}/#{pod_name}.podspec"
|
|
52
|
+
if File.exist?(podspec_path)
|
|
53
|
+
FileUtils.rm(podspec_path)
|
|
54
|
+
end
|
|
55
|
+
Build.log.detail("podspec 拷贝完毕")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def git_commit(commit_msg = nil)
|
|
59
|
+
commit_msg = repo_module.get_commit_msg
|
|
60
|
+
super commit_msg
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'repo'
|
|
4
|
+
require_relative 'build_item'
|
|
5
|
+
|
|
6
|
+
module Build
|
|
7
|
+
|
|
8
|
+
class RepoModule < Repo
|
|
9
|
+
# podspec 扩展字段:构建期写入的元数据(源码commit信息/产物架构/校验和等)。
|
|
10
|
+
# 命名刻意与 gem 名解耦,工具后续重命名不影响该数据契约;
|
|
11
|
+
# 未知嵌套字段会被 CocoaPods 整体忽略,不会与官方 podspec 属性冲突。
|
|
12
|
+
PODSPEC_METADATA_KEY = 'build_metadata'.freeze
|
|
13
|
+
|
|
14
|
+
# 版本分支默认前缀(build.yml 可在 profile 中通过 release_branch_prefix 定制)
|
|
15
|
+
DEFAULT_RELEASE_BRANCH_PREFIX = 'release'.freeze
|
|
16
|
+
|
|
17
|
+
# 分支中可解析的版本号规则(不限制段数):
|
|
18
|
+
# 主体: 至少两段点分数字,如 1.2 / 1.2.0 / 1.2.2.0
|
|
19
|
+
# 后缀(可选): 以 - 或 + 起始的字母数字串(内部允许 . -),如 1.2.2-fix / 1.2.2-beta.1 / 1.2.0+build.3
|
|
20
|
+
VERSION_PATTERN = '\\d+(?:\\.\\d+)+(?:[-+][0-9A-Za-z](?:[0-9A-Za-z.-]*[0-9A-Za-z])?)?'.freeze
|
|
21
|
+
|
|
22
|
+
# 从版本分支名解析出版本号,不符合规则返回nil。
|
|
23
|
+
# 规则: <前缀> + 可选分隔符(_/-) + 版本号(如 release_1.2.0 / release-1.2.2-fix)。
|
|
24
|
+
# 前缀本身已带分隔符(如 "release/")也兼容;版本部分须符合 VERSION_PATTERN,乱七八糟的字符不解析
|
|
25
|
+
# @param branch [String] 分支名
|
|
26
|
+
# @param prefix [String, nil] 前缀,空则用默认 release
|
|
27
|
+
# @return [String, nil]
|
|
28
|
+
def self.parse_version_from_branch(branch, prefix = nil)
|
|
29
|
+
p = prefix.to_s.strip
|
|
30
|
+
p = DEFAULT_RELEASE_BRANCH_PREFIX if p.empty?
|
|
31
|
+
match = branch.to_s.match(/\A#{Regexp.escape(p)}([_-]?)(#{VERSION_PATTERN})\z/)
|
|
32
|
+
match && match[2]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [BuildItem] 构建参数
|
|
36
|
+
attr_accessor :build_item
|
|
37
|
+
attr_accessor :pod_name
|
|
38
|
+
attr_accessor :pod_version
|
|
39
|
+
# 内部三方库处理标记(不锁分支/不改版本tag/允许同版本重复发布等)。
|
|
40
|
+
# 已无对外 --third 入口,仅 fork-github 流程由 CLI 内部置为 true,自研组件恒为 false
|
|
41
|
+
attr_accessor :third
|
|
42
|
+
attr_accessor :snapshot
|
|
43
|
+
attr_accessor :pod_version_final
|
|
44
|
+
|
|
45
|
+
# @return [String] podspec_json路径
|
|
46
|
+
attr_accessor :podspec_json_path
|
|
47
|
+
|
|
48
|
+
# @return [JSON] podspec_content
|
|
49
|
+
attr_accessor :podspec_content
|
|
50
|
+
|
|
51
|
+
# @return [String] 区别于pod_name, 特指打包后的framework的名字
|
|
52
|
+
attr_accessor :framework_name
|
|
53
|
+
|
|
54
|
+
# @return [Build::Hosting::RepoInfo] 代码托管平台上的仓库信息(Gitee为full_name,GitLab为数字ID)
|
|
55
|
+
attr_accessor :repo_info
|
|
56
|
+
|
|
57
|
+
# @return [String, nil] podspec相对仓库根目录的路径(podspec不在根目录时使用,如 Sub/Foo.podspec)
|
|
58
|
+
attr_accessor :podspec_rel_path
|
|
59
|
+
|
|
60
|
+
# @return [Array<String>, nil] 显式指定的打包集成subspec短名列表(nil=默认集成全部)。
|
|
61
|
+
# 用于互斥subspec组件(如FMDB的standard/standalone/SQLCipher是不同sqlite后端,全量合并编译必冲突),
|
|
62
|
+
# 经 build.yml components.<组件>.subspecs 或 --subspecs 声明
|
|
63
|
+
attr_accessor :build_subspecs
|
|
64
|
+
|
|
65
|
+
# @return [String, nil] 一仓多组件时的源码tag前缀(如 "Foo/"),最终tag为 Foo/1.0.0;二进制一组件一仓不使用
|
|
66
|
+
attr_accessor :tag_prefix
|
|
67
|
+
|
|
68
|
+
# @return [String] 版本分支前缀(分支名形如 release_1.2.0 时可从中解析版本号)
|
|
69
|
+
attr_accessor :release_branch_prefix
|
|
70
|
+
|
|
71
|
+
def initialize(path, ssh_url, branch, pod_name, pod_version, third, build_item,
|
|
72
|
+
podspec_rel_path: nil, tag_prefix: nil, release_branch_prefix: nil,
|
|
73
|
+
build_subspecs: nil)
|
|
74
|
+
super(path, ssh_url, branch)
|
|
75
|
+
@pod_name = pod_name
|
|
76
|
+
@pod_version = pod_version
|
|
77
|
+
@third = third.to_s.downcase == "true"
|
|
78
|
+
@build_item = build_item
|
|
79
|
+
@podspec_rel_path = podspec_rel_path.to_s.strip
|
|
80
|
+
@podspec_rel_path = nil if @podspec_rel_path && @podspec_rel_path.empty?
|
|
81
|
+
# subspec覆盖列表:规范化为去空白的短名数组,全空视为未指定(nil=集成全部)
|
|
82
|
+
@build_subspecs = Array(build_subspecs).map { |s| s.to_s.strip }.reject(&:empty?)
|
|
83
|
+
@build_subspecs = nil if @build_subspecs.empty?
|
|
84
|
+
prefix = tag_prefix.to_s.strip
|
|
85
|
+
@tag_prefix = if prefix.empty? || prefix.end_with?('/')
|
|
86
|
+
prefix.empty? ? nil : prefix
|
|
87
|
+
else
|
|
88
|
+
"#{prefix}/"
|
|
89
|
+
end
|
|
90
|
+
custom_prefix = release_branch_prefix.to_s.strip
|
|
91
|
+
@release_branch_prefix = custom_prefix.empty? ? DEFAULT_RELEASE_BRANCH_PREFIX : custom_prefix
|
|
92
|
+
validate
|
|
93
|
+
analyzer
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def validate
|
|
97
|
+
|
|
98
|
+
if pod_name.empty?or pod_version.empty?
|
|
99
|
+
error = "pod_name pod_version 均不能为空"
|
|
100
|
+
pusher.push("❌ 打包失败", error)
|
|
101
|
+
Process.exit(-1)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if pod_name == "xxx" or pod_version == "xxx" or ssh_url == "xxx" or branch == "xxx"
|
|
105
|
+
error = "pod_name pod_version ssh_url branch 任一个都不能为xxx"
|
|
106
|
+
pusher.push("❌ 打包失败", error)
|
|
107
|
+
Process.exit(-1)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if pod_version.include?("SNAPSHOT")
|
|
111
|
+
error = "版本号里不能带SNAPSHOT,如需SNAPSHOT请使用snapshot参数"
|
|
112
|
+
pusher.push("❌ 打包失败", error)
|
|
113
|
+
Process.exit(-1)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if self.third and self.build_item.snapshot
|
|
117
|
+
error = "三方库不能打SNAPSHOT包"
|
|
118
|
+
pusher.push("❌ 打包失败", error)
|
|
119
|
+
Process.exit(-1)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def analyzer
|
|
125
|
+
@pod_version_final = self.build_item.snapshot ? pod_version+"-SNAPSHOT" : pod_version
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# 打在组件仓上的实际tag名:一仓多组件时带组件名前缀(Foo/1.0.0)避免共仓tag冲突,
|
|
129
|
+
# 默认无前缀即裸版本号;二进制一组件一仓,前缀始终为空
|
|
130
|
+
def version_tag
|
|
131
|
+
"#{tag_prefix}#{pod_version_final}"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# 组件文件匹配根目录(实现文件/资源的相对路径基准),默认仓库根目录;
|
|
135
|
+
# podspec在子目录时由RepoModuleSource覆写为podspec所在目录(CocoaPods :podspec 语义一致)
|
|
136
|
+
def component_root_dir
|
|
137
|
+
path
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# 是否构建了二进制
|
|
141
|
+
def build_binary
|
|
142
|
+
build_item.real_device or build_item.simulator
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def update_binary
|
|
146
|
+
# Array()+dup 避免直接持有podspec_content内部的数组引用被后续append污染
|
|
147
|
+
source_files_array = Array(podspec_content["source_files"]).dup
|
|
148
|
+
|
|
149
|
+
sub_specs = podspec_content["subspecs"]
|
|
150
|
+
if sub_specs
|
|
151
|
+
sub_specs.each do |sub_spec|
|
|
152
|
+
# Array(nil)=[],subspec未声明source_files时安全跳过;元素统一展平为一维
|
|
153
|
+
source_files_array.concat(Array(sub_spec["source_files"]))
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# 定制组件:不编译framework,也不发布二进制(名单见BuildItem::NO_BINARY_PODS)
|
|
158
|
+
if Build::BuildItem::NO_BINARY_PODS.include?(pod_name)
|
|
159
|
+
build_item.real_device = false
|
|
160
|
+
build_item.simulator = false
|
|
161
|
+
build_item.header_only = false
|
|
162
|
+
warn_msg = "定制组件#{pod_name}不需要打二进制"
|
|
163
|
+
Build.log.warn(warn_msg)
|
|
164
|
+
pusher.push("【⚠️组件不构建二进制提醒】", warn_msg)
|
|
165
|
+
return
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
have_implementation = false
|
|
169
|
+
have_header = false
|
|
170
|
+
# 包含子模块的所有;source_files 可能是 glob、单个文件,也可能直接指向目录
|
|
171
|
+
source_files_array.each do |source_files|
|
|
172
|
+
source_files_path = "#{component_root_dir}/#{source_files}"
|
|
173
|
+
if FileHelper.have_implementation_files(source_files_path)
|
|
174
|
+
have_implementation = true
|
|
175
|
+
break
|
|
176
|
+
end
|
|
177
|
+
# 记录是否至少匹配到头文件(纯头文件组件判定)
|
|
178
|
+
have_header = true if FileHelper.have_header_files(source_files_path)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
if not have_implementation
|
|
182
|
+
build_item.real_device = false
|
|
183
|
+
build_item.simulator = false
|
|
184
|
+
if have_header
|
|
185
|
+
# 纯头文件组件:不编译framework,但仍发布头文件形态的二进制podspec,
|
|
186
|
+
# 保证二进制spec源也能解析到该组件(App默认优先二进制源)
|
|
187
|
+
build_item.header_only = true
|
|
188
|
+
warn_msg = "当前组件无实现文件(纯头文件组件),不编译framework,但仍发布头文件形态的二进制podspec"
|
|
189
|
+
Build.log.warn(warn_msg)
|
|
190
|
+
pusher.push("【⚠️纯头文件组件提醒】", warn_msg)
|
|
191
|
+
else
|
|
192
|
+
build_item.header_only = false
|
|
193
|
+
warn_msg = "当前组件无实现文件也无头文件,不构建二进制"
|
|
194
|
+
Build.log.warn(warn_msg)
|
|
195
|
+
pusher.push("【⚠️组件不构建二进制提醒】", warn_msg)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# 按配置裁剪了subspec的组件(update_podspec 会在build_metadata写入subspec_note),
|
|
201
|
+
# 各仓库提交信息据此追加关键字,便于在提交历史中快速识别与检索
|
|
202
|
+
def subspec_pruned?
|
|
203
|
+
metadata = podspec_content[PODSPEC_METADATA_KEY] || {}
|
|
204
|
+
!metadata["subspec_note"].to_s.empty?
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# 各仓库提交信息的关键字前缀:裁剪subspec / 模拟器产物裁剪arm64架构,可同时存在;
|
|
208
|
+
# 统一放在提交信息最前边,git log 列表展示被截断时也能看到
|
|
209
|
+
def commit_keyword_prefix
|
|
210
|
+
prefix = +""
|
|
211
|
+
prefix << "[裁剪subspec] " if subspec_pruned?
|
|
212
|
+
prefix << "[裁剪架构] " if build_item.respond_to?(:simulator_exclude_arm64) && build_item.simulator_exclude_arm64
|
|
213
|
+
prefix
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def get_commit_msg
|
|
217
|
+
# 扩展信息统一读取 build_metadata 嵌套字段
|
|
218
|
+
metadata = podspec_content[PODSPEC_METADATA_KEY] || {}
|
|
219
|
+
committer = metadata["committer"]
|
|
220
|
+
commit_time = metadata["commit_time"]
|
|
221
|
+
# 提交信息里的 SHA 仅供人工溯源,对齐 CocoaPods 官方 Specs 仓惯例取 7 位短哈希;
|
|
222
|
+
# 注意:build_metadata.commit_id(podspec.json 内)必须保留完整 40 位,
|
|
223
|
+
# 发布校验需拿它与 Gitee/GitLab API 返回的完整 SHA 精确比对,不可一并缩短
|
|
224
|
+
short_commit_id = metadata["commit_id"].to_s[0, 7]
|
|
225
|
+
"#{commit_keyword_prefix}#{self.pod_name} #{self.pod_version_final} (#{committer} #{commit_time} #{short_commit_id})"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# 重写父类方法
|
|
229
|
+
def git_commit(commit_msg = nil)
|
|
230
|
+
commit_msg = get_commit_msg
|
|
231
|
+
super commit_msg
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# 打标签
|
|
235
|
+
def git_tag
|
|
236
|
+
current = Dir.pwd
|
|
237
|
+
Dir.chdir(self.path)
|
|
238
|
+
|
|
239
|
+
dir_name = File.basename(self.path)
|
|
240
|
+
Build.log.step("推送版本号tag(#{dir_name})")
|
|
241
|
+
|
|
242
|
+
# 丢弃修改并拉取代码
|
|
243
|
+
discard_pull
|
|
244
|
+
|
|
245
|
+
tag = version_tag
|
|
246
|
+
|
|
247
|
+
# snapshot和三方库 需要删除老的标签
|
|
248
|
+
if self.build_item.snapshot or self.third
|
|
249
|
+
# 删除本地标签
|
|
250
|
+
git_tag_delete_local(tag)
|
|
251
|
+
|
|
252
|
+
# 删除远端标签
|
|
253
|
+
git_tag_delete_origin(tag)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# 本地打标签
|
|
257
|
+
git_tag_local(tag)
|
|
258
|
+
|
|
259
|
+
# 推送到远端
|
|
260
|
+
git_tag_origin(tag)
|
|
261
|
+
|
|
262
|
+
Dir.chdir(current)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# 重写父类方法 clone完毕后获取仓库信息
|
|
266
|
+
def git_clone(only_head)
|
|
267
|
+
super
|
|
268
|
+
info = hosting.find_project(pod_name, http_url, can_raise: true)
|
|
269
|
+
|
|
270
|
+
unless info
|
|
271
|
+
return
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
@repo_info = info
|
|
275
|
+
Build.log.info("查询(#{http_url})仓库信息: #{info.full_name} 命名空间:#{info.namespace_path}")
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
end
|