pindo 5.12.2 → 5.13.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6095e9d8ae3f34ca9e43e111344d3769c62e4d23b929ed2f8dcbab2288296107
4
- data.tar.gz: 9c45c852836d6c9549d1625866fbee560dd38abb1b793401b80ff3c103e2f5a8
3
+ metadata.gz: ce0a5c40dcd8dbdcef15ad36aebc63fa189108aa38e05923e81662830a4a2996
4
+ data.tar.gz: c05cd7079948fa242597eceaccb3cab522035fad0a63b53a3e9a0af6296309f9
5
5
  SHA512:
6
- metadata.gz: 74666b706663478292b86f5caacd7c17846507ce8aef44b8b7481c73d84f89f9a766c425939c2b5954dc536b480e150d3fff174325683f2b44e5b5d067e8477d
7
- data.tar.gz: ca31fa0a538fac32db28d7e657a04b0eb3c3304880e3dbb219c1787c26e4bf6f264e4b2e3181acb84378fdb48f4250a13bc6f719c3e30546ab848e271d090058
6
+ metadata.gz: f7f88c219338108d5107f7b3436763a93186e91bebc5b27d608f9ae1f2e7d01185ea0727aa1162357ae07fd8aae682d883b3c57a676e328d096b04ce7bebbb08
7
+ data.tar.gz: 22cc175b1716238b98613116c9103d4b2324e3e3394f2f965a8d76c99144e3c197793ccdfefa733aea0d3e516340582b938a3b3ea533e150baa9a18d3406049a
@@ -1,7 +1,6 @@
1
1
 
2
2
  require 'pindo/command/android/autobuild'
3
3
  require 'pindo/command/android/autoresign'
4
- require 'pindo/command/android/build'
5
4
  require 'pindo/command/android/keystore'
6
5
 
7
6
 
@@ -104,7 +104,7 @@ module Pindo
104
104
  when :android
105
105
  puts "Android工程, 请使用 pindo and autobuild"
106
106
  when :unity
107
- raise Informative, "Unity工程, 请使用 pindo unity ipa 或者pindo unity apk"
107
+ raise Informative, "Unity工程, 请使用 pindo unity autobuild --types=ipa,apk"
108
108
  else
109
109
  raise Informative, "当前目录不是工程目录,不能编译"
110
110
  end
@@ -82,7 +82,7 @@ module Pindo
82
82
  puts "Android 工程, 请使用 pindo and build"
83
83
  Pindo::Command::Android::Build::run(args_temp)
84
84
  when :unity
85
- raise Informative, "Unity 工程, 请使用 pindo unity ipa 或者pindo unity apk"
85
+ raise Informative, "Unity 工程, 请使用 pindo unity autobuild --types=ipa,apk"
86
86
  else
87
87
  raise Informative, "当前目录不是工程目录,不能编译"
88
88
  end
@@ -91,7 +91,7 @@ module Pindo
91
91
  when :android
92
92
  raise Informative, "Android 工程, 请使用 pindo and build"
93
93
  when :unity
94
- raise Informative, "Unity 工程, 请使用 pindo unity ipa"
94
+ raise Informative, "Unity 工程, 请使用 pindo unity autobuild --types=ipa"
95
95
  else
96
96
  raise Informative, "当前目录不是工程目录,不能编译"
97
97
  end
@@ -97,6 +97,9 @@ module Pindo
97
97
  puts "⚠ Keystore 签名配置跳过(使用工程原有配置)"
98
98
  end
99
99
 
100
+ # 处理 Play Asset Delivery 配置(如果存在)
101
+ setup_play_asset_delivery(project_dir)
102
+
100
103
  # 构建 APK
101
104
  build_apk(project_dir, debug)
102
105
  end
@@ -298,6 +301,113 @@ module Pindo
298
301
  end
299
302
  end
300
303
 
304
+ # 设置 Play Asset Delivery:直接扫描导出工程中的资源目录,按照 Android 原生方式创建 .androidpack 目录
305
+ def setup_play_asset_delivery(project_dir)
306
+ # 获取 unityLibrary 路径
307
+ unity_library_path = File.join(project_dir, "unityLibrary", "src", "main")
308
+ unless File.directory?(unity_library_path)
309
+ puts "警告:Unity Library 目录不存在: #{unity_library_path}"
310
+ return
311
+ end
312
+
313
+ # 扫描 assets 目录下的资源(Unity 构建时会将 StreamingAssets 复制到这里)
314
+ assets_path = File.join(unity_library_path, "assets")
315
+ unless File.directory?(assets_path)
316
+ puts "未找到 assets 目录,跳过 Play Asset Delivery 设置"
317
+ return
318
+ end
319
+
320
+ # 扫描 assets 目录下的所有一级子目录
321
+ # 这些目录对应 StreamingAssets/{DefaultYooFolderName} 下的资源包
322
+ asset_subdirs = Dir.glob(File.join(assets_path, "*")).select { |path| File.directory?(path) }
323
+
324
+ if asset_subdirs.empty?
325
+ puts "未找到 assets 下的子目录,跳过 Play Asset Delivery 设置"
326
+ return
327
+ end
328
+
329
+ puts "检测到 #{asset_subdirs.length} 个 assets 子目录,开始设置 Play Asset Delivery..."
330
+
331
+ begin
332
+ # 收集所有创建的 asset pack 模块名
333
+ created_pack_modules = []
334
+
335
+ # 扫描每个子目录,为每个子目录创建一个 asset pack 模块
336
+ asset_subdirs.each do |subdir|
337
+ original_pack_name = File.basename(subdir)
338
+ if original_pack_name.downcase == 'bin'
339
+ puts "跳过 bin 目录,保持在 base 模块中"
340
+ next
341
+ end
342
+ sanitized_pack_name = sanitize_pack_name(original_pack_name)
343
+ module_name = "#{sanitized_pack_name}_pack"
344
+
345
+ # 检查目录是否为空
346
+ if Dir.glob(File.join(subdir, "*")).empty?
347
+ puts "警告:跳过空的 Asset Pack 目录: #{subdir}"
348
+ next
349
+ end
350
+
351
+ # 创建模块目录(在项目顶级目录,与 launcher、unityLibrary 同级)
352
+ android_pack_dir = File.join(project_dir, module_name)
353
+ FileUtils.rm_rf(android_pack_dir) if File.directory?(android_pack_dir)
354
+ FileUtils.mkdir_p(android_pack_dir)
355
+
356
+ # 在 asset pack 模块中创建 src/main/assets 目录
357
+ module_assets_dir = File.join(android_pack_dir, "src", "main", "assets")
358
+ FileUtils.mkdir_p(module_assets_dir)
359
+
360
+ # 复制整个子目录到模块的 assets 下,保留原始目录名
361
+ FileUtils.cp_r(subdir, module_assets_dir)
362
+
363
+ # 从 assets 目录中删除资源,避免被打包到 base 模块
364
+ puts " 从 assets 目录移除资源 #{subdir},避免重复打包到 base 模块..."
365
+ FileUtils.rm_rf(subdir)
366
+
367
+ # 创建 build.gradle 文件(默认使用 install-time delivery mode)
368
+ build_gradle_content = <<~GRADLE
369
+ plugins {
370
+ id 'com.android.asset-pack'
371
+ }
372
+
373
+ assetPack {
374
+ packName = "#{module_name}"
375
+ dynamicDelivery {
376
+ deliveryType = "install-time"
377
+ }
378
+ }
379
+ GRADLE
380
+
381
+ build_gradle_path = File.join(android_pack_dir, "build.gradle")
382
+ File.write(build_gradle_path, build_gradle_content)
383
+
384
+ # 记录模块名(项目顶级目录下的简单模块名)
385
+ created_pack_modules << ":#{module_name}"
386
+
387
+ puts "✓ 已创建 Asset Pack: #{module_name} -> #{android_pack_dir}"
388
+ end
389
+
390
+ # 更新 settings.gradle 文件,注册 asset pack 模块
391
+ if created_pack_modules.any?
392
+ GradleHelper.update_settings_gradle(project_dir, created_pack_modules)
393
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
394
+ GradleHelper.update_launcher_build_gradle(project_dir, created_pack_modules)
395
+ puts "✓ Play Asset Delivery 设置完成,共创建 #{created_pack_modules.length} 个 Asset Pack"
396
+ else
397
+ puts "未找到有效的 Asset Pack 目录"
398
+ end
399
+ rescue => e
400
+ puts "警告:设置 Play Asset Delivery 失败: #{e.message}"
401
+ puts e.backtrace.first(5).join("\n")
402
+ end
403
+ end
404
+
405
+ def sanitize_pack_name(name)
406
+ sanitized = name.to_s.gsub(/[^A-Za-z0-9_]/, '_')
407
+ sanitized = "p_#{sanitized}" unless sanitized.match?(/^[A-Za-z]/)
408
+ sanitized = sanitized.gsub(/__+/, '_')
409
+ sanitized.empty? ? "pack" : sanitized
410
+ end
301
411
 
302
412
  end
303
413
  end
@@ -559,7 +559,95 @@ module Pindo
559
559
  end
560
560
  rescue => e
561
561
  false
562
+ end
563
+
564
+ end
565
+
566
+ # =================== Play Asset Delivery 相关方法 ===================
567
+
568
+ # 更新 settings.gradle 文件,注册 asset pack 模块
569
+ def self.update_settings_gradle(project_dir, pack_modules)
570
+ settings_gradle_path = File.join(project_dir, "settings.gradle")
571
+ settings_gradle_kts_path = File.join(project_dir, "settings.gradle.kts")
572
+
573
+ # 优先使用 settings.gradle.kts,否则使用 settings.gradle
574
+ settings_file = File.exist?(settings_gradle_kts_path) ? settings_gradle_kts_path : settings_gradle_path
575
+
576
+ unless File.exist?(settings_file)
577
+ puts "警告:未找到 settings.gradle 或 settings.gradle.kts 文件"
578
+ return
579
+ end
580
+
581
+ content = File.read(settings_file)
582
+ original_content = content.dup
583
+
584
+ # 模块名已经是正确的格式(如 :FGUI.androidpack)
585
+ pack_module_names = pack_modules
586
+
587
+ # 移除已存在的 asset pack 模块引用(避免重复)
588
+ pack_module_names.each do |module_name|
589
+ # 移除可能存在的旧引用
590
+ content.gsub!(/^\s*include\s+['"]#{Regexp.escape(module_name)}['"]\s*$/, '')
591
+ content.gsub!(/,\s*['"]#{Regexp.escape(module_name)}['"]/, '')
592
+ end
593
+
594
+ # 查找 include 语句的位置
595
+ include_pattern = /include\s+(['"]:launcher['"],\s*['"]:unityLibrary['"])/
596
+ if content.match(include_pattern)
597
+ # 在现有的 include 语句中添加 asset pack 模块
598
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
599
+ content.gsub!(include_pattern, "include \\1, #{pack_includes}")
600
+ else
601
+ # 如果没有找到标准格式,尝试在文件末尾添加
602
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
603
+ content += "\ninclude #{pack_includes}\n" unless content.include?(pack_includes)
604
+ end
605
+
606
+ # 只有当内容发生变化时才写入
607
+ if content != original_content
608
+ File.write(settings_file, content)
609
+ puts "✓ 已更新 #{File.basename(settings_file)},注册 #{pack_modules.length} 个 Asset Pack 模块"
610
+ puts " 模块: #{pack_module_names.join(', ')}"
611
+ else
612
+ puts "✓ #{File.basename(settings_file)} 已包含 Asset Pack 模块引用"
613
+ end
614
+ end
615
+
616
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
617
+ def self.update_launcher_build_gradle(project_dir, pack_modules)
618
+ launcher_build_gradle_path = File.join(project_dir, "launcher", "build.gradle")
619
+ unless File.exist?(launcher_build_gradle_path)
620
+ puts "警告:未找到 launcher/build.gradle 文件"
621
+ return
622
+ end
623
+
624
+ content = File.read(launcher_build_gradle_path)
625
+ original_content = content.dup
626
+
627
+ # 检查是否已有 assetPacks 配置
628
+ if content.match(/assetPacks\s*=\s*\[/)
629
+ # 更新现有的 assetPacks 配置
630
+ content.gsub!(/assetPacks\s*=\s*\[[^\]]*\]/, "assetPacks = #{pack_modules.inspect}")
631
+ else
632
+ # 在 android 块中添加 assetPacks 配置
633
+ android_block_pattern = /(android\s*\{)/
634
+ if content.match(android_block_pattern)
635
+ # 在 android { 后添加 assetPacks 配置
636
+ content.gsub!(android_block_pattern, "\\1\n assetPacks = #{pack_modules.inspect}")
637
+ else
638
+ puts "警告:未找到 android 块,无法添加 assetPacks 配置"
639
+ return
562
640
  end
563
641
  end
642
+
643
+ # 只有当内容发生变化时才写入
644
+ if content != original_content
645
+ File.write(launcher_build_gradle_path, content)
646
+ puts "✓ 已更新 launcher/build.gradle,添加 assetPacks 配置"
647
+ else
648
+ puts "✓ launcher/build.gradle 已包含 assetPacks 配置"
649
+ end
650
+ end
651
+
564
652
  end
565
653
  end
@@ -36,7 +36,7 @@ module Pindo
36
36
  attr_accessor :context, :metadata
37
37
  attr_reader :created_at, :started_at, :finished_at
38
38
  attr_accessor :retry_count # 剩余重试次数
39
- attr_reader :retry_mode, :retry_delay
39
+ attr_reader :retry_mode, :retry_delay, :max_retry_count # max_retry_count: 初始最大重试次数
40
40
  attr_accessor :callbacks_setup # 标记回调是否已经设置
41
41
 
42
42
  def initialize(name, options = {})
@@ -64,6 +64,7 @@ module Pindo
64
64
  # 重试配置
65
65
  @retry_mode = options[:retry_mode] || self.class.default_retry_mode
66
66
  @retry_count = options[:retry_count] || self.class.default_retry_count
67
+ @max_retry_count = @retry_count # 保存初始最大重试次数
67
68
  @retry_delay = options[:retry_delay] || self.class.default_retry_delay
68
69
  end
69
70
 
@@ -220,10 +221,16 @@ module Pindo
220
221
  end
221
222
  end
222
223
 
224
+ # 计算当前重试次数
225
+ def current_retry_attempt
226
+ @max_retry_count - @retry_count + 1
227
+ end
228
+
223
229
  # 立即重试
224
230
  def handle_immediate_retry
225
- puts "⚠️ 任务失败,立即重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
226
- puts " 错误: #{@error.message}"
231
+ attempt = current_retry_attempt
232
+ Funlog.warning("任务 [#{@name}] 失败,立即重试 (第#{attempt}次/共#{@max_retry_count}次)")
233
+ Funlog.warning(" 错误: #{@error.message}")
227
234
 
228
235
  before_retry
229
236
  reset_for_retry
@@ -232,9 +239,10 @@ module Pindo
232
239
 
233
240
  # 延迟重试
234
241
  def handle_delayed_retry
235
- puts "⚠️ 任务失败,延迟重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
236
- puts " 错误: #{@error.message}"
237
- puts " 延迟: #{@retry_delay}"
242
+ attempt = current_retry_attempt
243
+ Funlog.warning("任务 [#{@name}] 失败,延迟重试 (第#{attempt}次/共#{@max_retry_count}次)")
244
+ Funlog.warning(" 错误: #{@error.message}")
245
+ Funlog.warning(" 延迟: #{@retry_delay}秒")
238
246
 
239
247
  before_retry
240
248
  sleep(@retry_delay) if @retry_delay > 0
@@ -245,8 +253,9 @@ module Pindo
245
253
 
246
254
  # 下个任务重试
247
255
  def handle_next_task_retry
248
- puts "⚠️ 任务失败,下个任务重试 (剩余#{@retry_count}次)".yellow if defined?(String.yellow)
249
- puts " 错误: #{@error.message}"
256
+ attempt = current_retry_attempt
257
+ Funlog.warning("任务 [#{@name}] 失败,下个任务重试 (第#{attempt}次/共#{@max_retry_count}次)")
258
+ Funlog.warning(" 错误: #{@error.message}")
250
259
 
251
260
  before_retry
252
261
  @status = TaskStatus::FAILED
@@ -258,8 +267,8 @@ module Pindo
258
267
  def finalize_failure
259
268
  @status = TaskStatus::FAILED
260
269
 
261
- puts "[Task] #{@name} 最终失败".red if defined?(String.red)
262
- puts " 错误: #{@error.message}".red if defined?(String.red)
270
+ Funlog.instance.fancyinfo_error("[Task] #{@name} 最终失败")
271
+ Funlog.instance.fancyinfo_error(" 错误: #{@error.message}")
263
272
 
264
273
  run_callbacks(:on_failure)
265
274
  raise @error if should_raise_on_failure?
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.12.2"
9
+ VERSION = "5.13.1"
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.12.2
4
+ version: 5.13.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -315,7 +315,6 @@ files:
315
315
  - lib/pindo/command/android.rb
316
316
  - lib/pindo/command/android/autobuild.rb
317
317
  - lib/pindo/command/android/autoresign.rb
318
- - lib/pindo/command/android/build.rb
319
318
  - lib/pindo/command/android/keystore.rb
320
319
  - lib/pindo/command/appstore.rb
321
320
  - lib/pindo/command/appstore/adhocbuild.rb
@@ -1,186 +0,0 @@
1
- require 'highline/import'
2
- require 'fileutils'
3
- require 'json'
4
- require 'pindo/module/build/build_helper'
5
- require 'pindo/module/build/git_repo_helper'
6
- require 'pindo/module/android/android_build_helper'
7
-
8
- module Pindo
9
- class Command
10
- class Android < Command
11
- class Build < Android
12
-
13
- self.summary = '只编译APK不修改工程'
14
- self.description = <<-DESC
15
- 只编译APK不修改工程
16
-
17
- 支持功能:
18
-
19
- * 编译Android工程
20
-
21
- * 生成APK文件
22
-
23
- * 支持上传到JPS测试平台
24
-
25
- * 支持发送测试通知
26
-
27
- 使用示例:
28
-
29
- $ pindo android build # 编译APK
30
-
31
- $ pindo android build --upload # 编译并上传到JPS
32
-
33
- $ pindo android build --send # 编译、上传并发送通知
34
-
35
- $ pindo android build --proj="My App" # 指定项目名称
36
- DESC
37
-
38
- def self.options
39
- [
40
- ['--proj', '指定上传到测试平台的项目名称'],
41
- ['--upload', '上传编译后的apk到测试平台'],
42
- ['--send', '上传成功后发送测试通知'],
43
- ].concat(super)
44
- end
45
-
46
- def initialize(argv)
47
- @args_upload_flag = argv.flag?('upload', false)
48
- @args_send_flag = argv.flag?('send', false)
49
- @args_proj_name = argv.option('proj')
50
-
51
- if @args_send_flag
52
- @args_upload_flag = true
53
- end
54
-
55
- super
56
- @additional_args = argv.remainder!
57
- end
58
-
59
- def run
60
-
61
- pindo_project_dir = Dir.pwd
62
-
63
- build_helper = Pindo::BuildHelper.share_instance
64
- project_type = build_helper.project_type(pindo_project_dir)
65
-
66
- args_temp = []
67
- args_temp << "--proj=#{@args_proj_name}" if @args_proj_name
68
- args_temp << "--upload" if @args_upload_flag
69
- args_temp << "--send" if @args_send_flag
70
- case project_type
71
- when :ios
72
- raise Informative, "iOS 工程, 请使用 pindo ios build"
73
- when :android
74
- android_build
75
- when :unity
76
- raise Informative, "Unity 工程, 请使用 pindo unity apk"
77
- else
78
- raise Informative, "当前目录不是工程目录,不能编译"
79
- end
80
- end
81
-
82
- def android_build
83
- pindo_project_dir = Dir.pwd
84
- build_helper = Pindo::BuildHelper.share_instance
85
- if @args_upload_flag
86
- git_repo_helper = Pindo::GitRepoHelper.share_instance
87
- is_need_add_tag, tag_action_parms = git_repo_helper.check_is_need_add_tag?(pindo_project_dir)
88
- if is_need_add_tag
89
- git_repo_helper.create_and_push_tag(
90
- project_dir: pindo_project_dir,
91
- mode: 'minor',
92
- force_retag: tag_action_parms&.include?('--retag') || false,
93
- custom_tag: nil,
94
- release_branch: 'master'
95
- )
96
- end
97
- end
98
-
99
- app_info_obj = nil
100
- workflow_info = nil
101
- if @args_upload_flag
102
- proj_name = @args_proj_name
103
- # 传入 package_type 获取 workflow_info
104
- app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
105
- working_directory: Dir.pwd,
106
- proj_name: proj_name,
107
- package_type: 'apk'
108
- )
109
-
110
- # ===== 使用 workflow 配置更新 Android 项目 =====
111
- if workflow_info && workflow_info[:package_name]
112
- workflow_packname = workflow_info[:package_name]
113
-
114
- puts "\n使用工作流配置更新 Android 项目:"
115
- puts " Workflow Package Name: #{workflow_packname}"
116
-
117
- # 一次性更新 App Name、Application ID 和 URL Schemes
118
- Pindo::AndroidConfigHelper.update_project_with_workflow(
119
- project_dir: pindo_project_dir,
120
- workflow_packname: workflow_packname
121
- )
122
-
123
- # 添加基于 Application ID 的 Scheme(在 workflow 设置完成后)
124
- Pindo::AndroidConfigHelper.add_application_id_based_scheme(
125
- project_dir: pindo_project_dir
126
- )
127
- else
128
- raise Informative, "未获取到工作流信息"
129
- end
130
- end
131
-
132
-
133
- android_build_helper = Pindo::AndroidBuildHelper.share_instance
134
-
135
- begin
136
- apk_path = android_build_helper.auto_build_apk(pindo_project_dir, !@args_release_flag)
137
- ipa_file_upload = Dir.glob(apk_path).max_by {|f| File.mtime(f)}
138
-
139
- if !ipa_file_upload.nil? && !app_info_obj.nil?
140
-
141
- description = nil
142
- result_data = PgyerHelper.share_instace.start_upload(
143
- app_info_obj: app_info_obj,
144
- ipa_file_upload: ipa_file_upload,
145
- description: description,
146
- workflow_info: workflow_info
147
- )
148
- if !result_data.nil? && !result_data["data"].nil? && !result_data["data"]["id"].nil?
149
- PgyerHelper.share_instace.print_app_version_info(
150
- app_info_obj: app_info_obj,
151
- app_version_info_obj: result_data["data"]
152
- )
153
- if @args_send_flag
154
- # 始终发送给自己
155
- PgyerHelper.share_instace.send_apptest_msg(
156
- app_info_obj: app_info_obj,
157
- app_version_info_obj: result_data["data"],
158
- receiveType: "self"
159
- )
160
-
161
- # 额外发送到测试群
162
- PgyerHelper.share_instace.send_apptest_msg(
163
- app_info_obj: app_info_obj,
164
- app_version_info_obj: result_data["data"],
165
- chatEnv: "DevTest",
166
- receiveType: "chat"
167
- )
168
- end
169
- end
170
- end
171
-
172
- # 只在构建成功完成时弹出目标文件夹
173
- puts "\e[32m构建完成!正在打开目标文件夹...\e[0m"
174
- system "open #{pindo_project_dir}"
175
-
176
- rescue => e
177
- puts "\e[31m构建失败: #{e.message}\e[0m"
178
- puts "\e[33m正在打开项目文件夹以便检查错误...\e[0m"
179
- system "open #{pindo_project_dir}"
180
- raise e
181
- end
182
- end
183
- end
184
- end
185
- end
186
- end