如何在appveyor.yml中的多行上拆分命令

时间:2016-06-04 06:43:11

标签: yaml appveyor

我想在我的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解释器会在每行末尾看到延续标记(^),并将它们视为一个很长的命令,除了那个Appveyor似乎无法识别^标记,因此它一次将每行发送到cmd.exe,而不是将整个多行块一起发送。

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

我试过了:

  • 单行间距,每行末尾没有多余字符。根据{{​​3}},单行YML线应该被打包成一行,但Appveyor不会发生这种情况。
  • 每行末尾没有多余字符的双行间距行。这应该是使每一行成为一个单独的命令,实际上它们是,因为第一个FOR命令因error 255而失败,因为它不完整(只有FOR行存在而不是其余的循环。)
  • ^结尾的双倍行间距。 Appveyor一次只运行一行,所以我在第一个不完整的error 255命令上得到FOR
  • 单行间隔行以^结尾,如上所示。与来自不完整error 255命令的双倍行间距FOR相同。
  • 使用&& ^结束每一行确实在运行单独的命令(例如多个msbuild语句)时有效,但这不适用于FOR循环,因为您不能{ {1}}之前没有命令。

&&中的多行上分割单个cmd命令是否有诀窍?

5 个答案:

答案 0 :(得分:3)

  

如何在appveyor.yml中的多行上拆分命令?

以下是batch,cmd,ps。

的一些语法示例

我希望这些例子可以节省你一些时间......

语法示例

<强>批量

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/*
    )

<强> 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
        }
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"
  }

答案 1 :(得分:2)

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

build_script:
- build.cmd

答案 2 :(得分:1)

使用双引号

http.cors().and().csrf().disable().
        authorizeRequests()
        .antMatchers("/token/*").permitAll()
        .anyRequest().permitAll()
        .and()
        .httpBasic()
//        .formLogin()
//        .loginPage("/login")
//        .permitAll()
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

您可以检查yaml ref,更准确地说是this example

我在使用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的细微之处:

  • 保持易于阅读/书写的多行表达式
  • 具有有效存储应用程序的单行值。

您可以查看where I use it,并了解build passes的情况。

对于其他读者,请注意,行将被折叠,因此,需要使用特殊的语法编写该行以支持...您不能省略{ {1}},例如由OP给出的表达式。

答案 3 :(得分:0)

如果你知道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:

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"

(上例中的任何换行之前没有空格)

使用folded block style scalar(使用>)可以让您在经历时很少控制标量的折叠。在折叠(或字面)块样式标量中也无法转义序列。

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

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 ) )

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

  

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

答案 4 :(得分:0)

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

不幸的是,要使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中的某些命令,因为它们在bash中引入了\r\n,而您只需要\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"