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,129 @@
1
+ #coding=utf-8
2
+
3
+ require 'logger'
4
+ require 'fileutils'
5
+ module MGit
6
+
7
+ # 日志模块配置
8
+ class Loger
9
+
10
+ MGIT_LOG_FILE_NAME = 'mgit.log'
11
+
12
+ #
13
+ # 配置Log模块
14
+ #
15
+ # @param root [String] 工程根目录
16
+ #
17
+ def self.config(root)
18
+ # 是否开启log
19
+ begin
20
+ log_enable = MGit::MGitConfig.query_with_key(root, :logenable)
21
+ rescue MGitClass::Error => e
22
+ log_enable = TRUE
23
+ end
24
+ MGit::Loger.set_log_enable(log_enable)
25
+
26
+ # 配置log路径
27
+ log_dir = File.join(root, MGit::Constants::PROJECT_DIR[:log_dir])
28
+ FileUtils.mkdir_p(log_dir) if !Dir.exist?(log_dir)
29
+ file_path = File.join(log_dir, MGIT_LOG_FILE_NAME)
30
+ MGit::Loger.set_log_file(file_path)
31
+
32
+ # 配置log的level
33
+ begin
34
+ log_level = MGit::MGitConfig.query_with_key(root, :loglevel)
35
+ rescue MGitClass::Error => e
36
+ log_level = 1
37
+ end
38
+ MGit::Loger.set_log_level(log_level)
39
+
40
+ end
41
+
42
+ end
43
+
44
+
45
+ # 日志模块
46
+ class Loger
47
+ DEFAULT_SHIFT_SIZE = 1048576 #每个文件1M
48
+ DEFAULT_SHIFT_AGE = 10 # 保留10个文件
49
+ DEFAULT_LOG_FILE = "./mgit.log"
50
+
51
+ #
52
+ # 设置mgit log是否开启 默认开启
53
+ #
54
+ # @param log_enable [Boolean] 是否开启log日志
55
+ #
56
+ def self.set_log_enable(log_enable)
57
+ @log_enable = log_enable
58
+ end
59
+
60
+ #
61
+ # 设置mgit log的打印等级
62
+ #
63
+ # @param level [Enumerable]: Logger::DEBUG | Logger::INFO | Logger::ERROR | Logger::FATAL
64
+ #
65
+ def self.set_log_level(level)
66
+ self.logger.level = level
67
+ end
68
+
69
+ #
70
+ # 设置mgit log的文件名, 默认路径在工作区的 .mgit/logs/mgit.log
71
+ #
72
+ def self.set_log_file(file_path)
73
+ @log_file = file_path
74
+ end
75
+
76
+ #
77
+ # 打印 DEBUG类型的log
78
+ #
79
+ def self.debug(message)
80
+ self.logger.debug(message) if @log_enable
81
+ end
82
+
83
+ #
84
+ # 打印 DEBUG类型的log
85
+ #
86
+ def self.info(message)
87
+ self.logger.info(message) if @log_enable
88
+ end
89
+
90
+ #
91
+ # 打印 WARN类型的log
92
+ #
93
+ def self.warn(message)
94
+ self.logger.warn(message) if @log_enable
95
+ end
96
+
97
+ #
98
+ # 打印 ERROR类型的log
99
+ #
100
+ def self.error(message)
101
+ self.logger.error(message) if @log_enable
102
+ end
103
+
104
+ #
105
+ # 打印 FATAL类型的log
106
+ #
107
+ def self.fatal(message)
108
+ self.logger.fatal(message) if @log_enable
109
+ end
110
+
111
+ private
112
+ def self.logger
113
+ unless @logger
114
+ @log_enable ||= TRUE
115
+ @log_level ||= Logger::INFO
116
+ @log_file ||= DEFAULT_LOG_FILE
117
+ @logger = Logger.new(@log_file, shift_age = DEFAULT_SHIFT_AGE, shift_size = DEFAULT_SHIFT_SIZE)
118
+ @logger.level = @log_level
119
+ @logger.datetime_format = '%Y-%m-%d %H:%M:%S'
120
+ @logger.formatter = proc do | severity, datetime, progname, msg|
121
+ "#{datetime} - #{severity} - : #{msg}\n"
122
+ end
123
+ end
124
+ @logger
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,222 @@
1
+ #coding=utf-8
2
+
3
+ require_relative 'utils'
4
+
5
+ module MGit
6
+ class MGitConfig
7
+
8
+ CONFIG_KEY = {
9
+ :managegit => {
10
+ :info => '是否将.git实体托管给MGit,托管后仓库内的.git目录是软链 (true/false)',
11
+ :type => 'Boolean',
12
+ :default => true
13
+ },
14
+ :maxconcurrentcount => {
15
+ :info => 'MGit操作的最大并发数? (Integer)',
16
+ :type => 'Integer',
17
+ :default => MGit::Utils.logical_cpu_num
18
+ },
19
+ :syncworkspace => {
20
+ :info => '是否按照配置表同步工作区? (true/false)',
21
+ :type => 'Boolean',
22
+ :default => true
23
+ },
24
+ :savecache => {
25
+ :info => '同步工作区时回收的仓库是否保留到缓存中? (true/false)',
26
+ :type => 'Boolean',
27
+ :default => false
28
+ },
29
+ :logenable => {
30
+ :info => '是否开启日志打印,操作日志会收集到.mgit/log目录下? (true/false)',
31
+ :type => 'Boolean',
32
+ :default => true
33
+ },
34
+ :loglevel => {
35
+ :info => '日志的打印级别, DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, FATAL = 4',
36
+ :type => 'Integer',
37
+ :default => 1
38
+ }
39
+ }
40
+
41
+ class << self
42
+
43
+ # 查询配置
44
+ #
45
+ # @param root [String] 工程根目录
46
+ #
47
+ # @raise [MGit::Error] 异常错误
48
+ #
49
+ def query(root)
50
+ config, error = __load_file(root)
51
+ if !error.nil?
52
+ raise Error.new(error)
53
+ return
54
+ elsif block_given?
55
+ # 如果文件存在但无内容,此时读取到的数据类型是FalseClass,此处统一规范化
56
+ config = {} if !config.is_a?(Hash)
57
+ yield(config)
58
+ end
59
+ end
60
+
61
+ # Description of #query_with_key
62
+ #
63
+ # @param root [String] 工程根目录
64
+ #
65
+ # @param key_symbol [Symbol] 符号key值
66
+ #
67
+ # @return [Object] 配置值
68
+ #
69
+ # @raise [MGit::Error] 异常错误
70
+ def query_with_key(root, key_symbol)
71
+ query(root) { |config|
72
+ if !config[key_symbol.to_s].nil?
73
+ return config[key_symbol.to_s]
74
+ elsif !CONFIG_KEY[key_symbol].nil?
75
+ return CONFIG_KEY[key_symbol][:default]
76
+ else
77
+ return nil
78
+ end
79
+ }
80
+ end
81
+
82
+ # 更新配置
83
+ #
84
+ # @param root [String] 工程根目录
85
+ #
86
+ # @raise [MGit::Error] 异常错误
87
+ #
88
+ def update(root)
89
+ # 加载配置
90
+ config, error = __load_file(root)
91
+ if !error.nil?
92
+ raise Error.new(error)
93
+ return
94
+ end
95
+
96
+ # 如果文件存在但无内容,此时读取到的数据类型是FalseClass,此处统一规范化
97
+ config = {} if !config.is_a?(Hash)
98
+
99
+ # 更新
100
+ yield(config) if block_given?
101
+
102
+ # 更新完后校验格式
103
+ if !config.is_a?(Hash)
104
+ raise Error.new("工具配置更新数据格式错误,更新失败!")
105
+ return
106
+ end
107
+
108
+ # 写回配置
109
+ error = write_to_file(root, config)
110
+ if !error.nil?
111
+ raise Error.new(error)
112
+ return
113
+ end
114
+ end
115
+
116
+ # 列出所有配置
117
+ #
118
+ # @param root [String] 工程根目录
119
+ #
120
+ def dump_config(root)
121
+ query(root) { |config|
122
+ CONFIG_KEY.each_with_index { |(key, value_dict), index|
123
+ line = "#{Output.blue_message("[#{value_dict[:info]}]")}\n#{key.to_s}: "
124
+ set_value = config[key.to_s]
125
+ if !set_value.nil?
126
+ line += "#{set_value}\n\n"
127
+ else
128
+ line += "#{value_dict[:default]}\n\n"
129
+ end
130
+ puts line
131
+ }
132
+ }
133
+ end
134
+
135
+ # 验证一个value的值是否符合key的类型
136
+ #
137
+ # @param root [String] 工程根目录
138
+ #
139
+ # @param key [String] 字符串key值
140
+ #
141
+ # @param value [String] 字符串格式的值
142
+ #
143
+ # @return [Object] key值对应的合法类型value值
144
+ #
145
+ def to_suitable_value_for_key(root, key, value)
146
+ return unless CONFIG_KEY.keys.include?(key.to_sym)
147
+ return nil if !value.is_a?(String)
148
+
149
+ key_dict = CONFIG_KEY[key.to_sym]
150
+ set_value = nil
151
+
152
+ # 是否是数字
153
+ if key_dict[:type] == 'Integer' && value.to_i.to_s == value
154
+ set_value = value.to_i
155
+
156
+ # 是否是true
157
+ elsif key_dict[:type] == 'Boolean' && value.to_s.downcase == 'true'
158
+ set_value = true
159
+
160
+ # 是否是false
161
+ elsif key_dict[:type] == 'Boolean' && value.to_s.downcase == 'false'
162
+ set_value = false
163
+
164
+ # 是否是其他字符串
165
+ elsif key_dict[:type] == 'String' && value.is_a?(String)
166
+ set_value = value
167
+ end
168
+
169
+ set_value
170
+ end
171
+
172
+ private
173
+
174
+ # 加载mgit配置文件
175
+ #
176
+ # @param root [String] 工程根目录
177
+ #
178
+ # @return [(Hash, Boolean)] (配置内容,错误信息)
179
+ #
180
+ def __load_file(root)
181
+ config_path = File.join(root, Constants::MGIT_CONFIG_PATH)
182
+ if File.exists?(config_path)
183
+ begin
184
+ return YAML.load_file(config_path), nil
185
+ rescue => e
186
+ return nil, "工具配置文件\"#{File.basename(config_path)}\"读取失败,原因:\n#{e.message}"
187
+ end
188
+ end
189
+
190
+ [nil, nil]
191
+ end
192
+
193
+ # 将配置写回文件
194
+ #
195
+ # @param root [String] 工程根目录
196
+ #
197
+ # @param content [Hash] 新配置
198
+ #
199
+ # @return [String] 错误信息
200
+ #
201
+ def write_to_file(root, content)
202
+ config_path = File.join(root, Constants::MGIT_CONFIG_PATH)
203
+ begin
204
+ FileUtils.rm_f(config_path) if File.exist?(config_path)
205
+
206
+ dir_name = File.dirname(config_path)
207
+ FileUtils.mkdir_p(dir_name) if !Dir.exist?(dir_name)
208
+
209
+ file = File.new(config_path, 'w')
210
+ if !file.nil?
211
+ file.write(content.to_yaml)
212
+ file.close
213
+ end
214
+ return nil
215
+ rescue => e
216
+ return "工具配置文件\"#{File.basename(config_path)}\"写入失败,原因:\n#{e.message}"
217
+ end
218
+ end
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,139 @@
1
+ #coding=utf-8
2
+
3
+ module MGit
4
+ # 本类用于缓存/加载操作中间态
5
+ class OperationProgressContext
6
+
7
+ # 现场信息关键字段
8
+ CONTEXT_CMD = 'cmd'
9
+ CONTEXT_OPTS = 'opts'
10
+ CONTEXT_BRANCH = 'branch'
11
+ CONTEXT_REPOS = 'repos'
12
+ CONTEXT_OTHER = 'other'
13
+
14
+ attr_accessor :type # String: 本次进入中间态的操作类型,可自定义,如'merge_in_progress','rebase_in_progress'等。该字段用于索引缓存的中间态信息,需要唯一。
15
+ attr_accessor :cmd # String: 本次执行指令,如'merge','checkout'等
16
+ attr_accessor :opts # String: 本次执行参数,如'--no-ff','--ff'等
17
+ attr_accessor :branch # String: 仓库当前分支
18
+ attr_accessor :repos # [String]: 本次执行哪些仓库的名称数组
19
+ attr_accessor :other # Object: 其他信息,可自定义
20
+
21
+ def initialize(type)
22
+ self.type = type
23
+ self.other = {}
24
+ end
25
+
26
+ # 将中间态对象序列化为Hash
27
+ def serialize
28
+ return {
29
+ CONTEXT_CMD => self.cmd,
30
+ CONTEXT_OPTS => self.opts,
31
+ CONTEXT_BRANCH => self.branch,
32
+ CONTEXT_REPOS => self.repos,
33
+ CONTEXT_OTHER => self.other
34
+ }
35
+ end
36
+
37
+ # 反序列化
38
+ #
39
+ # @param dict [Hash] 中间态Hash
40
+ #
41
+ def deserialize(dict)
42
+ self.cmd = dict[CONTEXT_CMD]
43
+ self.opts = dict[CONTEXT_OPTS]
44
+ self.branch = dict[CONTEXT_BRANCH]
45
+ self.repos = dict[CONTEXT_REPOS]
46
+ self.other = dict[CONTEXT_OTHER]
47
+ end
48
+
49
+ # 校验中间态是否合法,仓库可缺省,若缺省则表示所有仓库
50
+ #
51
+ # @return [Boolean] 是否合法
52
+ #
53
+ def validate?
54
+ return !self.cmd.nil? && !self.opts.nil? && !self.branch.nil?
55
+ end
56
+ end
57
+
58
+ class OperationProgressManager
59
+
60
+ PROGRESS_TYPE = {
61
+ :merge => 'merge_in_progress',
62
+ :rebase => 'rebase_in_progress',
63
+ :pull => 'pull_in_progress'
64
+ }.freeze
65
+
66
+ class << self
67
+
68
+ # 进入中间态
69
+ #
70
+ # @param root [String] 多仓库根目录
71
+ #
72
+ # @param context [OperationProgressContext] 中间态对象
73
+ #
74
+ def trap_into_progress(root, context)
75
+ begin
76
+ MGitConfig.update(root) { |config|
77
+ config[context.type] = context.serialize
78
+ }
79
+ rescue Error => e
80
+ Output.puts_fail_message(e.msg)
81
+ end
82
+ end
83
+
84
+ # 删除中间态
85
+ #
86
+ # @param root [String] 多仓库根目录
87
+ #
88
+ # @param type [String] 自定义Key值,用于索引中间态信息
89
+ #
90
+ def remove_progress(root, type)
91
+ begin
92
+ MGitConfig.update(root) { |config|
93
+ config.delete(type)
94
+ }
95
+ rescue Error => e
96
+ Output.puts_fail_message(e.msg)
97
+ end
98
+ end
99
+
100
+ # 是否处于中间态中
101
+ def is_in_progress?(root, type)
102
+ is_in_progress = false
103
+ begin
104
+ MGitConfig.query(root) { |config|
105
+ is_in_progress = !config[type].nil?
106
+ }
107
+ rescue Error => e
108
+ Output.puts_fail_message(e.msg)
109
+ end
110
+ return is_in_progress
111
+ end
112
+
113
+ # 加载中间态上下文
114
+ #
115
+ # @param root [String] 多仓库根目录
116
+ #
117
+ # @param type [String] 自定义Key值,用于索引中间态信息
118
+ #
119
+ # @return [OperationProgressContext,String] 中间态对象;错误信息
120
+ #
121
+ def load_context(root, type)
122
+ context = nil
123
+ error = nil
124
+ begin
125
+ MGitConfig.query(root) { |config|
126
+ dict = config[type]
127
+ context = OperationProgressContext.new(type)
128
+ context.deserialize(dict)
129
+ }
130
+ rescue Error => e
131
+ Output.puts_fail_message(e.msg)
132
+ error = e.msg
133
+ end
134
+ return context, error
135
+ end
136
+
137
+ end
138
+ end
139
+ end