【问题标题】:set pipefail for commands run by tup为 tup 运行的命令设置 pipefail
【发布时间】:2016-03-07 16:22:00
【问题描述】:

在大量 Tupfile 中,我使用大量流水线,例如

: input |> < %f command1 | command2 > %o |> output

问题在于 Tup 调用 system,它在 sh 中执行这些 :-rules,它不支持 set -o pipefail。结果,如果只有command1 失败,tup 仍会将其标记为成功,因为它的退出代码为 0。这是很成问题的。

我知道有两种解决方案,但都不是理想的。

一个。我可以放弃流水线,而是这样做:

: input |> < %f command1 > %o |> intermediate
: intermediate |> < %f command2 > %o |> output

这可行,但需要繁琐地重写一堆规则,更重要的是,每次更新都会使用更多的磁盘空间和磁盘写入。

b) 我可以将每个命令包装在bash 中,例如:

: input |> bash -c 'set -o pipefail && < %f command1 | command2 > %o' |> output

这似乎稍微好一点,因为它涉及更少的重写,并且避免了 io,但仍然非常麻烦。它还需要在我的 :-rules 中转义任何 '

理想情况下,Tup 配置可以指定使用什么 shell/解释器来读取 :-rules。理想情况下,还会有一个公共前缀的配置,因此所有脚本都可以使用set -o pipefail &amp;&amp; 或我想要的任何其他内容运行。据我所知,这不可能立即实现。每当 tup 调用规则时,都需要编写 system 的包装器。但是,也许我错过了 Tup 的某些方面,这些方面将允许比提出的两种解决方案更优雅的东西。

编辑: 虽然对系统的调用确实允许我将管道故障“注入”到对系统的调用中。我错过了程序使用系统运行的事实。在邮件列表的一些帮助下,事实证明它们实际上是使用execle 运行的。下面是我用来做插入的代码,以防有人想要完成同样的事情。

解决方案

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>

int execle(const char* path, const char* arg0, ...) {
    /* We're going to interpose this function, modify the arguments if we need
     * to, and then convert it into a call to execve. Due to a weirdness in the
     * consts of the api, we need to discard a const qualifier on the
     * characters in the arguments. The call is `int execve(const char*
     * filename, char* const argv[], char* const envp[]);` but it should
     * probably be `int execve(const char* filename, const char* const argv[],
     * char* const envp[]);` at the very least, e.g. arguments shouldn't be
     * modified. These aren't actually modified by the call, so in order to
     * avoid the inefficiency of copying the strings into memory we don't need,
     * we just do this unsafely and compile with `-Wno-discarded-qualifiers`.
     * */

    // Count the number of variable arguments for malloc
    unsigned int num_args;
    va_list ap;
    va_start(ap, arg0);
    if (arg0) {
        num_args = 1;
        while(va_arg(ap, const char*)) {
            num_args++;
        }
    } else {
        num_args = 0;
    }
    char* const* env = va_arg(ap, char* const*); // Also grab env
    va_end(ap);

    // Test for specific tup execle call
    va_start(ap, arg0);
    int intercept = num_args == 4
        && strcmp(path, "/bin/sh") == 0
        && strcmp(arg0, "/bin/sh") == 0
        && strcmp(va_arg(ap, const char*), "-e") == 0
        && strcmp(va_arg(ap, const char*), "-c") == 0;
    va_end(ap);

    // Switch on whether to intercept the call, or pass it on
    /*const*/ char** args;
    if (intercept) { // We want to switch to bash with pipefail enabled
        args = malloc(7 * sizeof(args));
        path = "/bin/bash";
        args[0] = "/bin/bash";
        args[1] = "-e";
        args[2] = "-o";
        args[3] = "pipefail";
        args[4] = "-c";

        va_start(ap, arg0);
        va_arg(ap, const char*);
        va_arg(ap, const char*);
        args[5] = va_arg(ap, const char*); // command
        va_end(ap);

        args[6] = NULL;

    } else { // Just copy args into a null terminated array for execve
        args = malloc((num_args + 1) * sizeof(*args));

        char** ref = args;
        if (arg0) {
            *ref++ = arg0;
            const char* arg;
            va_start(ap, arg0);
            while ((arg = va_arg(ap, const char*))) {
                *ref++ = arg;
            }
            va_end(ap);
        }
        *ref = NULL;

    }

    int error_code = execve(path, args, env);

    free(args);
    return error_code;
}

【问题讨论】:

    标签: bash tup


    【解决方案1】:

    您可以实现自己的 system

    switch(pid = fork()) {
      case 0:
        // Modify command to prepend "set -o pipefail &&" to it.
        execl("/bin/bash", "bash", "-c", command, (char *) 0);
     case -1: // handle fork error
     default:
        waitpid(pid, ...);
    }
    

    LD_PRELOADsystem 实现到您的tup 进程中。

    如果你不想做低级进程管理,你可以插入system只是将命令包裹在bash -c "set -o pipefail &amp;&amp; " 中并转义引号,然后调用原来的system .有关库插入,请参阅 this article

    【讨论】:

      猜你喜欢
      • 2013-12-27
      • 1970-01-01
      • 1970-01-01
      • 2018-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 2020-09-29
      相关资源
      最近更新 更多