m-git 2.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +85 -0
  4. data/lib/m-git.rb +66 -0
  5. data/lib/m-git/argv.rb +170 -0
  6. data/lib/m-git/argv/opt.rb +38 -0
  7. data/lib/m-git/argv/opt_list.rb +71 -0
  8. data/lib/m-git/argv/parser.rb +66 -0
  9. data/lib/m-git/base_command.rb +271 -0
  10. data/lib/m-git/command/add.rb +41 -0
  11. data/lib/m-git/command/branch.rb +90 -0
  12. data/lib/m-git/command/checkout.rb +106 -0
  13. data/lib/m-git/command/clean.rb +64 -0
  14. data/lib/m-git/command/commit.rb +84 -0
  15. data/lib/m-git/command/config.rb +202 -0
  16. data/lib/m-git/command/delete.rb +99 -0
  17. data/lib/m-git/command/fetch.rb +32 -0
  18. data/lib/m-git/command/forall.rb +81 -0
  19. data/lib/m-git/command/info.rb +74 -0
  20. data/lib/m-git/command/init.rb +324 -0
  21. data/lib/m-git/command/log.rb +73 -0
  22. data/lib/m-git/command/merge.rb +381 -0
  23. data/lib/m-git/command/pull.rb +364 -0
  24. data/lib/m-git/command/push.rb +311 -0
  25. data/lib/m-git/command/rebase.rb +348 -0
  26. data/lib/m-git/command/reset.rb +31 -0
  27. data/lib/m-git/command/self.rb +223 -0
  28. data/lib/m-git/command/stash.rb +189 -0
  29. data/lib/m-git/command/status.rb +135 -0
  30. data/lib/m-git/command/sync.rb +327 -0
  31. data/lib/m-git/command/tag.rb +67 -0
  32. data/lib/m-git/command_manager.rb +24 -0
  33. data/lib/m-git/error.rb +20 -0
  34. data/lib/m-git/foundation.rb +25 -0
  35. data/lib/m-git/foundation/constants.rb +107 -0
  36. data/lib/m-git/foundation/dir.rb +25 -0
  37. data/lib/m-git/foundation/duration_recorder.rb +92 -0
  38. data/lib/m-git/foundation/git_message_parser.rb +50 -0
  39. data/lib/m-git/foundation/lock.rb +32 -0
  40. data/lib/m-git/foundation/loger.rb +129 -0
  41. data/lib/m-git/foundation/mgit_config.rb +222 -0
  42. data/lib/m-git/foundation/operation_progress_manager.rb +139 -0
  43. data/lib/m-git/foundation/timer.rb +74 -0
  44. data/lib/m-git/foundation/utils.rb +361 -0
  45. data/lib/m-git/hooks_manager.rb +96 -0
  46. data/lib/m-git/manifest.rb +181 -0
  47. data/lib/m-git/manifest/cache_manager.rb +44 -0
  48. data/lib/m-git/manifest/internal.rb +182 -0
  49. data/lib/m-git/manifest/light_repo.rb +108 -0
  50. data/lib/m-git/manifest/light_repo_generator.rb +87 -0
  51. data/lib/m-git/manifest/linter.rb +153 -0
  52. data/lib/m-git/open_api.rb +427 -0
  53. data/lib/m-git/open_api/script_download_info.rb +37 -0
  54. data/lib/m-git/output/output.rb +461 -0
  55. data/lib/m-git/plugin_manager.rb +112 -0
  56. data/lib/m-git/repo.rb +133 -0
  57. data/lib/m-git/repo/status.rb +481 -0
  58. data/lib/m-git/repo/sync_helper.rb +254 -0
  59. data/lib/m-git/template.rb +9 -0
  60. data/lib/m-git/template/local_manifest.rb +27 -0
  61. data/lib/m-git/template/manifest_hook.rb +28 -0
  62. data/lib/m-git/template/post_download_hook.rb +29 -0
  63. data/lib/m-git/template/post_hook.rb +31 -0
  64. data/lib/m-git/template/pre_exec_hook.rb +31 -0
  65. data/lib/m-git/template/pre_hook.rb +29 -0
  66. data/lib/m-git/template/pre_push_hook.rb +32 -0
  67. data/lib/m-git/version.rb +6 -0
  68. data/lib/m-git/workspace.rb +648 -0
  69. data/lib/m-git/workspace/path_helper.rb +56 -0
  70. data/lib/m-git/workspace/workspace_helper.rb +159 -0
  71. data/m-git +1 -0
  72. data/mgit +19 -0
  73. metadata +218 -0
@@ -0,0 +1,254 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+
5
+ class Repo
6
+ class SyncHelper
7
+
8
+ class << self
9
+
10
+ # 同步新仓库
11
+ #
12
+ # @param repo [MGigClass::Repo] Repo对象
13
+ #
14
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
15
+ #
16
+ # @param link_git [Boolean] 下载新仓库的时候是否托管.git实体并在工作区创建其软链接
17
+ #
18
+ # @return [String, Repo] String:执行结果,成功返回nil,错误返回错误信息,Repo:成功返回nil,错误返回新生成的repo对象
19
+ #
20
+ def sync_new_repo(light_repo, root, link_git:true)
21
+ def __sync_local_repo(light_repo, root, link_git:true)
22
+ output, repo = nil, nil
23
+ git_entity = File.join(light_repo.git_store_dir(root), '.git')
24
+ # 先git clone -- local_git_repo,再软链git_entity,再checkout分支
25
+ clone_url = "git clone -- #{git_entity} #{light_repo.abs_dest(root)}"
26
+ Utils.execute_shell_cmd(clone_url) { |stdout, stderr, status|
27
+ if status.success?
28
+ repo = Repo.generate_strictly(root, light_repo)
29
+ repo_git = File.join(repo.path, '.git')
30
+ manage_git = MGitConfig.query_with_key(root, :managegit)
31
+ if manage_git && link_git
32
+ FileUtils.rm_rf(repo_git)
33
+ Utils.link(git_entity, repo_git)
34
+ end
35
+ msg = ''
36
+ # 如果从本地clone的话,remote url是指向本地的,需要更新
37
+ error_message = sync_remote_url(repo, light_repo)
38
+ msg += error_message + "\n" if !error_message.nil?
39
+ # 本地仓库可能太旧,执行pull更新代码和新分支
40
+ success, error_message = repo.execute_git_cmd('fetch', '')
41
+ if !success && !error_message.nil? && error_message.length > 0
42
+ msg += "由于存在本地仓库源,已从本地克隆,但代码更新失败,请自行fetch最新代码。原因:\n" + error_message + "\n"
43
+ end
44
+
45
+ # 同步锁定点
46
+ error_message = sync_lock_point(repo, light_repo)
47
+ msg += error_message if !error_message.nil?
48
+
49
+ output = msg.length > 0 ? msg : nil
50
+ else
51
+ output = "同步仓库\"#{light_repo.name}\"时clone失败,如果远程仓库不存在,请在配置文件中删除该仓库并重试。原因:\n#{stderr}"
52
+ end
53
+ }
54
+ [output, repo]
55
+ end
56
+
57
+ def __sync_remote_repo(light_repo, root, link_git:true)
58
+ #
59
+ output, repo = nil, nil
60
+ clone_url = light_repo.clone_url(root)
61
+
62
+ Utils.execute_shell_cmd(clone_url) { |stdout, stderr, status|
63
+ if status.success?
64
+ repo = Repo.generate_strictly(root, light_repo)
65
+ begin
66
+ # 查询配置看是否需要托管.git实体, 根据mgit config -s managegit false配置。
67
+ # 若是,那么.git实体会放在.mgit/source-git/文件夹下
68
+ manage_git = MGitConfig.query_with_key(root, :managegit)
69
+ Utils.link_git(repo.path, light_repo.git_store_dir(root)) if manage_git && link_git
70
+ rescue Error => _
71
+ end
72
+ msg = ''
73
+ # 同步锁定点
74
+ error_message = sync_lock_point(repo, light_repo)
75
+ msg += error_message if !error_message.nil?
76
+
77
+ output = msg.length > 0 ? msg : nil
78
+ else
79
+ output = "同步仓库\"#{light_repo.name}\"时clone失败,如果远程仓库不存在,请在配置文件中删除该仓库并重试。原因:\n#{stderr}"
80
+ end
81
+ }
82
+
83
+ [output, repo]
84
+ end
85
+
86
+ git_entity = File.join(light_repo.git_store_dir(root), '.git')
87
+ if File.exist?(git_entity)
88
+ __sync_local_repo(light_repo, root, link_git: link_git)
89
+ else
90
+ __sync_remote_repo(light_repo, root, link_git: link_git)
91
+ end
92
+ end
93
+
94
+ # 同步已有仓库
95
+ #
96
+ # @param repo [Repo] Repo对象
97
+ #
98
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
99
+ #
100
+ # @return [string] 执行结果,成功返回nil,错误返回错误信息
101
+ #
102
+ def sync_exist_repo(repo, light_repo)
103
+ msg = ''
104
+
105
+ if light_repo.lock
106
+ # 同步锁定点
107
+ error_message = sync_lock_point(repo, light_repo)
108
+ msg += error_message + "\n" if !error_message.nil?
109
+ end
110
+
111
+ # 同步remote url
112
+ error_message = sync_remote_url(repo, light_repo)
113
+ msg += error_message + "\n" if !error_message.nil?
114
+
115
+ return msg.length > 0 ? msg : nil
116
+ end
117
+
118
+ # 同步锁定点
119
+ #
120
+ # @param repo [Repo] Repo对象
121
+ #
122
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
123
+ #
124
+ # @return [string] 执行结果,成功返回nil,错误返回错误信息
125
+ #
126
+ def sync_lock_point(repo, light_repo)
127
+ if repo.status_checker.status == Status::GIT_REPO_STATUS[:dirty]
128
+ return "#{light_repo.name}有本地改动,无法锁定,请自行清空修改后重试!"
129
+ end
130
+
131
+ if !light_repo.commit_id.nil?
132
+ return sync_commit_id(repo, light_repo)
133
+ elsif !light_repo.tag.nil?
134
+ return sync_tag(repo, light_repo)
135
+ elsif !light_repo.branch.nil?
136
+ return sync_branch(repo, light_repo)
137
+ end
138
+ end
139
+
140
+ # 同步tag
141
+ # @param repo [Repo] Repo对象
142
+ #
143
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
144
+ #
145
+ # @return [string] 执行结果,成功返回nil,错误返回错误信息
146
+ #
147
+ def sync_tag(repo, light_repo)
148
+ if !light_repo.tag.nil?
149
+ success, output = repo.execute_git_cmd('checkout', light_repo.tag)
150
+ return output if !success
151
+ else
152
+ return "\"#{repo.path}\"的仓库配置未指定tag!"
153
+ end
154
+ end
155
+
156
+ # 同步commit id
157
+ # @param repo [Repo] Repo对象
158
+ #
159
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
160
+ #
161
+ # @return [string] 执行结果,成功返回nil,错误返回错误信息
162
+ #
163
+ def sync_commit_id(repo, light_repo)
164
+ if !light_repo.commit_id.nil?
165
+ success, output = repo.execute_git_cmd('checkout', light_repo.commit_id)
166
+ return output if !success
167
+ else
168
+ return "\"#{repo.path}\"的仓库配置未指定commit id!"
169
+ end
170
+ end
171
+
172
+ # 同步分支
173
+ #
174
+ # @param repo [Repo] Repo对象
175
+ #
176
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
177
+ #
178
+ # @return [string] 执行结果,成功返回nil,错误返回错误信息
179
+ #
180
+ def sync_branch(repo, light_repo)
181
+
182
+ current_branch = repo.status_checker.current_branch(strict_mode:false)
183
+ local_branch_exist = repo.status_checker.local_branch_exist?(light_repo.branch)
184
+ remote_branch_exist = repo.status_checker.remote_branch_exist?(light_repo.branch)
185
+ is_dirty = repo.status_checker.status == Status::GIT_REPO_STATUS[:dirty]
186
+
187
+ # 当前已在目标切换分支则不操作
188
+ if current_branch == light_repo.branch
189
+ return nil
190
+
191
+ # 本地或远程存在目标分支则切换
192
+ elsif local_branch_exist || remote_branch_exist || Utils.branch_exist_on_remote?(light_repo.branch, light_repo.url)
193
+
194
+ # 本地无目标分支则先拉取
195
+ if !local_branch_exist && !remote_branch_exist
196
+ success, error = repo.execute_git_cmd('fetch', '')
197
+ return error if !success
198
+ end
199
+
200
+ if !is_dirty
201
+ success, output = repo.execute_git_cmd('checkout', light_repo.branch)
202
+ return output if !success
203
+ else
204
+ return "本地有改动, 无法切换到分支\"#{light_repo.branch}\", 请处理后重试!"
205
+ end
206
+
207
+ else
208
+ return "仓库分支\"#{light_repo.branch}\"不存在,请检查是否拼写错误!"
209
+ end
210
+
211
+ end
212
+
213
+ # 同步remote url
214
+ #
215
+ # @param repo [Repo] Repo对象
216
+ #
217
+ # @param light_repo [Manifest::LightRepo] LightRepo对象
218
+ #
219
+ # @return [Boolean] 执行结果,成功返回nil,错误返回错误信息
220
+ #
221
+ def sync_remote_url(repo, light_repo)
222
+ return nil if light_repo.url.nil?
223
+
224
+ success, output = repo.execute_git_cmd('remote', "set-url origin #{light_repo.url}")
225
+ return success ? nil : output
226
+ end
227
+
228
+ # 生成本地裸库路径
229
+ #
230
+ # @param repo_name [String] 仓库名
231
+ #
232
+ # @return [String] 本地裸库路径
233
+ #
234
+ def local_bare_git_url(path)
235
+ if File.exist?(path)
236
+ return path
237
+ else
238
+ return nil
239
+ end
240
+ end
241
+
242
+ # 删除失效的仓库目录
243
+ #
244
+ # @param repo_abs_path [String] 仓库完整路径
245
+ #
246
+ def delete_legacy_repo(repo_abs_path)
247
+ FileUtils.remove_dir(repo_abs_path, true) if File.exist?(repo_abs_path)
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,9 @@
1
+ #coding=utf-8
2
+
3
+ require 'm-git/template/local_manifest'
4
+ require 'm-git/template/manifest_hook'
5
+ require 'm-git/template/post_download_hook'
6
+ require 'm-git/template/post_hook'
7
+ require 'm-git/template/pre_exec_hook'
8
+ require 'm-git/template/pre_hook'
9
+ require 'm-git/template/pre_push_hook'
@@ -0,0 +1,27 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ module_function
6
+ def default_template
7
+ return "{
8
+ \"#{Constants::CONFIG_KEY[:repositories]}\": {
9
+
10
+ }
11
+ }
12
+ "
13
+ end
14
+
15
+ def local_config_template(config_repo_name)
16
+ return "{
17
+ \"#{Constants::CONFIG_KEY[:mgit_excluded]}\": true,
18
+ \"#{Constants::CONFIG_KEY[:repositories]}\": {
19
+ \"#{config_repo_name}\": {
20
+ \"#{Constants::REPO_CONFIG_KEY[:mgit_excluded]}\": false
21
+ }
22
+ }
23
+ }
24
+ "
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ MANIFEST_HOOK_TEMPLATE = '
6
+ #coding=utf-8
7
+
8
+ module MGitTemplate
9
+
10
+ class ManifestHook
11
+
12
+ # hook接口,用于生成manifest.json文件。文件本地地址必须设置为<PROJ_ROOT>/.mgit/source-config/manifest.json
13
+ #
14
+ # 若解析失败,可抛出异常:
15
+ #
16
+ # raise MGit::Error.new("失败原因...", type: MGit::MGIT_ERROR_TYPE[:config_generate_error])
17
+ #
18
+ # 异常抛出后程序终止
19
+ def self.run()
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ '
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ POST_DOWNLOAD_HOOK_TEMPLATE = '
6
+ #coding=utf-8
7
+
8
+ module MGitTemplate
9
+
10
+ class PostDownloadHook
11
+
12
+ # hook接口,单个仓库下载完成后调用
13
+ #
14
+ # @param name [String] 下载仓库名
15
+ #
16
+ # @param path [String] 下载仓库的本地绝对路径
17
+ #
18
+ # @return [Boolean] 是否改动仓库HEAD
19
+ #
20
+ def self.run(name, path)
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ '
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ POST_CUSTOMIZED_HOOK_TEMPLATE = '
6
+ #coding=utf-8
7
+
8
+ module MGitTemplate
9
+
10
+ class PostHook
11
+
12
+ # hook接口,用于接受本次指令执行后的数据
13
+ #
14
+ # @param cmd [String] 本次执行指令
15
+ #
16
+ # @param opts [String] 本次执行指令参数
17
+ #
18
+ # @param mgit_root [String] mgit根目录
19
+ #
20
+ # @param exec_repos [Array<Manifest::LightRepo>] 本次执行指令的LightRepo数组
21
+ #
22
+ def self.run(cmd, opts, mgit_root, exec_repos)
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ '
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ PRE_CUSTOMIZED_EXEC_HOOK_TEMPLATE = '
6
+ #coding=utf-8
7
+
8
+ module MGitTemplate
9
+
10
+ class PreExecHook
11
+
12
+ # hook接口,用于接受本次指令执行前的数据
13
+ #
14
+ # @param cmd [String] 本次执行指令
15
+ #
16
+ # @param opts [String] 本次执行指令参数
17
+ #
18
+ # @param mgit_root [String] mgit根目录
19
+ #
20
+ # @param exec_repos [Array<Manifest::LightRepo>] 本次执行指令的LightRepo数组
21
+ #
22
+ def self.run(cmd, opts, mgit_root, exec_repos)
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ '
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ module Template
5
+ PRE_CUSTOMIZED_HOOK_TEMPLATE = '
6
+ #coding=utf-8
7
+
8
+ module MGitTemplate
9
+
10
+ class PreHook
11
+
12
+ # hook接口,用于接受本次指令执行前的数据
13
+ #
14
+ # @param cmd [String] 本次执行指令
15
+ #
16
+ # @param opts [String] 本次执行指令参数
17
+ #
18
+ # @param mgit_root [String] mgit根目录
19
+ #
20
+ def self.run(cmd, opts, mgit_root)
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ '
28
+ end
29
+ end