作为项目构建过程的一部分,我编写了一个简单的脚本,该脚本打开一个子进程管道以执行make命令,这最终将导致创建tar文件,然后最终将生成的tar发布到我们的构建目录中。脚本如下:
#!/usr/bin/env python3
import os, shutil, utils
# Set Environment Variables
utils.setupEnvironment()
if not os.path.isdir(os.environ["BUILD_PKGDEST"]):
os.makedirs(os.environ["BUILD_PKGDEST"])
utils.executeBuild(["make", "soltr_load", "CCACHE_WRITE=%s" % (os.environ["CCACHE_WRITE"])])
utils.publish("production", "soltr_%s.tar.gz" % (utils.getVersionInfo()))
如您所见,它正在调用两个util函数,executeBuild和publish,如下所示:
def executeBuild(command):
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
print (line.decode("utf-8").rstrip())
p.communicate()
def execute(command):
return subprocess.check_output(command).decode("UTF-8").rstrip()
def publish(pathToPublish, infile, outfile=None):
if outfile is None: outfile = infile
...
md5sum = execute(["md5sum", "%s/%s" % (ENV["BUILD_PKGDEST"], infile)])
...
据我了解,代码非常简单。在executeBuild期间,子进程将打开管道并运行我的make命令,而随后的for循环遍历其输出,并将其实时打印到控制台。 p.communicate()阻止脚本继续执行,直到关闭管道为止,在该管道上,发布步骤将触发并创建md5sum和发布两个文件。
我的问题是,在make命令仍在执行的同时,随机触发了发布步骤。有时需要3分钟,有时需要15分钟。 make命令平均应该可以运行20次。这是我的错误日志的示例。
14:00:23 ********************************************************************************
14:00:23 Original command follows:
14:00:23 ********************************************************************************
14:00:23 /opt/soldev/bin/ccd-gcc_v2 --ccd-distcc --ccd-cc /opt/soldev/toolchains/v1/targets/centos7-i686/bin/i686-target-linux-gnu-g++ -fpic -Wno-deprecated -Wignored-qualifiers -D_GLIBCXX_PERMIT_BACKWARD_HASH -mmmx -msse -m64 -march=x86-64 -Wa,--64 -DARCH=LINUX_X86_64 -fPIC -DSOLDEV_ENTERPRISE_EDITION -msse2 -g -rdynamic -Wall -Wextra -Wpointer-arith -Wwrite-strings -Werror -pipe -fexceptions -pthread -D_REENTRANT -O2 -Wno-strict-aliasing -fno-strict-aliasing -Woverloaded-virtual -Wno-format-extra-args -fmessage-length=0 -std=gnu++0x -D__STDC_FORMAT_MACROS -D_GLIBCXX_USE_CXX11_ABI=0 -
...
I/opt/soldev/targets/centos7-i686/usr/lib/glib-2.0/include -I/opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/base/obj_Linux-x86_64-centos7_opt -I//opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/solcbr/common/hw/src/bladeAdbSimulated.cpp -o common/hw/src/bladeAdbSimulated.omd5sum: /opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/solcbr/obj_Linux-x86_64-centos7_lm_vmr_opt/build_artifact/soltr_100.0<redacted>2.0.63.tar.gz: No such file or directory
14:00:35
14:00:35 /opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/solcbr/Rules.mk:173: recipe for target 'common/hw/src/bladeAdbSimulated.o' failed
14:00:35 make[3]: *** [common/hw/src/bladeAdbSimulated.o] Error 1
14:00:35 make[3]: *** Waiting for unfinished jobs....
14:00:35 make[2]: *** [obj_Linux-x86_64-centos7_lm_opt] Error 2
14:00:35 build/target.mk:53: recipe for target 'obj_Linux-x86_64-centos7_lm_opt' failed
14:00:35 Makefile:26: recipe for target 'appload' failed
14:00:35 make[1]: *** [appload] Error 2
14:00:35 make[1]: Leaving directory '/opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/solcbr'
14:00:35 __________Warning: 1 pump-mode compilation(s) failed on server, but succeeded locally.
14:00:35 __________Distcc-pump was demoted to plain mode. See the Distcc Discrepancy Symptoms section in the include_server(1) man page.
14:00:35 __________Shutting down distcc-pump include server
14:00:35 make: *** [soltr_load] Error 2
14:00:35 make: *** [soltr_load] Error 2
14:00:35 Traceback (most recent call last):
14:00:35 File "build-env/loadbuild/build_lm.py", line 11, in <module>
14:00:35 utils.publish("production", "soltr_%s.tar.gz" % (utils.getVersionInfo()))
14:00:35 File "/opt/sbox/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/build-env/loadbuild/utils.py", line 82, in publish
14:00:35 md5sum = execute(["md5sum", "%s/%s" % (ENV["BUILD_PKGDEST"], infile)])
14:00:35 File "/opt/sbox/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/build-env/loadbuild/utils.py", line 5, in execute
14:00:35 return subprocess.check_output(command).decode("UTF-8").rstrip()
14:00:35 File "/usr/lib64/python3.6/subprocess.py", line 336, in check_output
14:00:35 **kwargs).stdout
14:00:35 File "/usr/lib64/python3.6/subprocess.py", line 418, in run
14:00:35 output=stdout, stderr=stderr)
14:00:35 subprocess.CalledProcessError: Command '['md5sum', '/opt/cvsdirs/loadbuild/jenkins/slave/workspace/<redacted>/vrs32/solcbr/obj_Linux-x86_64-centos7_lm_vmr_opt/build_artifact/soltr_100.0<redacted>2.0.63.tar.gz']' returned non-zero exit status 1.
14:00:35 Build step 'Execute shell' marked build as failure
错误日志非常混乱,但是我可以解释一下,它列出了原始命令(该命令用于编译和构建代码),最后,您可以看到{{1} }附加到命令末尾。
由于md5sum命令需要tar文件而导致爆炸,由于make命令未完成,该文件未生成。这将返回错误,并导致仍在运行的原始命令也失败。但是,由于初始管道完成,由于在executeBuild中阻塞了管道,它甚至不应该到达md5sum命令(在发布步骤中)。
我对发生的事情的最佳猜测是,遍历管道输出的for循环到达其末端,并由于某种原因而继续前进,但是我不知道为什么这样做,因为我对{{ 1}}是它阻止脚本继续前进,直到关闭管道为止。如果有机会在命令完成之前退出了for循环,则应该将其阻塞直到结束为止;否则,它会被阻塞。它只是什么都不会打印。
我有办法解决此问题吗?我正在阅读的每个地方都说我正在使用的方法是实时打印标准输出的最佳方法,所以我想知道是否还有其他选择。