16

我想在我的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 ) )

额外的空格并不重要,重要的是从开头FOR到结尾的行)出现在同一行。

请注意,理论上 Appveyor 也可以看到以下内容:

@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会在每一^末尾看到继续标记(将整个多行块一起发送。^cmd.exe

这意味着第一个选项看起来是唯一可行的解​​决方案,其中构建 YAML 使得该FOR行及其之后的所有内容都合并为一行。

我努力了:

  • 每行末尾没有多余字符的单行距。根据本指南,单行距的 YML 行应该展开为一行,但 Appveyor 不会发生这种情况。
  • 双倍行距,每行末尾没有多余的字符。这应该使每一行成为一个单独的命令,实际上它们是,因为第一个FOR命令失败,error 255因为它不完整(只有FOR行存在,而不是循环的其余部分。)
  • 双倍行距以 . 结尾^。Appveyor 一次只运行每一行,所以我error 255在第一个不完整的FOR命令上得到一个。
  • 单行距以^如上所示终止。与双倍行距相同的问题,error 255来自不完整的FOR命令。
  • 在运行单独的命令(例如,多个语句)时,以 结束每一行&& ^确实有效msbuild,但这不适用于FOR循环,因为如果没有&&前面的命令,您将无法使用。

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

4

5 回答 5

8

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

下面是一些批处理、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 ..

deploy_script:
  # if tagged commit, build/upload wheel
  - IF "%APPVEYOR_REPO_TAG%"=="true" IF NOT "%TESTENV%"=="check" (
      pip install twine &&
      python setup.py register &&
      twine upload -u %PYPI_USER% -p %PYPI_PASS% dist/*
    )

命令

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"

附言

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
        }

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"
  }
于 2016-09-09T10:03:22.677 回答
4

使用双引号

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,更准确地说是this example

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

  • 在我身边保持一个易于读/写的多行表达式,
  • 具有有效存储应用程序的单行值。

你可以看看我在哪里使用它,看看构建是如何通过的。

对于其他读者,请注意,该行将被折叠,因此,需要使用特殊的语法来支持这一点……例如,您不能省略||OP 给出的表达式中的 。

于 2018-12-12T21:55:30.027 回答
3

除了批处理和 PS 之外,还有另一个提示要考虑。除了 mingw64 的“Git for Windows”版本之外, msys2/mingw32/mingw64 还安装在 appveyor VM 上C:\msys64\usr\bin\bash

不幸的是,让 bash 中的多行命令在 appveyor 中工作并不那么简单:

例子:

像这样的一段代码:

cd /tmp
for server in $(grep '^Server' /etc/pacman.d/mirrorlist.msys | awk '{print $3}' | shuf | arch=x86_64 envsubst); do
  echo Trying ${server}
  curl --connect-timeout 10 -LO ${server}msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz && break
done"

变成

  - >-
    C:\msys64\usr\bin\bash -lc "
    cd /tmp;
    for server in $(grep $'\x5eServer' /etc/pacman.d/mirrorlist.msys | awk '{print $3}' | shuf | arch=x86_64 /usr/bin/envsubst); do
    :;  echo Trying ${server};
    :;  curl --connect-timeout 10 -LO ${server}msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz && break;
    done"

为什么如此不同?

在 appveyor 中批量处理多行 bash 字符串会出现许多问题:

  1. 批处理中的多行字符串必须以^. 然而这样做
# Literal newlines were not working
- |
  bash -c "echo Not ^
           echo good"

# Double quotes become a literal quote
# Equivalent: echo This is""echo now dangling
#             and "" is an escaped "
- |
  bash -c "echo This is"^
          "echo now dangling"

# Double double quote cancel out, but you're back
# to a literal newline, not working
- |
  bash -c "echo This does not"^
          """echo work either"

# The `|` notation does not seem to be useful here
# It just results in a string that won't run in appveyor 
# as we desired, when using literal newlines.
  1. 折叠需要都在同一个缩进上,所以不允许额外的缩进
# > vs >- vs >+ isn't important, it just strips extra newlines at the end
- >
  bash -c "echo This
  echo works"

# Indent means literal newline again
- >
  bash -c "echo Does not
           echo work"

# Says "This echo says", not "This" and "says"
- >-
  bash -c "
  echo This
  echo says"

# Basically: bash -c "echo This; echo works"
- >-
  bash -c "
  echo This;
  echo works"
  1. 为了有正确的缩进,我们需要用一些虚拟字符来欺骗 yaml
# You cannot have ; after keywords then, do, etc...
- >-
  bash -c "
  if [ 1 == 1 ]; then
  ;  echo No;
  ;  echo good;
  fi

# Add in a dummy "true" + semicolon, as a no-op
- >-
  bash -c "
  if [ 1 == 1 ]; then
  :;  echo This works;
  fi

# Or if you prefer this style
- >-
  bash -c "if [ 1 == 1 ]; then
  :;         echo ""This also works"";
  :;       fi
  1. 臭名昭著的插入符号。显然某些东西扩展^^^,并且没有好的方法解决它
# echoes ^^
bash -c "echo ^"
bash -c "echo \^"
bash -c "echo \\^"

# echoes ^^^^ 
bash -c "echo ^^"

# Uses a hex notation to get around the issue
bash -c "echo $'\x5e'"
  1. 您必须小心 mingw64 中的某些命令,因为它们\r\n在 bash 中引入时您只需要一个\n
# 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"
于 2020-10-06T21:49:50.277 回答
3

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

build_script:
- build.cmd
于 2016-06-05T21:55:54.200 回答
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 )
)

然后很容易通过从 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 ) )

但是你不能缩进(从折叠块样式标量的细节):

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

于 2016-06-04T10:29:37.777 回答