-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrain_shell_scripter.py
executable file
·728 lines (561 loc) · 25 KB
/
rain_shell_scripter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import argparse
import csv
import inspect
import os
import re
import signal
from enum import Enum
from pathlib import Path
from shutil import copytree, SameFileError, copy
from happy_python import HappyLog
from happy_python import HappyPyException
from happy_python import dict_to_pretty_json
from happy_python import execute_cmd
from happy_python.happy_log import HappyLogLevel
log = HappyLog.get_instance()
__version__ = '1.4.1'
NULL_VALUE = 'NULL'
line_number = 0
# 变量暂存区
_var_tmp_storage_area = dict()
def _output_message_builder(message: str, status: bool):
return '行号:%s -> %s...[ %s ]' % (line_number, message, ('OK' if status else 'FAILED'))
def _output_message_builder_no_status(message: str):
return '行号:%s -> %s' % (line_number, message)
def _is_alpha_num_underline_str(value: str):
return bool(re.match(r'^\w+$', value))
def _make_error_message(row_desc: str, col_name: str, value_desc: str):
msg = '第%d行->%s模式的行,"%s"列应为"%s"' % (line_number, row_desc, col_name, value_desc)
raise HappyPyException(msg)
def _make_error_message_required(row_desc: str, col_name: str):
msg = '第%d行->%s模式的行,"%s"列需要指定值' % (line_number, row_desc, col_name)
raise HappyPyException(msg)
def _replace_var(s: str) -> (bool, str):
tmp = s
var_dict = {**_var_tmp_storage_area, **os.environ}
# 从暂存区读取变量值 & 从环境变量中读取变量值
for var_name, var_value in var_dict.items():
var_expr = '${%s}' % var_name
index = tmp.find(var_expr)
if index != -1:
# 非感叹号开头的变量,从变量树中查找
if var_value == '' or var_value is None:
log.error('替换变量时出现空值:%s -> %s,type=%s' % (var_name, var_value, type(var_value)))
raise HappyPyException(_output_message_builder(tmp, False))
tmp = tmp.replace(var_expr, var_value)
# 感叹号开头的变量,替换为空
while True:
m = re.match(r'.*(\${!?[a-zA-Z\d_]+}).*', tmp)
if m and m.group(1)[:3] == '${!':
tmp = tmp.replace(m.group(1), '')
else:
break
m = re.match(r'.*(\${[a-zA-Z\d_]+}).*', tmp)
if m:
log.error('存在未替换的变量:%s' % m.group(1))
raise HappyPyException(_output_message_builder(tmp, False))
return tmp
class ColInfo(Enum):
ModeType = '模式'
Expr = '表达式'
ReturnCode = '返回代码'
ReturnType = '返回类型'
DefaultValue = '默认值'
ReturnFilter = '过滤器'
VarName = '变量名'
Message = '提示消息'
__order__ = 'ModeType Expr ReturnCode ReturnType DefaultValue ReturnFilter VarName Message'
class ModeType(Enum):
CONST = 0
VAR = 1
ENV = 2
RUN = 3
MESSAGE = 4
STATEMENT = 5
# 复制文件
COPY = 6
class ReturnType(Enum):
NULL = 0
INT = 1
STR = 2
class CsvRow:
def __init__(self,
mode_type: ModeType,
expr_line: str,
return_code: int,
return_type: ReturnType,
default_value: str,
return_filter: str,
var_name: str,
message: str):
self.mode_type: ModeType = mode_type
self.expr_line = expr_line
self.return_code = return_code
self.return_type = return_type
self.default_value = default_value
# 使用正则表达式从命令执行中过滤出需要的部分
self.return_filter = return_filter
self.var_name = var_name
self.message = message
class ColValidator:
@staticmethod
def validate_mode_type(value: str):
try:
# noinspection PyUnusedLocal
tmp = ModeType[value]
except KeyError:
msg = '第%d行->%s:无效值"%s",可选值为CONST、VAR、ENV、RUN、MESSAGE、STATEMENT、COPY' \
% (line_number, ColInfo.ModeType.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_expr_line(value: str):
if not (value or value == NULL_VALUE):
msg = '第%d行->%s:无效值"%s",可以为NULL或非字符串' % (line_number, ColInfo.Expr.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_return_code(value: str):
if not (value and (value == NULL_VALUE or value.isdigit())):
msg = '第%d行->%s:无效值"%s",只能是数字' % (line_number, ColInfo.ReturnCode.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_return_type(value: str):
try:
# noinspection PyUnusedLocal
tmp = ReturnType[value]
except KeyError:
msg = '第%d行->%s:无效值"%s",可选值为NULL、INT、STR' % (line_number, ColInfo.ReturnType.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_default_value(value: str):
if not (value or value == NULL_VALUE):
msg = '第%d行->%s:无效值"%s",可以为NULL或非空字符串' % (line_number, ColInfo.DefaultValue.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_return_filter(value: str):
if not (value or value == NULL_VALUE):
msg = '第%d行->%s:无效值"%s",可以为NULL或不为空的字符串' % (line_number, ColInfo.ReturnFilter.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_var_name(value: str):
if not (value and (value == NULL_VALUE or _is_alpha_num_underline_str(value))):
msg = '第%d行->%s:无效值"%s",只能由数字、字母和下划线组成' % (line_number, ColInfo.VarName.value, value)
raise HappyPyException(msg)
@staticmethod
def validate_message(value: str):
if not value:
msg = '第%d行->%s:无效值"%s",只能是非空字符串' % (line_number, ColInfo.Message.value, value)
raise HappyPyException(msg)
class RowValidator:
@staticmethod
def validate_const_row(row: CsvRow):
assert row.mode_type == ModeType.CONST
row_desc = '常量'
if row.expr_line != NULL_VALUE:
_make_error_message(row_desc, ColInfo.Expr.value, NULL_VALUE)
if row.return_code != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnCode.value, NULL_VALUE)
if row.return_type == ReturnType.NULL:
_make_error_message_required(row_desc, ColInfo.ReturnType.value)
if not row.default_value or row.default_value == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.DefaultValue.value)
if row.return_filter != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnFilter.value, NULL_VALUE)
if row.var_name == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.VarName.value)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
@staticmethod
def validate_message_row(row: CsvRow):
assert row.mode_type == ModeType.MESSAGE
row_desc = '消息'
if row.expr_line != NULL_VALUE:
_make_error_message(row_desc, ColInfo.Expr.value, NULL_VALUE)
if row.return_code != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnCode.value, NULL_VALUE)
if row.return_type != ReturnType.NULL:
_make_error_message(row_desc, ColInfo.ReturnType.value, NULL_VALUE)
if row.default_value != NULL_VALUE:
_make_error_message(row_desc, ColInfo.DefaultValue.value, NULL_VALUE)
if row.return_filter != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnFilter.value, NULL_VALUE)
if row.var_name != NULL_VALUE:
_make_error_message(row_desc, ColInfo.VarName.value, NULL_VALUE)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
@staticmethod
def validate_env_row(row: CsvRow):
assert row.mode_type == ModeType.ENV
row_desc = '环境变量'
if row.expr_line != NULL_VALUE:
_make_error_message(row_desc, ColInfo.Expr.value, NULL_VALUE)
if row.return_code != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnCode.value, NULL_VALUE)
if row.return_type != ReturnType.NULL:
_make_error_message(row_desc, ColInfo.ReturnType.value, NULL_VALUE)
if row.default_value == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.DefaultValue.value)
if row.return_filter != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnFilter.value, NULL_VALUE)
if row.var_name == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.VarName.value)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
@staticmethod
def validate_run_row(row: CsvRow):
assert row.mode_type == ModeType.RUN
row_desc = '命令'
if row.expr_line == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Expr.value)
if row.return_code == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.ReturnCode.value)
# 忽略 row.return_type
if row.default_value != NULL_VALUE:
_make_error_message(row_desc, ColInfo.DefaultValue.value, NULL_VALUE)
if row.return_filter != NULL_VALUE:
# 设置了过滤器时,必须指定变量名和返回类型
if row.var_name == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.VarName.value)
if row.return_type == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.ReturnType.value)
else:
# 其它情况忽略 row.var_name
pass
# 设置了变量名时,必须设置返回类型
if row.var_name != NULL_VALUE:
if row.return_type == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.ReturnType.value)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
@staticmethod
def validate_statement_row(row: CsvRow):
assert row.mode_type == ModeType.STATEMENT
row_desc = '语句'
if row.expr_line == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Expr.value)
if row.return_code != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnCode.value, NULL_VALUE)
if row.return_filter != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnFilter.value, NULL_VALUE)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
@staticmethod
def validate_copy_row(row: CsvRow):
assert row.mode_type == ModeType.COPY
row_desc = '复制'
if row.expr_line == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Expr.value)
if row.return_code != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnCode.value, NULL_VALUE)
if row.default_value != NULL_VALUE:
_make_error_message(row_desc, ColInfo.DefaultValue.value, NULL_VALUE)
if row.return_filter != NULL_VALUE:
_make_error_message(row_desc, ColInfo.ReturnType.value, NULL_VALUE)
if row.var_name != NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.VarName.value)
if row.message == NULL_VALUE:
_make_error_message_required(row_desc, ColInfo.Message.value)
class RowHandler:
@staticmethod
def const_handler(row: CsvRow):
global _var_tmp_storage_area
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
var_name = row.var_name
var_value = _replace_var(row.default_value)
log.var('var_name', var_name)
log.var('var_value', var_value)
if row.return_type == ReturnType.INT:
_var_tmp_storage_area[var_name] = int(var_value)
elif row.return_type == ReturnType.STR:
_var_tmp_storage_area[var_name] = var_value
else:
_var_tmp_storage_area[var_name] = var_value
log.info(_output_message_builder(message, True))
log.exit_func(fn_name)
@staticmethod
def message_handler(row: CsvRow):
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
log.info(_output_message_builder_no_status(message))
log.exit_func(fn_name)
@staticmethod
def env_handler(row: CsvRow):
import os
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
env_name = row.var_name
env_value = _replace_var(row.default_value)
log.var('env_name', env_name)
log.var('env_value', env_value)
try:
os.environ[env_name] = env_value
log.info(_output_message_builder(message, True))
except Exception as e:
log.critical(e)
raise HappyPyException(_output_message_builder(message, False))
log.exit_func(fn_name)
@staticmethod
def run_handler(row: CsvRow):
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
expr_line = _replace_var(row.expr_line)
expected_return_code = int(row.return_code)
expected_return_type = row.return_type
return_filter = _replace_var(row.return_filter)
save_var_name = row.var_name
log.var('expr_line', expr_line)
log.var('expected_return_code', expected_return_code)
log.var('expected_return_type', expected_return_type)
log.var('return_filter', return_filter)
log.var('save_var_name', save_var_name)
return_code, result = execute_cmd(expr_line, remove_white_char='\n')
log.var('return_code', return_code)
log.var('result', result)
if expected_return_code == return_code:
if return_filter != NULL_VALUE and save_var_name != NULL_VALUE:
m = re.match(r'%s' % return_filter, result)
if m:
value = m.group(1)
# 保存筛选结果到暂存变量
if expected_return_type == ReturnType.INT:
exec('_var_tmp_storage_area[\'%s\'] = %d' % (save_var_name, int(value)), globals())
else:
exec('_var_tmp_storage_area[\'%s\'] = \'%s\'' % (save_var_name, m.group(1)), globals())
log.info(_output_message_builder(message, True))
else:
log.error(expr_line)
log.info(_output_message_builder(message, False))
raise HappyPyException('在执行结果上匹配过滤器,匹配内容为空')
else:
if save_var_name != NULL_VALUE:
_var_tmp_storage_area[save_var_name] = result
log.info(_output_message_builder(message, True))
else:
log.error(expr_line)
log.info(_output_message_builder(message, False))
raise HappyPyException('执行命令返回代码(%s)与预期(%s)不符' % (return_code, expected_return_code))
log.exit_func(fn_name)
@staticmethod
def statement_handler(row: CsvRow):
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
expr_line = _replace_var(row.expr_line)
return_filter = _replace_var(row.return_filter)
save_var_name = row.var_name
expected_return_type = row.return_type
is_expected_return_int_type = expected_return_type == ReturnType.INT
expected_return_value = int(row.default_value) if expected_return_type == ReturnType.INT else row.default_value
log.var('expr_line', expr_line)
log.var('return_filter', return_filter)
log.var('save_var_name', save_var_name)
log.var('expected_return_type', expected_return_type)
log.var('is_expected_return_int_type', is_expected_return_int_type)
log.var('expected_return_value', expected_return_value)
if expected_return_type == ReturnType.INT:
statement = 'tmp = int(%s)' % expr_line
else:
statement = 'tmp = %s' % expr_line
log.var('statement', statement)
try:
exec(statement, locals())
result = locals().get('tmp')
if expected_return_type != ReturnType.NULL and expected_return_value != ReturnType.NULL:
log.debug('以判断语句方式运行')
result = int(result) if is_expected_return_int_type else str(result)
if expected_return_value == result:
log.info(_output_message_builder(message, True))
# 保存执行结果到暂存变量
if save_var_name != NULL_VALUE:
_var_tmp_storage_area[save_var_name] = result
else:
log.info(_output_message_builder(message, False))
raise HappyPyException('返回值(%s)与预期(%s)不符' % (result, expected_return_value))
else:
log.debug('以赋值语句方式运行')
log.info(_output_message_builder(message, True))
# 保存执行结果到暂存变量
if save_var_name != NULL_VALUE:
_var_tmp_storage_area[save_var_name] = result
except Exception as e:
log.error(statement)
log.critical(e)
raise HappyPyException(_output_message_builder(message, False))
log.exit_func(fn_name)
@staticmethod
def copy_handler(row: CsvRow):
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
message = _replace_var(row.message)
log.var('message', message)
expr_line = _replace_var(row.expr_line)
log.var('expr_line', expr_line)
try:
src, dst = expr_line.split(' ')
src_path = Path(src)
dst_path = Path(dst)
if not src_path.exists():
raise HappyPyException(_output_message_builder('源文件或目录不存在:%s' % src_path, False))
if dst_path.is_file() and src_path.is_dir():
raise HappyPyException(_output_message_builder(
'不能将一个源目录(%s)复制到目标文件(%s)' % (src_path, dst_path), False))
if src_path.is_dir():
log.debug('复制源目录(%s)到目标目录(%s)' % (src_path, dst_path))
copytree(src, dst)
elif src_path.is_file() or src_path.is_symlink():
log.debug('复制源文件(%s)到目标文件或目录(%s)' % (src_path, dst_path))
copy(src, dst, follow_symlinks=True)
log.info(_output_message_builder(message, True))
except OSError as e:
log.critical(e)
raise HappyPyException(_output_message_builder('执行复制操作时,出现错误', False))
except SameFileError as e:
log.critical(e)
raise HappyPyException(_output_message_builder('源和目标指向同一个文件或目录', False))
log.exit_func(fn_name)
# 列数量
COL_SIZE = len(ColInfo)
# 每列对应的值校验函数
COL_VALIDATE_X_MAP = {
ColInfo.ModeType: ColValidator.validate_mode_type,
ColInfo.Expr: ColValidator.validate_expr_line,
ColInfo.ReturnCode: ColValidator.validate_return_code,
ColInfo.ReturnType: ColValidator.validate_return_type,
ColInfo.DefaultValue: ColValidator.validate_default_value,
ColInfo.ReturnFilter: ColValidator.validate_return_filter,
ColInfo.VarName: ColValidator.validate_var_name,
ColInfo.Message: ColValidator.validate_message,
}
# 每种模式的行逻辑校验函数
ROW_VALIDATE_X_MAP = {
ModeType.CONST: RowValidator.validate_const_row,
ModeType.MESSAGE: RowValidator.validate_message_row,
ModeType.ENV: RowValidator.validate_env_row,
ModeType.RUN: RowValidator.validate_run_row,
ModeType.STATEMENT: RowValidator.validate_statement_row,
ModeType.COPY: RowValidator.validate_copy_row,
}
# 每种模式的行处理函数
ROW_HANDLER_MAP = {
ModeType.CONST: RowHandler.const_handler,
ModeType.MESSAGE: RowHandler.message_handler,
ModeType.ENV: RowHandler.env_handler,
ModeType.RUN: RowHandler.run_handler,
ModeType.STATEMENT: RowHandler.statement_handler,
ModeType.COPY: RowHandler.copy_handler,
}
def to_csv_row_obj(row: list) -> CsvRow:
fn_name = inspect.stack()[0][3]
log.enter_func(fn_name)
log.var('row', row)
if len(row) != COL_SIZE:
raise HappyPyException('数组%s的数量不正确,应该有%d个元素' % (row, COL_SIZE))
n = 0
for c in ColInfo:
assert c in COL_VALIDATE_X_MAP
# 获取校验函数
col_validate_fun = COL_VALIDATE_X_MAP.get(c)
# 调用列对应的校验函数
col_validate_fun(row[n])
n += 1
mode_type = ModeType[row[0]]
expr_line = row[1]
return_code = row[2]
return_type = ReturnType[row[3]]
default_value = row[4]
return_filter = row[5]
var_name = row[6]
message = row[7]
csv_row = CsvRow(mode_type, expr_line, return_code, return_type,
default_value, return_filter, var_name, message)
row_validate_fun = ROW_VALIDATE_X_MAP.get(mode_type)
if row_validate_fun:
row_validate_fun(csv_row)
else:
msg = '第%d行->%s:无效值"%s",可选值为CONST、VAR、ENV、RUN、MESSAGE、STATEMENT、COPY' \
% (line_number, ColInfo.ModeType.value, row[1])
raise HappyPyException(msg)
log.exit_func(fn_name)
return csv_row
def raining(csv_file: str):
global line_number
try:
with open(csv_file, encoding='UTF-8') as f:
try:
reader = csv.reader(f)
for row in reader:
line_number += 1
# 跳过标题行
if line_number == 1:
continue
row_obj = to_csv_row_obj(row)
handler = ROW_HANDLER_MAP.get(row_obj.mode_type)
handler(row_obj)
except csv.Error as e:
msg = '解析CSV文件行时出现错误\n'
msg += '%s,%d行: %s' % (csv_file, reader.line_num, e)
raise HappyPyException(msg)
except FileExistsError as e:
msg = '读取文件错误:%s:%s' % (csv_file, e)
log.error(msg)
raise HappyPyException(msg)
except FileNotFoundError:
msg = '文件不存在:%s' % csv_file
log.error('文件不存在:%s' % csv_file)
raise HappyPyException(msg)
def main():
global log
parser = argparse.ArgumentParser(prog='rain_shell_scripter',
description='用Python加持Linux Shell脚本,编写CSV文件即可完美解决脚本中的返回值、数值运算、错误处理、流程控制难题~',
usage='%(prog)s -f|-l')
parser.add_argument('-f',
'--file',
help='CSV文件',
required=True,
action='store',
dest='csv_file')
parser.add_argument('-l',
'--log-level',
help='日志级别,CRITICAL|ERROR|WARNING|INFO|DEBUG|TRACE,默认等级3(INFO)',
type=int,
choices=HappyLogLevel.get_list(),
default=HappyLogLevel.INFO.value,
required=False,
dest='log_level')
parser.add_argument('-v',
'--version',
help='显示版本信息',
action='version',
version='%(prog)s/v' + __version__)
args = parser.parse_args()
log.set_level(args.log_level)
# noinspection PyUnusedLocal
def sigint_handler(sig, frame):
log.info('\n\n收到 Ctrl+C 信号,退出......')
# 前台运行收到 CTRL+C 信号,直接退出。
signal.signal(signal.SIGINT, sigint_handler)
try:
raining(args.csv_file)
log.debug('变量暂存区:\n' + dict_to_pretty_json(_var_tmp_storage_area))
except HappyPyException as e:
log.error(e)
exit(1)
if __name__ == '__main__':
main()