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.
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