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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/aeshelper.rb +1 -0
  3. data/lib/pindo/base/executable.rb +2 -0
  4. data/lib/pindo/base/git_handler.rb +45 -7
  5. data/lib/pindo/base/informative.rb +11 -0
  6. data/lib/pindo/base/plistbuddyexecutable.rb +2 -0
  7. data/lib/pindo/client/feishuclient.rb +1 -1
  8. data/lib/pindo/client/httpclient.rb +88 -12
  9. data/lib/pindo/command/android/autobuild.rb +3 -7
  10. data/lib/pindo/command/appstore/autobuild.rb +8 -18
  11. data/lib/pindo/command/gplay/pullconfig.rb +3 -2
  12. data/lib/pindo/command/ios/autobuild.rb +3 -7
  13. data/lib/pindo/command/jps/bind.rb +284 -121
  14. data/lib/pindo/command/jps/media.rb +1 -15
  15. data/lib/pindo/command/unity/autobuild.rb +5 -14
  16. data/lib/pindo/command/unity/packbuild.rb +3 -8
  17. data/lib/pindo/command/utils/tag.rb +2 -7
  18. data/lib/pindo/command/utils/updateconfig.rb +3 -2
  19. data/lib/pindo/command/web/autobuild.rb +23 -33
  20. data/lib/pindo/command.rb +1 -8
  21. data/lib/pindo/config/ios_config_parser.rb +26 -25
  22. data/lib/pindo/module/android/android_build_helper.rb +1 -1
  23. data/lib/pindo/module/android/android_config_helper.rb +1 -1
  24. data/lib/pindo/module/android/android_res_helper.rb +1 -1
  25. data/lib/pindo/module/pgyer/pgyerhelper.rb +87 -0
  26. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +29 -15
  27. data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +2 -3
  28. data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +30 -16
  29. data/lib/pindo/module/task/model/git/git_commit_task.rb +68 -13
  30. data/lib/pindo/module/task/model/git/git_tag_task.rb +16 -7
  31. data/lib/pindo/module/task/model/jps/jps_bind_package_task.rb +217 -0
  32. data/lib/pindo/module/task/model/jps/jps_message_task.rb +3 -2
  33. data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +168 -49
  34. data/lib/pindo/module/task/model/jps/jps_workflow_message_task.rb +190 -0
  35. data/lib/pindo/module/task/model/unity/unity_config_task.rb +4 -0
  36. data/lib/pindo/module/task/pindo_task.rb +1 -0
  37. data/lib/pindo/module/xcode/xcode_app_config.rb +26 -16
  38. data/lib/pindo/module/xcode/xcode_build_config.rb +2 -2
  39. data/lib/pindo/module/xcode/xcode_swark_helper.rb +5 -5
  40. data/lib/pindo/version.rb +1 -1
  41. 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 = find_git_root(@upload_path)
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,获取最新的符合规范的 commit
98
+ # 2. 如果没有提供 git_commit_id,尝试从依赖任务获取或自动获取
99
99
  if @git_commit_id.nil? || @git_commit_id.empty?
100
- git_info = Pindo::GitHandler.get_latest_conventional_commit(project_dir: git_root)
101
- @git_commit_id = git_info[:commit_id]
102
- @git_commit_time = git_info[:commit_time]
103
- @git_commit_desc = git_info[:commit_desc]
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
- # 构建文件列表参数: -f file1.mp4,file2.png,file3.mov
350
- file_list = files.map { |f| "\"#{f}\"" }.join(',')
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
- # 调用压缩工具: compress-cli -s -f file1,file2,file3 -o output_dir/
353
- # -s: 静默模式
354
- # -f: 文件列表
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
- Funlog.instance.fancyinfo_start("正在压缩 #{files.size} 个文件...")
360
- output = `#{cmd} 2>&1`
361
- exit_code = $?.exitstatus
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
- if exit_code != 0
364
- Funlog.instance.fancyinfo_error("压缩失败")
365
- puts " 错误信息: #{output.strip}" if output && !output.strip.empty?
366
- raise "媒体文件批量压缩失败: #{output.strip}"
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
- Funlog.instance.fancyinfo_error("压缩失败:未找到压缩结果")
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
- Funlog.instance.fancyinfo_success("压缩完成:#{format_file_size(original_total_size)} #{format_file_size(compressed_total_size)}(减少 #{total_ratio}%)")
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