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.
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+ require 'yaml'
3
+ require_relative 'build_item'
4
+ require_relative 'repo_xcode_package'
5
+ require_relative 'repo_module_source'
6
+
7
+ module Build
8
+ # 壳工程即打包工程:既承担 archive 打包(继承 RepoXcodePackage 的能力),
9
+ # 也承担组件版本号回写到壳工程并提交发布
10
+ class RepoXCodeShell < RepoXcodePackage
11
+
12
+ # 发布到壳工程中
13
+ def publish_shell(repo_module_source)
14
+ Build.log.step("(#{File.basename(self.path)})发布版本到壳工程中")
15
+ unless repo_module_source.build_item.publish_shell
16
+ Build.log.info("本次构建 publish_shell = false 不执行发布到壳工程中")
17
+ return
18
+ end
19
+
20
+ # 切换目录
21
+ current = FileUtils.pwd
22
+ Dir.chdir(self.path)
23
+
24
+ # 丢弃构建期对 tracked 文件的修改并拉取最新代码
25
+ discard_pull
26
+
27
+ # 清理构建期生成的临时文件(untracked,绝不能提交进壳工程)
28
+ local_yaml = File.join(self.path, LOCAL_DEPENDENCIES_FILE)
29
+ File.delete(local_yaml) if File.exist?(local_yaml)
30
+
31
+ # 更新yaml文件
32
+ yaml_file = update_shell_yaml(repo_module_source)
33
+
34
+ # 仅检查目标 yaml 是否有变更(构建产物 Pods/、build/ 等不参与判断)
35
+ change = git_file_changed?(yaml_file)
36
+
37
+ # 有变更
38
+ if change
39
+ # 仅暂存该 yaml,避免带入其它文件
40
+ git_add_files(yaml_file)
41
+
42
+ # 提交信息标注 target(取依赖文件名)与组件版本,便于在壳工程提交历史中检索;
43
+ # 裁剪了subspec/架构的组件在最前边追加关键字(与组件仓/specs仓提交信息保持一致)
44
+ target_name = File.basename(yaml_file).sub(/Dependencies\.yaml$/, '')
45
+ commit_msg = "#{repo_module_source.commit_keyword_prefix}[组件依赖更新] #{target_name}: #{repo_module_source.pod_name} #{repo_module_source.pod_version_final}"
46
+ git_commit(commit_msg)
47
+
48
+ # 推送远程仓库
49
+ git_push
50
+
51
+ end
52
+
53
+ # 还原目录
54
+ Dir.chdir(current)
55
+
56
+ # 推送结果
57
+ text = change ? "【✅ 组件发布到壳工程成功】" : "【✅ 当前组件已在到壳工程中】"
58
+ pusher.push(text)
59
+
60
+ end
61
+
62
+ private
63
+ # 更新target依赖文件中的组件版本(外科式修改,保留锚点变量/注释/空行)
64
+ # @return [String] 实际更新的 yaml 文件名
65
+ def update_shell_yaml(repo_module_source)
66
+ Build.log.info("更新yaml文件")
67
+ pod_name = repo_module_source.pod_name
68
+ pod_version = repo_module_source.pod_version_final
69
+ # 是否产出了二进制产物(真机/模拟器);否则为仅源码方式,需指定源码specs源
70
+ binary = !!(repo_module_source.build_item.real_device or repo_module_source.build_item.simulator)
71
+
72
+ yaml_path = locate_pod_dependency_file(pod_name)
73
+ if yaml_path
74
+ update_existing_pod(yaml_path, pod_name, pod_version, binary)
75
+ else
76
+ yaml_path = insert_new_pod(pod_name, pod_version, binary)
77
+ end
78
+
79
+ # 发布时顺带把该 target 依赖按组件名重排,头注释/SOURCES/锚点/字段格式保持原样
80
+ sort_pods_alphabetically(yaml_path)
81
+
82
+ File.basename(yaml_path)
83
+ end
84
+
85
+ # 将依赖文件 PODS 下的条目按组件名不区分大小写升序重排。
86
+ # 纯文本行级处理:头部初始化注释、--- 文档标记、SOURCES 锚点块、各条目字段与行内注释全部保留;
87
+ # 仅统一条目间的空行分隔。PODS 区域出现无法归属的注释/顶层内容等非规整结构时放弃排序,避免破坏文件
88
+ def sort_pods_alphabetically(yaml_path)
89
+ text = File.read(yaml_path)
90
+ sorted = sort_pods_text(text)
91
+ return if sorted.nil? || sorted == text
92
+
93
+ File.write(yaml_path, sorted)
94
+ Build.log.detail("依赖条目已按组件名重排: #{File.basename(yaml_path)}")
95
+ end
96
+
97
+ # @return [String, nil] 重排后的文本;无法安全重排时返回 nil
98
+ def sort_pods_text(text)
99
+ lines = text.lines
100
+ pods_idx = lines.index { |line| line =~ /^PODS:\s*$/ }
101
+ return nil unless pods_idx
102
+
103
+ head = lines[0..pods_idx]
104
+ entries = []
105
+ current = nil
106
+ Array(lines[(pods_idx + 1)..-1]).each do |line|
107
+ if line =~ /^- pod:\s+(.+?)\s*$/
108
+ name = Regexp.last_match(1).gsub(/\A["']|["']\z/, '')
109
+ current = [name, [line]]
110
+ entries << current
111
+ elsif line.strip.empty?
112
+ # 条目间空行仅作分隔,重排后统一重建
113
+ elsif line =~ /^\s+\S/
114
+ # 2空格缩进的字段(configurations/- Debug 等)归属当前条目;
115
+ # 出现在第一条目之前说明结构异常,放弃排序
116
+ return nil if entries.empty?
117
+ current[1] << line
118
+ else
119
+ # PODS 区域内的注释或其它顶层内容无法安全归位,放弃排序
120
+ return nil
121
+ end
122
+ end
123
+
124
+ return text if entries.size <= 1
125
+
126
+ blocks = entries.sort_by { |name, _| name.downcase }.map { |_, block_lines| block_lines.join }
127
+ head.join + blocks.join("\n")
128
+ end
129
+
130
+ # 更新已声明组件的version与source策略
131
+ def update_existing_pod(yaml_path, pod_name, pod_version, binary)
132
+ text = File.read(yaml_path)
133
+ text = edit_pod_block(text, pod_name) do |block|
134
+ block = set_block_field(block, 'version', pod_version)
135
+ block =
136
+ if binary
137
+ # 二进制发布: 走SOURCES第一个(二进制源),移除显式source
138
+ remove_block_field(block, 'source')
139
+ else
140
+ source = dependency_sources(yaml_path)[1]
141
+ Build.log.warn("#{pod_name}为仅源码组件,但#{File.basename(yaml_path)}的SOURCES未配置源码源(第2个),source保持原值") unless source
142
+ set_block_field(block, 'source', source) if source
143
+ block
144
+ end
145
+ block
146
+ end
147
+ File.write(yaml_path, text)
148
+ end
149
+
150
+ # 未声明组件: 写入主App target的依赖文件
151
+ def insert_new_pod(pod_name, pod_version, binary)
152
+ yaml_path = main_dependency_file
153
+ unless File.exist?(yaml_path)
154
+ error = "壳工程缺少主target依赖文件 #{File.basename(yaml_path)},无法回写组件 #{pod_name} 的版本号,请先在壳工程中执行 pod yaml init 或手动创建"
155
+ pusher.push("❌ 打包失败", error)
156
+ Process.exit(-1)
157
+ end
158
+
159
+ item = "- pod: #{pod_name}\n version: #{pod_version}\n"
160
+ unless binary
161
+ source = dependency_sources(yaml_path)[1]
162
+ item += " source: #{source}\n" if source
163
+ end
164
+
165
+ File.write(yaml_path, append_pod_item(File.read(yaml_path), item))
166
+ yaml_path
167
+ end
168
+
169
+ end
170
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+ require 'fileutils'
3
+
4
+ class FileHelper
5
+
6
+ # @api 把目录1中的文件全部覆盖拷贝到目录2中 除开.git文件夹不拷贝
7
+ # @param path1 原路径
8
+ # @param path2 目标路径
9
+ def FileHelper.cp_rf_exclude_git(path1, path2)
10
+ Dir.foreach(path2) do |file_name|
11
+ if file_name == "." or file_name == ".." or file_name == ".git"
12
+ next
13
+ end
14
+ sub_path = "#{path2}/#{file_name}"
15
+ FileUtils.rm_rf(sub_path)
16
+ end
17
+
18
+ Dir.foreach(path1) do |file_name|
19
+ if file_name == "." or file_name == ".." or file_name == ".git"
20
+ next
21
+ end
22
+
23
+ sub_path = "#{path1}/#{file_name}"
24
+
25
+ FileUtils.cp_r(sub_path, path2)
26
+ end
27
+ end
28
+
29
+ # 在目标路径下递归查找(隐藏文件夹除外)
30
+ def FileHelper.recursion_find(des_path, find, result_array)
31
+ if not result_array or not result_array.is_a?(Array)
32
+ return
33
+ end
34
+
35
+ find_path = "#{des_path}/#{find}"
36
+ if File.exist?(find_path)
37
+ result_array << find_path
38
+ else
39
+ Dir.foreach(des_path) { |file_name|
40
+ sub_path = "#{des_path}/#{file_name}"
41
+ if File.directory?(sub_path) and not file_name.start_with?(".")
42
+ FileHelper.recursion_find(sub_path, find, result_array)
43
+ end
44
+ }
45
+ end
46
+ end
47
+
48
+ # 除开隐藏文件夹的所有文件
49
+ def FileHelper.recursion_files(des_path, result_array)
50
+ if not result_array or not result_array.is_a?(Array)
51
+ return
52
+ end
53
+
54
+ if File.file?(des_path)
55
+ result_array << des_path
56
+ else
57
+ Dir.foreach(des_path) { |file_name|
58
+ sub_path = "#{des_path}/#{file_name}"
59
+ unless file_name.start_with?(".")
60
+ FileHelper.recursion_files(sub_path, result_array)
61
+ end
62
+ }
63
+ end
64
+ end
65
+
66
+ IMPLEMENTATION_EXTENDS = %w[.m .mm .c .cc .cpp .swift].freeze
67
+ HEADER_EXTENDS = %w[.h .hpp].freeze
68
+
69
+ # 按 podspec source_files 的语义展开为实际文件列表:
70
+ # - 指向目录:递归取目录下全部文件(CocoaPods 中 source_files 为目录即包含其下所有源文件)
71
+ # - 含 glob 通配符:按 glob 展开
72
+ # - 指向单个文件:返回该文件
73
+ # 仅返回普通文件,自动剔除目录项
74
+ def FileHelper.source_files_under(path)
75
+ files =
76
+ if File.directory?(path)
77
+ Dir.glob(File.join(path, '**', '*'))
78
+ elsif path =~ /[*?\[\]{}]/
79
+ Dir.glob(path)
80
+ else
81
+ File.exist?(path) ? [path] : []
82
+ end
83
+ files.select { |f| File.file?(f) }
84
+ end
85
+
86
+ # 路径下是否有OC/Swift的实现文件(支持 source_files 直接指向目录)
87
+ def FileHelper.have_implementation_files(path)
88
+ FileHelper.source_files_under(path).any? do |file_path_str|
89
+ IMPLEMENTATION_EXTENDS.include?(Pathname(file_path_str).extname.downcase)
90
+ end
91
+ end
92
+
93
+ # 路径下是否有头文件(支持 source_files 直接指向目录)
94
+ def FileHelper.have_header_files(path)
95
+ FileHelper.source_files_under(path).any? do |file_path_str|
96
+ HEADER_EXTENDS.include?(Pathname(file_path_str).extname.downcase)
97
+ end
98
+ end
99
+
100
+ end
@@ -0,0 +1,35 @@
1
+ class String
2
+ # ssh地址转为Http地址
3
+ # @return String
4
+ # @example
5
+ # git@gitee.com:owner/CocoaPods.git -> http://gitee.com/owner/CocoaPods.git
6
+ def ssh_to_http
7
+ if self.start_with?("git@") and self.end_with?(".git")
8
+ temp = self.sub(":", "/")
9
+ temp = temp.sub("git@", "http://")
10
+ # 只去结尾的.git,避免误伤仓名中段含.git的名字(如repo.github.io.git)
11
+ temp.sub(/\.git\z/, "")
12
+ else
13
+ self
14
+ end
15
+ end
16
+
17
+ def http_to_ssh
18
+ # https://gitee.com/owner/MJRefresh.git
19
+ # git@gitee.com:owner/MJRefresh.git
20
+ if self.start_with?("http://") or self.start_with?("https://")
21
+ temp = self.gsub("https://","git@")
22
+ temp = temp.gsub("http://","git@")
23
+ url = URI(self)
24
+ host = "#{url.host}:"
25
+ temp = temp.gsub(url.host, host)
26
+ temp = temp.gsub(":/", ":")
27
+ unless temp.end_with?(".git")
28
+ temp = "#{temp}.git"
29
+ end
30
+ temp
31
+ else
32
+ self
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pod
4
+ module BinaryPack
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "binary_pack/version"
4
+
5
+ # 核心代码位于 lib/core,直接加载
6
+ require_relative "../core/logger"
7
+ require_relative "../core/hook_manager"
8
+ require_relative "../core/auto_build"
9
+ require_relative "../core/cli"
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pod-binary-pack
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - wsp
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: git
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '5.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '6'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '5.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '6'
32
+ - !ruby/object:Gem::Dependency
33
+ name: cocoapods
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '1.15'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '1.15'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2'
52
+ - !ruby/object:Gem::Dependency
53
+ name: xcodeproj
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: '1.23'
59
+ type: :runtime
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '1.23'
66
+ - !ruby/object:Gem::Dependency
67
+ name: cocoapods-yaml
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '1.0'
73
+ type: :runtime
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '1.0'
80
+ description: iOS双私有源组件打包核心功能
81
+ email:
82
+ - wsp810@163.com
83
+ executables:
84
+ - pod-binary-pack
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - CHANGELOG.md
89
+ - LICENSE.txt
90
+ - README.md
91
+ - exe/pod-binary-pack
92
+ - lib/core/auto_build.rb
93
+ - lib/core/build_item.rb
94
+ - lib/core/cli.rb
95
+ - lib/core/commit.rb
96
+ - lib/core/config.rb
97
+ - lib/core/cost.rb
98
+ - lib/core/git_helper.rb
99
+ - lib/core/github_fork.rb
100
+ - lib/core/github_helper.rb
101
+ - lib/core/hook_manager.rb
102
+ - lib/core/hosting.rb
103
+ - lib/core/hosting/gitee_client.rb
104
+ - lib/core/hosting/gitee_provider.rb
105
+ - lib/core/hosting/gitlab_provider.rb
106
+ - lib/core/hosting/provider.rb
107
+ - lib/core/logger.rb
108
+ - lib/core/podspec.rb
109
+ - lib/core/push.rb
110
+ - lib/core/repo.rb
111
+ - lib/core/repo_cocoapods.rb
112
+ - lib/core/repo_module.rb
113
+ - lib/core/repo_module_binary.rb
114
+ - lib/core/repo_module_source.rb
115
+ - lib/core/repo_xcode.rb
116
+ - lib/core/repo_xcode_package.rb
117
+ - lib/core/repo_xcode_shell.rb
118
+ - lib/core/util/file_helper.rb
119
+ - lib/core/util/string.rb
120
+ - lib/pod/binary_pack.rb
121
+ - lib/pod/binary_pack/version.rb
122
+ homepage: https://rubygems.org/gems/pod-binary-pack
123
+ licenses:
124
+ - MIT
125
+ metadata:
126
+ documentation_uri: https://rubygems.org/gems/pod-binary-pack
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 3.2.0
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubygems_version: 3.6.9
142
+ specification_version: 4
143
+ summary: iOS双私有源组件打包
144
+ test_files: []