pindo 5.14.3 → 5.14.5
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/lib/pindo/base/aeshelper.rb +1 -0
- data/lib/pindo/base/executable.rb +2 -0
- data/lib/pindo/base/git_handler.rb +45 -7
- data/lib/pindo/base/informative.rb +11 -0
- data/lib/pindo/base/plistbuddyexecutable.rb +2 -0
- data/lib/pindo/client/feishuclient.rb +1 -1
- data/lib/pindo/client/httpclient.rb +88 -12
- data/lib/pindo/command/android/autobuild.rb +3 -7
- data/lib/pindo/command/appstore/autobuild.rb +8 -18
- data/lib/pindo/command/gplay/pullconfig.rb +3 -2
- data/lib/pindo/command/ios/autobuild.rb +3 -7
- data/lib/pindo/command/jps/bind.rb +284 -121
- data/lib/pindo/command/jps/media.rb +1 -15
- data/lib/pindo/command/unity/autobuild.rb +5 -14
- data/lib/pindo/command/unity/packbuild.rb +3 -8
- data/lib/pindo/command/utils/tag.rb +2 -7
- data/lib/pindo/command/utils/updateconfig.rb +3 -2
- data/lib/pindo/command/web/autobuild.rb +23 -33
- data/lib/pindo/command.rb +1 -8
- data/lib/pindo/config/ios_config_parser.rb +26 -25
- data/lib/pindo/module/android/android_build_helper.rb +1 -1
- data/lib/pindo/module/android/android_config_helper.rb +1 -1
- data/lib/pindo/module/android/android_res_helper.rb +1 -1
- data/lib/pindo/module/pgyer/pgyerhelper.rb +87 -0
- data/lib/pindo/module/task/model/build/android_build_dev_task.rb +29 -15
- data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +2 -3
- data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +30 -16
- data/lib/pindo/module/task/model/git/git_commit_task.rb +68 -13
- data/lib/pindo/module/task/model/git/git_tag_task.rb +16 -7
- data/lib/pindo/module/task/model/jps/jps_bind_package_task.rb +217 -0
- data/lib/pindo/module/task/model/jps/jps_message_task.rb +3 -2
- data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +168 -49
- data/lib/pindo/module/task/model/jps/jps_workflow_message_task.rb +190 -0
- data/lib/pindo/module/task/model/unity/unity_config_task.rb +4 -0
- data/lib/pindo/module/task/pindo_task.rb +1 -0
- data/lib/pindo/module/xcode/xcode_app_config.rb +26 -16
- data/lib/pindo/module/xcode/xcode_build_config.rb +2 -2
- data/lib/pindo/module/xcode/xcode_swark_helper.rb +5 -5
- data/lib/pindo/version.rb +1 -1
- metadata +13 -54
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
require 'pindo/module/task/model/jps_task'
|
|
2
|
+
require 'pindo/module/task/task_config'
|
|
3
|
+
require 'pindo/module/pgyer/pgyerhelper'
|
|
4
|
+
require 'pindo/base/git_handler'
|
|
5
|
+
|
|
6
|
+
module Pindo
|
|
7
|
+
module TaskSystem
|
|
8
|
+
# JPS 绑定包任务
|
|
9
|
+
# 将 Git commit 绑定到已上传的项目包(支持批量绑定)
|
|
10
|
+
#
|
|
11
|
+
# 支持两种模式:
|
|
12
|
+
# 1. 指定模式:传入 git_commit_id 和 app_version_list
|
|
13
|
+
# 2. 依赖模式:从依赖任务(GitCommitTask、JPSUploadTask)获取信息
|
|
14
|
+
class JPSBindPackageTask < JPSTask
|
|
15
|
+
attr_reader :git_commit_id, :git_commit_time, :git_commit_desc
|
|
16
|
+
attr_reader :app_version_list
|
|
17
|
+
|
|
18
|
+
# 任务键
|
|
19
|
+
def self.task_key
|
|
20
|
+
:jps_bind_package
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# 初始化绑定包任务
|
|
24
|
+
# @param app_version_list [Array<Hash>, nil] 应用版本信息列表(可选,如为 nil 则从依赖任务获取)
|
|
25
|
+
# @param options [Hash] 选项
|
|
26
|
+
# @option options [String] :git_commit_id Git commit SHA(可选,为空时从依赖任务获取)
|
|
27
|
+
# @option options [String] :git_commit_time Git commit 时间(可选)
|
|
28
|
+
# @option options [String] :git_commit_desc Git commit 描述(可选)
|
|
29
|
+
# @option options [String] :project_dir 项目目录(可选,用于自动获取 commit 信息)
|
|
30
|
+
# @option options [Hash] :app_info_obj JPS 应用信息对象(可选,继承自基类)
|
|
31
|
+
# @option options [Hash] :workflow_info 工作流信息(可选,继承自基类)
|
|
32
|
+
# @option options [String] :project_name 项目名称(可选,继承自基类)
|
|
33
|
+
def initialize(app_version_list = nil, options = {})
|
|
34
|
+
# 兼容性处理:如果传入的是单个 Hash,转为数组
|
|
35
|
+
if app_version_list.is_a?(Hash)
|
|
36
|
+
@app_version_list = [app_version_list]
|
|
37
|
+
elsif app_version_list.is_a?(Array)
|
|
38
|
+
@app_version_list = app_version_list
|
|
39
|
+
else
|
|
40
|
+
@app_version_list = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@git_commit_id = options[:git_commit_id]
|
|
44
|
+
@git_commit_time = options[:git_commit_time]
|
|
45
|
+
@git_commit_desc = options[:git_commit_desc]
|
|
46
|
+
@project_dir = options[:project_dir]
|
|
47
|
+
|
|
48
|
+
# 设置任务优先级为 LOW,确保在上传任务之后执行
|
|
49
|
+
options[:priority] ||= TaskPriority::LOW
|
|
50
|
+
|
|
51
|
+
super("绑定 Git Commit 到项目包", options)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def validate
|
|
55
|
+
# app_version_list 和 git_commit_id 可以延迟获取,不在这里验证
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# 绑定任务重试配置
|
|
60
|
+
def self.default_retry_mode
|
|
61
|
+
RetryMode::DELAYED
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.default_retry_count
|
|
65
|
+
2 # 绑定任务重试 2 次
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.default_retry_delay
|
|
69
|
+
3 # 延迟 3 秒
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
protected
|
|
73
|
+
|
|
74
|
+
# 构建任务参数(供其他任务使用)
|
|
75
|
+
def build_task_param
|
|
76
|
+
return {} unless @status == TaskStatus::SUCCESS && @result
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
git_commit_id: @git_commit_id,
|
|
80
|
+
app_version_list: @app_version_list,
|
|
81
|
+
bind_success: @result[:success],
|
|
82
|
+
bound_package_ids: @result[:bound_package_ids]
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def do_work
|
|
87
|
+
puts ""
|
|
88
|
+
puts " 📦 开始绑定 Git Commit 到项目包..."
|
|
89
|
+
|
|
90
|
+
# 1. 如果没有提供 app_version_list,从依赖任务获取
|
|
91
|
+
if @app_version_list.nil? || @app_version_list.empty?
|
|
92
|
+
fetch_app_version_from_dependencies
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# 验证 app_version_list
|
|
96
|
+
if @app_version_list.nil? || @app_version_list.empty?
|
|
97
|
+
raise "无法获取 app_version_list,请确保传入参数或添加 JPSUploadTask 依赖"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# 2. 如果没有提供 git_commit_id,从依赖任务获取或自动获取
|
|
101
|
+
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
102
|
+
fetch_git_commit_info
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# 验证 git_commit_id
|
|
106
|
+
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
107
|
+
raise "无法获取 git_commit_id,请确保传入参数或添加 GitCommitTask 依赖"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 3. 提取所有 project_package_ids
|
|
111
|
+
project_package_ids = @app_version_list.map { |pkg| pkg["id"] }.compact
|
|
112
|
+
if project_package_ids.empty?
|
|
113
|
+
raise "app_version_list 中的包都缺少 id 字段"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# 4. 打印绑定信息
|
|
117
|
+
puts ""
|
|
118
|
+
puts " 📝 绑定信息:"
|
|
119
|
+
puts " Git Commit: #{@git_commit_id[0..7]}"
|
|
120
|
+
puts " 包数量: #{project_package_ids.size} 个"
|
|
121
|
+
@app_version_list.each do |pkg|
|
|
122
|
+
package_type = pkg['nativePackageType'] || pkg['originalType'] || 'unknown'
|
|
123
|
+
puts " [#{package_type}] ID: #{pkg['id']}, Version: #{pkg['projectVersion']}, Build: #{pkg['build']}"
|
|
124
|
+
end
|
|
125
|
+
if @git_commit_desc
|
|
126
|
+
puts " Commit Desc: #{@git_commit_desc}"
|
|
127
|
+
end
|
|
128
|
+
if @git_commit_time
|
|
129
|
+
puts " Commit Time: #{@git_commit_time}"
|
|
130
|
+
end
|
|
131
|
+
puts ""
|
|
132
|
+
|
|
133
|
+
# 5. 确保 PgyerHelper 已登录
|
|
134
|
+
pgyer_helper = PgyerHelper.share_instace
|
|
135
|
+
unless pgyer_helper.login
|
|
136
|
+
raise "无法登录 JPS,请检查配置"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# 6. 批量绑定所有包
|
|
140
|
+
Funlog.instance.fancyinfo_start("正在绑定 #{project_package_ids.size} 个项目包...")
|
|
141
|
+
|
|
142
|
+
bind_result = pgyer_helper.bind_commit_to_package(
|
|
143
|
+
commit_id: @git_commit_id,
|
|
144
|
+
project_package_ids: project_package_ids
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if bind_result[:success]
|
|
148
|
+
Funlog.instance.fancyinfo_success("绑定成功!")
|
|
149
|
+
puts ""
|
|
150
|
+
|
|
151
|
+
{
|
|
152
|
+
success: true,
|
|
153
|
+
git_commit_id: @git_commit_id,
|
|
154
|
+
bound_package_ids: project_package_ids,
|
|
155
|
+
app_version_list: @app_version_list
|
|
156
|
+
}
|
|
157
|
+
else
|
|
158
|
+
if ENV['PINDO_DEBUG']
|
|
159
|
+
puts "[PINDO_DEBUG] bind_commit_to_package 返回结果: #{bind_result.inspect}"
|
|
160
|
+
puts "[PINDO_DEBUG] git_commit_id: #{@git_commit_id}"
|
|
161
|
+
puts "[PINDO_DEBUG] project_package_ids: #{project_package_ids.inspect}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
raise "绑定失败: #{bind_result[:error]}"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
# 从依赖任务获取 app_version_list
|
|
171
|
+
def fetch_app_version_from_dependencies
|
|
172
|
+
# 从 JPSUploadTask 获取数据
|
|
173
|
+
upload_data = get_data_param_by_key(:jps_upload)
|
|
174
|
+
|
|
175
|
+
if upload_data && upload_data[:task_param] && upload_data[:task_param][:app_version_info]
|
|
176
|
+
# 兼容单个版本信息,转为数组
|
|
177
|
+
@app_version_list = [upload_data[:task_param][:app_version_info]]
|
|
178
|
+
return
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# 兼容旧机制:从第一个依赖获取结果
|
|
182
|
+
unless @dependencies.empty?
|
|
183
|
+
upload_result = get_dependency_result(@dependencies.first)
|
|
184
|
+
|
|
185
|
+
if upload_result && upload_result[:app_version_info]
|
|
186
|
+
# 兼容单个版本信息,转为数组
|
|
187
|
+
@app_version_list = [upload_result[:app_version_info]]
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# 从依赖任务获取或自动获取 git commit 信息
|
|
193
|
+
def fetch_git_commit_info
|
|
194
|
+
# 1. 首先尝试从 GitCommitTask 依赖任务获取
|
|
195
|
+
git_commit_data = get_data_param_by_key(:git_commit)
|
|
196
|
+
if git_commit_data && git_commit_data[:task_param]
|
|
197
|
+
param = git_commit_data[:task_param]
|
|
198
|
+
@git_commit_id = param[:git_commit_id] if param[:git_commit_id]
|
|
199
|
+
@git_commit_time = param[:git_commit_time] if param[:git_commit_time]
|
|
200
|
+
@git_commit_desc = param[:git_commit_desc] if param[:git_commit_desc]
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# 2. 如果依赖任务没有提供,且指定了 project_dir,使用自动获取
|
|
204
|
+
if (@git_commit_id.nil? || @git_commit_id.empty?) && @project_dir
|
|
205
|
+
# 查找 git 仓库根目录
|
|
206
|
+
git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: @project_dir)
|
|
207
|
+
if git_root
|
|
208
|
+
git_info = Pindo::GitHandler.get_latest_conventional_commit(project_dir: git_root)
|
|
209
|
+
@git_commit_id = git_info[:commit_id]
|
|
210
|
+
@git_commit_time = git_info[:commit_time]
|
|
211
|
+
@git_commit_desc = git_info[:commit_desc]
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -86,7 +86,7 @@ module Pindo
|
|
|
86
86
|
rescue => e
|
|
87
87
|
# 外层错误保护:消息发送失败不应影响整体流程
|
|
88
88
|
puts " ⚠️ JPS 消息发送发生未预期错误: #{e.message}"
|
|
89
|
-
puts " ⚠️ 错误堆栈: #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
89
|
+
puts " ⚠️ 错误堆栈: #{e.backtrace.first(3).join("\n ")}" if ENV['PINDO_DEBUG'] && e.backtrace
|
|
90
90
|
puts " ℹ️ 消息发送失败不影响主流程\n"
|
|
91
91
|
|
|
92
92
|
# 消息发送失败不抛出异常,返回成功但带警告
|
|
@@ -105,7 +105,8 @@ module Pindo
|
|
|
105
105
|
# 从 dependencies 获取数据
|
|
106
106
|
upload_data = get_data_param_by_key(:jps_upload)
|
|
107
107
|
|
|
108
|
-
if upload_data && upload_data[:task_param]
|
|
108
|
+
if upload_data && upload_data[:task_param] &&
|
|
109
|
+
upload_data[:task_param][:app_version_info] && upload_data[:task_param][:app_info_obj]
|
|
109
110
|
param = upload_data[:task_param]
|
|
110
111
|
@app_version_info = param[:app_version_info] if @app_version_info.nil?
|
|
111
112
|
@app_info_obj = param[:app_info_obj] if @app_info_obj.nil?
|
|
@@ -90,17 +90,30 @@ module Pindo
|
|
|
90
90
|
|
|
91
91
|
def do_work
|
|
92
92
|
# 1. 查找 git 仓库根目录
|
|
93
|
-
git_root =
|
|
93
|
+
git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: @upload_path)
|
|
94
94
|
unless git_root
|
|
95
95
|
raise "未找到 git 仓库,请确保 upload_path 在 git 仓库内"
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
# 2. 如果没有提供 git_commit_id
|
|
98
|
+
# 2. 如果没有提供 git_commit_id,尝试从依赖任务获取或自动获取
|
|
99
99
|
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
# 2.1 首先尝试从 GitCommitTask 依赖任务获取
|
|
101
|
+
git_commit_data = get_data_param_by_key(:git_commit)
|
|
102
|
+
if git_commit_data && git_commit_data[:task_param]
|
|
103
|
+
param = git_commit_data[:task_param]
|
|
104
|
+
# 尝试从 task_param 获取 commit 信息
|
|
105
|
+
@git_commit_id = param[:git_commit_id] if param[:git_commit_id]
|
|
106
|
+
@git_commit_time = param[:git_commit_time] if param[:git_commit_time]
|
|
107
|
+
@git_commit_desc = param[:git_commit_desc] if param[:git_commit_desc]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 2.2 如果依赖任务没有提供,使用 get_latest_conventional_commit
|
|
111
|
+
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
112
|
+
git_info = Pindo::GitHandler.get_latest_conventional_commit(project_dir: git_root)
|
|
113
|
+
@git_commit_id = git_info[:commit_id]
|
|
114
|
+
@git_commit_time = git_info[:commit_time]
|
|
115
|
+
@git_commit_desc = git_info[:commit_desc]
|
|
116
|
+
end
|
|
104
117
|
end
|
|
105
118
|
|
|
106
119
|
# 验证 git_commit_id
|
|
@@ -110,8 +123,8 @@ module Pindo
|
|
|
110
123
|
|
|
111
124
|
# 3. 打印 git commit 信息
|
|
112
125
|
puts ""
|
|
113
|
-
puts " 📝 Commit: #{@git_commit_desc}" if @git_commit_desc
|
|
114
126
|
puts " ID: #{@git_commit_id[0..7]}"
|
|
127
|
+
puts " 📝 Commit: #{@git_commit_desc}" if @git_commit_desc
|
|
115
128
|
puts " Time: #{@git_commit_time}" if @git_commit_time
|
|
116
129
|
puts ""
|
|
117
130
|
|
|
@@ -192,20 +205,6 @@ module Pindo
|
|
|
192
205
|
|
|
193
206
|
private
|
|
194
207
|
|
|
195
|
-
# 查找 git 仓库根目录
|
|
196
|
-
# @param path [String] 起始路径
|
|
197
|
-
# @return [String, nil] git 仓库根目录路径,未找到返回 nil
|
|
198
|
-
def find_git_root(path)
|
|
199
|
-
current = File.expand_path(path)
|
|
200
|
-
while current != '/'
|
|
201
|
-
if File.exist?(File.join(current, '.git'))
|
|
202
|
-
return current
|
|
203
|
-
end
|
|
204
|
-
current = File.dirname(current)
|
|
205
|
-
end
|
|
206
|
-
nil
|
|
207
|
-
end
|
|
208
|
-
|
|
209
208
|
# 展开文件路径(支持通配符和目录)
|
|
210
209
|
# 自动过滤 3 小时以内的文件,超过 3 小时的文件归档
|
|
211
210
|
# @param paths [Array<String>] 原始路径列表
|
|
@@ -325,15 +324,6 @@ module Pindo
|
|
|
325
324
|
|
|
326
325
|
FileUtils.mkdir_p(compress_dir) unless Dir.exist?(compress_dir)
|
|
327
326
|
|
|
328
|
-
puts ""
|
|
329
|
-
puts " 📁 待压缩文件(共 #{files.size} 个)"
|
|
330
|
-
files.each_with_index do |file, index|
|
|
331
|
-
size_str = format_file_size(File.size(file))
|
|
332
|
-
file_name = File.basename(file)
|
|
333
|
-
puts " #{index + 1}. #{file_name} (#{size_str})"
|
|
334
|
-
end
|
|
335
|
-
puts ""
|
|
336
|
-
|
|
337
327
|
# MacCompressCliTool 路径
|
|
338
328
|
pindo_dir = File.expand_path(Pindoconfig.instance.pindo_dir)
|
|
339
329
|
compress_tool = File.join(pindo_dir, "pindo_common_config", "MacCompressCliTool")
|
|
@@ -346,40 +336,169 @@ module Pindo
|
|
|
346
336
|
# 计算原始文件总大小
|
|
347
337
|
original_total_size = files.sum { |f| File.size(f) }
|
|
348
338
|
|
|
349
|
-
#
|
|
350
|
-
|
|
339
|
+
# 是否开启调试模式
|
|
340
|
+
debug_mode = ENV['PINDO_DEBUG'] == '1'
|
|
341
|
+
|
|
342
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
343
|
+
# 📦 压缩准备
|
|
344
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
345
|
+
puts ""
|
|
346
|
+
puts " \e[1m📦 媒体文件压缩\e[0m"
|
|
347
|
+
puts " " + "─" * 60
|
|
348
|
+
puts ""
|
|
349
|
+
|
|
350
|
+
# 文件列表(对齐显示)
|
|
351
|
+
puts " 📁 \e[36m待压缩文件 (#{files.size} 个)\e[0m"
|
|
352
|
+
puts ""
|
|
353
|
+
files.each_with_index do |file, index|
|
|
354
|
+
size_str = format_file_size(File.size(file))
|
|
355
|
+
file_name = File.basename(file)
|
|
356
|
+
# 对齐:序号(3位) + 文件名(左对齐) + 大小(右对齐)
|
|
357
|
+
puts " \e[90m#{(index + 1).to_s.rjust(2)}.\e[0m %-40s \e[33m%8s\e[0m" % [file_name, size_str]
|
|
358
|
+
if debug_mode
|
|
359
|
+
puts " \e[90m路径: #{file}\e[0m"
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
puts ""
|
|
363
|
+
puts " \e[90m原始总大小: \e[33m#{format_file_size(original_total_size)}\e[0m"
|
|
364
|
+
puts ""
|
|
365
|
+
|
|
366
|
+
if debug_mode
|
|
367
|
+
puts " 🔧 \e[90m压缩工具: #{compress_tool}\e[0m"
|
|
368
|
+
puts " 📂 \e[90m输出目录: #{compress_dir}\e[0m"
|
|
369
|
+
puts ""
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
373
|
+
# 🔄 执行压缩
|
|
374
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
375
|
+
puts " " + "─" * 60
|
|
376
|
+
puts " 🔄 \e[36m正在压缩...\e[0m"
|
|
377
|
+
puts ""
|
|
378
|
+
|
|
379
|
+
# 逐个压缩文件(使用文件列表方式)
|
|
380
|
+
require 'shellwords'
|
|
381
|
+
|
|
382
|
+
compressed_files = []
|
|
383
|
+
failed_files = []
|
|
384
|
+
|
|
385
|
+
files.each_with_index do |file, index|
|
|
386
|
+
file_name = File.basename(file)
|
|
351
387
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
# -o: 输出目录
|
|
356
|
-
# 使用默认参数: 分辨率等级 3 (1280x720), 质量等级 3
|
|
357
|
-
cmd = "#{compress_tool} -s -f #{file_list} -o \"#{compress_dir}\""
|
|
388
|
+
# 显示进度(简洁模式)
|
|
389
|
+
progress = "#{index + 1}/#{files.size}"
|
|
390
|
+
print " [\e[33m#{progress.rjust(7)}\e[0m] #{file_name.ljust(40)} "
|
|
358
391
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
392
|
+
begin
|
|
393
|
+
# 创建临时文件列表(每个文件一个列表)
|
|
394
|
+
# MacCompressCliTool 的 -f 参数需要一个包含文件路径列表的文本文件
|
|
395
|
+
file_list_path = File.join(compress_dir, "file_list_#{index}.txt")
|
|
396
|
+
File.open(file_list_path, 'w:UTF-8') do |f|
|
|
397
|
+
f.puts(file)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# 调用压缩工具: compress-cli -s -f file_list.txt -o output_dir/
|
|
401
|
+
# -s: 静默模式
|
|
402
|
+
# -f: 文件列表文件路径
|
|
403
|
+
# -o: 输出目录
|
|
404
|
+
cmd = "#{Shellwords.escape(compress_tool)} -s -f #{Shellwords.escape(file_list_path)} -o #{Shellwords.escape(compress_dir)}"
|
|
405
|
+
|
|
406
|
+
if debug_mode
|
|
407
|
+
puts ""
|
|
408
|
+
puts " \e[90m完整路径: #{file}\e[0m"
|
|
409
|
+
puts " \e[90m文件列表: #{file_list_path}\e[0m"
|
|
410
|
+
puts " \e[90m执行命令: #{cmd}\e[0m"
|
|
411
|
+
print " "
|
|
412
|
+
end
|
|
362
413
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
414
|
+
output = `#{cmd} 2>&1`
|
|
415
|
+
exit_code = $?.exitstatus
|
|
416
|
+
|
|
417
|
+
# 清理临时文件列表
|
|
418
|
+
FileUtils.rm_f(file_list_path) if File.exist?(file_list_path)
|
|
419
|
+
|
|
420
|
+
if exit_code == 0
|
|
421
|
+
puts "\e[32m✓\e[0m"
|
|
422
|
+
else
|
|
423
|
+
puts "\e[31m✗\e[0m"
|
|
424
|
+
if debug_mode || output.strip.length < 100
|
|
425
|
+
puts " \e[31m失败原因: #{output.strip}\e[0m" unless output.strip.empty?
|
|
426
|
+
end
|
|
427
|
+
failed_files << file
|
|
428
|
+
end
|
|
429
|
+
rescue => e
|
|
430
|
+
puts "\e[31m✗\e[0m"
|
|
431
|
+
puts " \e[31m异常: #{e.message}\e[0m"
|
|
432
|
+
if debug_mode && e.backtrace
|
|
433
|
+
puts " \e[90m堆栈: #{e.backtrace.first(3).join("\n ")}\e[0m"
|
|
434
|
+
end
|
|
435
|
+
failed_files << file
|
|
436
|
+
end
|
|
367
437
|
end
|
|
368
438
|
|
|
369
439
|
# 从临时目录获取所有压缩后的媒体文件
|
|
370
440
|
compressed_files = get_media_files_from_dir(compress_dir)
|
|
371
441
|
|
|
442
|
+
puts ""
|
|
443
|
+
|
|
444
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
445
|
+
# ✅ 压缩结果
|
|
446
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
447
|
+
|
|
372
448
|
if compressed_files.empty?
|
|
373
|
-
|
|
449
|
+
puts " " + "─" * 60
|
|
450
|
+
puts " \e[31m✗ 压缩失败\e[0m"
|
|
451
|
+
puts ""
|
|
452
|
+
|
|
453
|
+
# 列出输出目录中的所有文件(调试用)
|
|
454
|
+
if debug_mode
|
|
455
|
+
puts " 🔍 输出目录内容:"
|
|
456
|
+
if Dir.exist?(compress_dir)
|
|
457
|
+
all_files = Dir.glob(File.join(compress_dir, "*"))
|
|
458
|
+
if all_files.empty?
|
|
459
|
+
puts " \e[90m(目录为空)\e[0m"
|
|
460
|
+
else
|
|
461
|
+
all_files.each { |f| puts " \e[90m- #{File.basename(f)}\e[0m" }
|
|
462
|
+
end
|
|
463
|
+
else
|
|
464
|
+
puts " \e[90m(目录不存在)\e[0m"
|
|
465
|
+
end
|
|
466
|
+
puts ""
|
|
467
|
+
end
|
|
468
|
+
|
|
374
469
|
raise "压缩失败:未在输出目录中找到压缩结果"
|
|
375
470
|
end
|
|
376
471
|
|
|
377
|
-
#
|
|
472
|
+
# 计算压缩后总大小和压缩率
|
|
378
473
|
compressed_total_size = compressed_files.sum { |f| File.size(f) }
|
|
379
474
|
total_ratio = ((1 - compressed_total_size.to_f / original_total_size) * 100).round(1)
|
|
475
|
+
success_count = files.size - failed_files.size
|
|
380
476
|
|
|
381
|
-
#
|
|
382
|
-
|
|
477
|
+
# 生成压缩率可视化进度条(20 个字符宽度)
|
|
478
|
+
bar_width = 20
|
|
479
|
+
filled_width = [(total_ratio / 5.0).round, bar_width].min # 每 5% 填充一格
|
|
480
|
+
bar_filled = "█" * filled_width
|
|
481
|
+
bar_empty = "░" * (bar_width - filled_width)
|
|
482
|
+
ratio_bar = "\e[32m#{bar_filled}\e[90m#{bar_empty}\e[0m"
|
|
483
|
+
|
|
484
|
+
puts " " + "─" * 60
|
|
485
|
+
puts " \e[32m✓ 压缩完成\e[0m"
|
|
486
|
+
puts ""
|
|
487
|
+
puts " 成功数量: \e[32m#{success_count}\e[0m / #{files.size}"
|
|
488
|
+
puts " 原始大小: \e[33m#{format_file_size(original_total_size)}\e[0m"
|
|
489
|
+
puts " 压缩后: \e[32m#{format_file_size(compressed_total_size)}\e[0m"
|
|
490
|
+
puts " 压缩率: #{ratio_bar} \e[1m#{total_ratio}%\e[0m"
|
|
491
|
+
|
|
492
|
+
if failed_files.any?
|
|
493
|
+
puts ""
|
|
494
|
+
puts " \e[31m失败文件 (#{failed_files.size}):\e[0m"
|
|
495
|
+
failed_files.each do |f|
|
|
496
|
+
puts " \e[31m✗\e[0m #{File.basename(f)}"
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
puts ""
|
|
501
|
+
puts " " + "─" * 60
|
|
383
502
|
puts ""
|
|
384
503
|
|
|
385
504
|
compressed_files
|