pindo 5.12.2 → 5.13.2
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/git_handler.rb +692 -0
- data/lib/pindo/command/android/autobuild.rb +2 -2
- data/lib/pindo/command/android.rb +0 -1
- data/lib/pindo/command/appstore/adhocbuild.rb +258 -311
- data/lib/pindo/command/appstore/autobuild.rb +203 -0
- data/lib/pindo/command/appstore/autoresign.rb +35 -17
- data/lib/pindo/command/appstore/bundleid.rb +120 -0
- data/lib/pindo/command/appstore/cert.rb +212 -0
- data/lib/pindo/command/appstore/configproj.rb +81 -0
- data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
- data/lib/pindo/command/appstore/iap.rb +788 -24
- data/lib/pindo/command/appstore/initconfig.rb +105 -0
- data/lib/pindo/command/appstore/itcapp.rb +95 -13
- data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
- data/lib/pindo/command/appstore/pem.rb +136 -0
- data/lib/pindo/command/appstore/pullconfig.rb +99 -0
- data/lib/pindo/command/appstore/quswark.rb +87 -0
- data/lib/pindo/command/appstore/quswauth.rb +67 -0
- data/lib/pindo/command/appstore/tag.rb +77 -0
- data/lib/pindo/command/appstore.rb +13 -1
- data/lib/pindo/command/env/quarkenv.rb +11 -13
- data/lib/pindo/command/env/swarkenv.rb +11 -16
- data/lib/pindo/command/ios/autobuild.rb +64 -43
- data/lib/pindo/command/ios/autoresign.rb +34 -19
- data/lib/pindo/command/ios/build.rb +10 -7
- data/lib/pindo/command/ios/cert.rb +27 -20
- data/lib/pindo/command/jps/upload.rb +3 -3
- data/lib/pindo/command/unity/autobuild.rb +2 -2
- data/lib/pindo/command/utils/clearcert.rb +2 -17
- data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
- data/lib/pindo/command/utils/renewcert.rb +62 -38
- data/lib/pindo/command/utils/renewproj.rb +0 -3
- data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
- data/lib/pindo/command/utils.rb +2 -0
- data/lib/pindo/command/web/autobuild.rb +2 -2
- data/lib/pindo/command.rb +30 -3
- data/lib/pindo/config/build_info_manager.rb +176 -0
- data/lib/pindo/config/ios_config_parser.rb +404 -0
- data/lib/pindo/module/android/android_build_helper.rb +110 -0
- data/lib/pindo/module/android/android_config_helper.rb +9 -5
- data/lib/pindo/module/android/gradle_helper.rb +88 -0
- data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
- data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
- data/lib/pindo/module/build/build_helper.rb +12 -0
- data/lib/pindo/module/build/swark_helper.rb +116 -77
- data/lib/pindo/module/cert/cert_helper.rb +74 -0
- data/lib/pindo/module/cert/pem_helper.rb +72 -0
- data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +208 -6
- data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
- data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
- data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
- data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
- data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
- data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +197 -0
- data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +367 -0
- data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +37 -27
- data/lib/pindo/module/task/model/build/ios_build_task.rb +13 -0
- data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
- data/lib/pindo/module/task/model/build_task.rb +15 -12
- data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
- data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
- data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
- data/lib/pindo/module/task/pindo_task.rb +19 -10
- data/lib/pindo/module/unity/unity_helper.rb +2 -1
- data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
- data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
- data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
- data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
- data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
- data/lib/pindo/options/core/global_options_state.rb +268 -0
- data/lib/pindo/options/core/option_configuration.rb +206 -0
- data/lib/pindo/options/core/option_initializer.rb +51 -0
- data/lib/pindo/options/core/option_item.rb +144 -0
- data/lib/pindo/options/core/option_value_parser.rb +54 -0
- data/lib/pindo/options/groups/build_options.rb +60 -0
- data/lib/pindo/options/groups/jps_options.rb +70 -0
- data/lib/pindo/options/groups/option_group.rb +73 -0
- data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
- data/lib/pindo/options/options.rb +14 -0
- data/lib/pindo/version.rb +1 -1
- metadata +49 -41
- data/lib/pindo/command/android/build.rb +0 -186
- data/lib/pindo/command/appstore/import.rb +0 -259
- data/lib/pindo/command/deploy/build.rb +0 -250
- data/lib/pindo/command/deploy/bundleid.rb +0 -259
- data/lib/pindo/command/deploy/cert.rb +0 -202
- data/lib/pindo/command/deploy/check.rb +0 -93
- data/lib/pindo/command/deploy/configproj.rb +0 -120
- data/lib/pindo/command/deploy/confusecode.rb +0 -262
- data/lib/pindo/command/deploy/confuseproj.rb +0 -122
- data/lib/pindo/command/deploy/iap.rb +0 -826
- data/lib/pindo/command/deploy/initconfig.rb +0 -138
- data/lib/pindo/command/deploy/itcapp.rb +0 -146
- data/lib/pindo/command/deploy/pem.rb +0 -55
- data/lib/pindo/command/deploy/pullconfig.rb +0 -56
- data/lib/pindo/command/deploy/pushconfig.rb +0 -93
- data/lib/pindo/command/deploy/quswark.rb +0 -156
- data/lib/pindo/command/deploy/quswauth.rb +0 -76
- data/lib/pindo/command/deploy/reportbug.rb +0 -145
- data/lib/pindo/command/deploy/resign.rb +0 -300
- data/lib/pindo/command/deploy/tag.rb +0 -108
- data/lib/pindo/command/deploy/uploadipa.rb +0 -73
- data/lib/pindo/command/deploy.rb +0 -42
- data/lib/pindo/command/dev/autobuild.rb +0 -117
- data/lib/pindo/command/dev/build.rb +0 -94
- data/lib/pindo/command/dev/debug.rb +0 -112
- data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
- data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
- data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
- data/lib/pindo/options/appconfigoptions.rb +0 -24
- data/lib/pindo/options/deployoptions.rb +0 -372
|
@@ -5,10 +5,9 @@ require 'highline'
|
|
|
5
5
|
|
|
6
6
|
module Pindo
|
|
7
7
|
class Command
|
|
8
|
-
class
|
|
9
|
-
class Updateconfig <
|
|
10
|
-
|
|
11
|
-
include Command::DeployOptions
|
|
8
|
+
class Utils < Command
|
|
9
|
+
class Updateconfig < Utils
|
|
10
|
+
|
|
12
11
|
include Hashhelper
|
|
13
12
|
include Appselect
|
|
14
13
|
|
|
@@ -22,9 +21,9 @@ module Pindo
|
|
|
22
21
|
- 保留用户自定义配置的同时更新模板结构
|
|
23
22
|
|
|
24
23
|
使用示例:
|
|
25
|
-
pindo
|
|
26
|
-
pindo
|
|
27
|
-
pindo
|
|
24
|
+
pindo utils updateconfig path/to/config.json
|
|
25
|
+
pindo utils updateconfig ./config.json
|
|
26
|
+
pindo utils updateconfig config.json
|
|
28
27
|
DESC
|
|
29
28
|
|
|
30
29
|
self.arguments = [
|
data/lib/pindo/command/utils.rb
CHANGED
|
@@ -10,6 +10,8 @@ require 'pindo/command/utils/renewcert'
|
|
|
10
10
|
require 'pindo/command/utils/repoinit'
|
|
11
11
|
require 'pindo/command/utils/feishu'
|
|
12
12
|
require 'pindo/command/utils/tag'
|
|
13
|
+
require 'pindo/command/utils/updateconfig'
|
|
14
|
+
require 'pindo/command/utils/fabric'
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
module Pindo
|
|
@@ -9,7 +9,7 @@ require 'pindo/module/task/task_manager'
|
|
|
9
9
|
require 'pindo/module/task/model/git_tag_task'
|
|
10
10
|
require 'pindo/module/task/model/unity_export_task'
|
|
11
11
|
require 'pindo/module/task/model/build_task'
|
|
12
|
-
require 'pindo/module/task/model/
|
|
12
|
+
require 'pindo/module/task/model/jps_upload_task'
|
|
13
13
|
|
|
14
14
|
module Pindo
|
|
15
15
|
class Command
|
|
@@ -234,7 +234,7 @@ module Pindo
|
|
|
234
234
|
if @args_upload_flag
|
|
235
235
|
# WebGL 输出路径: GoodPlatform/WebGL/build
|
|
236
236
|
webgl_build_path = File.join(config[:project_path], 'GoodPlatform', 'WebGL', 'build')
|
|
237
|
-
upload_task = Pindo::TaskSystem::
|
|
237
|
+
upload_task = Pindo::TaskSystem::JPSUploadTask.new(
|
|
238
238
|
'html',
|
|
239
239
|
webgl_build_path,
|
|
240
240
|
nil,
|
data/lib/pindo/command.rb
CHANGED
|
@@ -28,16 +28,15 @@ module Pindo
|
|
|
28
28
|
|
|
29
29
|
require "fastlane"
|
|
30
30
|
require "match"
|
|
31
|
-
require 'pindo/options/
|
|
31
|
+
require 'pindo/options/options'
|
|
32
32
|
require 'pindo/module/appselect'
|
|
33
33
|
require 'pindo/module/build/confuse_xcodeproj'
|
|
34
|
-
require 'pindo/module/cert/
|
|
34
|
+
require 'pindo/module/cert/xcode_cert_helper'
|
|
35
35
|
|
|
36
36
|
require 'pindo/module/appstore/appstore_in_app_purchase'
|
|
37
37
|
require 'pindo/module/appstore/appstore_metadata_fastlane_helper'
|
|
38
38
|
require 'pindo/module/appstore/appstore_metadata_connect_api_helper'
|
|
39
39
|
|
|
40
|
-
require 'pindo/command/deploy'
|
|
41
40
|
require 'pindo/command/env'
|
|
42
41
|
require 'pindo/command/utils'
|
|
43
42
|
require 'pindo/command/jps'
|
|
@@ -65,6 +64,34 @@ module Pindo
|
|
|
65
64
|
# 注意:缓存组的定义已经移至 PindoContext#get_command_group 中统一管理
|
|
66
65
|
# 使用命令名作为组名,如 ios:autobuild, and:autobuild, web:autobuild
|
|
67
66
|
|
|
67
|
+
# 自动推导命令名称
|
|
68
|
+
# @return [String] 命令名称,例如:Pindo::Command::Ios::Autobuild → 'ios:autobuild'
|
|
69
|
+
def self.command_name
|
|
70
|
+
@command_name ||= begin
|
|
71
|
+
# 从类名推导,例如:
|
|
72
|
+
# Pindo::Command::Ios::Autobuild → ['Ios', 'Autobuild'] → 'ios:autobuild'
|
|
73
|
+
parts = name.split('::').drop(2) # 去掉 'Pindo' 和 'Command'
|
|
74
|
+
parts.map(&:downcase).join(':')
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# 初始化参数(便捷方法)
|
|
79
|
+
# @param argv [CLAide::ARGV] 命令行参数
|
|
80
|
+
# @param command_name [String, nil] 命令名称(可选,默认自动推导)
|
|
81
|
+
# @param directory [String, nil] 工作目录(可选,默认当前目录)
|
|
82
|
+
# @param enable_cache [Boolean, nil] 是否启用缓存(可选,默认使用 use_cache?)
|
|
83
|
+
# @return [OptionConfiguration] 参数配置对象
|
|
84
|
+
def initialize_options(argv, command_name: nil, directory: nil, enable_cache: nil)
|
|
85
|
+
Pindo::Options::OptionInitializer.initialize(
|
|
86
|
+
self,
|
|
87
|
+
argv,
|
|
88
|
+
self.class.option_items,
|
|
89
|
+
command_name || self.class.command_name,
|
|
90
|
+
directory: directory,
|
|
91
|
+
enable_cache: enable_cache.nil? ? self.class.use_cache? : enable_cache
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
68
95
|
|
|
69
96
|
DEFAULT_ROOT_OPTIONS = [
|
|
70
97
|
['--version', '查看pindo版本'],
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'pindo/base/githelper'
|
|
4
|
+
|
|
5
|
+
module Pindo
|
|
6
|
+
|
|
7
|
+
# 构建信息管理器
|
|
8
|
+
# 负责管理应用配置仓库的拉取、更新等操作
|
|
9
|
+
class BuildInfoManager
|
|
10
|
+
include Singleton
|
|
11
|
+
include Pindo::Githelper
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def share_instance
|
|
15
|
+
instance
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# 拉取应用配置仓库
|
|
20
|
+
# @param repo_name [String] 仓库名称(Bundle ID)
|
|
21
|
+
# @param target_dir [String, nil] 目标目录(默认:当前目录)
|
|
22
|
+
# @return [Boolean] 是否成功拉取配置
|
|
23
|
+
def pull_appconfig_with_reponame(repo_name:, target_dir: nil)
|
|
24
|
+
return false if repo_name.nil? || repo_name.empty?
|
|
25
|
+
|
|
26
|
+
# 规范化仓库名称:去除尾部的 .* (通配符转换)
|
|
27
|
+
normalized_repo_name = repo_name.end_with?('.*') ? repo_name.chomp('.*') : repo_name
|
|
28
|
+
|
|
29
|
+
# 获取配置仓库目录
|
|
30
|
+
begin
|
|
31
|
+
app_config_dir = clong_buildconfig_repo(repo_name: normalized_repo_name)
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
puts "拉取配置仓库失败: #{e.message}"
|
|
34
|
+
return false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# 确定目标目录
|
|
38
|
+
target_dir ||= Dir.pwd
|
|
39
|
+
|
|
40
|
+
# 如果配置仓库目录与目标目录不同,且存在 config.json,则复制
|
|
41
|
+
if !app_config_dir.eql?(target_dir) && File.exist?(File.join(app_config_dir, 'config.json'))
|
|
42
|
+
begin
|
|
43
|
+
FileUtils.cp_r(File.join(app_config_dir, "config.json"), target_dir)
|
|
44
|
+
puts "✓ 配置文件已复制到: #{target_dir}"
|
|
45
|
+
return true
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
puts "复制配置文件失败: #{e.message}"
|
|
48
|
+
return false
|
|
49
|
+
end
|
|
50
|
+
elsif app_config_dir.eql?(target_dir)
|
|
51
|
+
puts "✓ 配置文件已存在于目标目录"
|
|
52
|
+
return true
|
|
53
|
+
else
|
|
54
|
+
puts "⚠ 配置仓库中未找到 config.json"
|
|
55
|
+
return false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# 创建应用配置仓库
|
|
60
|
+
# @param bundle_id [String] Bundle ID(作为仓库名称)
|
|
61
|
+
# @param test_flag [Boolean] 是否为测试环境(默认:false)
|
|
62
|
+
# @return [String, nil] 成功返回配置仓库目录路径,失败返回 nil
|
|
63
|
+
def create_appconfig_with_bundleid(bundle_id:, test_flag: false)
|
|
64
|
+
return nil if bundle_id.nil? || bundle_id.empty?
|
|
65
|
+
|
|
66
|
+
require_relative '../client/giteeclient'
|
|
67
|
+
|
|
68
|
+
# 获取 Gitee 客户端
|
|
69
|
+
gitee_client = GiteeClient.new(access_token: pindo_single_config.gitee_api_key)
|
|
70
|
+
|
|
71
|
+
# 获取模板配置仓库目录
|
|
72
|
+
demo_dir = clong_buildconfig_repo(repo_name: pindo_single_config.demo_bundle_id)
|
|
73
|
+
|
|
74
|
+
# 确定仓库公开类型和所有者组织
|
|
75
|
+
public_type = 0
|
|
76
|
+
owner_org = pindo_single_config.build_deploy_org
|
|
77
|
+
repo_name = bundle_id
|
|
78
|
+
|
|
79
|
+
if test_flag
|
|
80
|
+
owner_org = pindo_single_config.build_test_org
|
|
81
|
+
public_type = 2
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# 创建 Gitee 仓库
|
|
85
|
+
success = gitee_client.gitee_create_repo(
|
|
86
|
+
owner: owner_org,
|
|
87
|
+
repo_name: repo_name,
|
|
88
|
+
public_type: public_type
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if success
|
|
92
|
+
# 如果是测试环境,修改仓库设置
|
|
93
|
+
if test_flag
|
|
94
|
+
modify_repo_setting(repo_name: repo_name, owner_org: owner_org)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# 克隆配置仓库
|
|
98
|
+
app_config_dir = clong_buildconfig_repo(repo_name: repo_name)
|
|
99
|
+
system "open #{app_config_dir}"
|
|
100
|
+
|
|
101
|
+
if File.exist?(app_config_dir)
|
|
102
|
+
# 从模板仓库复制配置文件
|
|
103
|
+
update_appconfig_repo(
|
|
104
|
+
bundle_id: bundle_id,
|
|
105
|
+
demo_dir: demo_dir,
|
|
106
|
+
app_config_dir: app_config_dir
|
|
107
|
+
)
|
|
108
|
+
puts "✓ 配置仓库创建成功: #{app_config_dir}"
|
|
109
|
+
return app_config_dir
|
|
110
|
+
else
|
|
111
|
+
puts "❌ 创建应用配置仓库失败"
|
|
112
|
+
return nil
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
# 仓库已存在,直接打开
|
|
116
|
+
app_config_dir = clong_buildconfig_repo(repo_name: repo_name)
|
|
117
|
+
system "open #{app_config_dir}"
|
|
118
|
+
puts "⚠ 配置仓库已存在: #{app_config_dir}"
|
|
119
|
+
return app_config_dir
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
# 修改仓库设置(测试环境)
|
|
126
|
+
def modify_repo_setting(repo_name:, owner_org:)
|
|
127
|
+
pindo_setting_dir = pindo_single_config.pindo_env_configdir
|
|
128
|
+
git_repo_file = pindo_single_config.git_base_url_fullname
|
|
129
|
+
git_repo_json = JSON.parse(File.read(git_repo_file))
|
|
130
|
+
git_repo_json ||= {}
|
|
131
|
+
|
|
132
|
+
if git_repo_json
|
|
133
|
+
git_repo_json[repo_name] = owner_org
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
File.open(git_repo_file, "w") do |f|
|
|
137
|
+
f.write(JSON.pretty_generate(git_repo_json))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
git_addpush_repo(path: pindo_setting_dir, message: "add #{repo_name}")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# 更新应用配置仓库(从模板复制)
|
|
144
|
+
def update_appconfig_repo(bundle_id:, demo_dir:, app_config_dir:)
|
|
145
|
+
return unless File.exist?(demo_dir)
|
|
146
|
+
|
|
147
|
+
# 复制 config.json
|
|
148
|
+
if File.exist?(File.join(demo_dir, "config.json"))
|
|
149
|
+
FileUtils.cp_r(File.join(demo_dir, "config.json"), app_config_dir)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# 复制 fastlane 目录
|
|
153
|
+
if File.exist?(File.join(demo_dir, "fastlane"))
|
|
154
|
+
FileUtils.cp_r(File.join(demo_dir, "fastlane"), app_config_dir)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# 复制 launch 目录
|
|
158
|
+
if File.exist?(File.join(demo_dir, "launch"))
|
|
159
|
+
FileUtils.cp_r(File.join(demo_dir, "launch"), app_config_dir)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# 替换 config.json 中的 Bundle ID
|
|
163
|
+
config_file = File.join(app_config_dir, "config.json")
|
|
164
|
+
if File.exist?(config_file)
|
|
165
|
+
text = File.read(config_file)
|
|
166
|
+
demo_bundle_id = pindo_single_config.demo_bundle_id
|
|
167
|
+
new_contents = text.gsub(/#{demo_bundle_id}/, bundle_id)
|
|
168
|
+
File.open(config_file, "w") { |file| file.puts new_contents }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# 提交并推送到远程仓库
|
|
172
|
+
git_addpush_repo(path: app_config_dir, message: "init app config")
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Pindo
|
|
5
|
+
# iOS 配置解析器(单例模式)
|
|
6
|
+
# 专门用于解析和处理 iOS 项目的 config.json 配置文件
|
|
7
|
+
#
|
|
8
|
+
# 使用示例:
|
|
9
|
+
# parser = Pindo::IosConfigParser.instance
|
|
10
|
+
# parser.load_config(config_file: 'path/to/config.json')
|
|
11
|
+
#
|
|
12
|
+
# # 获取 Apple ID
|
|
13
|
+
# apple_id = parser.apple_id
|
|
14
|
+
#
|
|
15
|
+
# # 获取 Bundle ID 映射
|
|
16
|
+
# bundle_id_map = parser.get_bundle_id_map
|
|
17
|
+
#
|
|
18
|
+
# # 命令行参数覆盖
|
|
19
|
+
# parser.override_apple_id('custom@apple.com')
|
|
20
|
+
# parser.override_bundle_id('com.example.app')
|
|
21
|
+
class IosConfigParser
|
|
22
|
+
include Singleton
|
|
23
|
+
|
|
24
|
+
attr_reader :config_file_path, :config_json
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@config_file_path = nil
|
|
28
|
+
@config_json = nil
|
|
29
|
+
@config_data = {}
|
|
30
|
+
@overrides = {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# 加载配置文件
|
|
34
|
+
# @param config_file [String] config.json 文件路径
|
|
35
|
+
# @raise [StandardError] 文件不存在或格式错误
|
|
36
|
+
def load_config(config_file:)
|
|
37
|
+
unless File.exist?(config_file)
|
|
38
|
+
raise "配置文件不存在: #{config_file}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@config_file_path = File.expand_path(config_file)
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
@config_json = JSON.parse(File.read(@config_file_path))
|
|
45
|
+
rescue JSON::ParserError => e
|
|
46
|
+
raise "配置文件格式错误: #{e.message}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# 解析配置
|
|
50
|
+
parse_config_data
|
|
51
|
+
|
|
52
|
+
# 检查配置版本
|
|
53
|
+
check_config_version
|
|
54
|
+
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# 重新加载配置文件
|
|
59
|
+
def reload
|
|
60
|
+
return unless @config_file_path
|
|
61
|
+
load_config(config_file: @config_file_path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# 清除所有配置和覆盖
|
|
65
|
+
def clear
|
|
66
|
+
@config_file_path = nil
|
|
67
|
+
@config_json = nil
|
|
68
|
+
@config_data = {}
|
|
69
|
+
@overrides = {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# ==================== 账号信息 ====================
|
|
73
|
+
|
|
74
|
+
# 获取 Apple ID
|
|
75
|
+
# @return [String, nil] Apple 账号 ID
|
|
76
|
+
def apple_id
|
|
77
|
+
@overrides[:apple_id] || @config_data[:apple_id]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# 覆盖 Apple ID(命令行参数)
|
|
81
|
+
# @param value [String] Apple ID
|
|
82
|
+
def override_apple_id(value)
|
|
83
|
+
@overrides[:apple_id] = value if value && !value.empty?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# 获取公司名称
|
|
87
|
+
# @return [String, nil] 公司名称
|
|
88
|
+
def company_name
|
|
89
|
+
@overrides[:company_name] || @config_data[:company_name]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# 覆盖公司名称
|
|
93
|
+
# @param value [String] 公司名称
|
|
94
|
+
def override_company_name(value)
|
|
95
|
+
@overrides[:company_name] = value if value && !value.empty?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# ==================== Bundle ID 信息 ====================
|
|
99
|
+
|
|
100
|
+
# 获取主应用 Bundle ID
|
|
101
|
+
# @return [String, nil] Bundle ID
|
|
102
|
+
def bundle_id
|
|
103
|
+
@overrides[:bundle_id] || @config_data[:bundle_id]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# 覆盖主应用 Bundle ID(命令行参数)
|
|
107
|
+
# @param value [String] Bundle ID
|
|
108
|
+
def override_bundle_id(value)
|
|
109
|
+
@overrides[:bundle_id] = value if value && !value.empty?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# 获取 Push Content Extension Bundle ID
|
|
113
|
+
# @return [String, nil]
|
|
114
|
+
def bundle_id_pushcontent
|
|
115
|
+
@config_data[:bundle_id_pushcontent]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# 获取 Push Service Extension Bundle ID
|
|
119
|
+
# @return [String, nil]
|
|
120
|
+
def bundle_id_pushservice
|
|
121
|
+
@config_data[:bundle_id_pushservice]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# 获取 Keyboard Extension Bundle ID
|
|
125
|
+
# @return [String, nil]
|
|
126
|
+
def bundle_id_keyboard
|
|
127
|
+
@config_data[:bundle_id_keyboard]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# 获取 iMessage Extension Bundle ID
|
|
131
|
+
# @return [String, nil]
|
|
132
|
+
def bundle_id_imessage
|
|
133
|
+
@config_data[:bundle_id_imessage]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# 获取通用 Extension Bundle ID
|
|
137
|
+
# @return [String, nil]
|
|
138
|
+
def bundle_id_extension
|
|
139
|
+
@config_data[:bundle_id_extension]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# 获取 Siri Extension Bundle ID
|
|
143
|
+
# @return [String, nil]
|
|
144
|
+
def bundle_id_siri
|
|
145
|
+
@config_data[:bundle_id_siri]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# 获取 Siri UI Extension Bundle ID
|
|
149
|
+
# @return [String, nil]
|
|
150
|
+
def bundle_id_siriui
|
|
151
|
+
@config_data[:bundle_id_siriui]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# 获取 Widget Extension Bundle ID
|
|
155
|
+
# @return [String, nil]
|
|
156
|
+
def bundle_id_widget
|
|
157
|
+
@config_data[:bundle_id_widget]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# 获取广告 Extension Bundle ID
|
|
161
|
+
# @return [String, nil]
|
|
162
|
+
def bundle_id_extensionad
|
|
163
|
+
@config_data[:bundle_id_extensionad]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# 获取 Porn Extension Bundle ID
|
|
167
|
+
# @return [String, nil]
|
|
168
|
+
def bundle_id_extensionporn
|
|
169
|
+
@config_data[:bundle_id_extensionporn]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# 获取 Watch App Bundle ID
|
|
173
|
+
# @return [String, nil]
|
|
174
|
+
def bundle_id_watchapp
|
|
175
|
+
@config_data[:bundle_id_watchapp]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# 获取 Watch App Extension Bundle ID
|
|
179
|
+
# @return [String, nil]
|
|
180
|
+
def bundle_id_watchapp_extension
|
|
181
|
+
@config_data[:bundle_id_watchapp_extension]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# 获取所有 Bundle ID 的映射
|
|
185
|
+
# @return [Hash] Bundle ID 映射,键为类型,值为 Bundle ID
|
|
186
|
+
# @example
|
|
187
|
+
# {
|
|
188
|
+
# "bundle_id" => "com.example.app",
|
|
189
|
+
# "bundle_id_pushcontent" => "com.example.app.content",
|
|
190
|
+
# "bundle_id_pushservice" => "com.example.app.service",
|
|
191
|
+
# ...
|
|
192
|
+
# }
|
|
193
|
+
def get_bundle_id_map
|
|
194
|
+
{
|
|
195
|
+
"bundle_id" => bundle_id,
|
|
196
|
+
"bundle_id_pushcontent" => bundle_id_pushcontent,
|
|
197
|
+
"bundle_id_pushservice" => bundle_id_pushservice,
|
|
198
|
+
"bundle_id_keyboard" => bundle_id_keyboard,
|
|
199
|
+
"bundle_id_imessage" => bundle_id_imessage,
|
|
200
|
+
"bundle_id_extension" => bundle_id_extension,
|
|
201
|
+
"bundle_id_siri" => bundle_id_siri,
|
|
202
|
+
"bundle_id_siriui" => bundle_id_siriui,
|
|
203
|
+
"bundle_id_widget" => bundle_id_widget,
|
|
204
|
+
"bundle_id_extensionad" => bundle_id_extensionad,
|
|
205
|
+
"bundle_id_extensionporn" => bundle_id_extensionporn,
|
|
206
|
+
"bundle_id_watchapp" => bundle_id_watchapp,
|
|
207
|
+
"bundle_id_watchapp_extension" => bundle_id_watchapp_extension
|
|
208
|
+
}.compact
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# 获取 Bundle ID 数组(去除 nil 值)
|
|
212
|
+
# @return [Array<String>] Bundle ID 数组
|
|
213
|
+
def get_bundle_id_array
|
|
214
|
+
get_bundle_id_map.values
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# ==================== App Group 和 iCloud ====================
|
|
218
|
+
|
|
219
|
+
# 获取 App Group ID
|
|
220
|
+
# @return [String, nil]
|
|
221
|
+
def group_id
|
|
222
|
+
@config_data[:group_id]
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# 获取 iCloud Container ID
|
|
226
|
+
# @return [String, nil]
|
|
227
|
+
def icloud_id
|
|
228
|
+
@config_data[:icloud_id]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# ==================== 应用信息 ====================
|
|
232
|
+
|
|
233
|
+
# 获取应用名称
|
|
234
|
+
# @return [String, nil]
|
|
235
|
+
def app_name
|
|
236
|
+
@config_data[:app_name]
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# 获取应用版本
|
|
240
|
+
# @return [String, nil]
|
|
241
|
+
def app_version
|
|
242
|
+
@config_data[:app_version]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# 获取 App ID (Apple Store Connect)
|
|
246
|
+
# @return [String, nil]
|
|
247
|
+
def app_id_ios
|
|
248
|
+
@config_data[:app_id_ios]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# ==================== 项目信息 ====================
|
|
252
|
+
|
|
253
|
+
# 获取项目名称
|
|
254
|
+
# @return [String, nil]
|
|
255
|
+
def project_name
|
|
256
|
+
@config_data[:project_name]
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# 获取 Xcode 构建类型
|
|
260
|
+
# @return [String, nil]
|
|
261
|
+
def xcode_build_type
|
|
262
|
+
@config_data[:xcode_build_type]
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# 获取 iOS 部署目标版本
|
|
266
|
+
# @return [String, nil]
|
|
267
|
+
def ios_deployment_target
|
|
268
|
+
@config_data[:ios_deployment_target]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# ==================== 配置验证 ====================
|
|
272
|
+
|
|
273
|
+
# 验证必需的配置项是否存在
|
|
274
|
+
# @param required_keys [Array<Symbol>] 必需的配置键
|
|
275
|
+
# @raise [StandardError] 缺少必需配置
|
|
276
|
+
def validate_required(*required_keys)
|
|
277
|
+
missing_keys = []
|
|
278
|
+
|
|
279
|
+
required_keys.each do |key|
|
|
280
|
+
value = send(key) rescue nil
|
|
281
|
+
missing_keys << key if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
unless missing_keys.empty?
|
|
285
|
+
raise "配置文件缺少必需项: #{missing_keys.join(', ')}"
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# 检查配置是否已加载
|
|
290
|
+
# @return [Boolean]
|
|
291
|
+
def loaded?
|
|
292
|
+
!@config_json.nil?
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# ==================== 调试和信息 ====================
|
|
296
|
+
|
|
297
|
+
# 打印所有配置信息(用于调试)
|
|
298
|
+
def print_config_info
|
|
299
|
+
puts "\n" + "=" * 80
|
|
300
|
+
puts "iOS 配置信息"
|
|
301
|
+
puts "=" * 80
|
|
302
|
+
puts "配置文件: #{@config_file_path}"
|
|
303
|
+
puts
|
|
304
|
+
puts "【账号信息】"
|
|
305
|
+
puts " Apple ID: #{apple_id}"
|
|
306
|
+
puts " Company Name: #{company_name}"
|
|
307
|
+
puts
|
|
308
|
+
puts "【应用信息】"
|
|
309
|
+
puts " App Name: #{app_name}"
|
|
310
|
+
puts " App Version: #{app_version}"
|
|
311
|
+
puts " App ID (iOS): #{app_id_ios}"
|
|
312
|
+
puts
|
|
313
|
+
puts "【Bundle ID】"
|
|
314
|
+
puts " Main App: #{bundle_id}"
|
|
315
|
+
get_bundle_id_map.each do |type, id|
|
|
316
|
+
next if type == "bundle_id"
|
|
317
|
+
puts " #{type}: #{id}"
|
|
318
|
+
end
|
|
319
|
+
puts
|
|
320
|
+
puts "【App Group & iCloud】"
|
|
321
|
+
puts " Group ID: #{group_id}"
|
|
322
|
+
puts " iCloud ID: #{icloud_id}"
|
|
323
|
+
puts
|
|
324
|
+
puts "【项目信息】"
|
|
325
|
+
puts " Project Name: #{project_name}"
|
|
326
|
+
puts " Xcode Build Type: #{xcode_build_type}"
|
|
327
|
+
puts " iOS Deployment Target: #{ios_deployment_target}"
|
|
328
|
+
puts "=" * 80
|
|
329
|
+
puts
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
private
|
|
333
|
+
|
|
334
|
+
# 解析配置数据
|
|
335
|
+
def parse_config_data
|
|
336
|
+
return unless @config_json
|
|
337
|
+
|
|
338
|
+
# 解析账号信息
|
|
339
|
+
if @config_json['account_info']
|
|
340
|
+
account_info = @config_json['account_info']
|
|
341
|
+
@config_data[:apple_id] = account_info['apple_acount_id']
|
|
342
|
+
@config_data[:company_name] = account_info['acount_company_name']
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# 解析应用信息
|
|
346
|
+
if @config_json['app_info']
|
|
347
|
+
app_info = @config_json['app_info']
|
|
348
|
+
@config_data[:bundle_id] = app_info['app_identifier']
|
|
349
|
+
@config_data[:bundle_id_pushcontent] = app_info['app_identifier_pushcontent']
|
|
350
|
+
@config_data[:bundle_id_pushservice] = app_info['app_identifier_pushservice']
|
|
351
|
+
@config_data[:bundle_id_keyboard] = app_info['app_identifier_keyboard']
|
|
352
|
+
@config_data[:bundle_id_imessage] = app_info['app_identifier_imessage']
|
|
353
|
+
@config_data[:bundle_id_extension] = app_info['app_identifier_extension']
|
|
354
|
+
@config_data[:bundle_id_siri] = app_info['app_identifier_siri']
|
|
355
|
+
@config_data[:bundle_id_siriui] = app_info['app_identifier_siriui']
|
|
356
|
+
@config_data[:bundle_id_widget] = app_info['app_identifier_widget']
|
|
357
|
+
@config_data[:bundle_id_extensionad] = app_info['app_identifier_extensionad']
|
|
358
|
+
@config_data[:bundle_id_extensionporn] = app_info['app_identifier_extensionporn']
|
|
359
|
+
@config_data[:bundle_id_watchapp] = app_info['app_identifier_watchapp']
|
|
360
|
+
@config_data[:bundle_id_watchapp_extension] = app_info['app_identifier_watchapp_extension']
|
|
361
|
+
|
|
362
|
+
@config_data[:app_name] = app_info['app_name']
|
|
363
|
+
@config_data[:app_version] = app_info['app_version']
|
|
364
|
+
@config_data[:app_id_ios] = app_info['app_id_ios']
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# 解析 App Setting
|
|
368
|
+
if @config_json['app_setting']
|
|
369
|
+
app_setting = @config_json['app_setting']
|
|
370
|
+
@config_data[:group_id] = app_setting['app_group_id']
|
|
371
|
+
@config_data[:icloud_id] = app_setting['app_icloud_id']
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# 解析项目信息
|
|
375
|
+
if @config_json['project_info']
|
|
376
|
+
project_info = @config_json['project_info']
|
|
377
|
+
@config_data[:project_name] = project_info['project_name']
|
|
378
|
+
@config_data[:xcode_build_type] = project_info['xcode_build_type']
|
|
379
|
+
@config_data[:ios_deployment_target] = project_info['ios_deployment_targe'] # 注意:原配置中是 targe 而不是 target
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# 检查配置版本
|
|
384
|
+
def check_config_version
|
|
385
|
+
return unless @config_json
|
|
386
|
+
return unless @config_json['app_info']
|
|
387
|
+
return unless @config_json['app_info']['app_config_version']
|
|
388
|
+
|
|
389
|
+
require_relative '../base/funlog'
|
|
390
|
+
|
|
391
|
+
remote_version = @config_json['app_info']['app_config_version'].to_s
|
|
392
|
+
project_dir = File.dirname(@config_file_path)
|
|
393
|
+
local_version_file = File.join(project_dir, ".app_config_version")
|
|
394
|
+
|
|
395
|
+
if File.exist?(local_version_file)
|
|
396
|
+
local_version = File.read(local_version_file).strip
|
|
397
|
+
if local_version != remote_version
|
|
398
|
+
Funlog.instance.fancyinfo_warning("配置版本不匹配!本地: #{local_version}, 远程: #{remote_version}")
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
end
|
|
404
|
+
end
|