首页 > 解决方案 > 将文件中的每个文件路径替换为符号链接后面的路径

问题描述

我正在使用 Typescript 使用 Jenkins 构建项目。它使用“jest”生成包含代码覆盖率数据的“lcov.info”文件。工作区有一些符号链接。“lcov.info”文件中的结果路径代表链接的“源”,而不是目标。这应该没问题,假设工具链中的所有内容都理解符号链接。

不幸的是,我还在使用稍旧版本的 SonarQube,它使用的是稍旧版本的 SonarTS 插件,它不理解符号链接,因此找不到所有路径。

我不知道 SonarTS 中的错误是否已在未来版本中修复。等待升级是不可能的。

我之前为此编写了一个头脑简单的 sed 脚本,当时我对符号链接后面的实际绝对路径所做的假设是正确的。这个假设现在不正确,所以我必须在 Jenkins 管道脚本中构建一个更复杂的 bash 命令行。

我的第一次尝试看起来像这样:

sh "cat coverage/lcov.info | sed -e 's/^SF:(.*)/SF:`ls -L \\1`/g' > /tmp/lcov.info"

我的意图是用符号链接后面的“ls -L”结果替换文件路径。这不起作用,因为...脚本获取字符串“\1”,而不是我想要的。我可以理解为什么会这样,因为反引号表达式可能是在构建正则表达式之前构建的。

我宁愿不构建多行脚本并将其存储在构建中,而是内联编写它。

我猜想用 awk 来做这件事可能更实用,但是我已经有一段时间没有 awk-ed 一些不平凡的东西了。

更新

尽管我为此找到了一个粗糙的 bash 解决方案,但我发现 perl 解决方案很有吸引力,因为它更简单。但是,我实际上无法让它工作。

我创建了一个名为“dir1”的目录,并在其中放置了一个名为“stuff”的空文件。我创建了一个名为“dir2”的符号链接,它指向“dir1”。我创建了一个名为“junk1”的文件,其内容如下:

SF:dir2/stuff
SF:dir2/stuff

另请注意:

% ls -lt dir2
lrwxrwxrwx 1 dk068x dk068x 4 Dec 16 13:22 dir2 -> dir1/

然后我运行以下命令并得到指示的结果:

% cat junk1 | perl -pe 's/^(SF:)(.*)/ $1 . readlink $2 /ge'
SF:
SF:

我在 Cygwin 和 Ubuntu VM 上都对此进行了测试。

标签: jenkinsawksedsymlink

解决方案


如果Perl是您的选择,请尝试:

perl -pe 's/^(SF:)(.*)/ $1 . readlink $2 /ge' < coverage/lcov.info > /tmp/lcov.info
  • readlink函数返回符号链接的值。
  • 运算符的e选项s/pattern/replacement/使替换成为 的表达式Perl

[更新]

现在脚本分析info文件中描述的路径以递归查找符号链接子字符串。

#!/bin/bash

perl -lne '
    use strict;
    use warnings;

    my $col1;                   # 1st column of the info file
    my $col2;                   # 2nd column of the info file
    my $real_path;              # resolved path (final)
    my $link_substr;            # substring of $path which is a symlink
    my $link_result;            # output of readlink

    # return substring which is a symlink
    sub checklink() {
        my $path = shift;
        while (1) {
            return $path if -l $path;   # $path is a symlink
            return "" if $path !~ m#/#; # return "" if $path contains no symlink
            $path =~ s#/[^/]*$##;       # remove the rightmost "/" and following substring
        }
    }
    if (/^(SF:)(.*)/) {
        $col1 = $1; $col2 = $2;
        $link_substr = &checklink($col2);
        if ($link_substr ne "") {
            $link_result = readlink($link_substr);
            $link_result =~ s#/$##;     # remove trailing "/" if any
            $real_path = $link_result . substr($col2, length($link_substr));
        } else {
            $real_path = $col2;
        }
        print $col1, $real_path;
    }
' coverage/lcov.info > /tmp/lcov.info

推荐阅读