使用python子进程模块处理扩展的git命令

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用python子进程模块处理扩展的git命令相关的知识,希望对你有一定的参考价值。

我正在尝试检索和处理git仓库中历史版本文件的数据。我希望有一个字典,每个条目都有<hash>, <time of commit>, <value retrieved from contents of a file revision>, <commit message>

我想我从每个文件修订版中检索的数据,以及用它们完成的任何计算,最好使用python来处理。子进程模块似乎最适合集成我的git命令。

下面我展示了我如何定义一个函数getval(key, filename),我曾希望将<SHA-1 hash>:<Value>输出到控制台,但是希望有更多信息的字典......还有<time><commit message>

我帮助操作离子加速器,我们使用git存储'savesets' - 或与给定加速器调节相关的值。这些文件中的值中包括电荷(Q)和质量(A)。最终,我想要检索两个值,得到比率(Q / A),并显示文件修订版哈希值列表,这些列表按照费用:我们提供的离子质量比与该文件修订版中的设置进行排序。

Sample of file (for 56Fe17+):

# Date: 2018-12-21 01:49:16.888 PV,SELECTED,TIMESTAMP,STATUS,SEVERITY,VALUE_TYPE,VALUE,READBACK,READBACK_VALUE,DELTA,READ_ONLY REA_EXP:LINE,0,1544047322.881066957,NO_ALARM,NONE,enum,"JENSA~[UDF;AT-TPC;GPL;JENSA]",,"---",,true REA_BTS19:BEAM:OPTICSFILE,0,1541798820.065952460,NO_ALARM,NONE,string,"BTS19_test3.data",,"---",,true REA_BTS19:BEAM:A_BOOK,0,1545322510.562031883,NO_ALARM,NONE,double,"56.0",,"---",,true REA_BTS19:BEAM:Z_BOOK,0,1545322567.544226340,NO_ALARM,NONE,double,"26.0",,"---",,true REA_BTS19:BEAM:Q_BOOK,0,1545322512.701768974,NO_ALARM,NONE,double,"17.0",,"---",,true

到目前为止 - 在这里的其他人的帮助下 - 我已经找到了一个git one-liner,它会抓住一个键[字符串]的给定文件的修订历史,并使用sed和awk输出<hash>:<val associated with the key>

Git Oneliner I'm Starting with:

git grep 'BTS19:BEAM:A_BOOK' $(git rev-list --all) -- ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp | sed 's/:/,/' | awk -F, '{print $1 ":" $8}'

Oneliner's Output

e78f73fe6f90e93d5b3ccf90975b0e540d12ce09:"56.0" 4b94745bd0a6594bb42a774c95b5fc0847ef2d82:"56.0" f2d5e263deac1d9112be791b39f4ce1b1b34e55d:"56.0" c03800de52143ddb2abfab51fcc665ff5470e363:"56.0" 4a3a564a6d87bc6ff5f3dc7fec7670aeecfe6a79:"58.0" d591941e51c4eab1237ce726a2a49448114b8f26:"58.0" a9c8f5cdf224ff4fd94514c33888796760afd792:"58.0" 2f221492beea1663216dcfb27da89343817b11fd:"58.0"

我也开始玩子进程python模块。但我正在努力弄清楚如何处理我更复杂的git命令。一般来说,我希望能够传递密钥和文件......就像getval(key, filename)一样。

当我的cmd字符串是['git','grep',str,'$(git rev-list --all)',' - ',pathspec]时,它返回错误,指出'$(git rev-list - - 所有''含糊不清。认为它没有被扩展,我添加了一个单独的进程来执行嵌套命令,但我不确定我是否正确地执行此操作。

My Python file (gitfun.py): which I'm currently running the function from

import sys, os
import subprocess

def getval(str, pathspec, repoDir='/mnt/d/stash.projects/rea'):
    p1 = subprocess.Popen(["git", "rev-list", "--all"], stdout=subprocess.PIPE)
    output, err = p1.communicate()

    cmd = ['git', 'grep', str, output, '--', pathspec]        
    p2 = subprocess.Popen(cmd, cwd=repoDir)
    p2.wait()

cwd = '/mnt/d/stash.projects/rea'
filename = 'ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp'
os.chdir(cwd)
getval('BTS19:BEAM:A_BOOK', filename)

目前它正在返回'file name too long'(即使我不相信它确实太长)我尝试将git config中的core.longpaths更改为true,但这没有任何效果。再次,为什么我怀疑我没有正确处理$(git rev-list --all)扩展的替换。

对于此代码,我希望看起来像这样:

522628b8d3db01ac330240b28935933b0448649c:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true 2557c599d2dc67d80ffc5b9be3f79899e0c15a10:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true 7fc97ec2aa76f32265196c42dbcd289c49f0ad93:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true ...

但我最终想要一个输出到控制台,看起来与上面的git one-liner相同,或者更好的是,我可以打印到控制台或做其他事情的字典。

答案

请记住,您的shell使用空格标记命令行。

运行git rev-list --all时,输出如下:

2a4be2748fad885f88163a5b9b1b438fe3cb2ece
c1a30c743eb810fbefe1dc314277931fa33842b3
b2e5c75131e94a3543e5dcf9fb641ccd553906b4
95718f7e128a8b36ca93d6589328cc5b739668b1
87a9ada188a8cd1c13e48c21f093be7027d61eca

当你把它替换成你的git grep命令时......

git grep 'BTS19:BEAM:A_BOOK' $(git rev-list --all) -- 
ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp

......每一行都是一个单独的参数。也就是说,如果git rev-list --all的输出正是我上面所示,那么你的单行将被标记为以下参数,为了清楚起见,我为每行列出了一个:

git
grep
BTS19:BEAM:A_BOOK
2a4be2748fad885f88163a5b9b1b438fe3cb2ece
c1a30c743eb810fbefe1dc314277931fa33842b3
b2e5c75131e94a3543e5dcf9fb641ccd553906b4
95718f7e128a8b36ca93d6589328cc5b739668b1
87a9ada188a8cd1c13e48c21f093be7027d61eca
--
ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp

但是你没有在你的Python代码中这样做!你将git rev-list --all的整个输出作为一个参数。这意味着您尝试执行的命令具有固定数量(6)的参数:

git
grep
BTS19:BEAM:A_BOOK
2a4be2748fad885f88163a5b9b1b438fe3cb2ece c1a30c743eb810fbefe1dc314277931fa33842b3 b2e5c75131e94a3543e5dcf9fb641ccd553906b4 95718f7e128a8b36ca93d6589328cc5b739668b1 87a9ada188a8cd1c13e48c21f093be7027d61eca
--
ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp

所有这些修订都捆绑在一个参数中,这就是“文件名太长”错误的来源。您需要将该输出拆分为多个参数,就像shell一样:

p1 = subprocess.Popen(["git", "rev-list", "--all"], stdout=subprocess.PIPE)
output, err = p1.communicate()

cmd = ['git', 'grep', str] + output.splitlines() + ['--', pathspec]        
p2 = subprocess.Popen(cmd, cwd=repoDir)
p2.wait()

以上是关于使用python子进程模块处理扩展的git命令的主要内容,如果未能解决你的问题,请参考以下文章

Python2/3 中执行外部命令(Linux)和程序(exe) -- 子进程模块 subprocess

如何捕获从 python 子进程运行的 git clone 命令的输出

获取子进程的pid

甚至在完成后仍运行无限子进程的多处理模块

在 Python 子进程模块中过滤掉需要终端的命令

使用带有 python3 的子进程模块管道两个命令时遇到问题