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,67 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
|
5
|
+
# @!scope 类似 git tag
|
6
|
+
#
|
7
|
+
class Tag < BaseCommand
|
8
|
+
|
9
|
+
def execute(argv)
|
10
|
+
Workspace.check_branch_consistency
|
11
|
+
|
12
|
+
Output.puts_start_cmd
|
13
|
+
|
14
|
+
exec_repos = all_repos + locked_repos
|
15
|
+
|
16
|
+
if argv.git_opts.empty?
|
17
|
+
_, error_repos = Workspace.execute_git_cmd_with_repos(argv.cmd, argv.git_opts, exec_repos)
|
18
|
+
Output.puts_succeed_cmd(argv.absolute_cmd) if error_repos.length == 0
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
error_repos = {}
|
23
|
+
no_tag_repos = []
|
24
|
+
exec_repos.each { |repo|
|
25
|
+
success, output = repo.execute_git_cmd(argv.cmd, argv.git_opts)
|
26
|
+
if success
|
27
|
+
tags = output.split("\n")
|
28
|
+
if tags.length > 0
|
29
|
+
puts Output.generate_title_block(repo.name) {
|
30
|
+
Output.generate_table(tags, separator:"")
|
31
|
+
}
|
32
|
+
else
|
33
|
+
no_tag_repos.push(repo.name)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
error_repos[repo.name] = output
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
if no_tag_repos.length > 0
|
41
|
+
puts "\n"
|
42
|
+
Output.puts_remind_block(no_tag_repos, "以上仓库尚未创建tag!")
|
43
|
+
end
|
44
|
+
|
45
|
+
if error_repos.length > 0
|
46
|
+
Workspace.show_error(error_repos)
|
47
|
+
else
|
48
|
+
Output.puts_succeed_cmd(argv.absolute_cmd)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def enable_repo_selection
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.description
|
58
|
+
"增删查或验证标签。增加标签示例:mgit tag -a 'v0.0.1' -m 'Tag description message'"
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.usage
|
62
|
+
"mgit tag [<git-tag-option>] [(--mrepo|--el-mrepo) <repo>...] [--help]"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module MGit
|
3
|
+
class CommandManager
|
4
|
+
class << self
|
5
|
+
# cmd generate
|
6
|
+
#
|
7
|
+
def commands
|
8
|
+
@commands ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def register_command(cmd, cls)
|
12
|
+
commands[cmd] = cls
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](cmd)
|
16
|
+
class_with_command(cmd)
|
17
|
+
end
|
18
|
+
|
19
|
+
def class_with_command(cmd)
|
20
|
+
commands[cmd]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/m-git/error.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
|
5
|
+
MGIT_ERROR_TYPE = {
|
6
|
+
:config_name_error => 'config_name_error',
|
7
|
+
:config_generate_error => 'config_generate_error'
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
class Error < StandardError
|
11
|
+
attr_reader :msg
|
12
|
+
attr_reader :type
|
13
|
+
|
14
|
+
def initialize(msg, type:nil)
|
15
|
+
@msg = msg
|
16
|
+
@type = type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
require 'm-git/foundation/constants'
|
4
|
+
require 'm-git/foundation/dir'
|
5
|
+
require 'm-git/foundation/git_message_parser'
|
6
|
+
require 'm-git/foundation/lock'
|
7
|
+
require 'm-git/foundation/loger'
|
8
|
+
require 'm-git/foundation/duration_recorder'
|
9
|
+
require 'm-git/foundation/mgit_config'
|
10
|
+
require 'm-git/foundation/operation_progress_manager'
|
11
|
+
require 'm-git/foundation/timer'
|
12
|
+
require 'm-git/foundation/utils'
|
13
|
+
|
14
|
+
module MGit
|
15
|
+
module Foundation
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# 异常终止
|
19
|
+
def help!(msg, title:nil)
|
20
|
+
Output.puts_terminate_message(msg, title:title)
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Constants
|
5
|
+
PROJECT_DIR = {
|
6
|
+
:hooks => '.mgit/hooks',
|
7
|
+
:source_config => '.mgit/source-config',
|
8
|
+
:source_git => '.mgit/source-git',
|
9
|
+
:snapshot => '.mgit/snapshot',
|
10
|
+
:log_dir => '.mgit/logs'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
HOOK_NAME = {
|
14
|
+
:pre_hook => 'pre_hook.rb',
|
15
|
+
:post_hook => 'post_hook.rb',
|
16
|
+
:manifest_hook => 'manifest_hook.rb',
|
17
|
+
:post_download_hook => 'post_download_hook.rb',
|
18
|
+
:pre_push_hook => 'pre_push_hook.rb',
|
19
|
+
:pre_exec_hook => 'pre_exec_hook.rb'
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
MGIT_CONFIG_PATH = ".mgit/config.yml"
|
23
|
+
|
24
|
+
CONFIG_FILE_NAME = {
|
25
|
+
:manifest => 'manifest.json',
|
26
|
+
:manifest_cache => '.manifest_cache.json',
|
27
|
+
:local_manifest => 'local_manifest.json'
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
# 全局配置
|
31
|
+
CONFIG_KEY = {
|
32
|
+
# [String] 包含仓库的文件夹相对.mgit目录路径,完整路径如:<.mgit所在路径>/dest/<repo_name>,与abs-dest同时指定时无效
|
33
|
+
:dest => 'dest',
|
34
|
+
# [Boolean] 是否将所有仓库排除mgit管理
|
35
|
+
:mgit_excluded => 'mgit-excluded',
|
36
|
+
# [String] 远程仓库根目录,完整URL:remote/remote_path
|
37
|
+
:remote => 'remote',
|
38
|
+
# [String] 远程仓库相对目录,完整URL:remote/remote_path
|
39
|
+
:repositories => 'repositories',
|
40
|
+
# [String] mgit版本
|
41
|
+
:version => 'version',
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
# 仓库配置
|
45
|
+
REPO_CONFIG_KEY = {
|
46
|
+
# [String] 仓库完整路径
|
47
|
+
:abs_dest => 'abs-dest',
|
48
|
+
# [Boolean] 是否是配置仓库
|
49
|
+
:config_repo => 'config-repo',
|
50
|
+
# [String] 包含仓库的文件夹相对.mgit目录路径,完整路径如:<.mgit所在路径>/dest/<repo_name>,与abs-dest同时指定时无效
|
51
|
+
:dest => 'dest',
|
52
|
+
# [Boolean] 是否是占位仓库,占位操作不会让mgit进行常规操作(隐含指定mgit_excluded为true),标记为占位的仓库组装器组装时不需要使用
|
53
|
+
:dummy => 'dummy',
|
54
|
+
# [Json] 锁定状态,见REPO_CONFIG_LOCK_KEY
|
55
|
+
:lock => 'lock',
|
56
|
+
# [Boolean] 是否排除mgit管理,被排除的仓库不会让mgit进行常规操作,若未标记dummy,则为不被mgit管理,但组装器需要的仓库
|
57
|
+
:mgit_excluded => 'mgit-excluded',
|
58
|
+
# [String] 远程仓库根目录,完整URL:remote/remote_path
|
59
|
+
:remote => 'remote',
|
60
|
+
# [String] 远程仓库相对目录,完整URL:remote/remote_path
|
61
|
+
:remote_path => 'remote-path'
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
# 必须全局字段
|
65
|
+
REQUIRED_CONFIG_KEY = [
|
66
|
+
CONFIG_KEY[:remote],
|
67
|
+
CONFIG_KEY[:version],
|
68
|
+
CONFIG_KEY[:dest],
|
69
|
+
CONFIG_KEY[:repositories]
|
70
|
+
].freeze
|
71
|
+
|
72
|
+
# 必须仓库配置字段
|
73
|
+
REQUIRED_REPO_CONFIG_KEY = [
|
74
|
+
REPO_CONFIG_KEY[:remote_path],
|
75
|
+
].freeze
|
76
|
+
|
77
|
+
REPO_CONFIG_LOCK_KEY = {
|
78
|
+
:branch => 'branch',
|
79
|
+
:commit_id => 'commit-id',
|
80
|
+
:tag => 'tag'
|
81
|
+
}.freeze
|
82
|
+
|
83
|
+
SNAPSHOT_KEY = {
|
84
|
+
:time_stamp => 'time-stamp',
|
85
|
+
:message => 'message',
|
86
|
+
:snapshot => 'snapshot'
|
87
|
+
}.freeze
|
88
|
+
|
89
|
+
CONFIG_CACHE_KEY = {
|
90
|
+
:hash => 'hash',
|
91
|
+
:cache => 'cache'
|
92
|
+
}.freeze
|
93
|
+
|
94
|
+
# 定义字段用于调用git(shell)指令前export,便于仓库git hook区分来进行其余操作
|
95
|
+
MGIT_EXPORT_INFO = {
|
96
|
+
# 是否是MGit操作的git指令
|
97
|
+
:MGIT_TRIGGERRED => 1,
|
98
|
+
# 本次MGit操作的唯一标示
|
99
|
+
:MGIT_OPT_ID => SecureRandom.uuid
|
100
|
+
}.freeze
|
101
|
+
|
102
|
+
# 临时中央仓库名
|
103
|
+
CENTRAL_REPO = "Central".freeze
|
104
|
+
|
105
|
+
INIT_CACHE_DIR_NAME = "pmet_tini_tigm".freeze
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
class Dir
|
3
|
+
|
4
|
+
# 检查传入路径是不是git仓库
|
5
|
+
#
|
6
|
+
# @param path [String] 仓库路径
|
7
|
+
#
|
8
|
+
def self.is_git_repo?(path)
|
9
|
+
return false unless File.directory?(path)
|
10
|
+
git_dir = File.join(path, '.git')
|
11
|
+
File.directory?(git_dir)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.is_in_git_repo?(path)
|
15
|
+
check_path = path
|
16
|
+
result = is_git_repo?(check_path)
|
17
|
+
while !result
|
18
|
+
check_path = File.dirname(check_path)
|
19
|
+
break if check_path == '/'
|
20
|
+
result = is_git_repo?(check_path)
|
21
|
+
end
|
22
|
+
result
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
|
5
|
+
# 计时器
|
6
|
+
#
|
7
|
+
class DurationRecorder
|
8
|
+
|
9
|
+
DEFAULT_DURATION_KEY = 'default_duration_key'
|
10
|
+
|
11
|
+
module Status
|
12
|
+
# 停止态
|
13
|
+
IDLE = 0
|
14
|
+
# 暂停态
|
15
|
+
PAUSE = 1
|
16
|
+
# 计时中
|
17
|
+
RUNNING = 2
|
18
|
+
end
|
19
|
+
|
20
|
+
include Status
|
21
|
+
|
22
|
+
@@status = {}
|
23
|
+
@@duration = {}
|
24
|
+
@@time_stamp = {}
|
25
|
+
@@lock = Mutex.new
|
26
|
+
|
27
|
+
def self.start(duration_key:DEFAULT_DURATION_KEY, use_lock:false)
|
28
|
+
mutex_exec(use_lock) {
|
29
|
+
status = IDLE if @@status[duration_key].nil?
|
30
|
+
if status == IDLE
|
31
|
+
@@duration[duration_key] = 0.0
|
32
|
+
@@time_stamp[duration_key] = Time.new.to_f
|
33
|
+
@@status[duration_key] = RUNNING
|
34
|
+
else
|
35
|
+
puts '需要停止计时后重新开始计时'
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.pause(duration_key:DEFAULT_DURATION_KEY, use_lock:false)
|
41
|
+
mutex_exec(use_lock) {
|
42
|
+
if @@status[duration_key] == RUNNING
|
43
|
+
current = Time.new.to_f
|
44
|
+
@@duration[duration_key] += (current - @@time_stamp[duration_key])
|
45
|
+
@@time_stamp.delete(duration_key)
|
46
|
+
@@status[duration_key] = PAUSE
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.resume(duration_key:DEFAULT_DURATION_KEY, use_lock:false)
|
52
|
+
mutex_exec(use_lock) {
|
53
|
+
if @@status[duration_key] == PAUSE
|
54
|
+
@@time_stamp[duration_key] = Time.new.to_f
|
55
|
+
@@status[duration_key] = RUNNING
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.end(duration_key:DEFAULT_DURATION_KEY, use_lock:false)
|
61
|
+
mutex_exec(use_lock) {
|
62
|
+
if @@status[duration_key] != IDLE
|
63
|
+
current = Time.new.to_f
|
64
|
+
@@duration[duration_key] += (current - @@time_stamp[duration_key])
|
65
|
+
@@time_stamp.delete(duration_key)
|
66
|
+
@@status[duration_key] = IDLE
|
67
|
+
return @@duration[duration_key]
|
68
|
+
else
|
69
|
+
puts '没有需要停止的计时'
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# 多线程执行保护
|
77
|
+
#
|
78
|
+
# @param use_lock [Boolean] 执行是否加锁
|
79
|
+
#
|
80
|
+
def self.mutex_exec(use_lock)
|
81
|
+
if use_lock
|
82
|
+
@@lock.lock
|
83
|
+
yield if block_given?
|
84
|
+
@@lock.unlock
|
85
|
+
else
|
86
|
+
yield if block_given?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
module MGit
|
3
|
+
# Git interact message parse with git-server
|
4
|
+
#
|
5
|
+
class GitMessageParser
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String] error message
|
12
|
+
# @return [nil] none error
|
13
|
+
#
|
14
|
+
def parse_fetch_msg(input)
|
15
|
+
parse_pull_msg(input)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String] error message
|
19
|
+
# @return [nil] none error
|
20
|
+
#
|
21
|
+
def parse_pull_msg(input)
|
22
|
+
__default_parse_msg(input)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [String] error message
|
26
|
+
# @return [nil] none error
|
27
|
+
#
|
28
|
+
def parse_push_msg(input)
|
29
|
+
__default_parse_msg(input)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] codereview的url地址
|
33
|
+
# 默认无解析
|
34
|
+
def parse_code_review_url(input)
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def __default_parse_msg(msg)
|
39
|
+
return if msg.nil? || msg.empty?
|
40
|
+
|
41
|
+
key_word = 'error:'
|
42
|
+
error_line = msg.split("\n").find {|line|
|
43
|
+
# 解析 "error: failed to push some refs..."
|
44
|
+
line.include?(key_word)
|
45
|
+
}
|
46
|
+
msg if error_line
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module MGit
|
3
|
+
class Lock
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# @!scope 互斥执行锁
|
7
|
+
# @example
|
8
|
+
# mutex_exec do
|
9
|
+
# exec..
|
10
|
+
# end
|
11
|
+
def mutex_exec
|
12
|
+
@mutex = Mutex.new if @mutex.nil?
|
13
|
+
@mutex.lock
|
14
|
+
yield if block_given?
|
15
|
+
@mutex.unlock
|
16
|
+
end
|
17
|
+
|
18
|
+
# @!scope 互斥显示锁
|
19
|
+
# @example
|
20
|
+
# mutex_puts do
|
21
|
+
# exec..
|
22
|
+
# end
|
23
|
+
def mutex_puts
|
24
|
+
@mutex_puts = Mutex.new if @mutex_puts.nil?
|
25
|
+
@mutex_puts.lock
|
26
|
+
yield if block_given?
|
27
|
+
@mutex_puts.unlock
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|