如何在Buildbot步骤中“source”一个环境?

11

在 Buildbot 中,我需要在执行编译步骤之前能够"source"一个环境。

如果我正在使用 bash 从命令行构建应用程序,则必须执行以下操作:

. envrionment-set-up-script
build_command

在build bot的master.cfg文件中,我尝试了以下操作:

factory.addStep(ShellCommand(command=["source","environment-set-up-script"])
factory.addStep(ShellCommand(command=[".","environment-set-up-script"]))
factory.addStep(Configure(command=["source","environment-set-up-script"]))
factory.addStep(Configure(command=[".","environment-set-up-script"]))

所有这些都失败了,因为找不到命令,这很合理,因为它是Bash内置的。

此外,我认为这不是正确的方法,因为当调用工厂的下一步时,环境未必会被使用。

6个回答

9
在使用OpenEmbedded/Yocto时,我们通过类似以下方式解决了问题:
class EnvStep(ShellCommand):
    def __init__(self, command='', **kwargs):
        kwargs['command'] = [
            'bash', '-c', 'source environment-set-up-script; %s' % command
        ]
        ShellCommand.__init__(self, **kwargs)

接着,添加一个EnvStep,将其command参数设置为foo,可以让我们在源于environment-set-up-script的环境中运行foo。换句话说,您可以通过调用该步骤来使用它。

factory.addStep(EnvStep(command='foo'))

并且数据的来源将会自动完成。

我们还有许多其他自定义构建步骤,需要源代码环境被引用,所以我们让它们继承EnvStep而不是ShellCommand以便环境能够自动处理。


5
经过一些实验,我找到了一种方法来实现这个目标。 您需要:
  • 运行一个bash子shell,并设置应该用于该shell的环境,即使用环境变量BASH_ENV将bash调用并设置为要源入环境的文件。
  • 在bash中运行env命令以捕获环境
  • env命令的结果解析为属性(使用SetProperty步骤)
  • 将该属性用作后续步骤中的env参数
注意:环境应解析为可用作env参数的字典。
    from buildbot.process.factory import BuildFactory
    from buildbot.steps.shell import ShellCommand, SetProperty
    from buildbot.process.properties import Property  

    def glob2list(rc, stdout, stderr):
        ''' Function used as the extrat_fn function for SetProperty class
            This takes the output from env command and creates a dictionary of 
            the environment, the result of which is stored in a property names
            env'''
        if not rc:
            env_list = [ l.strip() for l in stdout.split('\n') ]
            env_dict={ l.split('=',1)[0]:l.split('=',1)[1] for l in 
                          env_list if len(l.split('=',1))==2}
            return {'env':env_dict}

    #This is the equivalent of running source MyWorkdir/my-shell-script then  
    #capturing the environment afterwords.
    factory.addStep(SetProperty(command="bash -c env",
                extract_fn=glob2list,       
                workdir='MyWorkdir',
                env={BASH_ENV':'my-shell-script' }))

    #Do another step with the environment that was sourced from 
    #MyWorkdir/my-shell-script
    factory.addStep(ShellCommand(command=["env"],
                workdir="MyWorkdir",
                env=Property('env')))

唯一可能失败的情况是,如果源脚本启动了某个进程,a) 该进程无法在其 shell 死亡后继续运行,并且 b) 被环境引用。 - Douglas Leeder
相比于这里描述的一些简单选项,这相当强大,但肯定会给您带来很多灵活性。考虑将其概括并提交为Buildbot的补丁? - djmitche

4
您可以使用env参数来设置ShellCommand构建步骤的环境变量,以便为您的命令设置环境。(http://docs.buildbot.net/0.8.1/Using-ShellCommands.html)
如果您希望环境变量适用于所有构建命令,您还可以在启动构建从属之前设置环境变量。
基本上有以下三种方法:
  1. 确定所需的环境变量并将其传递给env。
  2. 在启动构建从属之前获取配置信息。
  3. 将源代码和构建命令包装到一个shell脚本中,并作为单个构建步骤运行。

_env_参数在执行特定命令时向环境中添加一组已知的环境值。我可以很好地通过需要被源引用的shell脚本并计算出环境。所涉及的shell脚本不是我的,而是开放式嵌入式工具的一部分。因此,在我的控制范围之外,在源控件中可能会发生更改。因此,问题是如何“源”环境并将其应用于进一步的构建步骤。 - Simon Black
我可能会选择在单个构建步骤中运行所有内容,通过将所有内容包装在一个shell脚本中。 - Douglas Leeder

2

还有一个Visual Studio开发的例子也很有用。

通过使用常见的工具脚本,为每台机器设置正确的环境,同一构建者可以使用多个版本的VS,并支持多个体系结构的本地和交叉编译。

# A raw text string to get around windows quoting problems in buildbot.
vscomntools=r""""%VS120COMNTOOLS%\VsDevCmd.bat" %PROCESSOR_ARCHITECTURE% & set"""

# Determine MSVC Environment using VS Common Tools for build steps.
f.addStep(SetProperty(
    command=vscomntools,
    extract_fn=glob2list))

另一个选择是在每个命令前尝试引用批处理文件、&符号和命令。

0
    steps.ShellCommand(
            name = "Example",
            command = ["/bin/bash", "-c", "source <BASH SCRIPT>"],
            haltOnFailure = True,
            description = "Example"
    ),

问题在于以下的构建步骤将会生成一个新的 shell 并且不会继承那些被引用的函数。 - Andy J

0
我用了一种略有不同的方法来解决这个问题。我在Windows工作机上安装了一个批处理文件,启动时调用环境设置批处理文件,然后执行预定命令。当然,批处理文件在转发参数方面非常糟糕,并且Visual Studio 2017的VsDevCmd.bat会覆盖当前工作目录,这使得这个过程更加困难。但是,如果您在工作机上安装以下文件,则可以使用VS2017进行构建:
@ECHO OFF
@REM Calls a single command from the environment set from visual studio vcvars.
@REM Usage:
@REM withvcvars-2017.bat <arch> [command]
@REM 
@REM Run VsDevCmd.bat /help to see available arches
@REM See below instantiation for more fine grained option setting.

set ARCH=%1
shift

setlocal enabledelayedexpansion

@rem Replace __ with = in batch files.
@rem This works around idiotic lack of equals signs in args
@rem args contains full args string with substitutions in place
:argloop
if "%~1" NEQ "" (

    set str=%~1
    set out=!str:__==!
    set %~1=!out!
    set args=!args!!out! 

    SHIFT
    goto :argloop
)

@rem Aside from batch files being too moronic to allow for equals signs in args,
@rem VsDevCmd.bat idiotically clobbers the current working directory when it's called.
set CWD=%cd%

echo Calling VsDevCmd.bat for arch %ARCH%
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=%ARCH% -winsdk=8.1 -app_platform=Desktop -no_logo

@rem Who lets these things out the door?
cd %CWD%

@ECHO ON
%args%

完成此操作后,您可以在buildbot主逻辑中创建一个函数,该函数将附加此批处理文件:

def _withvcvars(year, arch, cmd):     
    base_cmd = ["%swithvcvars-%s.bat" % ('\\path\\to\\batchfile\\', year), arch]      
    return base+cmd

这使您能够运行命令,其中调用msbuild.exe并期望其参数中有等号。只需将它们指定为双下划线:

withvcvars-2017.bat amd64 msbuild.exe your.sln /p:Configuration__Release /p:Platform__x64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接