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,37 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
module MGit
|
3
|
+
class OpenApi
|
4
|
+
|
5
|
+
module DownloadResult
|
6
|
+
SUCCESS = 0
|
7
|
+
FAIL = 1
|
8
|
+
EXIST = 2
|
9
|
+
end
|
10
|
+
|
11
|
+
class ScriptDownloadInfo
|
12
|
+
|
13
|
+
# [String] 下载仓库名
|
14
|
+
attr_reader :repo_name
|
15
|
+
|
16
|
+
# [String] 下载仓库本地地址
|
17
|
+
attr_reader :repo_path
|
18
|
+
|
19
|
+
# [OpenApi::DOWNLOAD_RESULT] 下载结果
|
20
|
+
attr_reader :result
|
21
|
+
|
22
|
+
# [String] 执行输出,若出错,该变量保存出错信息,可能为nil
|
23
|
+
attr_reader :output
|
24
|
+
|
25
|
+
# [Float] 当前仓库在整个下载任务中所处进度(如10个任务,当前第5个下载完,则progress=0.5),并非单仓库下载进度。
|
26
|
+
attr_reader :progress
|
27
|
+
|
28
|
+
def initialize(repo_name, repo_path, result, output, progress)
|
29
|
+
@repo_name = repo_name
|
30
|
+
@repo_path = repo_path
|
31
|
+
@result = result
|
32
|
+
@output = output
|
33
|
+
@progress = progress
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,461 @@
|
|
1
|
+
#coding=utf-8
|
2
|
+
|
3
|
+
require 'm-git/foundation'
|
4
|
+
|
5
|
+
module MGit
|
6
|
+
module Output
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# --- 简单输出 ---
|
10
|
+
|
11
|
+
def puts_cancel_message
|
12
|
+
puts_fail_message("执行取消!")
|
13
|
+
end
|
14
|
+
|
15
|
+
def puts_succeed_cmd(cmd)
|
16
|
+
puts_success_message("指令[ mgit #{cmd} ]执行成功!")
|
17
|
+
end
|
18
|
+
|
19
|
+
def puts_start_cmd
|
20
|
+
puts_processing_message("开始执行...")
|
21
|
+
end
|
22
|
+
|
23
|
+
def puts_fail_cmd(cmd)
|
24
|
+
puts_fail_message("指令[ mgit #{cmd} ]执行失败!")
|
25
|
+
end
|
26
|
+
|
27
|
+
def puts_nothing_to_do_cmd
|
28
|
+
puts_remind_message("没有仓库需要执行指令!")
|
29
|
+
end
|
30
|
+
|
31
|
+
def puts_success_message(str)
|
32
|
+
MGit::Loger.info(str.strip)
|
33
|
+
puts success_message(str)
|
34
|
+
end
|
35
|
+
|
36
|
+
def puts_remind_message(str)
|
37
|
+
MGit::Loger.info(str)
|
38
|
+
puts remind_message(str)
|
39
|
+
end
|
40
|
+
|
41
|
+
def puts_terminate_message(str, title:nil)
|
42
|
+
MGit::Loger.error("#{title}: #{str}")
|
43
|
+
puts terminate_message(str, title:title)
|
44
|
+
end
|
45
|
+
|
46
|
+
def puts_fail_message(str)
|
47
|
+
MGit::Loger.error(str)
|
48
|
+
puts fail_message(str)
|
49
|
+
end
|
50
|
+
|
51
|
+
def puts_processing_message(str)
|
52
|
+
MGit::Loger.info(str)
|
53
|
+
puts processing_message(str)
|
54
|
+
end
|
55
|
+
|
56
|
+
def puts_fail_block(list, bottom_summary)
|
57
|
+
puts generate_fail_block(list, bottom_summary)
|
58
|
+
end
|
59
|
+
|
60
|
+
def puts_remind_block(list, bottom_summary)
|
61
|
+
puts generate_remind_block(list, bottom_summary)
|
62
|
+
end
|
63
|
+
|
64
|
+
def puts_processing_block(list, bottom_summary)
|
65
|
+
puts generate_processing_block(list, bottom_summary)
|
66
|
+
end
|
67
|
+
|
68
|
+
def puts_fail_combined_block(list_array, bottom_summary, title:nil)
|
69
|
+
puts generate_fail_combined_block(list_array, bottom_summary, title:title)
|
70
|
+
end
|
71
|
+
|
72
|
+
def puts_in_pager(output)
|
73
|
+
begin
|
74
|
+
pager = TTY::Pager.new
|
75
|
+
pager.page(output)
|
76
|
+
rescue => _
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# --- 交互式输出 ---
|
81
|
+
|
82
|
+
def continue_with_user_remind?(msg)
|
83
|
+
puts blue_message("[?] #{msg} Y/n")
|
84
|
+
MGit::DurationRecorder.pause
|
85
|
+
input = nil
|
86
|
+
loop do
|
87
|
+
input = STDIN.gets.chomp.downcase
|
88
|
+
if input == 'y' || input == 'yes' || input == 'n' || input == 'no'
|
89
|
+
break
|
90
|
+
end
|
91
|
+
puts blue_message("[?] 输入不合法,#{msg} Y/n")
|
92
|
+
end
|
93
|
+
MGit::DurationRecorder.resume
|
94
|
+
return input == 'y' || input == 'yes'
|
95
|
+
end
|
96
|
+
|
97
|
+
def continue_with_interact_repos?(repos, msg)
|
98
|
+
output = generate_table(repos, separator:'|') + "\n"
|
99
|
+
output += blue_message("[?] #{msg} Y/n")
|
100
|
+
puts output
|
101
|
+
MGit::DurationRecorder.pause
|
102
|
+
input = nil
|
103
|
+
loop do
|
104
|
+
input = STDIN.gets.chomp.downcase
|
105
|
+
if input == 'y' || input == 'yes' || input == 'n' || input == 'no'
|
106
|
+
break
|
107
|
+
end
|
108
|
+
puts blue_message("[?] 输入不合法,#{msg} Y/n")
|
109
|
+
end
|
110
|
+
MGit::DurationRecorder.resume
|
111
|
+
return input == 'y' || input == 'yes'
|
112
|
+
end
|
113
|
+
|
114
|
+
def continue_with_combined_interact_repos?(repos_array, msg, title:nil)
|
115
|
+
output = generate_table_combination(repos_array, title:title, separator:'|') + "\n"
|
116
|
+
output += blue_message("[?] #{msg} Y/n")
|
117
|
+
puts output
|
118
|
+
MGit::DurationRecorder.pause
|
119
|
+
input = nil
|
120
|
+
loop do
|
121
|
+
input = STDIN.gets.chomp.downcase
|
122
|
+
if input == 'y' || input == 'yes' || input == 'n' || input == 'no'
|
123
|
+
break
|
124
|
+
end
|
125
|
+
puts blue_message("[?] 输入不合法,#{msg} Y/n")
|
126
|
+
end
|
127
|
+
MGit::DurationRecorder.resume
|
128
|
+
return input == 'y' || input == 'yes'
|
129
|
+
end
|
130
|
+
|
131
|
+
# 显示一组复合表格并显示多选项操作
|
132
|
+
#
|
133
|
+
# @param list_array [Array<Array>] 包含表格内容的数组,其中每个元素为数组,表示一张表格内容,list_array内容为:【【title1, list1】,【title2, list2】...】, title<String>为标题,list<Array>为单张表格元素数组,所有内容会被渲染为多张表格然后合并为一张
|
134
|
+
#
|
135
|
+
# @param msg [string] 交互消息
|
136
|
+
#
|
137
|
+
# @param selection [Array] 选型数组,如:【'a: 跳过并继续', 'b: 强制执行', 'c: 终止'】
|
138
|
+
#
|
139
|
+
def interact_with_multi_selection_combined_repos(list_array, msg, selection)
|
140
|
+
puts generate_table_combination(list_array, separator:'|')
|
141
|
+
puts blue_message("[?] #{msg},请选择操作:\n#{selection.join("\n")}")
|
142
|
+
MGit::DurationRecorder.pause
|
143
|
+
input = STDIN.gets.chomp
|
144
|
+
MGit::DurationRecorder.resume
|
145
|
+
yield(input) if block_given?
|
146
|
+
end
|
147
|
+
|
148
|
+
# --- 特定消息生成器 ---
|
149
|
+
|
150
|
+
def processing_message(str)
|
151
|
+
return yellow_message("[~] #{str}")
|
152
|
+
end
|
153
|
+
|
154
|
+
def remind_message(str)
|
155
|
+
return blue_message("[!] #{str}")
|
156
|
+
end
|
157
|
+
|
158
|
+
def success_message(str)
|
159
|
+
return green_message("[✔] #{str}")
|
160
|
+
end
|
161
|
+
|
162
|
+
def fail_message(str)
|
163
|
+
return red_message("[✘] #{str}")
|
164
|
+
end
|
165
|
+
|
166
|
+
def terminate_message(str, title:nil)
|
167
|
+
header = "执行终止"
|
168
|
+
header = title if !title.nil?
|
169
|
+
return red_message("[✘✘✘ #{header} ✘✘✘] #{str}")
|
170
|
+
end
|
171
|
+
|
172
|
+
# --- 有色输出生成器 ---
|
173
|
+
|
174
|
+
# 绿色提示信息
|
175
|
+
def green_message(str)
|
176
|
+
return "\033[32m#{str}\033[0m"
|
177
|
+
end
|
178
|
+
|
179
|
+
# 青色提示信息
|
180
|
+
def blue_message(str)
|
181
|
+
return "\033[36m#{str}\033[0m"
|
182
|
+
end
|
183
|
+
|
184
|
+
# 紫红色提示信息
|
185
|
+
def red_message(str)
|
186
|
+
return "\033[31m#{str}\033[0m"
|
187
|
+
end
|
188
|
+
|
189
|
+
# 黄色提示信息
|
190
|
+
def yellow_message(str)
|
191
|
+
return "\033[33m#{str}\033[0m"
|
192
|
+
end
|
193
|
+
|
194
|
+
def info_title(str)
|
195
|
+
return "\033[4m#{str}\033[0m"
|
196
|
+
end
|
197
|
+
|
198
|
+
# --- 格式化输出生成器 ---
|
199
|
+
|
200
|
+
def generate_fail_combined_block(list_array, bottom_summary, title:nil)
|
201
|
+
return '' if list_array.nil? || list_array.length == 0
|
202
|
+
output = generate_table_combination(list_array, title: title, separator:'|') + "\n"
|
203
|
+
output += fail_message(bottom_summary)
|
204
|
+
return output
|
205
|
+
end
|
206
|
+
|
207
|
+
def generate_remind_block(list, bottom_summary)
|
208
|
+
msg = generate_block(list, remind_message(bottom_summary))
|
209
|
+
MGit::Loger.info(bottom_summary)
|
210
|
+
return msg
|
211
|
+
end
|
212
|
+
|
213
|
+
def generate_fail_block(list, bottom_summary)
|
214
|
+
msg = generate_block(list, fail_message(bottom_summary))
|
215
|
+
MGit::Loger.info(bottom_summary)
|
216
|
+
return msg
|
217
|
+
end
|
218
|
+
|
219
|
+
def generate_processing_block(list, bottom_summary)
|
220
|
+
msg = generate_block(list, processing_message(bottom_summary))
|
221
|
+
MGit::Loger.info(bottom_summary)
|
222
|
+
return msg
|
223
|
+
end
|
224
|
+
|
225
|
+
def generate_block(list, bottom_summary)
|
226
|
+
return '' if list.nil? || list.length == 0
|
227
|
+
output = generate_table(list, separator:'|') + "\n"
|
228
|
+
output += bottom_summary
|
229
|
+
MGit::Loger.info(list)
|
230
|
+
return output
|
231
|
+
end
|
232
|
+
|
233
|
+
def generate_title_block(title, has_separator:true)
|
234
|
+
title = "--- #{title} ---"
|
235
|
+
separator = ''
|
236
|
+
separator = "\n" + '=' * string_length_by_ascii(title) if has_separator
|
237
|
+
output = blue_message(title + separator) + "\n"
|
238
|
+
output += yield(output)
|
239
|
+
return output
|
240
|
+
end
|
241
|
+
|
242
|
+
# 生成合成表格(将多个表格融合为一个)
|
243
|
+
#
|
244
|
+
# @param list_array [Array<Array>] 包含表格内容的数组,其中每个元素为数组,表示一张表格内容,list_array内容为:【【title1, list1】,【title2, list2】...】, title<String>为标题,list<Array>为单张表格元素数组,所有内容会被渲染为多张表格然后合并为一张
|
245
|
+
#
|
246
|
+
# @param title [String] default: nil 表格标题
|
247
|
+
#
|
248
|
+
# @param separator [String] default: '' 表格内元素分割线
|
249
|
+
#
|
250
|
+
# @return [String] 生成的合成表格
|
251
|
+
#
|
252
|
+
def generate_table_combination(list_array, title:nil, separator:'')
|
253
|
+
table_width = -1
|
254
|
+
head_separator = "| "
|
255
|
+
middle_separator = " #{separator} "
|
256
|
+
tail_separator = " |"
|
257
|
+
head_tail_padding = head_separator.length + tail_separator.length
|
258
|
+
|
259
|
+
list_array.each { |list|
|
260
|
+
items = list.last
|
261
|
+
max_table_width, _, _ = calculate_table_info(items, head_separator, middle_separator, tail_separator, title:list.first)
|
262
|
+
table_width = max_table_width if !max_table_width.nil? && max_table_width > table_width
|
263
|
+
}
|
264
|
+
|
265
|
+
output = ''
|
266
|
+
if !title.nil? && table_width > 0
|
267
|
+
|
268
|
+
title_length = string_length_by_ascii(title)
|
269
|
+
table_width = title_length + head_tail_padding if table_width < title_length + head_tail_padding
|
270
|
+
|
271
|
+
space = secure(table_width - head_tail_padding - title_length) / 2
|
272
|
+
head_line = head_separator + ' ' * space + title
|
273
|
+
head_line = head_line + ' ' * secure(table_width - string_length_by_ascii(head_line) - tail_separator.length) + tail_separator + "\n"
|
274
|
+
|
275
|
+
output += '-' * table_width + "\n"
|
276
|
+
output += head_line
|
277
|
+
end
|
278
|
+
|
279
|
+
list_array.each_with_index { |list, idx|
|
280
|
+
sub_title = list.first if !list.first.nil? && list.first != ''
|
281
|
+
output += generate_table(list.last, title:sub_title, separator:separator, fixed_width:table_width, hide_footer_line:idx != list_array.length - 1)
|
282
|
+
}
|
283
|
+
return output
|
284
|
+
end
|
285
|
+
|
286
|
+
# 生成表格
|
287
|
+
#
|
288
|
+
# @param list [Array] 包含表格中显示内容
|
289
|
+
#
|
290
|
+
# @param title [String] default: nil 表格标题
|
291
|
+
#
|
292
|
+
# @param separator [String] default: '' 表格内部分割线
|
293
|
+
#
|
294
|
+
# @param fixed_width [Number] default: -1 可指定表格宽度,若指定宽度大于计算所得最大宽度,则使用该指定宽度
|
295
|
+
#
|
296
|
+
# @param hide_footer_line [Boolean] default: false 隐藏底部分割线
|
297
|
+
#
|
298
|
+
# @return [String] 已生成的表格字符串
|
299
|
+
#
|
300
|
+
def generate_table(list, title:nil, separator:'', fixed_width:-1, hide_footer_line:false)
|
301
|
+
return '' if list.nil? || list.length == 0
|
302
|
+
|
303
|
+
output = ''
|
304
|
+
head_separator = "| "
|
305
|
+
middle_separator = " #{separator} "
|
306
|
+
tail_separator = " |"
|
307
|
+
head_tail_padding = head_separator.length + tail_separator.length
|
308
|
+
|
309
|
+
max_table_width, column, max_meta_display_length_by_ascii = calculate_table_info(list, head_separator, middle_separator, tail_separator, title:title, fixed_width:fixed_width)
|
310
|
+
|
311
|
+
if !max_table_width.nil? && !column.nil? && !max_meta_display_length_by_ascii.nil?
|
312
|
+
if !title.nil?
|
313
|
+
title_length = string_length_by_ascii(title)
|
314
|
+
title = head_separator + title + ' ' * secure(max_table_width - title_length - head_tail_padding) + tail_separator
|
315
|
+
|
316
|
+
max_table_width = title_length + head_tail_padding if max_table_width < title_length + head_tail_padding
|
317
|
+
output += '-' * max_table_width + "\n"
|
318
|
+
output += title + "\n"
|
319
|
+
|
320
|
+
# 处理标题下的分割线
|
321
|
+
output += head_separator + '-' * title_length + ' ' * secure(max_table_width - head_tail_padding - title_length) + tail_separator + "\n"
|
322
|
+
else
|
323
|
+
output += '-' * max_table_width + "\n"
|
324
|
+
end
|
325
|
+
|
326
|
+
list.each_slice(column).to_a.each { |row|
|
327
|
+
line = head_separator
|
328
|
+
row.each_with_index { |item, idx|
|
329
|
+
# 最大显示宽度由纯ascii字符个数度量,而输出时中文占2个ascii字符宽度
|
330
|
+
# ljust方法以字符做计算,一个汉字会被认为是一个字符,但占了2单位宽度,需要把显示宽度根据汉字个数做压缩,如:
|
331
|
+
# 最长显示字符(纯ascii字符):'abcdef1234', 字符长度10,占10个ascii字符显示宽度
|
332
|
+
# 需要输出字符串:'[删除]abc',字符长度7,但有2个汉字,占9个ascii字符显示宽度
|
333
|
+
# 因此,ljust接受宽度字符个数:10 - 2 = 8
|
334
|
+
# 即对于'[删除]abc'这样的字符串,8个字符对应的ascii字符显示宽度('[删除]abc ', 注意8个字符宽度此时有一个空格)和'abcdef1234'显示宽度等长
|
335
|
+
line += item.ljust(max_meta_display_length_by_char(item, max_meta_display_length_by_ascii))
|
336
|
+
line += middle_separator if idx != row.length - 1
|
337
|
+
}
|
338
|
+
last_line_space = ' ' * secure(max_table_width - string_length_by_ascii(line) - tail_separator.length)
|
339
|
+
line += last_line_space + tail_separator
|
340
|
+
output += line + "\n"
|
341
|
+
}
|
342
|
+
output += '-' * max_table_width if !hide_footer_line
|
343
|
+
else
|
344
|
+
if list.length > 1
|
345
|
+
output = list.join("\n")
|
346
|
+
else
|
347
|
+
output = list.first + "\n"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
return output
|
352
|
+
end
|
353
|
+
|
354
|
+
# 计算表格信息
|
355
|
+
#
|
356
|
+
# @param list [Array] 包含表格中显示内容
|
357
|
+
#
|
358
|
+
# @param head_separator [String] 表格头部分割线
|
359
|
+
#
|
360
|
+
# @param middle_separator [String] 表格中部分割线
|
361
|
+
#
|
362
|
+
# @param tail_separator [String] 表格尾部分割线
|
363
|
+
#
|
364
|
+
# @param fixed_width [Number] default: -1 可指定表格宽度,若指定宽度大于计算所得最大宽度,则使用该指定宽度
|
365
|
+
#
|
366
|
+
# @return [Objtct...] 返回表格最大宽度,表格列数,表格中一个项目显示的最大长度
|
367
|
+
#
|
368
|
+
def calculate_table_info(list, head_separator, middle_separator, tail_separator, title:nil, fixed_width:-1)
|
369
|
+
return nil if list.nil? || list.length == 0
|
370
|
+
|
371
|
+
head_tail_padding = head_separator.length + tail_separator.length
|
372
|
+
|
373
|
+
max_meta_display_length_by_ascii = -1
|
374
|
+
list.each { |item|
|
375
|
+
display_length = string_length_by_ascii(item)
|
376
|
+
if max_meta_display_length_by_ascii < display_length
|
377
|
+
max_meta_display_length_by_ascii = display_length
|
378
|
+
end
|
379
|
+
}
|
380
|
+
|
381
|
+
# 终端宽度。
|
382
|
+
# -1:减去最后一行"\n"
|
383
|
+
screen_width = `tput cols`.to_i - 1
|
384
|
+
if screen_width > 0 && screen_width > max_meta_display_length_by_ascii + head_tail_padding
|
385
|
+
# 定义:
|
386
|
+
# n:列数
|
387
|
+
# a:单个item最大长度
|
388
|
+
# b:分隔字符长度
|
389
|
+
# l:表格宽度减去前后padding的长度
|
390
|
+
# 如:| [abc]def | [def]abcd | [zz]asdf |
|
391
|
+
# 有: |<------------ l ------------>|
|
392
|
+
# |<- a -->|
|
393
|
+
# n=3,a=9,b=3(' | '.length == 3),l=31
|
394
|
+
|
395
|
+
# 计算l
|
396
|
+
raw_length = screen_width - head_tail_padding
|
397
|
+
|
398
|
+
# 计算列数:n * a + (n - 1) * b = l => n = (l + b) / (a + b)
|
399
|
+
column = (raw_length + middle_separator.length) / (max_meta_display_length_by_ascii + middle_separator.length)
|
400
|
+
|
401
|
+
# 如果计算得到的列数小于item个数,那么取item个数为最大列数
|
402
|
+
column = list.length if column > list.length
|
403
|
+
|
404
|
+
# 计算一个item的平均长度“al”,由
|
405
|
+
# 1. n * a + (n - 1) * b = l
|
406
|
+
# 2. al = l / n
|
407
|
+
# => al = (n * (a + b) - b) / n
|
408
|
+
average_length = (column * (max_meta_display_length_by_ascii + middle_separator.length) - middle_separator.length) / column.to_f
|
409
|
+
|
410
|
+
# 表格最大宽度为:n * al + head_tail_padding
|
411
|
+
max_table_width = (column * average_length + head_tail_padding).ceil
|
412
|
+
|
413
|
+
# 如果title最宽,则使用title宽度
|
414
|
+
if !title.nil? && title.is_a?(String)
|
415
|
+
title_length = string_length_by_ascii(head_separator + title + tail_separator)
|
416
|
+
max_table_width = title_length if max_table_width < title_length && title_length < screen_width
|
417
|
+
end
|
418
|
+
|
419
|
+
# 如果指定了一个合理的宽度,则使用该宽度
|
420
|
+
max_table_width = fixed_width if max_table_width < fixed_width && fixed_width <= screen_width
|
421
|
+
|
422
|
+
return max_table_width, column, max_meta_display_length_by_ascii
|
423
|
+
else
|
424
|
+
return nil
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# 输出时中文占2个字符宽度,根据字符串中的汉字个数重新计算字符串长度(以纯ascii字符作度量)
|
429
|
+
def string_length_by_ascii(str)
|
430
|
+
chinese_chars = str.scan(/\p{Han}/)
|
431
|
+
length = str.length + chinese_chars.length
|
432
|
+
return length
|
433
|
+
end
|
434
|
+
|
435
|
+
# 输出时中文占2个字符宽度,根据字符串中的汉字个数重新计算最大显示字符长度(以包括汉字在内的字符作度量)
|
436
|
+
def max_meta_display_length_by_char(str, max_meta_display_length_by_ascii)
|
437
|
+
chinese_chars = str.scan(/\p{Han}/)
|
438
|
+
return max_meta_display_length_by_ascii - chinese_chars.length
|
439
|
+
end
|
440
|
+
|
441
|
+
# 保证数字大于0
|
442
|
+
def secure(num)
|
443
|
+
return num > 0 ? num : 0
|
444
|
+
end
|
445
|
+
|
446
|
+
# --- 进度条 ---
|
447
|
+
|
448
|
+
def update_progress(totaltasks, finishtasks)
|
449
|
+
totalmark = 30
|
450
|
+
progress = totaltasks > 0 ? (finishtasks * 100.0 / totaltasks).round : 100
|
451
|
+
progress_str = ''
|
452
|
+
pre_num = (totalmark / 100.0 * progress).round
|
453
|
+
progress_str += '#' * pre_num
|
454
|
+
progress_str += ' ' * (totalmark - pre_num)
|
455
|
+
bar = "\r[#{progress_str}] #{progress}%"
|
456
|
+
bar += "\n" if progress == 100
|
457
|
+
print bar
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|