命令拼接类 CmdCache
在 DataAnalysisTableRecord类和TaskParam类中都通过cmd_cache属性封装了该类的一个实例。
在这两个类对应的使用场景中,都可以使用cmd_cache的add方法来拼接命令,为了便于使用,这两个类通过同名函数透传调用了该方法,
即调用 record.add()|task_param.add() 等同于调用 record.cmd_cache.add()|task_param.cmd_cache.add()。
使用cmd_cache的add方法拼接好命令之后,可以调用record.run_scripts()|task_param.run_scripts()方法,该方法在cmd_cache.run()函数的基础上增加了额外的功能。建议开发人员不要直接调用 record.cmd_cache.run()|task_param.cmd_cache.run()。run_scripts方法内部通过history_files删除了历史文件,并在执行命令时切换了命令执行所在的目录。
最后,值得说明的是record.clean_cache()|task_param.clean_cache() 方法,该方法透传调用了 cmd_cache.clean_cache(),作用是清除缓存里记录的之前的命令,如果业务里需要执行多条命令,在每次拼接命令之前需要调用该命令。
add 方法
record.add()|task_param.add() 等价于 CmdCache.add(scripts=default_null, key=default_null, value=default_null, ignore_default=None, r_bool_default=None):
scripts:default_null|str|list,调用脚本或功能名称key:default_null|None|str,命令选项,如-i,-c等,可不存在value:default_null|None|str,命令选项的值,如infile.txt,red等,可不存在ignore_default:None|str|bool,如果不为None,则当给定值与value值相同时,忽略拼接该参数。r_bool_default:None|bool,如果不为None,则必须为bool类型,此时为将value转化成bool类型,并与其比较,不同则拼接到命令中,相同则忽略。
下面给出一些示例说明:
scripts,key,value三个参数不能同时为空,必须指定至少一个
1. 仅指定 scripts
from hippo.web.utils import CmdCache
cmd_cache = CmdCache()
cmd_cache.add(scripts="nvidia-smi") # 1.仅包含scripts (str)
cmd_cache.get_str()
# nvidia-smi
cmd_cache.clean_cache() # 清空之前的拼接命令缓存
cmd_cache.add(scripts=["sleep", "5"]) # 2.仅包含scripts (list);list 必须全为字符串
cmd_cache.get_str()
# sleep 5
cmd_cache.clean_cache() # 清空之前的拼接命令缓存
cmd_cache.add(scripts="ls -l") # 也可以直接将命令拼接好,不规范用法
cmd_cache.get_str()
# ls -l
# note: 指定scripts时,不能给空字符串, cmd_cache.add(scripts="") 会导致异常
2. 一些常见的命令行类型
当scripts指定为脚本或命令名时,key和value参数有三种拼接的可能情形,
1. 没有value,此时仅指定key参数即可
2. 没有key,此时key=None
3. 同时存在,此时程序会对value参数在特殊情况下进行一些处理。详见下面代码示例中的说明
cmd_cache.clean_cache() # 清空之前的拼接命令缓存
cmd_cache.add(scripts="ls")
cmd_cache.add(key="-l") # 没有value
cmd_cache.get_str()
# ls -l
cmd_cache.clean_cache() # 清空之前的拼接命令缓存
cmd_cache.add(scripts="sleep")
cmd_cache.add(key=None, value="5") # 没有key
cmd_cache.get_str()
# sleep 5
cmd_cache.clean_cache() # 清空之前的拼接命令缓存
cmd_cache.add(scripts="demo_shell.sh")
cmd_cache.add(key="-i", value=1) # 支持 int
cmd_cache.add(key="-f", value=1.2) # 支持 float
cmd_cache.add(key="-b", value=True) # 支持 bool,拼接的值为True
cmd_cache.add(key="--title", value="main title") # 包含空格
cmd_cache.add(key="--sub-title", value="-log x^2") # 以-开头的参数,拼接中进行特殊处理
cmd_cache.add(key="--disc", value="&#;|") # 包含特殊字符
cmd_cache.add(key="--single", value="包含'引号") # 包含特殊字符
cmd_cache.add(key="--double", value='包含"引号') # 包含特殊字符
cmd_cache.get_str()
# demo_shell.sh -i 1 -f 1.2 -b True --title "main title" --sub-title="-log x^2" --disc "&#;|" --single "包含'引号" --double '包含"引号'
3. ignore_default的说明
cmd_cache.clean_cache()
color = "red" # or "yellow"
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="-c", value=color, ignore_default="red")
cmd_cache.get_str()
# color="red",则
# demo.py -i infile.txt
# color="yellow",则
# demo.py -i infile.txt -c yellow
4. r_bool_default 的说明
r_bool_default指定值必须为布尔类型,该参数一般用于R脚本的logical类型参数,当用户选择的参数和给定默认值相同,则最后的命令行会忽略拼接该参数。
与给定的值不同时,会传入R中需要的命令行参数(大写的TRUE或FALSE)
# type 1
cmd_cache.clean_cache()
smooth_roc = False # or True
cmd_cache.add("demo.r")
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="--smooth_roc", value=smooth_roc, r_bool_default=True)
cmd_cache.get_str()
# demo.r -i infile.txt --smooth_roc FALSE ## when smooth_roc=False
# demo.r -i infile.txt ## when smooth_roc=True,忽略该参数
# type 2
cmd_cache.clean_cache()
smooth_roc = False # or True
cmd_cache.add("demo.r")
cmd_cache.add(key="-i", value="infile.txt")
cmd_cache.add(key="--smooth_roc", value=smooth_roc, r_bool_default=False)
cmd_cache.get_str()
# demo.r -i infile.txt ## when smooth_roc=False,忽略该参数
# demo.r -i infile.txt --smooth_roc FALSE ## when smooth_roc=True
run_scripts 方法
在接口或者任务代码中请使用 .run_scripts()执行脚本命令,不要使用 .cmd_cache.run() 方法,这是因为就命令执行而言两者并无区别,但是 .run_scripts() 在业务代码和任务代码执行中增加了额外的处理,现就这些细节详细说明:
.run_scripts(self, history_files: str | List[str], force_use_dir=None, stdout=None, stderr=None)
history_files:str|list,参数接受一个文件路径,或多个文件路径的列表,执行命令之前会删除这些文件,注意只能删除force_use_dir路径下的文件force_use_dir:None|str,参数为None时,默认使用工作空间下的output目录,可以指定其他执行目录,但不建议用户修改该输出目录stdout:None|filestream,命令执行时使用的输出流,默认使用subprocess.PIPE,filestream可以是一个文件路径或一个文件流stderr:None|filestream,命令执行时使用的错误流,默认使用subprocess.PIPE,filestream可以是一个文件路径或一个文件流
# 这里示意在业务代码中,任务代码中`.run_scripts()`的使用逻辑相同
@bp.route("/demo_code", methods=['POST'])
@platform_monitor()
def demo_code():
record = DataAnalysisTableRecord(__file__)
infile = record.get_input_param('infile')
name = record.get_input_param('name')
output = f"{name}.png"
record.add(scripts="run.sh")
record.add(key="-i",value=infile)
record.add(key="-o",value=output)
record.run_scripts(history_files=output)
# note:
# 1. 这里之所以可以使用相对路径,是因为 run_scripts 执行时默认拼接了进入 force_use_dir 目录的操作
# 2. history_files 可以删除指定文件或文件列表,这里不支持正则匹配模式,如果输出文件是通过后缀匹配出来的,可以先执行匹配输出文件的逻辑得到文件列表传入
pass
clean_cache 方法
.clean_cache() 只是清空之前拼接的命令行,一般只有在同一个业务过程中多次执行脚本才需要调用该方法。
该方法的逻辑比较简单,这里不在赘述。