Yaml 如何在appveyor.yml中将命令拆分为多行

Yaml 如何在appveyor.yml中将命令拆分为多行,yaml,appveyor,Yaml,Appveyor,我想在我的appveyor.yml文件中跨多行拆分一个长的构建命令,但是我无法将其展开,因此当第一个FOR命令被切断并返回错误时,构建失败。我不知道如何正确分割.yml文件中的行,以便在Appveyor中重新组装。如何做到这一点 以下是一个简化版本: build_script: - cmd: >- @echo off FOR %%P IN (x86,x64) DO ( ^ FOR %%C IN (Debug,Release) DO ( ^ msb

我想在我的
appveyor.yml
文件中跨多行拆分一个长的构建命令,但是我无法将其展开,因此当第一个
FOR
命令被切断并返回错误时,构建失败。我不知道如何正确分割
.yml
文件中的行,以便在Appveyor中重新组装。如何做到这一点

以下是一个简化版本:

build_script:
- cmd: >-
    @echo off
    FOR %%P IN (x86,x64) DO ( ^
      FOR %%C IN (Debug,Release) DO ( ^
        msbuild ^
          /p:Configuration=%%C ^
          /p:Platform=%%P ... ^
        || EXIT 1 ^
      ) ^
    )
我希望它在AppVeyor中显示为:

@echo off
FOR %%P IN (x86,x64) DO ( FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 ) )
额外的空格并不重要,重要的一点是以
开头的一行直到最后一行出现在同一行

请注意,从理论上讲,验船师也可以看到:

@echo off
FOR %%P IN (x86,x64) DO ( ^
  FOR %%C IN (Debug,Release) DO ( ^
    msbuild ^
      /p:Configuration=%%C ^
      /p:Platform=%%P ... ^
    || EXIT 1 ^
  ) ^
)
由于Windows
cmd.exe
解释器随后会在每行末尾看到延续标记(
^
),并将它们视为一个大的长命令,除了Appveyor似乎无法识别
^
标记,因此它会将每行发送到
cmd.exe
,一次发送一个,而不是将整个多行块一起发送

这意味着第一个选项看起来像是唯一可行的解决方案,其中YAML的构造使得
行的及其后的所有内容组合成一行

我试过:

  • 单行间距,每行末尾无额外字符。根据,单间距的YML线应该展开为一条线,但Appveyor不会这样做
  • 双倍行距的行,每行末尾没有额外字符。这应该使每一行都成为一个单独的命令,事实上,它们是这样的,因为第一个
    FOR
    命令失败,出现
    错误255
    ,因为它不完整(只有
    FOR
    行存在,而不是循环的其余部分。)
  • ^
    结尾的双倍行距线。Appveyor一次只运行一行,因此我在第一个不完整的
    FOR
    命令中得到了一个
    错误255
  • 如上所示,以
    ^
    结尾的单间隔行。与双倍行距的行相同,
    错误255
    来自不完整的
    FOR
    命令
  • 在运行单独的命令(例如,多个
    msbuild
    语句)时,用
    &&^
    结束每一行实际上是可行的,但这不适用于
    FOR
    循环,因为如果前面没有命令,则不能使用
    &

appveyor.yml
中,是否有将单个
cmd
命令拆分为多行的技巧?

如果您知道appveyor期望的是什么(我不知道),让我们假设:

@echo off
FOR %%P IN (x86,x64) DO (
    FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 )
)
然后,通过转储YAML(例如从Python中转储),可以轻松生成适当的YAML:

import sys
import ruamel.yaml

appveyor_str = """\
@echo off
FOR %%P IN (x86,x64) DO (
    FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 )
)
"""

data = dict(build_script=[dict(cmd=appveyor_str)])

ruamel.yaml.round_trip_dump(data, sys.stdout)
给你:

build_script:
- cmd: "@echo off\nFOR %%P IN (x86,x64) DO (\n    FOR %%C IN (Debug,Release) DO (\
    \ msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 )\n)\n"
(在上述示例中,任何换行符前都没有空格)

使用(带
)时,您几乎无法控制标量的折叠。也不可能在折叠(或文字)块样式标量中转义序列

如果您的多行字符串不需要转义,您可以尝试作为块样式标量转储:

import sys
import ruamel.yaml

appveyor_str = """\
@echo off
FOR %%P IN (x86,x64) DO (
    FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 )
)
"""

data = dict(build_script=[dict(cmd=ruamel.yaml.scalarstring.PreservedScalarString(appveyor_str))])

ruamel.yaml.round_trip_dump(data, sys.stdout)
其中:

build_script:
- cmd: |
    @echo off
    FOR %%P IN (x86,x64) DO (
        FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 )
    )
(即,确切地说,你放进了什么)

如果您将所有内容右对齐(其可读性不如您所希望的那样),并在第一次输出后使用双换行符,则您将获得所需的输出:

import sys
import ruamel.yaml

yaml_str = """\
build_script:
- cmd: >-
    @echo off

    FOR %%P IN (x86,x64) DO (
    FOR %%C IN (Debug,Release) DO (
    msbuild
    /p:Configuration=%%C
    /p:Platform=%%P ...
    || EXIT 1
    )
    )
"""

data = ruamel.yaml.load(yaml_str)

print(data['build_script'][0]['cmd'])
给出:

@echo off
FOR %%P IN (x86,x64) DO ( FOR %%C IN (Debug,Release) DO ( msbuild /p:Configuration=%%C /p:Platform=%%P ... || EXIT 1 ) )
但不能缩进(从折叠块样式标量的细节):

以空白字符开头的行(更多缩进行)不会折叠


CMD
命令总是分成单独的行,并通过包装到
.CMD
文件中逐个运行。将您的代码放入
build.cmd
,提交到repo,然后调用为:

build_script:
- build.cmd
如何在appveyor.yml中将命令拆分为多行

下面是batch、cmd、ps的一些语法示例

我希望这些例子能为您节省一些时间

语法示例

批量

# please note the & at EOL in the next example
install:
    # Install VULKAN_SDK 
    - if not exist %VULKAN_SDK% (
       curl -L --silent --show-error --output Vulkan_SDK_Installer.exe https://sdk.lunarg.com/sdk/download/%VULKAN_VERSION%/windows/VulkanSDK-%VULKAN_VERSION%-Installer.exe?Human=true &
       Vulkan_SDK_Installer.exe /S
    )
    - dir %VULKAN_SDK%

before_build:
  - |-
    set MINGW32_ARCH=i686-w64-mingw32
  - if exist %PREFIX% set NEEDDEPENDS=rem

  # Depends
  - |-
    %NEEDDEPENDS% mkdir %PREFIX%\include\SDL2
    %NEEDDEPENDS% mkdir %PREFIX%\lib
    %NEEDDEPENDS% cd %TEMP%
    %NEEDDEPENDS% appveyor DownloadFile https://sourceforge.net/projects/gnuwin32/files/gettext/0.14.4/gettext-0.14.4-lib.zip
    %NEEDDEPENDS% mkdir gettext-0.14.4-lib
    %NEEDDEPENDS% move gettext-0.14.4-lib.zip gettext-0.14.4-lib
    %NEEDDEPENDS% cd gettext-0.14.4-lib
    %NEEDDEPENDS% 7z x gettext-0.14.4-lib.zip > nul
    %NEEDDEPENDS% copy include\* %PREFIX%\include > nul
    %NEEDDEPENDS% copy lib\* %PREFIX%\lib > nul
    %NEEDDEPENDS% cd ..

CMD

before_build:
    - cmd: >-     

        mkdir build

        cd .\build

        set OpenBLAS_HOME=%APPVEYOR_BUILD_FOLDER%/%MXNET_OPENBLAS_DIR%

        set OpenCV_DIR=%APPVEYOR_BUILD_FOLDER%/%MXNET_OPENCV_DIR%/build

        cmake .. -DOPENCV_DIR=%OpenCV_DIR% -DUSE_CUDA=0 -DUSE_CUDNN=0 -DUSE_NVRTC=0 -DUSE_OPENCV=1 -DUSE_OPENMP=1 -DUSE_BLAS=open -DUSE_DIST_KVSTORE=0 -G "Visual Studio 12 2013 Win64"
PS

install:
    - ps: >-

        git submodule init

        git submodule update

        if (!(Test-Path ${env:MXNET_OPENBLAS_FILE})) {

            echo "Downloading openblas from ${env:MXNET_OPENBLAS_PKG} ..."

            appveyor DownloadFile "${env:MXNET_OPENBLAS_PKG}" -FileName ${env:MXNET_OPENBLAS_FILE} -Timeout 1200000
        }



使用双引号:

build_script:
- cmd: "
    @echo off
    FOR %%P IN (x86,x64) DO (
      FOR %%C IN (Debug,Release) DO (
        msbuild
          /p:Configuration=%%C
          /p:Platform=%%P ...
        || EXIT 1
      )
    )"
您可以更精确地检查yaml ref

我使用appveyor遇到了同样的问题(多么奇怪的限制!)。使用双引号使我能够利用YAML微妙之处:

  • 在我这边保持一个易于阅读/书写的多行表达式
  • 按应用程序有效存储单行值
你可以看一看,看看这是怎么回事


对于其他读者,请注意,行将被折叠,因此,需要使用特殊语法来编写,以支持。。。在OP所给出的表达式中,您不能省略<代码> >代码> .< /P> < P>,有另一个提示要考虑其他批处理和PS。MysS2/MINW32/MINW64安装在AppVEYOR VMs>代码>:\Mys64 \ Ur\bin \Bash < /C>,除了“WINDOWS”版本的MINW64。< /P> 不幸的是,让bash中的多行命令在appveyor中工作并不是那么简单:

例如:

下面是一段代码:

cd/tmp
对于$中的服务器(grep'^server'/etc/pacman.d/mirrorlist.msys | awk'{print$3}'| shuf | arch=x86_64 envsubst);做
回显尝试${server}
curl--连接超时10-LO${server}msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz&&break
完成”
变成

->-
C:\msys64\usr\bin\bash-lc”
cd/tmp;
对于$中的服务器(grep$'\x5eServer'/etc/pacman.d/mirrorlist.msys | awk'{print$3}'| shuf | arch=x86_64/usr/bin/envsubst);做
:;  回显尝试${server};
:;  curl——连接超时10-LO${server}msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz&&break;
完成”
为什么会如此不同? appveyor中批处理多行bash字符串时会出现许多问题:

  • 批处理中的多行字符串必须以
    ^
    .Ho结尾
    install:
          - ps: |
              Add-Type -AssemblyName System.IO.Compression.FileSystem
              if (!(Test-Path -Path "C:\maven" )) {
                (new-object System.Net.WebClient).DownloadFile('https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip', 'C:\maven-bin.zip')
                [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\maven-bin.zip", "C:\maven")
              }
    
    on_success:
      - ps: |
      if ($true)
      {
        Write-Host "Success"
      }
    
    build_script:
    - cmd: "
        @echo off
        FOR %%P IN (x86,x64) DO (
          FOR %%C IN (Debug,Release) DO (
            msbuild
              /p:Configuration=%%C
              /p:Platform=%%P ...
            || EXIT 1
          )
        )"
    
    # This is really using /mingw64/bin/envsubst in MINGW64 mode
    bash -c "for x in $(echo $'${PWD}\n${OLDPWD}' | envsubst); do
             :;  echo ""${x}"" | xxd;
             done"
    
    # Either need to have MSYSTEM set to MSYS, or
    bash -c "for x in $(echo $'${PWD}\n${OLDPWD}' | /usr/bin/envsubst); do
             :;  echo ""${x}"" | xxd;
             done"
    
    # or, as a last resort, use dos2unix
    bash -c "for x in $(echo $'${PWD}\n${OLDPWD}' | envsubst | dos2unix); do
             :;  echo ""${x}"" | xxd;
             done"