pindo 5.7.1 → 5.8.0
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/funlog.rb +41 -0
- data/lib/pindo/command/android/autobuild.rb +22 -51
- data/lib/pindo/command/android/build.rb +4 -16
- data/lib/pindo/command/android/debug.rb +4 -16
- data/lib/pindo/command/ios/adhoc.rb +4 -27
- data/lib/pindo/command/ios/autobuild.rb +27 -51
- data/lib/pindo/command/ios/build.rb +4 -23
- data/lib/pindo/module/android/android_build_config_helper.rb +142 -21
- data/lib/pindo/module/android/androidreshelper.rb +176 -0
- data/lib/pindo/module/android/apk_helper.rb +19 -4
- data/lib/pindo/module/android/gradle_helper.rb +2 -108
- data/lib/pindo/module/build/buildhelper.rb +2 -2
- data/lib/pindo/module/pgyer/pgyerhelper.rb +1 -1
- data/lib/pindo/module/unity/nugethelper.rb +71 -1
- data/lib/pindo/module/xcode/xcodebuildconfig.rb +101 -83
- data/lib/pindo/version.rb +1 -1
- metadata +3 -2
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'pindo/base/executable'
|
|
4
|
+
require_relative '../../base/funlog'
|
|
5
|
+
|
|
6
|
+
module Pindo
|
|
7
|
+
|
|
8
|
+
module AndroidResHelper
|
|
9
|
+
extend Pindo::Executable
|
|
10
|
+
executable :sips
|
|
11
|
+
|
|
12
|
+
# Android icon 各密度尺寸定义
|
|
13
|
+
ANDROID_ICON_DENSITIES = {
|
|
14
|
+
'mdpi' => 48,
|
|
15
|
+
'hdpi' => 72,
|
|
16
|
+
'xhdpi' => 96,
|
|
17
|
+
'xxhdpi' => 144,
|
|
18
|
+
'xxxhdpi' => 192
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
# 创建单个密度的Android icon(同时生成方形和圆形命名)
|
|
22
|
+
# @param icon_name [String] 原始icon路径
|
|
23
|
+
# @param new_icon_dir [String] 输出目录
|
|
24
|
+
# @param density [String] 密度名称(mdpi, hdpi等)
|
|
25
|
+
# @param size [Integer] 图标尺寸
|
|
26
|
+
# @return [Hash] 生成的图标路径,失败返回nil
|
|
27
|
+
def self.create_icon_for_density(icon_name:nil, new_icon_dir:nil, density:nil, size:nil)
|
|
28
|
+
unless File.exist?(icon_name)
|
|
29
|
+
Funlog.instance.fancyinfo_error("文件不存在: #{icon_name}")
|
|
30
|
+
return nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
density_dir = File.join(new_icon_dir, "mipmap-#{density}")
|
|
35
|
+
FileUtils.mkdir_p(density_dir)
|
|
36
|
+
|
|
37
|
+
result = {}
|
|
38
|
+
|
|
39
|
+
# 生成两个文件:ic_launcher.png 和 ic_launcher_round.png
|
|
40
|
+
# 注意:两个都是方形,不切圆角,只是文件名不同
|
|
41
|
+
['ic_launcher.png', 'ic_launcher_round.png'].each do |filename|
|
|
42
|
+
output_path = File.join(density_dir, filename)
|
|
43
|
+
|
|
44
|
+
command = [
|
|
45
|
+
'sips',
|
|
46
|
+
'--matchTo', '/System/Library/ColorSync/Profiles/sRGB Profile.icc',
|
|
47
|
+
'-z', size.to_s, size.to_s,
|
|
48
|
+
icon_name,
|
|
49
|
+
'--out', output_path
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
Executable.capture_command('sips', command, capture: :out)
|
|
53
|
+
|
|
54
|
+
unless File.exist?(output_path)
|
|
55
|
+
Funlog.instance.fancyinfo_error("生成icon失败: #{output_path}")
|
|
56
|
+
return nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
result[filename] = output_path
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return result
|
|
63
|
+
rescue => e
|
|
64
|
+
Funlog.instance.fancyinfo_error("生成#{density}密度icon时出错: #{e.message}")
|
|
65
|
+
return nil
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# 创建所有密度的Android icons
|
|
70
|
+
# @param icon_name [String] 原始icon路径(建议512x512或1024x1024)
|
|
71
|
+
# @param new_icon_dir [String] 输出目录
|
|
72
|
+
# @return [Hash] 所有生成的图标路径,按密度分组,失败返回nil
|
|
73
|
+
def self.create_icons(icon_name:nil, new_icon_dir:nil)
|
|
74
|
+
unless File.exist?(icon_name)
|
|
75
|
+
Funlog.instance.fancyinfo_error("文件不存在: #{icon_name}")
|
|
76
|
+
return nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
begin
|
|
80
|
+
FileUtils.mkdir_p(new_icon_dir)
|
|
81
|
+
rescue => e
|
|
82
|
+
Funlog.instance.fancyinfo_error("创建输出目录失败: #{e.message}")
|
|
83
|
+
return nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
all_icons = {}
|
|
87
|
+
success_count = 0
|
|
88
|
+
|
|
89
|
+
ANDROID_ICON_DENSITIES.each do |density, size|
|
|
90
|
+
icons = create_icon_for_density(
|
|
91
|
+
icon_name: icon_name,
|
|
92
|
+
new_icon_dir: new_icon_dir,
|
|
93
|
+
density: density,
|
|
94
|
+
size: size
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if icons
|
|
98
|
+
all_icons[density] = icons
|
|
99
|
+
success_count += 1
|
|
100
|
+
else
|
|
101
|
+
Funlog.instance.fancyinfo_error("#{density}密度icon生成失败,跳过")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# 如果所有密度都失败了,返回 nil
|
|
106
|
+
return success_count > 0 ? all_icons : nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# 安装Android icon到项目中
|
|
110
|
+
# @param proj_dir [String] Android项目目录
|
|
111
|
+
# @param new_icon_dir [String] icon文件目录(包含各密度文件夹)
|
|
112
|
+
# @return [Boolean] 是否成功安装
|
|
113
|
+
def self.install_icon(proj_dir:nil, new_icon_dir:nil)
|
|
114
|
+
unless proj_dir && File.directory?(proj_dir)
|
|
115
|
+
Funlog.instance.fancyinfo_error("项目目录不存在: #{proj_dir}")
|
|
116
|
+
return false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
unless new_icon_dir && File.directory?(new_icon_dir)
|
|
120
|
+
Funlog.instance.fancyinfo_error("Icon目录不存在: #{new_icon_dir}")
|
|
121
|
+
return false
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
begin
|
|
125
|
+
# 查找 res 目录(支持 app/src/main/res 和 unityLibrary/src/main/res)
|
|
126
|
+
possible_res_dirs = [
|
|
127
|
+
File.join(proj_dir, "app/src/main/res"),
|
|
128
|
+
File.join(proj_dir, "unityLibrary/src/main/res")
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
res_dir = possible_res_dirs.find { |dir| File.directory?(dir) }
|
|
132
|
+
|
|
133
|
+
unless res_dir
|
|
134
|
+
Funlog.instance.fancyinfo_error("未找到Android res目录,检查的路径:\n#{possible_res_dirs.join("\n")}")
|
|
135
|
+
return false
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
success_count = 0
|
|
139
|
+
total_files = 0
|
|
140
|
+
|
|
141
|
+
ANDROID_ICON_DENSITIES.keys.each do |density|
|
|
142
|
+
source_dir = File.join(new_icon_dir, "mipmap-#{density}")
|
|
143
|
+
target_dir = File.join(res_dir, "mipmap-#{density}")
|
|
144
|
+
|
|
145
|
+
next unless File.directory?(source_dir)
|
|
146
|
+
|
|
147
|
+
# 创建目标目录
|
|
148
|
+
FileUtils.mkdir_p(target_dir) unless File.directory?(target_dir)
|
|
149
|
+
|
|
150
|
+
# 复制两个图标文件
|
|
151
|
+
['ic_launcher.png', 'ic_launcher_round.png'].each do |filename|
|
|
152
|
+
source_file = File.join(source_dir, filename)
|
|
153
|
+
target_file = File.join(target_dir, filename)
|
|
154
|
+
|
|
155
|
+
if File.exist?(source_file)
|
|
156
|
+
FileUtils.cp(source_file, target_file)
|
|
157
|
+
success_count += 1
|
|
158
|
+
total_files += 1
|
|
159
|
+
puts " ✓ 已安装 mipmap-#{density}/#{filename}"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
puts "\n总计安装 #{success_count}/#{total_files} 个图标文件"
|
|
165
|
+
|
|
166
|
+
return success_count > 0
|
|
167
|
+
rescue => e
|
|
168
|
+
Funlog.instance.fancyinfo_error("安装icon时出错: #{e.message}")
|
|
169
|
+
puts e.backtrace
|
|
170
|
+
return false
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
@@ -80,9 +80,15 @@ module Pindo
|
|
|
80
80
|
# 构建 APK
|
|
81
81
|
# 确保使用正确的 Java 版本 (Java 11+)
|
|
82
82
|
java_cmd = find_java_command
|
|
83
|
-
|
|
83
|
+
|
|
84
|
+
# 验证 Java 版本
|
|
85
|
+
unless verify_java_version(java_cmd)
|
|
86
|
+
raise RuntimeError, "Java 版本不符合要求,bundletool 需要 Java 11+,当前使用的 Java: #{java_cmd}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# 使用数组形式构建命令,正确处理包含空格的路径
|
|
84
90
|
bundletool_cmd = [
|
|
85
|
-
|
|
91
|
+
java_cmd, "-jar", bundle_tool, "build-apks",
|
|
86
92
|
"--bundle=#{paths[:bundle]}",
|
|
87
93
|
"--output=#{paths[:output_apks]}",
|
|
88
94
|
"--ks=#{ks}",
|
|
@@ -90,9 +96,18 @@ module Pindo
|
|
|
90
96
|
"--ks-key-alias=#{key_alias}",
|
|
91
97
|
"--key-pass=pass:#{key_pass}",
|
|
92
98
|
"--mode=universal"
|
|
93
|
-
]
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
# 验证关键文件是否存在
|
|
102
|
+
unless File.exist?(paths[:bundle])
|
|
103
|
+
raise RuntimeError, "AAB 文件不存在: #{paths[:bundle]}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
unless File.exist?(ks)
|
|
107
|
+
raise RuntimeError, "Keystore 文件不存在"
|
|
108
|
+
end
|
|
94
109
|
|
|
95
|
-
unless system(bundletool_cmd)
|
|
110
|
+
unless system(*bundletool_cmd)
|
|
96
111
|
# 检查是否是 Java 版本问题
|
|
97
112
|
if java_cmd == 'java'
|
|
98
113
|
raise RuntimeError, "APKS 构建失败。可能是 Java 版本不兼容,bundletool 需要 Java 11+,请检查 JAVA_HOME 环境变量或安装正确的 Java 版本"
|
|
@@ -7,8 +7,6 @@ module Pindo
|
|
|
7
7
|
module GradleHelper
|
|
8
8
|
include BaseAndroidHelper
|
|
9
9
|
|
|
10
|
-
# 常量定义
|
|
11
|
-
RECOMMENDED_GRADLE_VERSION = '7.6.4'
|
|
12
10
|
|
|
13
11
|
# Gradle缓存目录
|
|
14
12
|
GRADLE_CACHE_DIR = File.expand_path("~/.pindo/pindo_common_config/android_tools/gradle-cache")
|
|
@@ -52,51 +50,8 @@ module Pindo
|
|
|
52
50
|
end
|
|
53
51
|
|
|
54
52
|
def update_gradle_version(project_path)
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
unless File.exist?(wrapper_path)
|
|
59
|
-
puts "\e[33m⚠ 未找到gradle-wrapper.properties文件,跳过版本更新\e[0m"
|
|
60
|
-
return false
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
content = File.read(wrapper_path)
|
|
64
|
-
original_content = content.dup
|
|
65
|
-
|
|
66
|
-
# 解析当前版本
|
|
67
|
-
current_version = parse_gradle_version(wrapper_path)
|
|
68
|
-
if current_version.nil?
|
|
69
|
-
puts "\e[33m⚠ 无法解析当前Gradle版本\e[0m"
|
|
70
|
-
return false
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
puts "当前Gradle版本: #{current_version}"
|
|
74
|
-
|
|
75
|
-
# 根据当前版本智能选择目标版本
|
|
76
|
-
target_version = determine_target_gradle_version(current_version)
|
|
77
|
-
|
|
78
|
-
if target_version == current_version
|
|
79
|
-
puts "\e[32m✓ Gradle版本已是最新,无需更新\e[0m"
|
|
80
|
-
return true
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
puts "更新Gradle版本: #{current_version} -> #{target_version}"
|
|
84
|
-
|
|
85
|
-
# 更新版本
|
|
86
|
-
content.gsub!("gradle-#{current_version}-bin.zip", "gradle-#{target_version}-bin.zip")
|
|
87
|
-
content.gsub!("gradleVersion=#{current_version}", "gradleVersion=#{target_version}")
|
|
88
|
-
|
|
89
|
-
if content != original_content
|
|
90
|
-
File.write(wrapper_path, content)
|
|
91
|
-
puts "\e[32m✓ Gradle版本更新完成\e[0m"
|
|
92
|
-
|
|
93
|
-
# 重新配置gradle wrapper
|
|
94
|
-
setup_gradle_wrapper_from_properties(project_path)
|
|
95
|
-
return true
|
|
96
|
-
else
|
|
97
|
-
puts "\e[33m⚠ Gradle版本更新失败,未找到匹配的版本字符串\e[0m"
|
|
98
|
-
return false
|
|
99
|
-
end
|
|
53
|
+
# 直接调用setup_gradle_wrapper_from_properties,功能相同
|
|
54
|
+
setup_gradle_wrapper_from_properties(project_path)
|
|
100
55
|
end
|
|
101
56
|
|
|
102
57
|
# 基于gradle-wrapper.properties自动配置gradle工具
|
|
@@ -128,28 +83,6 @@ module Pindo
|
|
|
128
83
|
end
|
|
129
84
|
end
|
|
130
85
|
|
|
131
|
-
# 检查gradle wrapper配置是否完整
|
|
132
|
-
def verify_gradle_wrapper_setup(project_path)
|
|
133
|
-
wrapper_dir = File.join(project_path, "gradle/wrapper")
|
|
134
|
-
wrapper_jar_path = File.join(wrapper_dir, "gradle-wrapper.jar")
|
|
135
|
-
gradlew_path = File.join(project_path, "gradlew")
|
|
136
|
-
properties_path = File.join(wrapper_dir, "gradle-wrapper.properties")
|
|
137
|
-
|
|
138
|
-
all_exist = File.exist?(wrapper_jar_path) &&
|
|
139
|
-
File.exist?(gradlew_path) &&
|
|
140
|
-
File.exist?(properties_path)
|
|
141
|
-
|
|
142
|
-
if all_exist
|
|
143
|
-
puts "\e[32m✓ Gradle Wrapper配置完整\e[0m"
|
|
144
|
-
return true
|
|
145
|
-
else
|
|
146
|
-
puts "\e[33m⚠ Gradle Wrapper配置不完整:\e[0m"
|
|
147
|
-
puts " gradle-wrapper.jar: #{File.exist?(wrapper_jar_path) ? '✓' : '✗'}"
|
|
148
|
-
puts " gradlew: #{File.exist?(gradlew_path) ? '✓' : '✗'}"
|
|
149
|
-
puts " gradle-wrapper.properties: #{File.exist?(properties_path) ? '✓' : '✗'}"
|
|
150
|
-
return false
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
86
|
|
|
154
87
|
private
|
|
155
88
|
|
|
@@ -170,21 +103,6 @@ module Pindo
|
|
|
170
103
|
nil
|
|
171
104
|
end
|
|
172
105
|
|
|
173
|
-
# 根据当前版本确定目标版本
|
|
174
|
-
def determine_target_gradle_version(current_version)
|
|
175
|
-
# 主版本号匹配
|
|
176
|
-
major_version = current_version.split('.').first.to_i
|
|
177
|
-
case major_version
|
|
178
|
-
when 0..6
|
|
179
|
-
return RECOMMENDED_GRADLE_VERSION # 旧版本升级到推荐版本
|
|
180
|
-
when 7
|
|
181
|
-
return current_version # 已经是7.x,保持当前版本
|
|
182
|
-
when 8
|
|
183
|
-
return current_version # 已经是8.x,保持当前版本
|
|
184
|
-
else
|
|
185
|
-
return RECOMMENDED_GRADLE_VERSION # 默认升级到推荐版本
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
106
|
|
|
189
107
|
# 简化的Gradle Wrapper生成策略
|
|
190
108
|
def setup_gradle_wrapper_improved(project_path, gradle_version)
|
|
@@ -296,7 +214,6 @@ module Pindo
|
|
|
296
214
|
|
|
297
215
|
# 简化的curl命令,避免特殊字符问题
|
|
298
216
|
cmd = "curl -L -o '#{output_path}' '#{url}'"
|
|
299
|
-
# puts "执行命令: #{cmd}"
|
|
300
217
|
|
|
301
218
|
if system(cmd)
|
|
302
219
|
puts "✓ curl下载成功: #{File.size(output_path)} 字节"
|
|
@@ -340,31 +257,12 @@ module Pindo
|
|
|
340
257
|
|
|
341
258
|
# 设置Gradle环境变量
|
|
342
259
|
def setup_gradle_environment(gradle_home)
|
|
343
|
-
puts "设置Gradle环境变量..."
|
|
344
|
-
|
|
345
260
|
# 直接检查gradle可执行文件
|
|
346
261
|
gradle_bin_dir = File.join(gradle_home, "bin")
|
|
347
262
|
gradle_executable = File.join(gradle_bin_dir, "gradle")
|
|
348
263
|
|
|
349
|
-
puts "检查gradle可执行文件: #{gradle_executable}"
|
|
350
|
-
|
|
351
264
|
unless File.exist?(gradle_executable)
|
|
352
265
|
puts "✗ Gradle可执行文件不存在: #{gradle_executable}"
|
|
353
|
-
# 列出gradle_home目录内容用于调试
|
|
354
|
-
if File.directory?(gradle_home)
|
|
355
|
-
puts "gradle_home目录内容:"
|
|
356
|
-
Dir.entries(gradle_home).each do |entry|
|
|
357
|
-
next if entry.start_with?('.')
|
|
358
|
-
entry_path = File.join(gradle_home, entry)
|
|
359
|
-
if File.directory?(entry_path)
|
|
360
|
-
puts " 目录: #{entry}"
|
|
361
|
-
else
|
|
362
|
-
puts " 文件: #{entry}"
|
|
363
|
-
end
|
|
364
|
-
end
|
|
365
|
-
else
|
|
366
|
-
puts "gradle_home目录不存在: #{gradle_home}"
|
|
367
|
-
end
|
|
368
266
|
return false
|
|
369
267
|
end
|
|
370
268
|
|
|
@@ -373,8 +271,6 @@ module Pindo
|
|
|
373
271
|
ENV['PATH'] = "#{gradle_bin_dir}:#{ENV['PATH']}"
|
|
374
272
|
|
|
375
273
|
puts "✓ Gradle环境变量设置完成"
|
|
376
|
-
puts " GRADLE_HOME: #{ENV['GRADLE_HOME']}"
|
|
377
|
-
puts " PATH已更新: #{gradle_bin_dir}"
|
|
378
274
|
|
|
379
275
|
true
|
|
380
276
|
end
|
|
@@ -384,10 +280,8 @@ module Pindo
|
|
|
384
280
|
Dir.chdir(project_path) do
|
|
385
281
|
# 使用gradle wrapper命令
|
|
386
282
|
cmd = "gradle wrapper"
|
|
387
|
-
# puts "执行命令: #{cmd}"
|
|
388
283
|
|
|
389
284
|
if system(cmd)
|
|
390
|
-
# puts "✓ 官方Gradle命令生成wrapper成功"
|
|
391
285
|
return true
|
|
392
286
|
else
|
|
393
287
|
puts "✗ 官方Gradle命令生成wrapper失败"
|
|
@@ -26,9 +26,9 @@ module Pindo
|
|
|
26
26
|
xcdoe_unitylib_project = Xcodeproj::Project::open(unity_project_path)
|
|
27
27
|
xcdoe_unitylib_project.targets.each do |target|
|
|
28
28
|
if target.name == 'Unity-iPhone'
|
|
29
|
-
target.shell_script_build_phases
|
|
29
|
+
target.shell_script_build_phases&.each do |phase|
|
|
30
30
|
if phase.name.eql?("Crashlytics Run Script")
|
|
31
|
-
target.
|
|
31
|
+
target.build_phases.delete(phase)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
end
|
|
@@ -615,7 +615,7 @@ module Pindo
|
|
|
615
615
|
|
|
616
616
|
projectId = app_info_obj["id"]
|
|
617
617
|
packageId = app_version_info_obj["id"]
|
|
618
|
-
indexNo = app_version_info_obj["
|
|
618
|
+
indexNo = app_version_info_obj["indexNo"]
|
|
619
619
|
|
|
620
620
|
if projectId.nil? || packageId.nil?
|
|
621
621
|
Funlog.instance.fancyinfo_error("缺少必要的项目ID或包ID")
|
|
@@ -164,6 +164,40 @@ module Pindo
|
|
|
164
164
|
# 解析和验证
|
|
165
165
|
# ============================================
|
|
166
166
|
|
|
167
|
+
# 从 package.json 的 author 字段提取作者名称
|
|
168
|
+
# 支持两种格式:
|
|
169
|
+
# 1. 字符串: "Wade"
|
|
170
|
+
# 2. 对象: {"name": "Wade", "email": "wade@example.com"}
|
|
171
|
+
def self.extract_author_name(author_field)
|
|
172
|
+
return 'Unity Package' if author_field.nil?
|
|
173
|
+
|
|
174
|
+
if author_field.is_a?(Hash)
|
|
175
|
+
# 如果是对象,提取 name 字段
|
|
176
|
+
author_name = author_field['name'] || author_field[:name] || 'Unity Package'
|
|
177
|
+
elsif author_field.is_a?(String)
|
|
178
|
+
# 如果是字符串,直接使用
|
|
179
|
+
author_name = author_field
|
|
180
|
+
else
|
|
181
|
+
author_name = 'Unity Package'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# 确保是简单的文本,去除换行和多余空格
|
|
185
|
+
author_name.to_s.strip.gsub(/[\r\n]+/, ' ')
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# 验证 authors 字段格式(必须是简单文本,不能是 JSON)
|
|
189
|
+
def self.validate_authors_format(authors_text)
|
|
190
|
+
return false if authors_text.nil? || authors_text.empty?
|
|
191
|
+
|
|
192
|
+
# 检查是否包含 JSON 特征({, }, :, "name", "email" 等)
|
|
193
|
+
if authors_text.include?('{') || authors_text.include?('}') ||
|
|
194
|
+
authors_text.include?('"name"') || authors_text.include?('"email"')
|
|
195
|
+
return false
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
true
|
|
199
|
+
end
|
|
200
|
+
|
|
167
201
|
# 解析 package.json
|
|
168
202
|
def self.parse_package_json(package_dir)
|
|
169
203
|
file_path = File.join(package_dir, "package.json")
|
|
@@ -238,6 +272,25 @@ module Pindo
|
|
|
238
272
|
unless missing.empty?
|
|
239
273
|
raise Informative, ".nuspec 缺少必需字段: #{missing.join(', ')}"
|
|
240
274
|
end
|
|
275
|
+
|
|
276
|
+
# 验证 authors 字段格式
|
|
277
|
+
if nuspec_info['authors']
|
|
278
|
+
unless validate_authors_format(nuspec_info['authors'])
|
|
279
|
+
raise Informative, <<~ERROR
|
|
280
|
+
.nuspec 文件中的 <authors> 字段格式错误!
|
|
281
|
+
|
|
282
|
+
当前格式: #{nuspec_info['authors']}
|
|
283
|
+
|
|
284
|
+
正确格式应该是简单的文本,例如:
|
|
285
|
+
<authors>Wade</authors>
|
|
286
|
+
|
|
287
|
+
错误格式示例:
|
|
288
|
+
<authors>{"name": "wade","email": "joymaker@unipod.dev"}</authors>
|
|
289
|
+
|
|
290
|
+
请修正 .nuspec 文件中的 authors 字段。
|
|
291
|
+
ERROR
|
|
292
|
+
end
|
|
293
|
+
end
|
|
241
294
|
end
|
|
242
295
|
|
|
243
296
|
# ============================================
|
|
@@ -259,6 +312,23 @@ module Pindo
|
|
|
259
312
|
description = package_info['description'] || package_info['displayName'] || 'Unity Package'
|
|
260
313
|
release_notes = package_info['releaseNotes'] || package_info['changelogUrl'] || 'No release notes'
|
|
261
314
|
|
|
315
|
+
# 提取 author 名称(支持字符串和对象格式)
|
|
316
|
+
author_name = extract_author_name(package_info['author'])
|
|
317
|
+
|
|
318
|
+
# 验证 author 格式
|
|
319
|
+
unless validate_authors_format(author_name)
|
|
320
|
+
raise Informative, <<~ERROR
|
|
321
|
+
package.json 中的 author 字段格式无法转换为有效的 <authors> 格式!
|
|
322
|
+
|
|
323
|
+
当前 author 值: #{package_info['author'].inspect}
|
|
324
|
+
提取的作者名称: #{author_name}
|
|
325
|
+
|
|
326
|
+
请确保 author 字段为以下格式之一:
|
|
327
|
+
1. 字符串: "author": "Wade"
|
|
328
|
+
2. 对象: "author": {"name": "Wade", "email": "wade@example.com"}
|
|
329
|
+
ERROR
|
|
330
|
+
end
|
|
331
|
+
|
|
262
332
|
# 构建基础的 metadata 内容
|
|
263
333
|
metadata_content = []
|
|
264
334
|
metadata_content << " <id>#{nuspec_id}</id>"
|
|
@@ -267,7 +337,7 @@ module Pindo
|
|
|
267
337
|
if package_info['displayName'] && !package_info['displayName'].empty?
|
|
268
338
|
metadata_content << " <title>#{package_info['displayName']}</title>"
|
|
269
339
|
end
|
|
270
|
-
metadata_content << " <authors>#{
|
|
340
|
+
metadata_content << " <authors>#{author_name}</authors>"
|
|
271
341
|
metadata_content << " <requireLicenseAcceptance>false</requireLicenseAcceptance>"
|
|
272
342
|
metadata_content << " <license type=\"expression\">MIT</license>"
|
|
273
343
|
metadata_content << " <projectUrl>#{project_url}</projectUrl>"
|