easyai 1.7.0 → 2.0.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.
@@ -1,258 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'fileutils'
4
- require 'open3'
5
- require 'json'
6
- require 'tmpdir'
7
- require_relative '../base/file_crypto'
8
- require_relative '../base/system_keychain'
9
-
10
- module EasyAI
11
- # EasyAIConfig 类负责配置仓库的下载、更新和文件解密
12
- class EasyAIConfig
13
- REPO_URL = "https://gitee.com/goodtools/EasyAISetting.git"
14
- EASYAI_DIR = File.expand_path('~/.easyai')
15
- CONFIG_REPO_DIR = File.join(EASYAI_DIR, 'EasyAISetting')
16
-
17
- class << self
18
- # 初始化配置仓库
19
- def initialize(options = {})
20
- verbose = options[:verbose] || false
21
- ensure_repo_ready(verbose)
22
- # 确保临时目录存在
23
- @temp_dir ||= File.join(Dir.tmpdir, "easyai_#{Process.pid}")
24
- FileUtils.mkdir_p(@temp_dir) unless Dir.exist?(@temp_dir)
25
- end
26
-
27
- # 核心接口:获取解密后的配置内容
28
- # @param filename [String] 配置文件名
29
- # @param options [Hash] 选项
30
- # @return [Hash, nil] 解密后的配置内容
31
- def get_config(filename, options = {})
32
- return nil unless filename
33
-
34
- ensure_repo_ready(options[:verbose])
35
- filename = normalize_filename(filename)
36
-
37
- # 查找加密文件的实际路径(支持子目录)
38
- encrypted_path = find_encrypted_file(filename)
39
- return nil unless encrypted_path
40
-
41
- # 解密到临时目录
42
- temp_decrypted_path = get_temp_path(filename)
43
-
44
- # 解密文件
45
- return nil unless decrypt_file(encrypted_path, temp_decrypted_path, options[:verbose])
46
-
47
- # 读取并解析配置
48
- result = read_json_file(temp_decrypted_path, options[:verbose])
49
-
50
- # 立即清理临时文件
51
- FileUtils.rm_f(temp_decrypted_path) if File.exist?(temp_decrypted_path)
52
-
53
- result
54
- end
55
-
56
- # 获取配置文件路径(用于需要文件路径的场景)
57
- def get_config_path(filename, options = {})
58
- return nil unless filename
59
-
60
- ensure_repo_ready(options[:verbose])
61
- filename = normalize_filename(filename)
62
-
63
- # 查找加密文件的实际路径(支持子目录)
64
- encrypted_path = find_encrypted_file(filename)
65
- return nil unless encrypted_path
66
-
67
- # 解密到临时目录
68
- temp_decrypted_path = get_temp_path(filename)
69
-
70
- # 解密文件
71
- return nil unless decrypt_file(encrypted_path, temp_decrypted_path, options[:verbose])
72
-
73
- File.exist?(temp_decrypted_path) ? temp_decrypted_path : nil
74
- end
75
-
76
- # 清理所有临时文件
77
- def cleanup(verbose = false)
78
- if @temp_dir && Dir.exist?(@temp_dir)
79
- FileUtils.rm_rf(@temp_dir)
80
- puts "✓ 已清理临时目录" if verbose
81
- end
82
- @temp_dir = nil
83
- end
84
-
85
- private
86
-
87
- # 确保配置仓库就绪
88
- def ensure_repo_ready(verbose = false)
89
- FileUtils.mkdir_p(EASYAI_DIR) unless Dir.exist?(EASYAI_DIR)
90
-
91
- if Dir.exist?(CONFIG_REPO_DIR)
92
- update_repo(verbose)
93
- else
94
- download_repo(verbose)
95
- end
96
-
97
- # 确保临时目录存在
98
- @temp_dir ||= File.join(Dir.tmpdir, "easyai_#{Process.pid}")
99
- FileUtils.mkdir_p(@temp_dir) unless Dir.exist?(@temp_dir)
100
- end
101
-
102
- # 标准化文件名
103
- def normalize_filename(filename)
104
- filename.end_with?('.json') ? filename : "#{filename}.json"
105
- end
106
-
107
- # 查找加密文件(支持子目录)
108
- def find_encrypted_file(filename)
109
- # 直接在根目录查找
110
- root_path = File.join(CONFIG_REPO_DIR, "#{filename}.encrypted")
111
- return root_path if File.exist?(root_path)
112
-
113
- # 在子目录中查找(保持原有路径)
114
- if filename.include?('/')
115
- sub_path = File.join(CONFIG_REPO_DIR, "#{filename}.encrypted")
116
- return sub_path if File.exist?(sub_path)
117
- end
118
-
119
- nil
120
- end
121
-
122
- # 获取临时文件路径
123
- def get_temp_path(filename)
124
- # 保持文件名结构,替换 / 为 _
125
- safe_filename = filename.gsub('/', '_')
126
- File.join(@temp_dir, safe_filename)
127
- end
128
-
129
- # 读取 JSON 文件
130
- def read_json_file(file_path, verbose = false)
131
- return nil unless File.exist?(file_path)
132
-
133
- begin
134
- content = File.read(file_path)
135
- JSON.parse(content)
136
- rescue JSON::ParserError => e
137
- puts "✗ 解析配置文件失败: #{e.message}" if verbose
138
- nil
139
- rescue => e
140
- puts "✗ 读取配置文件失败: #{e.message}" if verbose
141
- nil
142
- end
143
- end
144
-
145
- # 下载配置仓库
146
- def download_repo(verbose = false)
147
- # 根据测试环境变量选择分支
148
- branch = get_target_branch
149
- puts "正在下载配置仓库 (#{branch} 分支)..." if verbose
150
-
151
- cmd = "git clone --depth 1 --branch #{branch} #{REPO_URL} #{CONFIG_REPO_DIR} 2>&1"
152
- _, _, status = Open3.capture3(cmd)
153
-
154
- if status.success?
155
- puts "✓ 配置仓库下载成功 (#{branch} 分支)" if verbose
156
- true
157
- else
158
- puts "✗ 配置仓库下载失败,请检查网络连接" if verbose
159
- false
160
- end
161
- rescue => e
162
- puts "✗ 下载配置仓库失败: #{e.message}" if verbose
163
- false
164
- end
165
-
166
- # 获取目标分支
167
- def get_target_branch
168
- # 检查是否有测试环境变量
169
- if ENV['EASYAI_TEST_PASSWORD'] || ENV['EASYAI_DEV_MODE']
170
- 'dev'
171
- else
172
- 'master'
173
- end
174
- end
175
-
176
- # 更新配置仓库
177
- def update_repo(verbose = false)
178
- return false unless Dir.exist?(CONFIG_REPO_DIR)
179
-
180
- target_branch = get_target_branch
181
-
182
- Dir.chdir(CONFIG_REPO_DIR) do
183
- # 重置本地更改
184
- system("git reset --hard HEAD > /dev/null 2>&1")
185
-
186
- # 获取当前分支
187
- current_branch = `git branch --show-current`.chomp
188
-
189
- # 如果需要切换分支
190
- if current_branch != target_branch
191
- puts "切换到 #{target_branch} 分支..." if verbose
192
- system("git fetch origin #{target_branch} > /dev/null 2>&1")
193
- system("git checkout #{target_branch} > /dev/null 2>&1")
194
- end
195
-
196
- # 拉取最新更新
197
- _, _, status = Open3.capture3("git pull --force 2>&1")
198
-
199
- if status.success?
200
- puts "✓ 配置仓库已更新 (#{target_branch} 分支)" if verbose
201
- else
202
- puts "⚠️ 配置更新失败,使用现有配置" if verbose
203
- end
204
- end
205
- true
206
- rescue => e
207
- puts "⚠️ 更新配置时出错: #{e.message}" if verbose
208
- true
209
- end
210
-
211
- # 解密文件
212
- def decrypt_file(encrypted_path, decrypted_path, verbose = false)
213
- puts "正在解密: #{File.basename(encrypted_path)}..." if verbose
214
-
215
- # 智能密码获取:环境变量 > 系统钥匙串 > 用户输入
216
- password = get_decryption_password(verbose)
217
- return false unless password
218
-
219
- # 使用静态方法解密文件
220
- Base::FileCrypto.decrypt_file(encrypted_path, password[:value], decrypted_path)
221
- File.chmod(0600, decrypted_path)
222
-
223
- # 如果密码来自用户输入且解密成功,保存到钥匙串
224
- if password[:from_user_input]
225
- Base::SystemKeychain.store_password(password[:value])
226
- end
227
-
228
- true
229
- rescue => e
230
- puts "✗ 解密失败: #{e.message}" if verbose
231
- false
232
- end
233
-
234
- # 智能密码获取
235
- def get_decryption_password(verbose = false)
236
- # 1. 优先使用环境变量(用于测试和自动化)
237
- if ENV['EASYAI_TEST_PASSWORD']
238
- puts "使用环境变量密码" if verbose
239
- return { value: ENV['EASYAI_TEST_PASSWORD'], from_user_input: false }
240
- end
241
-
242
- # 2. 尝试从系统钥匙串获取
243
- stored_password = Base::SystemKeychain.get_stored_password
244
- if stored_password && !stored_password.empty?
245
- puts "使用系统存储的密码" if verbose
246
- return { value: stored_password, from_user_input: false }
247
- end
248
-
249
- # 3. 提示用户输入
250
- puts "请输入解密密码(成功后将自动保存)" if verbose
251
- password = Base::FileCrypto.get_password("请输入解密密码: ")
252
- return nil unless password && !password.empty?
253
-
254
- { value: password, from_user_input: true }
255
- end
256
- end
257
- end
258
- end