pindo 5.11.1 → 5.11.3

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,494 @@
1
+ require 'singleton'
2
+ require 'thread'
3
+
4
+ module Pindo
5
+ module TaskSystem
6
+ class TaskManager
7
+ include Singleton
8
+
9
+ def initialize
10
+ @pending_queue = [] # 待执行队列
11
+ @triggered_queue = [] # 已触发队列
12
+ @running_tasks = [] # 正在运行的任务
13
+ @completed_tasks = [] # 已完成的任务
14
+ @task_locks = {
15
+ exclusive: Mutex.new,
16
+ type_locks: {}
17
+ }
18
+ @queue_mutex = Mutex.new
19
+ @queue_condition = ConditionVariable.new # 用于等待/通知机制
20
+ @running = false
21
+ end
22
+
23
+ # 添加任务
24
+ def add_task(task, options = {})
25
+ raise ArgumentError, "Task must be a PindoTask" unless task.is_a?(PindoTask)
26
+
27
+ # 验证任务
28
+ unless task.validate
29
+ raise ArgumentError, "Task validation failed: #{task.name}"
30
+ end
31
+
32
+ # 处理依赖
33
+ if options[:wait_for]
34
+ task.dependencies.concat(Array(options[:wait_for]))
35
+ end
36
+
37
+ @queue_mutex.synchronize do
38
+ @pending_queue << task
39
+ # 按优先级排序
40
+ @pending_queue.sort_by! { |t| -t.priority }
41
+ # 通知等待的线程有新任务
42
+ @queue_condition.signal
43
+ end
44
+
45
+ task.id
46
+ end
47
+
48
+ # 批量添加任务
49
+ def add_tasks(tasks)
50
+ tasks.map { |task| add_task(task) }
51
+ end
52
+
53
+ # 开始执行(主线程循环)
54
+ def start
55
+ return if @running
56
+ @running = true
57
+
58
+ puts "\n[TaskManager] 开始执行任务调度...".cyan if defined?(String.cyan)
59
+
60
+ # 主线程循环:负责触发任务
61
+ while @running
62
+ task = nil
63
+
64
+ @queue_mutex.synchronize do
65
+ # 等待直到有可执行的任务或应该停止
66
+ while @running && !should_stop_locked?
67
+ task = get_next_executable_task_locked
68
+ if task
69
+ break
70
+ else
71
+ # 没有可执行的任务,等待通知
72
+ # 设置超时避免死锁,同时定期检查依赖状态
73
+ @queue_condition.wait(@queue_mutex, 1.0)
74
+
75
+ # 检查是否有因依赖失败需要级联处理的任务
76
+ check_and_cascade_failures_locked
77
+ end
78
+ end
79
+
80
+ # 如果应该停止且没有任务,退出循环
81
+ break if should_stop_locked? && task.nil?
82
+ end
83
+
84
+ # 在锁外触发任务
85
+ if task
86
+ trigger_task(task)
87
+ end
88
+
89
+ # 清理已完成的异步任务
90
+ cleanup_finished_tasks
91
+ end
92
+
93
+ # 等待所有触发的任务完成
94
+ wait_all_triggered_tasks
95
+
96
+ puts "\n[TaskManager] 所有任务执行完毕".green if defined?(String.green)
97
+ @running = false
98
+ end
99
+
100
+ # 停止执行
101
+ def stop
102
+ @running = false
103
+ end
104
+
105
+ # 等待所有任务完成
106
+ def wait_all
107
+ while @pending_queue.any? || @running_tasks.any?
108
+ sleep(0.1)
109
+ end
110
+ end
111
+
112
+ # 获取任务状态
113
+ def task_status(task_id)
114
+ task = find_task(task_id)
115
+ task&.status
116
+ end
117
+
118
+ # 取消任务
119
+ def cancel_task(task_id)
120
+ task = find_task(task_id)
121
+ task&.cancel
122
+ end
123
+
124
+ # 获取执行报告
125
+ def execution_report
126
+ @queue_mutex.synchronize do
127
+ {
128
+ pending: @pending_queue.count,
129
+ triggered: @triggered_queue.count,
130
+ running: @running_tasks.count,
131
+ completed: @completed_tasks.count,
132
+ success: @completed_tasks.count { |t| t.status == TaskStatus::SUCCESS },
133
+ failed: @completed_tasks.count { |t| t.status == TaskStatus::FAILED },
134
+ tasks: (@pending_queue + @triggered_queue + @running_tasks + @completed_tasks).map do |task|
135
+ {
136
+ id: task.id,
137
+ name: task.name,
138
+ type: task.type,
139
+ status: task.status,
140
+ execution_type: task.execution_type,
141
+ execution_mode: task.execution_mode,
142
+ error: task.error&.message,
143
+ progress: task.progress,
144
+ execution_time: task.execution_time
145
+ }
146
+ end
147
+ }
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ # 获取下一个可执行的任务(需要在锁内调用)
154
+ def get_next_executable_task_locked
155
+ task = @pending_queue.find do |t|
156
+ can_execute?(t)
157
+ end
158
+
159
+ if task
160
+ @pending_queue.delete(task)
161
+ task
162
+ end
163
+ end
164
+
165
+ # 获取下一个可执行的任务(带锁版本,向后兼容)
166
+ def get_next_executable_task
167
+ @queue_mutex.synchronize do
168
+ get_next_executable_task_locked
169
+ end
170
+ end
171
+
172
+ # 检查并级联处理失败的依赖(需要在锁内调用)
173
+ def check_and_cascade_failures_locked
174
+ @pending_queue.each do |task|
175
+ dependency_check = check_dependencies(task)
176
+ if dependency_check == :failed || dependency_check == :cancelled
177
+ cascade_failure_locked(task, dependency_check)
178
+ end
179
+ end
180
+ end
181
+
182
+ # 级联失败处理(锁内版本)
183
+ def cascade_failure_locked(task, reason)
184
+ case reason
185
+ when :failed
186
+ task.status = TaskStatus::FAILED
187
+ task.error = RuntimeError.new("依赖任务失败")
188
+ if defined?(String.red)
189
+ puts "[TaskManager] 任务 #{task.name} 因依赖失败而被标记为失败".red
190
+ else
191
+ puts "[TaskManager] 任务 #{task.name} 因依赖失败而被标记为失败"
192
+ end
193
+ when :cancelled
194
+ task.status = TaskStatus::CANCELLED
195
+ task.error = RuntimeError.new("依赖任务被取消")
196
+ if defined?(String.yellow)
197
+ puts "[TaskManager] 任务 #{task.name} 因依赖取消而被取消".yellow
198
+ else
199
+ puts "[TaskManager] 任务 #{task.name} 因依赖取消而被取消"
200
+ end
201
+ end
202
+
203
+ # 将任务移到完成队列
204
+ @pending_queue.delete(task)
205
+ @completed_tasks << task
206
+
207
+ # 通知可能有新的可执行任务
208
+ @queue_condition.signal
209
+ end
210
+
211
+ # 判断任务是否可以执行
212
+ def can_execute?(task)
213
+ # 1. 检查依赖状态
214
+ dependency_check = check_dependencies(task)
215
+
216
+ # 如果依赖检查返回 :failed 或 :cancelled,级联处理
217
+ if dependency_check == :failed || dependency_check == :cancelled
218
+ cascade_failure(task, dependency_check)
219
+ return false
220
+ elsif dependency_check == :waiting
221
+ return false # 依赖未完成,继续等待
222
+ end
223
+
224
+ # 2. 根据执行模式检查并发限制
225
+ case task.execution_mode
226
+ when ExecutionMode::EXCLUSIVE
227
+ # 独占模式:没有其他任务在运行
228
+ @running_tasks.empty?
229
+ when ExecutionMode::TYPE_EXCLUSIVE
230
+ # 类型独占:没有相同类型的任务在运行
231
+ !@running_tasks.any? { |t| t.type == task.type }
232
+ when ExecutionMode::CONCURRENT
233
+ # 并发模式:可以执行
234
+ true
235
+ else
236
+ true
237
+ end
238
+ end
239
+
240
+ # 检查依赖状态
241
+ def check_dependencies(task)
242
+ return :ready if task.dependencies.empty?
243
+
244
+ task.dependencies.each do |dep_id|
245
+ dep_task = find_task(dep_id)
246
+
247
+ # 依赖任务不存在
248
+ return :failed unless dep_task
249
+
250
+ # 检查依赖任务状态
251
+ case dep_task.status
252
+ when TaskStatus::SUCCESS
253
+ next # 这个依赖已完成
254
+ when TaskStatus::FAILED
255
+ return :failed # 依赖失败
256
+ when TaskStatus::CANCELLED
257
+ return :cancelled # 依赖被取消
258
+ else
259
+ return :waiting # 依赖未完成
260
+ end
261
+ end
262
+
263
+ :ready # 所有依赖都成功完成
264
+ end
265
+
266
+ # 级联失败处理
267
+ def cascade_failure(task, reason)
268
+ @queue_mutex.synchronize do
269
+ case reason
270
+ when :failed
271
+ task.status = TaskStatus::FAILED
272
+ task.error = RuntimeError.new("依赖任务失败")
273
+ if defined?(String.red)
274
+ puts "[TaskManager] 任务 #{task.name} 因依赖失败而被标记为失败".red
275
+ else
276
+ puts "[TaskManager] 任务 #{task.name} 因依赖失败而被标记为失败"
277
+ end
278
+ when :cancelled
279
+ task.status = TaskStatus::CANCELLED
280
+ task.error = RuntimeError.new("依赖任务被取消")
281
+ if defined?(String.yellow)
282
+ puts "[TaskManager] 任务 #{task.name} 因依赖取消而被取消".yellow
283
+ else
284
+ puts "[TaskManager] 任务 #{task.name} 因依赖取消而被取消"
285
+ end
286
+ end
287
+
288
+ # 将任务移到完成队列
289
+ @pending_queue.delete(task)
290
+ @completed_tasks << task
291
+ end
292
+ end
293
+
294
+ # 触发任务执行
295
+ def trigger_task(task)
296
+ # 获取任务锁
297
+ lock_acquired = acquire_lock(task)
298
+
299
+ unless lock_acquired
300
+ # 无法获取锁,任务返回队列
301
+ @queue_mutex.synchronize do
302
+ @pending_queue.unshift(task) # 放回队列前面
303
+ @queue_condition.signal
304
+ end
305
+ return
306
+ end
307
+
308
+ @queue_mutex.synchronize do
309
+ task.status = TaskStatus::TRIGGERED
310
+ @triggered_queue << task
311
+ @running_tasks << task
312
+ end
313
+
314
+ # 显示触发信息
315
+ execution_type_str = task.execution_type == ExecutionType::SYNC ? "同步" : "异步"
316
+ if defined?(String.blue)
317
+ puts "\n[#{Time.now.strftime('%H:%M:%S')}] 触发任务: #{task.name} (#{execution_type_str})".blue
318
+ else
319
+ puts "\n[#{Time.now.strftime('%H:%M:%S')}] 触发任务: #{task.name} (#{execution_type_str})"
320
+ end
321
+ puts " 类型: #{task.type}, 模式: #{task.execution_mode}"
322
+
323
+ # 设置任务完成回调
324
+ task.on(:after) do |t|
325
+ on_task_finished(t)
326
+ end
327
+
328
+ # 设置进度回调
329
+ task.on(:on_progress) do |t|
330
+ if defined?(String.cyan)
331
+ puts " [#{t.progress}%] #{t.progress_message}".cyan if t.progress_message
332
+ else
333
+ puts " [#{t.progress}%] #{t.progress_message}" if t.progress_message
334
+ end
335
+ end
336
+
337
+ # 根据执行类型触发任务
338
+ case task.execution_type
339
+ when ExecutionType::SYNC
340
+ # 同步执行:在当前线程(主线程)执行
341
+ if defined?(String.yellow)
342
+ puts " → 在主线程中同步执行".yellow
343
+ else
344
+ puts " → 在主线程中同步执行"
345
+ end
346
+ task.do_task
347
+ when ExecutionType::ASYNC
348
+ # 异步执行:在新线程执行
349
+ if defined?(String.yellow)
350
+ puts " → 在新线程中异步执行".yellow
351
+ else
352
+ puts " → 在新线程中异步执行"
353
+ end
354
+ task.async_do_task
355
+ else
356
+ # 默认异步
357
+ task.async_do_task
358
+ end
359
+ end
360
+
361
+ # 任务完成回调
362
+ def on_task_finished(task)
363
+ @queue_mutex.synchronize do
364
+ @running_tasks.delete(task)
365
+ @triggered_queue.delete(task)
366
+ @completed_tasks << task
367
+
368
+ # 释放任务锁
369
+ release_lock(task)
370
+
371
+ # 通知等待的线程,可能有新的任务可以执行
372
+ @queue_condition.signal
373
+ end
374
+
375
+ # 显示完成信息
376
+ if task.status == TaskStatus::SUCCESS
377
+ time_str = task.execution_time ? " (#{task.execution_time.round(2)}s)" : ""
378
+ if defined?(String.green)
379
+ puts "[#{Time.now.strftime('%H:%M:%S')}] ✅ 完成: #{task.name}#{time_str}".green
380
+ else
381
+ puts "[#{Time.now.strftime('%H:%M:%S')}] ✅ 完成: #{task.name}#{time_str}"
382
+ end
383
+ elsif task.status == TaskStatus::FAILED
384
+ if defined?(String.red)
385
+ puts "[#{Time.now.strftime('%H:%M:%S')}] ❌ 失败: #{task.name}".red
386
+ puts " 错误: #{task.error.message}".red if task.error
387
+ else
388
+ puts "[#{Time.now.strftime('%H:%M:%S')}] ❌ 失败: #{task.name}"
389
+ puts " 错误: #{task.error.message}" if task.error
390
+ end
391
+ end
392
+ end
393
+
394
+ # 清理已完成的异步任务
395
+ def cleanup_finished_tasks
396
+ @queue_mutex.synchronize do
397
+ @running_tasks.select(&:finished?).each do |task|
398
+ # 任务已经通过回调处理,这里只是确保清理
399
+ unless @completed_tasks.include?(task)
400
+ on_task_finished(task)
401
+ end
402
+ end
403
+ end
404
+ end
405
+
406
+ # 判断是否应该停止(需要在锁内调用)
407
+ def should_stop_locked?
408
+ @pending_queue.empty? && @running_tasks.empty?
409
+ end
410
+
411
+ # 判断是否应该停止(带锁版本)
412
+ def should_stop?
413
+ @queue_mutex.synchronize do
414
+ should_stop_locked?
415
+ end
416
+ end
417
+
418
+ # 等待所有已触发的任务完成
419
+ def wait_all_triggered_tasks
420
+ if defined?(String.yellow)
421
+ puts "\n等待所有异步任务完成...".yellow
422
+ else
423
+ puts "\n等待所有异步任务完成..."
424
+ end
425
+
426
+ while true
427
+ @queue_mutex.synchronize do
428
+ break if @triggered_queue.empty? && @running_tasks.empty?
429
+ end
430
+ sleep(0.1)
431
+ end
432
+ end
433
+
434
+ # 查找任务
435
+ def find_task(task_id)
436
+ all_tasks = []
437
+ @queue_mutex.synchronize do
438
+ all_tasks = @pending_queue + @triggered_queue + @running_tasks + @completed_tasks
439
+ end
440
+ all_tasks.find { |t| t.id == task_id }
441
+ end
442
+
443
+ # 获取类型锁
444
+ def type_lock(type)
445
+ @task_locks[:type_locks][type] ||= Mutex.new
446
+ end
447
+
448
+ # 获取任务锁
449
+ def acquire_lock(task)
450
+ case task.execution_mode
451
+ when ExecutionMode::EXCLUSIVE
452
+ # 独占模式:尝试获取全局锁
453
+ @task_locks[:exclusive].try_lock
454
+ when ExecutionMode::TYPE_EXCLUSIVE
455
+ # 类型独占:尝试获取类型锁
456
+ type_lock(task.type).try_lock
457
+ when ExecutionMode::CONCURRENT
458
+ # 并发模式:不需要锁
459
+ true
460
+ else
461
+ true
462
+ end
463
+ end
464
+
465
+ # 释放任务锁
466
+ def release_lock(task)
467
+ case task.execution_mode
468
+ when ExecutionMode::EXCLUSIVE
469
+ # 释放全局锁
470
+ @task_locks[:exclusive].unlock rescue nil
471
+ when ExecutionMode::TYPE_EXCLUSIVE
472
+ # 释放类型锁
473
+ type_lock(task.type).unlock rescue nil
474
+ end
475
+ end
476
+
477
+ # 清空所有队列(用于重置)
478
+ def clear_all
479
+ @queue_mutex.synchronize do
480
+ @pending_queue.clear
481
+ @triggered_queue.clear
482
+ @running_tasks.clear
483
+ @completed_tasks.clear
484
+
485
+ # 释放所有锁
486
+ @task_locks[:exclusive].unlock rescue nil
487
+ @task_locks[:type_locks].each_value do |lock|
488
+ lock.unlock rescue nil
489
+ end
490
+ end
491
+ end
492
+ end
493
+ end
494
+ end
@@ -308,7 +308,7 @@ module Pindo
308
308
  # 检查是否有构建错误的关键词
309
309
  if stdout_buffer.match?(/Build completed with a result of 'Failed'|Build completed with a result of 'Cancelled'|BuildPlayerWindow\+BuildMethod\+Invoke|error|Error|ERROR|exception|Exception|EXCEPTION|failed|Failed|FAILED/)
310
310
  build_success = false
311
- puts "\n\e[31m检测到构建错误信息,构建可能失败\e[0m"
311
+ # puts "\n\e[31m检测到构建错误信息,构建可能失败\e[0m"
312
312
  end
313
313
 
314
314
  if build_success
@@ -442,51 +442,27 @@ module Pindo
442
442
  puts result[:stdout]
443
443
  end
444
444
  else
445
- puts "Unity build failed"
446
- puts "Unity version: #{result[:unity_version]}"
447
- puts "Exit status: #{result[:exit_status]}"
448
-
449
- if !result[:stdout].empty?
450
- puts "Unity标准输出:"
451
- puts result[:stdout]
452
- end
453
-
454
- if !result[:stderr].empty?
455
- puts "Unity错误输出:"
456
- puts result[:stderr]
457
- else
458
- puts "Unity没有输出错误信息"
459
- end
460
-
461
- # 提供更详细的错误信息
462
- error_msg = "Unity构建失败 (退出码: #{result[:exit_status]})"
445
+ # 简单输出失败信息,不显示详细调试信息
446
+ puts "Unity构建失败! "
447
+
448
+ # 构造简洁的错误信息
463
449
 
464
- # 检查是否是Unity实例冲突错误
465
- if !result[:stdout].empty? && result[:stdout].include?("Multiple Unity instances cannot open the same project")
466
- error_msg = "Unity实例冲突错误:\n"
467
- error_msg += "检测到另一个Unity实例正在运行并打开了同一个项目。\n"
468
- error_msg += "请关闭所有Unity实例后重试。\n"
469
- error_msg += "可以使用以下命令检查Unity进程:\n"
470
- error_msg += " ps aux | grep -i unity\n"
471
- error_msg += "然后使用以下命令关闭Unity进程:\n"
472
- error_msg += " kill <进程ID>"
473
- # 检查是否是Android SDK下载问题
474
- elsif !result[:stdout].empty? && (result[:stdout].include?("Failed to download package") || result[:stdout].include?("Install Android SDK Platform"))
475
- error_msg = "Android SDK下载问题:\n"
476
- error_msg += "Unity在下载Android SDK组件时遇到网络问题。\n"
477
- error_msg += "解决方案:\n"
478
- error_msg += "1. 检查网络连接\n"
479
- error_msg += "2. 使用VPN或代理\n"
480
- error_msg += "3. 在Unity Editor中手动配置Android SDK路径\n"
481
- error_msg += "4. 清理Unity缓存: rm -rf Library/BuildCache\n"
482
- error_msg += "5. 重新运行构建命令"
483
- elsif !result[:stderr].empty?
484
- error_msg += "\n错误详情: #{result[:stderr].lines.first.strip}"
485
- elsif !result[:stdout].empty?
486
- error_msg += "\nUnity输出: #{result[:stdout].lines.first.strip}"
487
- end
450
+ # # 检查特定错误类型,提供简洁的错误信息
451
+ # if !result[:stdout].empty? && result[:stdout].include?("Multiple Unity instances cannot open the same project")
452
+ # error_msg = "Unity实例冲突:另一个Unity正在使用此项目,请关闭所有Unity实例后重试"
453
+ # elsif !result[:stdout].empty? && (result[:stdout].include?("Failed to download package") || result[:stdout].include?("Install Android SDK Platform"))
454
+ # error_msg = "Android SDK下载失败:请检查网络连接或手动配置SDK路径"
455
+ # elsif !result[:stderr].empty?
456
+ # # 只取第一行错误信息
457
+ # first_error = result[:stderr].lines.first.strip
458
+ # error_msg = "Unity构建失败: #{first_error}"
459
+ # elsif !result[:stdout].empty?
460
+ # # 只取第一行输出信息,不添加"Unity输出:"前缀
461
+ # first_output = result[:stdout].lines.first.strip
462
+ # error_msg = "Unity构建失败: #{first_output}"
463
+ # end
488
464
 
489
- raise error_msg
465
+ raise Informative, "GoodUnityBuild 导出时候失败!请确保GoodUnityBuild 能正常导出!!!"
490
466
  end
491
467
 
492
468
  result
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.11.1"
9
+ VERSION = "5.11.3"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pindo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.11.1
4
+ version: 5.11.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -414,8 +414,8 @@ files:
414
414
  - lib/pindo/command/web/run.rb
415
415
  - lib/pindo/config/pindoconfig.rb
416
416
  - lib/pindo/config/pindouserlocalconfig.rb
417
- - lib/pindo/module/android/android_build_config_helper.rb
418
417
  - lib/pindo/module/android/android_build_helper.rb
418
+ - lib/pindo/module/android/android_config_helper.rb
419
419
  - lib/pindo/module/android/android_project_helper.rb
420
420
  - lib/pindo/module/android/android_res_helper.rb
421
421
  - lib/pindo/module/android/gp_compliance_helper.rb
@@ -437,6 +437,12 @@ files:
437
437
  - lib/pindo/module/cert/provisioning_helper.rb
438
438
  - lib/pindo/module/cert/xcodecerthelper.rb
439
439
  - lib/pindo/module/pgyer/pgyerhelper.rb
440
+ - lib/pindo/module/task/model/build_task.rb
441
+ - lib/pindo/module/task/model/unity_export_task.rb
442
+ - lib/pindo/module/task/model/upload_task.rb
443
+ - lib/pindo/module/task/pindo_task.rb
444
+ - lib/pindo/module/task/task_config.rb
445
+ - lib/pindo/module/task/task_manager.rb
440
446
  - lib/pindo/module/unity/nuget_helper.rb
441
447
  - lib/pindo/module/unity/unity_helper.rb
442
448
  - lib/pindo/module/webserver/brotli_file_handler.rb