m-git 2.5.4
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +85 -0
- data/lib/m-git.rb +66 -0
- data/lib/m-git/argv.rb +170 -0
- data/lib/m-git/argv/opt.rb +38 -0
- data/lib/m-git/argv/opt_list.rb +71 -0
- data/lib/m-git/argv/parser.rb +66 -0
- data/lib/m-git/base_command.rb +271 -0
- data/lib/m-git/command/add.rb +41 -0
- data/lib/m-git/command/branch.rb +90 -0
- data/lib/m-git/command/checkout.rb +106 -0
- data/lib/m-git/command/clean.rb +64 -0
- data/lib/m-git/command/commit.rb +84 -0
- data/lib/m-git/command/config.rb +202 -0
- data/lib/m-git/command/delete.rb +99 -0
- data/lib/m-git/command/fetch.rb +32 -0
- data/lib/m-git/command/forall.rb +81 -0
- data/lib/m-git/command/info.rb +74 -0
- data/lib/m-git/command/init.rb +324 -0
- data/lib/m-git/command/log.rb +73 -0
- data/lib/m-git/command/merge.rb +381 -0
- data/lib/m-git/command/pull.rb +364 -0
- data/lib/m-git/command/push.rb +311 -0
- data/lib/m-git/command/rebase.rb +348 -0
- data/lib/m-git/command/reset.rb +31 -0
- data/lib/m-git/command/self.rb +223 -0
- data/lib/m-git/command/stash.rb +189 -0
- data/lib/m-git/command/status.rb +135 -0
- data/lib/m-git/command/sync.rb +327 -0
- data/lib/m-git/command/tag.rb +67 -0
- data/lib/m-git/command_manager.rb +24 -0
- data/lib/m-git/error.rb +20 -0
- data/lib/m-git/foundation.rb +25 -0
- data/lib/m-git/foundation/constants.rb +107 -0
- data/lib/m-git/foundation/dir.rb +25 -0
- data/lib/m-git/foundation/duration_recorder.rb +92 -0
- data/lib/m-git/foundation/git_message_parser.rb +50 -0
- data/lib/m-git/foundation/lock.rb +32 -0
- data/lib/m-git/foundation/loger.rb +129 -0
- data/lib/m-git/foundation/mgit_config.rb +222 -0
- data/lib/m-git/foundation/operation_progress_manager.rb +139 -0
- data/lib/m-git/foundation/timer.rb +74 -0
- data/lib/m-git/foundation/utils.rb +361 -0
- data/lib/m-git/hooks_manager.rb +96 -0
- data/lib/m-git/manifest.rb +181 -0
- data/lib/m-git/manifest/cache_manager.rb +44 -0
- data/lib/m-git/manifest/internal.rb +182 -0
- data/lib/m-git/manifest/light_repo.rb +108 -0
- data/lib/m-git/manifest/light_repo_generator.rb +87 -0
- data/lib/m-git/manifest/linter.rb +153 -0
- data/lib/m-git/open_api.rb +427 -0
- data/lib/m-git/open_api/script_download_info.rb +37 -0
- data/lib/m-git/output/output.rb +461 -0
- data/lib/m-git/plugin_manager.rb +112 -0
- data/lib/m-git/repo.rb +133 -0
- data/lib/m-git/repo/status.rb +481 -0
- data/lib/m-git/repo/sync_helper.rb +254 -0
- data/lib/m-git/template.rb +9 -0
- data/lib/m-git/template/local_manifest.rb +27 -0
- data/lib/m-git/template/manifest_hook.rb +28 -0
- data/lib/m-git/template/post_download_hook.rb +29 -0
- data/lib/m-git/template/post_hook.rb +31 -0
- data/lib/m-git/template/pre_exec_hook.rb +31 -0
- data/lib/m-git/template/pre_hook.rb +29 -0
- data/lib/m-git/template/pre_push_hook.rb +32 -0
- data/lib/m-git/version.rb +6 -0
- data/lib/m-git/workspace.rb +648 -0
- data/lib/m-git/workspace/path_helper.rb +56 -0
- data/lib/m-git/workspace/workspace_helper.rb +159 -0
- data/m-git +1 -0
- data/mgit +19 -0
- metadata +218 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
# 计时器,用于统计指令执行耗时
|
5
|
+
class Timer
|
6
|
+
|
7
|
+
@@time_stamp = {}
|
8
|
+
@@duration = {}
|
9
|
+
@@lock = Mutex.new
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# 开始计时
|
14
|
+
#
|
15
|
+
# @param repo_name [String] 仓库名
|
16
|
+
#
|
17
|
+
# @param use_lock [Boolean] default: false 是否加锁
|
18
|
+
#
|
19
|
+
def start(repo_name, use_lock:false)
|
20
|
+
return if repo_name.nil?
|
21
|
+
mutex_exec(use_lock) {
|
22
|
+
@@time_stamp[repo_name] = Time.new if @@time_stamp[repo_name].nil?
|
23
|
+
@@duration[repo_name] = 0 if @@duration[repo_name].nil?
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
# 停止计时
|
28
|
+
#
|
29
|
+
# @param repo_name [String] 仓库名
|
30
|
+
#
|
31
|
+
# @param use_lock [Boolean] default: false 是否加锁
|
32
|
+
#
|
33
|
+
def stop(repo_name, use_lock:false)
|
34
|
+
return if repo_name.nil?
|
35
|
+
mutex_exec(use_lock) {
|
36
|
+
if !@@time_stamp[repo_name].nil? && !@@duration[repo_name].nil?
|
37
|
+
@@duration[repo_name] += Time.new.to_f - @@time_stamp[repo_name].to_f
|
38
|
+
@@time_stamp[repo_name] = nil
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
# 显示最耗时仓库
|
44
|
+
#
|
45
|
+
# @param threshold [Type] default: 5 耗时提示阈值,时间超过该阈值则将仓库纳入提醒集合
|
46
|
+
#
|
47
|
+
def show_time_consuming_repos(threshold:5)
|
48
|
+
repos = []
|
49
|
+
@@duration.sort_by { |repo_name,seconds| seconds }.reverse.first(5).each { |info|
|
50
|
+
repo_name = info.first
|
51
|
+
seconds = info.last
|
52
|
+
repos.push("[#{seconds.round(2)}s]#{repo_name}") if seconds > threshold
|
53
|
+
}
|
54
|
+
Output.puts_remind_block(repos, "以上为最耗时且耗时超过#{threshold}s的仓库,请自行关注影响速度的原因。") if repos.length > 0
|
55
|
+
end
|
56
|
+
|
57
|
+
# 多线程执行保护
|
58
|
+
#
|
59
|
+
# @param use_lock [Boolean] 执行是否加锁
|
60
|
+
#
|
61
|
+
def mutex_exec(use_lock)
|
62
|
+
if use_lock
|
63
|
+
@@lock.lock
|
64
|
+
yield if block_given?
|
65
|
+
@@lock.unlock
|
66
|
+
else
|
67
|
+
yield if block_given?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,361 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Utils
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def logical_cpu_num
|
8
|
+
if @logical_cpu_num.nil?
|
9
|
+
begin
|
10
|
+
num = `sysctl -n hw.logicalcpu`
|
11
|
+
num = `cat /proc/cpuinfo | grep "processor" | wc -l` unless $?.success?
|
12
|
+
@logical_cpu_num = num
|
13
|
+
rescue Exception => _
|
14
|
+
@logical_cpu_num = "5"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
@logical_cpu_num.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
# ----- Shell指令相关 -----
|
21
|
+
|
22
|
+
# 执行shell指令
|
23
|
+
def execute_shell_cmd(cmd)
|
24
|
+
begin
|
25
|
+
(stdout, stderr, status) = Open3.capture3(cmd)
|
26
|
+
rescue => e
|
27
|
+
puts "\n"
|
28
|
+
Foundation.help!("指令 \"#{cmd}\" 执行异常:#{e.message}")
|
29
|
+
end
|
30
|
+
yield(stdout, stderr, status) if block_given?
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# ----- 目录相关 -----
|
35
|
+
|
36
|
+
# 改变当前路径
|
37
|
+
def change_dir(dir)
|
38
|
+
return if dir == Dir.pwd
|
39
|
+
begin
|
40
|
+
Dir.chdir(dir)
|
41
|
+
rescue => e
|
42
|
+
raise "目录切换失败:#{e.message}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# 在某路径下执行代码
|
47
|
+
def execute_under_dir(dir)
|
48
|
+
origin_dir = Dir.pwd
|
49
|
+
change_dir(dir)
|
50
|
+
yield() if block_given?
|
51
|
+
change_dir(origin_dir)
|
52
|
+
end
|
53
|
+
|
54
|
+
# 计算相对目录
|
55
|
+
#
|
56
|
+
# @param dir_a [String] 目录A,如‘/a/b/A’
|
57
|
+
#
|
58
|
+
# @param dir_b [String] 目录B,如‘/a/c/B’
|
59
|
+
#
|
60
|
+
# @return [String] A目录下文件相对B目录的路径,如‘../../c/B’
|
61
|
+
#
|
62
|
+
def relative_dir(dir_a, dir_b, realpath: true)
|
63
|
+
if realpath
|
64
|
+
(Pathname.new(dir_a).realpath.relative_path_from(Pathname.new(dir_b).realpath)).to_s
|
65
|
+
else
|
66
|
+
(Pathname.new(dir_a).relative_path_from(Pathname.new(dir_b))).to_s
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# 扩展成完整路径
|
71
|
+
#
|
72
|
+
# @param path [String] 路径名
|
73
|
+
#
|
74
|
+
# @param base [Type] default: nil 基准路径
|
75
|
+
#
|
76
|
+
# @return [String] 扩展后的完整路径
|
77
|
+
#
|
78
|
+
def expand_path(path, base:nil)
|
79
|
+
pn = Pathname.new(path)
|
80
|
+
if pn.relative?
|
81
|
+
base = Dir.pwd if base.nil?
|
82
|
+
File.expand_path(File.join(base, path))
|
83
|
+
else
|
84
|
+
path
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# 初始化缓存目录
|
89
|
+
#
|
90
|
+
# @return [String] 目录地址
|
91
|
+
#
|
92
|
+
def generate_init_cache_path(root)
|
93
|
+
temp_dir = ".#{Constants::INIT_CACHE_DIR_NAME}__#{Process.pid}__#{Time.new.to_i.to_s}"
|
94
|
+
File.join(root,temp_dir)
|
95
|
+
end
|
96
|
+
|
97
|
+
# 创建软连接
|
98
|
+
#
|
99
|
+
# @param target_path [String] 目标文件(文件夹)的绝对路径
|
100
|
+
#
|
101
|
+
# @param link_path [String] 软连接所在绝对路径
|
102
|
+
#
|
103
|
+
def link(target_path, link_path)
|
104
|
+
target_relative_path = File.join(relative_dir(File.dirname(target_path), File.dirname(link_path)), File.basename(target_path))
|
105
|
+
FileUtils.symlink(target_relative_path, link_path, force:true)
|
106
|
+
end
|
107
|
+
|
108
|
+
# 显示下载仓库信息
|
109
|
+
#
|
110
|
+
# @param missing_light_repos [Array<LightRepo>] 缺失仓库配置对象
|
111
|
+
#
|
112
|
+
def show_clone_info(root, missing_light_repos)
|
113
|
+
notice_repo = []
|
114
|
+
clone_from_local = []
|
115
|
+
clone_from_remote = []
|
116
|
+
missing_light_repos.each { |light_repo|
|
117
|
+
if Dir.exist?(File.join(light_repo.git_store_dir(root), '.git'))
|
118
|
+
clone_from_local += [light_repo.name]
|
119
|
+
else
|
120
|
+
clone_from_remote += [light_repo.name]
|
121
|
+
end
|
122
|
+
}
|
123
|
+
|
124
|
+
notice_repo.push(['从本地导出', clone_from_local]) if clone_from_local.length > 0
|
125
|
+
notice_repo.push(['从远程下载', clone_from_remote]) if clone_from_remote.length > 0
|
126
|
+
|
127
|
+
puts Output.generate_table_combination(notice_repo, separator: "|")
|
128
|
+
Output.puts_processing_message('以上仓库本地缺失,处理中...')
|
129
|
+
end
|
130
|
+
|
131
|
+
# ----- Git相关 -----
|
132
|
+
|
133
|
+
# 在不拉取仓库的情况下,查询远程仓库是否存在某分支
|
134
|
+
#
|
135
|
+
# @return [Bool] 是否存在分支
|
136
|
+
#
|
137
|
+
def branch_exist_on_remote?(branch, git_url)
|
138
|
+
return false if branch.nil? || git_url.nil?
|
139
|
+
cmd = "git ls-remote --heads #{git_url} | grep \"#{branch}\""
|
140
|
+
execute_shell_cmd(cmd) { |stdout, stderr, status|
|
141
|
+
return status.success?
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
# 在不拉仓库的情况下,查询当前用户是否有权限拉取代码
|
146
|
+
#
|
147
|
+
# @return [Bool] 是否有权限
|
148
|
+
#
|
149
|
+
def has_permission_of_remote?(git_url)
|
150
|
+
return false if git_url.nil?
|
151
|
+
cmd = "git ls-remote --heads #{git_url}"
|
152
|
+
execute_shell_cmd(cmd) { |stdout, stderr, status|
|
153
|
+
return status.success?
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
# 链接.git仓库实体
|
158
|
+
# 1、如果git实体存在,则删除,以当前仓库的.git为主
|
159
|
+
# 2、移动仓库的.git到git实体
|
160
|
+
# 3、软链仓库的.git为git实体
|
161
|
+
#
|
162
|
+
# @param source_dir [String] 源码路径
|
163
|
+
#
|
164
|
+
# @param source_git_dir [String] 存放git实体的路径
|
165
|
+
#
|
166
|
+
#
|
167
|
+
#
|
168
|
+
def link_git(source_dir, source_git_dir)
|
169
|
+
|
170
|
+
# 工作区.git
|
171
|
+
origin_git = File.join(source_dir, '.git')
|
172
|
+
|
173
|
+
# 本地缓存的.git
|
174
|
+
target_git = File.join(source_git_dir, '.git')
|
175
|
+
|
176
|
+
FileUtils.remove_dir(target_git, true) if File.exist?(target_git)
|
177
|
+
FileUtils.mkdir_p(source_git_dir) unless File.exist?(source_git_dir)
|
178
|
+
|
179
|
+
FileUtils.mv(origin_git, source_git_dir)
|
180
|
+
|
181
|
+
# 创建.git软链接
|
182
|
+
link(target_git, origin_git)
|
183
|
+
end
|
184
|
+
|
185
|
+
# 根据url生成git实体存放路径
|
186
|
+
#
|
187
|
+
# @param url [String] 仓库url
|
188
|
+
#
|
189
|
+
# @return [String] .git实体存放地址,生成错误返回nil
|
190
|
+
#
|
191
|
+
def generate_git_store(root, url)
|
192
|
+
return if url.nil?
|
193
|
+
git_dir = File.join(root, Constants::PROJECT_DIR[:source_git])
|
194
|
+
begin
|
195
|
+
url_obj = URI(url)
|
196
|
+
# 去除shceme
|
197
|
+
url_path = File.join("#{url_obj.host}#{url_obj.port.nil? ? '' : ":#{url_obj.port}"}", url_obj.path)
|
198
|
+
# 去除后缀名
|
199
|
+
git_relative_dir = File.join(File.dirname(url_path), File.basename(url_path, File.extname(url_path)))
|
200
|
+
|
201
|
+
File.join(git_dir, git_relative_dir)
|
202
|
+
rescue
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# ----- 工作区同步相关 -----
|
207
|
+
|
208
|
+
# 同步工作区(缓存或弹出)
|
209
|
+
#
|
210
|
+
# @param root [String] mgit管理工程根目录
|
211
|
+
#
|
212
|
+
# @param config [Manifest] 配置对象
|
213
|
+
#
|
214
|
+
# @param recover_cache_if_cancelled [Boolean] 如果回收过程中取消操作,是否恢复缓存
|
215
|
+
# (需要自行判断,如果方法调用前缓存已经覆盖,那么需要恢复以保障下次同步操作正常执行
|
216
|
+
# 如果调用前缓存未被覆盖,则无需恢复,此时若强行恢复会干扰下次同步操作)
|
217
|
+
#
|
218
|
+
def sync_workspace(root, config, recover_cache_if_cancelled:true)
|
219
|
+
|
220
|
+
# 若有缓存仓库,则移到工作区
|
221
|
+
config.light_repos.each { |light_repo|
|
222
|
+
#【注意】url不一致会认为是不同仓库,将缓存当前仓库,并弹出url对应缓存(若对应缓存则不弹出)
|
223
|
+
Workspace.sync_workspace(root, light_repo)
|
224
|
+
}
|
225
|
+
|
226
|
+
# 更新冗余仓库数据
|
227
|
+
if config.previous_extra_light_repos.nil? || config.previous_extra_light_repos.length == 0
|
228
|
+
config.update_previous_extra_light_repos(root)
|
229
|
+
end
|
230
|
+
|
231
|
+
# 若工作区有多余仓库,则缓存
|
232
|
+
if !config.previous_extra_light_repos.nil? && config.previous_extra_light_repos.length > 0
|
233
|
+
|
234
|
+
dirty_repos = []
|
235
|
+
do_repos = []
|
236
|
+
config.previous_extra_light_repos.each { |light_repo|
|
237
|
+
|
238
|
+
# 如果仓库是主仓库,则不操作
|
239
|
+
next if light_repo.is_config_repo
|
240
|
+
|
241
|
+
repo, error = Repo.generate_softly(root, light_repo)
|
242
|
+
if error.nil?
|
243
|
+
if repo.status_checker.status == Repo::Status::GIT_REPO_STATUS[:dirty]
|
244
|
+
dirty_repos.push(repo)
|
245
|
+
else
|
246
|
+
do_repos.push(repo)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
}
|
250
|
+
|
251
|
+
if dirty_repos.length > 0
|
252
|
+
if Output.continue_with_interact_repos?(dirty_repos.map { |e| e.name }, '即将回收以上仓库,但存在本地改动,继续操作将丢失改动,是否取消?') ||
|
253
|
+
Output.continue_with_user_remind?("即将丢失改动,是否取消?")
|
254
|
+
# 用上次配置覆盖以恢复缓存,否则若此次缓存已被覆盖,取消后下次操作同步将失效
|
255
|
+
config.update_cache_with_content(root, config.previous_config) if recover_cache_if_cancelled
|
256
|
+
Foundation.help!('操作取消')
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
current_time = Time.new.strftime("%Y%m%d%H%M%S")
|
261
|
+
(dirty_repos + do_repos).each { |repo|
|
262
|
+
if dirty_repos.include?(repo)
|
263
|
+
repo.execute_git_cmd('add', '.')
|
264
|
+
repo.execute_git_cmd('stash', "save -u #{current_time}_MGit回收仓库自动stash")
|
265
|
+
end
|
266
|
+
|
267
|
+
begin
|
268
|
+
save_to_cache = MGitConfig.query_with_key(root, :savecache)
|
269
|
+
rescue Error => _
|
270
|
+
save_to_cache = false
|
271
|
+
end
|
272
|
+
|
273
|
+
# 如果仓库没有被管理,则不删除,直接缓存
|
274
|
+
is_git_managed = Dir.exist?(File.join(repo.config.git_store_dir(root), '.git'))
|
275
|
+
if save_to_cache || !is_git_managed
|
276
|
+
Workspace.push(root, repo.config)
|
277
|
+
else
|
278
|
+
FileUtils.rm_rf(repo.path) if Dir.exist?(repo.path)
|
279
|
+
end
|
280
|
+
}
|
281
|
+
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def pop_git_entity(root, config)
|
286
|
+
config.light_repos.each { |light_repo|
|
287
|
+
# 将托管的.git弹出到工作区
|
288
|
+
Workspace.pop_git_entity(root, light_repo)
|
289
|
+
}
|
290
|
+
end
|
291
|
+
|
292
|
+
def push_git_entity(root, config)
|
293
|
+
config.light_repos.each { |light_repo|
|
294
|
+
# 将工作区的.git托管给mgit
|
295
|
+
Workspace.push_git_entity(root, light_repo)
|
296
|
+
}
|
297
|
+
end
|
298
|
+
|
299
|
+
# 判断url是否一致
|
300
|
+
#
|
301
|
+
# @param url_a [String] url
|
302
|
+
#
|
303
|
+
# @param url_b [String] url
|
304
|
+
#
|
305
|
+
# @return [Boolean] 是否一致
|
306
|
+
#
|
307
|
+
def url_consist?(url_a, url_b)
|
308
|
+
# 删除冗余字符
|
309
|
+
temp_a = normalize_url(url_a)
|
310
|
+
temp_b = normalize_url(url_b)
|
311
|
+
|
312
|
+
# 同时不为nil判断内容是否相等
|
313
|
+
return temp_a == temp_b if !temp_a.nil? && !temp_b.nil?
|
314
|
+
# reutrn | temp_a | temp_b
|
315
|
+
# ----------------------
|
316
|
+
# true | nil | nil
|
317
|
+
# true | '' | nil
|
318
|
+
# true | nil | ''
|
319
|
+
# ----------------------
|
320
|
+
# false | nil | xxx
|
321
|
+
# false | xxx | nil
|
322
|
+
(temp_a.nil? && temp_b.nil?) || (!temp_a.nil? && temp_a.length == 0) || (!temp_b.nil? && temp_b.length == 0)
|
323
|
+
end
|
324
|
+
|
325
|
+
# 规范化url,删除冗余字符
|
326
|
+
#
|
327
|
+
# @param url [String] url字符串
|
328
|
+
#
|
329
|
+
# @return [String] 规范化后的url
|
330
|
+
#
|
331
|
+
def normalize_url(url)
|
332
|
+
return if url.nil?
|
333
|
+
refined_url = url.strip.sub(/(\/)+$/,'')
|
334
|
+
return refined_url if refined_url.length == 0
|
335
|
+
begin
|
336
|
+
uri = URI(refined_url)
|
337
|
+
return "#{uri.scheme}://#{uri.host}#{uri.port.nil? ? '' : ":#{uri.port}"}#{uri.path}"
|
338
|
+
rescue => _
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# 安全的路径拼接
|
343
|
+
#
|
344
|
+
# @param path_a [String] 路径a
|
345
|
+
#
|
346
|
+
# @param path_b [String] 路径b
|
347
|
+
#
|
348
|
+
# @return [String] 完整路径
|
349
|
+
#
|
350
|
+
def safe_join(path_a, path_b)
|
351
|
+
if !path_a.nil? && path_a.length > 0 && !path_b.nil? && path_b.length > 0
|
352
|
+
File.join(path_a, path_b)
|
353
|
+
elsif !path_a.nil? && path_a.length > 0
|
354
|
+
path_a
|
355
|
+
elsif !path_b.nil? && path_b.length > 0
|
356
|
+
path_b
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
module MGit
|
3
|
+
module HooksManager
|
4
|
+
|
5
|
+
# --- 执行hook ---
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# 获取配置表前执行的hook
|
9
|
+
#
|
10
|
+
# @param strict_mode [Boolean] default: true 严格模式下出错直接终止,非严格模式下出错抛出异常
|
11
|
+
#
|
12
|
+
# @return [Type] description_of_returned_object
|
13
|
+
#
|
14
|
+
def execute_manifest_hook(strict_mode:true)
|
15
|
+
__execute_hook_file(Constants::HOOK_NAME[:manifest_hook], 'MGitTemplate::ManifestHook') do |cls|
|
16
|
+
begin
|
17
|
+
cls.run
|
18
|
+
rescue Error => e
|
19
|
+
if strict_mode
|
20
|
+
Foundation.help!("配置表生成失败:#{e.msg}") if e.type == MGIT_ERROR_TYPE[:config_generate_error]
|
21
|
+
else
|
22
|
+
raise e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# mgit执行前的hook
|
29
|
+
def execute_mgit_pre_hook(cmd, pure_opts)
|
30
|
+
__execute_hook_file(Constants::HOOK_NAME[:pre_hook], 'MGitTemplate::PreHook') do |cls|
|
31
|
+
cls.run(cmd, pure_opts, Workspace.root)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# mgit执行后的hook
|
36
|
+
def execute_mgit_post_hook(cmd, pure_opts, light_repos)
|
37
|
+
__execute_hook_file(Constants::HOOK_NAME[:post_hook], 'MGitTemplate::PostHook') do |cls|
|
38
|
+
cls.run(cmd, pure_opts, Workspace.root, light_repos)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# mgit执行前的hook(用户级,此时已经完成状态检查,可以在内部获取到仓库配置对象)
|
43
|
+
# 可以按需插入到不同指令的执行前时机下调用,然后在方法中通过'cmd'参数判断当前执行到是哪个指令
|
44
|
+
# 目前仅插入到commit指令,后续可按需插入
|
45
|
+
def execute_mgit_pre_exec_hook(cmd, pure_opts, light_repos)
|
46
|
+
__execute_hook_file(Constants::HOOK_NAME[:pre_exec_hook], 'MGitTemplate::PreExecHook') do |cls|
|
47
|
+
cls.run(cmd, pure_opts, Workspace.root, light_repos)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# 功能类似'execute_mgit_pre_exec_hook',但仅仅是push指令专用(内部不用判断'cmd',cmd一定是push,可替换为'execute_mgit_pre_exec_hook')
|
52
|
+
def execute_mgit_pre_push_hook(cmd, pure_opts, light_repos)
|
53
|
+
__execute_hook_file(Constants::HOOK_NAME[:pre_push_hook], 'MGitTemplate::PrePushHook') do |cls|
|
54
|
+
cls.run(cmd, pure_opts, Workspace.root, light_repos)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# 执行下载后的hook
|
59
|
+
#
|
60
|
+
# @param repo_name [String] 仓库ming
|
61
|
+
#
|
62
|
+
# @param repo_path [String] 仓库本地路径
|
63
|
+
#
|
64
|
+
# @param root [String] .mgit所在目录
|
65
|
+
#
|
66
|
+
# @param error [String] 错误信息,nil表示成功
|
67
|
+
#
|
68
|
+
# @return [Boolean] hook是否操作过仓库分支
|
69
|
+
#
|
70
|
+
def execute_post_download_hook(repo_name, repo_path)
|
71
|
+
changed = __execute_hook_file(Constants::HOOK_NAME[:post_download_hook], 'MGitTemplate::PostDownloadHook') do |cls|
|
72
|
+
cls.run(repo_name, repo_path)
|
73
|
+
end
|
74
|
+
changed == true
|
75
|
+
end
|
76
|
+
|
77
|
+
# 执行hook文件
|
78
|
+
#
|
79
|
+
# @param file_name [String] hook文件名
|
80
|
+
#
|
81
|
+
# @param hook_class [String] hook Class name
|
82
|
+
#
|
83
|
+
# block
|
84
|
+
def __execute_hook_file(file_name, hook_class)
|
85
|
+
file_path = File.join(Workspace.hooks_dir, file_name)
|
86
|
+
if File.exists?(file_path)
|
87
|
+
require file_path
|
88
|
+
end
|
89
|
+
if Object.const_defined?(hook_class) && hook = Object.const_get(hook_class)
|
90
|
+
return yield(hook) if block_given?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|