【问题标题】:Terminate makefile command when subcommand throws?子命令抛出时终止makefile命令?
【发布时间】:2012-05-11 21:46:46
【问题描述】:

我有以下 Makefile:

#runs the working directory unit tests
test:
    @NODE_ENV=test; \
        mocha --ignore-leaks $(shell find ./test -name \*test.js);

#deploys working directory
deploy:
    @make test; \
    make deploy-git; \
    make deploy-servers;

#deploys working to git deployment branch
deploy-git:
    @status=$$(git status --porcelain); \
    if test "x$${status}" = x; then \
        git branch -f deployment; \
        git push origin deployment; \
        echo "Done deploying to git deployment branch."; \
    else \
        git status; \
        echo "Error: cannot deploy. Working directory is dirty."; \
    fi

deploy-servers:
#   for each server
#       @DEPLOY_SERVER_IP = "127.0.0.1"; \
#       make deploy-server

#deploy-server:
#   connect to this server with ssh
#   check if app is already running
#   stop the app on the server if already running
#   set working directory to app folder
#   update deployment git branch
#   use git to move head to deployment branch
#   start app again

请注意,deploy-serversdeploy-server 目前只是假的。这是deploy 命令应该做的:

  1. 运行测试 (make test),失败时退出
  2. 将当前头推送到部署分支 (make deploy-git),失败退出
  3. 在服务器上拉部署分支 (make deploy-servers)

你可以在 Makefile 中看到:

deploy:
    @make test; \
    make deploy-git; \
    make deploy-servers;

问题是我不知道如何防止make deploy-gitmake test 失败时执行,以及如何防止make deploy-servers 在测试失败或make deploy-git 失败时执行。

有没有明确的方法可以做到这一点,还是我应该求助于使用 shell 文件或用普通的编程语言编写这些工具?

【问题讨论】:

    标签: shell makefile


    【解决方案1】:

    其他人给出的答案是基于将“配方”分成单独的命令。

    在不可行的情况下,您可以在 shell 脚本中使用set -e 使其在命令失败时终止:

    target:
            set -e ; \
              command1 ; \
              command2 ; command3 ; \
              ... commandN
    

    这是相同的set -e,当某些命令未成功终止时,您可以将它放在 shell 脚本的顶部附近以使其保释。

    假设我们对command2command3 的终止状态不感兴趣。假设这些指示失败或不可靠地使用终止状态是可以的。然后,我们可以编写一个显式退出测试来代替set -e

    target:
            command1 ; \
            command2 || exit 1 ; \
            command3 ; \
            true  # exit 0 will do here also.
    

    由于command3 可以指示失败,并且我们不希望它使我们的构建失败,因此我们添加了一个成功的虚拟命令。

    【讨论】:

    • 非常高兴你用这些有用的信息扩展给定的答案。我希望我能接受很多答案..
    【解决方案2】:

    make 应该已经这样做了;它使用sh -e 执行复杂的命令,如果命令非零退出(只要它不在与 POSIX 兼容的 shell 中的循环中),它将中止执行,并在命令失败时中止整个Makefile,除非您特别告知它不。如果您感到偏执,可以在命令中使用&& 代替;

    【讨论】:

    • 我有兴趣了解更多相关信息(“它使用sh -e [and] 执行复杂的命令,如果命令退出非零”)。有没有人有更多信息的参考链接?
    【解决方案3】:

    shell 命令的退出状态 list 是列表中最后一个命令的退出状态。只需将您的命令列表变成单独的单个简单命令。默认情况下,make 在命令返回非零时停止。所以你得到你想要的

    deploy:
        @make test
        make deploy-git
        make deploy-servers
    

    如果你曾经想要忽略一个简单命令的退出状态,你可以在它前面加上一个破折号:

     target:
         cmd1
         -cmd2 # It is okay if this fails
         cmd3
    

    您的make 手册包含所有详细信息。

    【讨论】:

    • +1,但请注意 OP,您可能希望(至少)执行 make test $(MAKEFLAGS) 以将任何其他命令行标志传播到子公司。
    • @William - 这取决于我的品牌(GNU Make 3.81)似乎会自动执行此操作。我刚测试是因为你的评论让我很紧张。
    【解决方案4】:

    我通过在潜在断点处代理到新的 make 命令解决了这个问题:

    .PHONY cmd_name cmd_name_contd
    
    cmd_name:
        if [ "`pwd`" = "/this/dir" ]; then make cmd_name_contd; fi
    
    cmd_name_contd:
        @echo "The directory was good, continuing"
    

    这样,如果目录错误,它只是静默退出,您还可以添加一个带有消息的 else 条件以在失败时显示。

    【讨论】:

      猜你喜欢
      • 2020-12-30
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-25
      相关资源
      最近更新 更多