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,66 @@
1
+
2
+ module MGit
3
+ class ARGV
4
+ module Parser
5
+
6
+ # @param [Array] argv
7
+ #
8
+ # @return [String, Array, Array]
9
+ # 返回cmd 和 参数列表
10
+ # # 将参数初步分解,便于后续处理
11
+ # 如:argv = [command zzzz -u sdfsd sdf --mmmm yoo ssss qqq --test asdfa asd ad f --xxx asd as dfa --yoo="ajsdaf" --ppp -abc]
12
+ # 分解为:command, [zzzz], [[-u, sdfsd, sdf], [--mmmm, yoo, ssss, qqq], [--test, asdfa, asd, ad, f], [--xxx, asd, as, dfa], [--yoo, "ajsdaf"], [--ppp], [-a], [-b], [-c]]
13
+ #
14
+ # 初步解析参数
15
+ def self.parse(argv)
16
+ absolute_cmd = argv.join(' ')
17
+ cmd = argv.shift
18
+ pure_opts = argv.join(' ')
19
+
20
+ # 将参数初步分解,便于后续处理
21
+ # 如:zzzz -u sdfsd sdf --mmmm yoo ssss qqq --test asdfa asd ad f --xxx asd as dfa --yoo="ajsdaf" --ppp -abc
22
+ # 分解为:[[zzzz], [-u, sdfsd, sdf], [--mmmm, yoo, ssss, qqq], [--test, asdfa, asd, ad, f], [--xxx, asd, as, dfa], [--yoo, "ajsdaf"], [--ppp], [-a], [-b], [-c]]
23
+ temp = []
24
+ raw_opts = []
25
+ argv.each_with_index { |e, idx|
26
+
27
+ Foundation.help!("参数\"#{e}\"格式错误,请使用格式如:\"--long\"或\"-s\"") if (e =~ /---/) == 0
28
+
29
+ # 检查是否是带'--'或'-'的参数
30
+ if (e =~ /-/) == 0
31
+ # 回收缓存
32
+ raw_opts.push(temp) if temp.length != 0
33
+ # 清空临时缓存
34
+ temp = []
35
+
36
+ # 如果是合并的短指令,如'-al = -a + -l',则分拆后直接装入raw_opts数组
37
+ # 因为只有不需要传入值的短参数才能合并,因此不利用临时缓存读取后续参数值
38
+ if e.length > 2 && (e =~ /--/).nil? && !e.include?('=')
39
+ e.split('')[1..-1].each { |s|
40
+ raw_opts.push(["-#{s}"])
41
+ }
42
+ next
43
+ end
44
+
45
+ # 处理带‘=’的传值参数
46
+ loc = (e =~ /=/)
47
+ if loc
48
+ temp.unshift(e[(loc + 1)..-1])
49
+ temp.unshift(e[0..loc - 1])
50
+ elsif e.length != 0
51
+ temp.push(e)
52
+ end
53
+
54
+ elsif e.length != 0
55
+ temp.push(e)
56
+ end
57
+
58
+ if idx == argv.length - 1
59
+ raw_opts.push(temp)
60
+ end
61
+ }
62
+ ARGV.new(cmd, pure_opts, absolute_cmd, raw_opts)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,271 @@
1
+ #coding=utf-8
2
+ #
3
+
4
+ require 'm-git/command_manager'
5
+
6
+ module MGit
7
+ class BaseCommand
8
+
9
+ def self.inherited(sub_klass)
10
+ CommandManager.register_command(sub_klass.cmd, sub_klass)
11
+ end
12
+
13
+ # 当前命令行的命令比如checkout / status /..
14
+ def self.cmd
15
+ name.split('::').last.downcase
16
+ end
17
+
18
+ # 引入所有自定义指令
19
+ Dir[File.join(__dir__, 'command', '*.rb')].each { |cmd|
20
+ require cmd
21
+ }
22
+
23
+ HIGH_PRIORITY_OPT_LIST = {
24
+ :help => '--help',
25
+ :help_s => '-h',
26
+ :auto_exec => '--auto-exec'
27
+ }.freeze
28
+
29
+ # 注意使用时跟指令自身设置的参数对比,避免冲突
30
+ SELECTABLE_OPT_LIST = {
31
+ :mrepo => '--mrepo',
32
+ :mrepo_s => '-m',
33
+ :exclude_mrepo => '--el-mrepo',
34
+ :exclude_mrepo_s => '-e',
35
+ :include_lock => '--include-lock',
36
+ :include_lock_s => '-i',
37
+ :continue => '--continue',
38
+ :abort => '--abort',
39
+ }.freeze
40
+
41
+ # 初始化
42
+ #
43
+ # @param argv [ARGV::Opt] 输入参数对象
44
+ #
45
+ def initialize(argv)
46
+ # 指令解析
47
+ setup_argv(argv)
48
+ process_highest_priority_option(argv)
49
+ validate(argv)
50
+ @argv = argv
51
+ end
52
+
53
+ #--- 禁止覆写 ---
54
+ # 执行主方法
55
+ def run
56
+ begin
57
+ __config_repo_filter
58
+ pre_exec
59
+ execute(@argv)
60
+ post_exec
61
+ rescue SystemExit, Interrupt
62
+ did_interrupt
63
+ end
64
+ end
65
+ #---------------
66
+ # Workspace Bridge
67
+ def all_repos(except_config:false)
68
+ Workspace.all_repos(except_config: except_config)
69
+ end
70
+
71
+ def locked_repos
72
+ Workspace.locked_repos
73
+ end
74
+
75
+ def exec_light_repos
76
+ Workspace.exec_light_repos
77
+ end
78
+
79
+ def generate_config_repo
80
+ Workspace.generate_config_repo
81
+ end
82
+ # -----------
83
+ private
84
+ def __config_repo_filter
85
+ cfg = Workspace.filter_config
86
+ cfg.include_lock = !@argv.opt(SELECTABLE_OPT_LIST[:include_lock]).nil? || include_lock_by_default
87
+ cfg.select_repos = @argv.opt(SELECTABLE_OPT_LIST[:mrepo])
88
+ cfg.exclude_repos = @argv.opt(SELECTABLE_OPT_LIST[:exclude_mrepo])
89
+ cfg.auto_exec = @argv.opt_list.did_set_opt?(HIGH_PRIORITY_OPT_LIST[:auto_exec])
90
+ end
91
+ #--- 基类调用,禁止覆写 ---
92
+ # 配置参数对象
93
+ def setup_argv(argv)
94
+ argv.register_opts(options)
95
+ argv.resolve!
96
+
97
+ argv.opt_list.opts.each do |opt|
98
+ next if opt.empty?
99
+ revise_option_value(opt)
100
+ end
101
+ end
102
+
103
+ # 处理最高优指令
104
+ def process_highest_priority_option(argv)
105
+ if argv.opt_list.did_set_opt?(HIGH_PRIORITY_OPT_LIST[:help])
106
+ usage(argv)
107
+ exit
108
+ end
109
+ end
110
+
111
+ #-------------------------------------------------------
112
+
113
+ #--- 可选覆写 ---
114
+ # 此处有pre hook,覆写时需要先调用super, 特殊指令除外
115
+ def pre_exec
116
+ # 开始计时
117
+ MGit::DurationRecorder.start
118
+ # 配置根目录
119
+ Workspace.setup_multi_repo_root
120
+
121
+ # 配置log
122
+ MGit::Loger.config(Workspace.root)
123
+ MGit::Loger.info("~~~ #{@argv.absolute_cmd} ~~~")
124
+
125
+ # 执行前置hook
126
+ HooksManager.execute_mgit_pre_hook(@argv.cmd, @argv.pure_opts)
127
+
128
+ # 解析配置文件
129
+ Workspace.setup_config
130
+
131
+ # 校验实体仓库
132
+ Workspace.setup_all_repos
133
+ end
134
+
135
+ # 此处有post hook,覆写时需要最后调用super, 特殊指令除外
136
+ def post_exec
137
+ # 执行后置hook
138
+ HooksManager.execute_mgit_post_hook(@argv.cmd, @argv.pure_opts, Workspace.exec_light_repos)
139
+ # 打点结束
140
+ duration = MGit::DurationRecorder.end
141
+ MGit::Loger.info("~~~ #{@argv.absolute_cmd}, 耗时:#{duration} s ~~~")
142
+ end
143
+
144
+ # 【子类按需覆写修改返回值】返回true表示可以支持自动执行
145
+ def enable_auto_execution
146
+ false
147
+ end
148
+
149
+ # 【子类按需覆写修改返回值】返回true表示可以支持"--mrepo"等可选选项
150
+ def enable_repo_selection
151
+ false
152
+ end
153
+
154
+ # 【子类按需覆写修改返回值】是否使默认添加选项(如‘--help’)和可选添加的选项(如‘--mrepo’)支持短指令
155
+ def enable_short_basic_option
156
+ false
157
+ end
158
+
159
+ # 【子类按需覆写修改返回值】是否添加操作lock仓库的选项(如‘--include-lock’)
160
+ def enable_lock_operation
161
+ false
162
+ end
163
+
164
+ # 【子类按需覆写修改返回值】是否自动将lock仓库加入到操作集中
165
+ def include_lock_by_default
166
+ false
167
+ end
168
+
169
+ # 【子类按需覆写修改返回值】是否添加‘--continue’参数,要在指令中自行控制中间态操作
170
+ def enable_continue_operation
171
+ false
172
+ end
173
+
174
+ # 【子类按需覆写修改返回值】是否添加‘--abort’参数
175
+ def enable_abort_operation
176
+ false
177
+ end
178
+
179
+ # 【子类按需覆写修改实现】按下ctrl+c后调用
180
+ def did_interrupt
181
+ end
182
+
183
+ # 可覆写该方法,返回该指令的描述
184
+ def self.description
185
+ end
186
+
187
+ # 可覆写该方法,返回该指令的用法
188
+ def self.usage
189
+ end
190
+ #---------------
191
+
192
+ #--- 强制覆写 ---
193
+ # 子类指令执行主方法
194
+ def execute(argv)
195
+ Foundation.help!("请覆写父类方法: \"execute(argv)\"")
196
+ end
197
+ #---------------
198
+
199
+ #--- 如果要接管某个指令(即为它添加自定义参数) ---
200
+ # --- 强制覆写(若该指令不带任何自定义参数,则无须覆写) ---
201
+ # 注册选项,覆写时注意返回"[...].concat(super)"
202
+ def options
203
+ opts = [
204
+ ARGV::Opt.new(HIGH_PRIORITY_OPT_LIST[:help],
205
+ short_key:(HIGH_PRIORITY_OPT_LIST[:help_s] if enable_short_basic_option),
206
+ info:"显示帮助。",
207
+ type: :boolean)
208
+ ]
209
+
210
+ opts.push(
211
+ ARGV::Opt.new(HIGH_PRIORITY_OPT_LIST[:auto_exec],
212
+ info:'指定该参数会跳过所有交互场景,并自动选择需要的操作执行。该参数主要用于脚本调用mgit进行自动化操作,日常RD开发不应当使用。',
213
+ type: :boolean)
214
+ ) if enable_auto_execution
215
+
216
+ opts.push(
217
+ ARGV::Opt.new(SELECTABLE_OPT_LIST[:mrepo],
218
+ short_key:(SELECTABLE_OPT_LIST[:mrepo_s] if enable_short_basic_option),
219
+ info:'指定需要执行该指令的仓库,可指定一个或多个,空格隔开,大小写均可,如:"--mrepo boxapp BBAAccount",若缺省则对所有仓库执行指令。'),
220
+ ARGV::Opt.new(SELECTABLE_OPT_LIST[:exclude_mrepo],
221
+ short_key:(SELECTABLE_OPT_LIST[:exclude_mrepo_s] if enable_short_basic_option),
222
+ info:'指定不需要执行该指令的仓库,可指定一个或多个,空格隔开,大小写均可,如:"--el-mrepo boxapp BBAAccount",若缺省则对所有仓库执行指令。与"--mrepo"同时指定时无效。')
223
+ ) if enable_repo_selection
224
+
225
+ opts.push(
226
+ ARGV::Opt.new(SELECTABLE_OPT_LIST[:include_lock], info:'指定该参数意味着同时也操作lock仓库。',
227
+ type: :boolean)
228
+ ) if enable_lock_operation
229
+
230
+ opts.push(
231
+ ARGV::Opt.new(SELECTABLE_OPT_LIST[:continue],
232
+ info:'MGit自定义参数,仅在操作多仓库过程中出现问题停止,执行状态进入中间态后可用。该参数只能单独使用,解决问题后可执行"mgit <cmd> --continue"继续操作其余仓库。',
233
+ type: :boolean)
234
+ ) if enable_continue_operation
235
+
236
+ opts.push(
237
+ ARGV::Opt.new(SELECTABLE_OPT_LIST[:abort],
238
+ info:'MGit自定义参数,仅在操作多仓库过程中出现问题停止,执行状态进入中间态后可用。该参数用于清除操作中间态,且只能单独使用:"mgit <cmd> --abort"。',
239
+ type: :boolean)
240
+ ) if enable_abort_operation
241
+
242
+ opts
243
+ end
244
+
245
+ # 解析参数并更新参数值到列表中
246
+ def revise_option_value(opt)
247
+ end
248
+
249
+ # --- 可选覆写(若该指令不带任何自定义参数,则无须覆写) ---
250
+ # 判断是否有必须参数漏传或数据格式不正确
251
+ def validate(argv)
252
+ end
253
+
254
+ # mgit是否输入--continue希望继续上次操作
255
+ def mgit_try_to_continue?
256
+ @argv.opt_list.did_set_opt?(SELECTABLE_OPT_LIST[:continue])
257
+ end
258
+
259
+ def mgit_try_to_abort?
260
+ @argv.opt_list.did_set_opt?(SELECTABLE_OPT_LIST[:abort])
261
+ end
262
+
263
+ # 显示指令使用信息
264
+ def usage(argv)
265
+ puts "#{Output.blue_message("[指令说明]")}\n#{self.class.description}"
266
+ puts "\n#{Output.blue_message("[指令格式]")}\n#{self.class.usage}"
267
+ argv.show_info
268
+ end
269
+
270
+ end
271
+ end
@@ -0,0 +1,41 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+
5
+ # @!scope [command] add
6
+ # follow git add
7
+ # eg: mgit add .
8
+ #
9
+ class Add < BaseCommand
10
+
11
+ # @overload
12
+ #
13
+ def execute(argv)
14
+ Workspace.check_branch_consistency
15
+ Output.puts_start_cmd
16
+ _, error_repos = Workspace.execute_git_cmd_with_repos(argv.cmd, argv.git_opts, all_repos)
17
+ Output.puts_succeed_cmd(argv.absolute_cmd) if error_repos.length == 0
18
+ end
19
+
20
+ # @overload
21
+ # @return [Boolean]
22
+ #
23
+ def enable_repo_selection
24
+ true
25
+ end
26
+
27
+ # @overload
28
+ #
29
+ def self.description
30
+ "将文件改动加入暂存区。"
31
+ end
32
+
33
+ # @overload
34
+ #
35
+ def self.usage
36
+ "mgit add [<git-add-option>] [(--mrepo|--el-mrepo) <repo>...] [--help]"
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,90 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+
5
+ # @!scope [command] branch
6
+ # follow git branch
7
+ # eg: mgit branch --compact
8
+ #
9
+ class Branch < BaseCommand
10
+
11
+ OPT_LIST = {
12
+ :compact => '--compact',
13
+ }.freeze
14
+
15
+ def options
16
+ [
17
+ ARGV::Opt.new(OPT_LIST[:compact], info:"以归类的方式显示所有仓库的当前分支。", type: :boolean)
18
+ ].concat(super)
19
+ end
20
+
21
+ def execute(argv)
22
+ Output.puts_start_cmd
23
+
24
+ if argv.opt(OPT_LIST[:compact])
25
+ show_compact_branches(argv)
26
+ return
27
+ end
28
+
29
+ # 无自定义参数则透传
30
+ extcute_as_common(argv)
31
+ end
32
+
33
+ # 常规执行
34
+ def extcute_as_common(argv)
35
+ error_repos = {}
36
+ all_repos.sort_by { |repo| repo.name }.each { |repo|
37
+ success, output = repo.execute_git_cmd(argv.cmd, argv.git_opts)
38
+ if success && output.length > 0
39
+ puts Output.generate_title_block(repo.name) {
40
+ output
41
+ } + "\n"
42
+ elsif !success
43
+ error_repos[repo.name] = output
44
+ end
45
+ }
46
+ if error_repos.length > 0
47
+ Workspace.show_error(error_repos)
48
+ else
49
+ Output.puts_succeed_cmd(argv.absolute_cmd)
50
+ end
51
+ end
52
+
53
+ # 以紧凑模式执行
54
+ def show_compact_branches(argv)
55
+ show_branches_for_repos(all_repos, false)
56
+ show_branches_for_repos(locked_repos, true)
57
+ Output.puts_succeed_cmd(argv.absolute_cmd)
58
+ end
59
+
60
+ # 紧凑地显示一组仓库分支
61
+ def show_branches_for_repos(repos, locked)
62
+ return if repos.nil?
63
+
64
+ list = {}
65
+ repos.sort_by { |repo| repo.name }.each { |repo|
66
+ branch = repo.status_checker.current_branch(strict_mode:false)
67
+ branch = 'HEAD游离,不在任何分支上!' if branch.nil?
68
+ list[branch] = [] if list[branch].nil?
69
+ list[branch].push(repo.name)
70
+ }
71
+ list.each { |branch, repo_names|
72
+ Output.puts_remind_block(repo_names, "以上仓库的当前分支:#{branch}#{' [锁定]' if locked}")
73
+ puts "\n"
74
+ }
75
+ end
76
+
77
+ def enable_repo_selection
78
+ true
79
+ end
80
+
81
+ def self.description
82
+ "创建、显示、删除分支。"
83
+ end
84
+
85
+ def self.usage
86
+ "mgit branch [<git-branch-option>|--compact] [(--mrepo|--el-mrepo) <repo>...] [--help]"
87
+ end
88
+ end
89
+
90
+ end