tests: rewrite test argv line wrapper in Python

As part of a goal to eliminate Perl from libvirt build tools,
rewrite the test-wrap-argv.pl tool in Python.

This was a straight conversion, manually going line-by-line to
change the syntax from Perl to Python. Thus the overall structure
of the file and approach is the same.

Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2019-08-30 13:22:54 +01:00
parent e0314b6855
commit 504f831957
5 changed files with 179 additions and 184 deletions

View File

@ -65,6 +65,7 @@ EXTRA_DIST = \
scripts/mock-noinline.py \
scripts/prohibit-duplicate-header.py \
scripts/reformat-news.py \
scripts/test-wrap-argv.py \
build-aux/syntax-check.mk \
build-aux/useless-if-before-free \
build-aux/vc-list-files \

View File

@ -2190,8 +2190,8 @@ header-ifdef:
$(PYTHON) $(top_srcdir)/scripts/header-ifdef.py
test-wrap-argv:
$(AM_V_GEN)$(VC_LIST) | $(GREP) -E '\.(ldargs|args)' | xargs \
$(PERL) $(top_srcdir)/tests/test-wrap-argv.pl --check
$(AM_V_GEN)$(VC_LIST) | $(GREP) -E '\.(ldargs|args)' | $(RUNUTF8) xargs \
$(PYTHON) $(top_srcdir)/scripts/test-wrap-argv.py --check
group-qemu-caps:
$(AM_V_GEN)$(PERL) $(top_srcdir)/tests/group-qemu-caps.pl --check $(top_srcdir)/

168
scripts/test-wrap-argv.py Executable file
View File

@ -0,0 +1,168 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
#
# This script is intended to be passed a list of .args files, used
# to store command line ARGV for the test suites. It will reformat
# them such that there is at most one '-param value' on each line
# of the file. Parameter values that are longer than 80 chars will
# also be split.
#
# If --in-place is supplied as the first parameter of this script,
# the files will be changed in place.
# If --check is the first parameter, the script will return
# a non-zero value if a file is not wrapped correctly.
# Otherwise the rewrapped files are printed to the standard output.
import argparse
import subprocess
import sys
def rewrap_line(line):
bits = line.split(" ")
# bits contains env vars, then the command line
# and then the arguments
env = []
cmd = None
args = []
if "=" not in bits[0]:
cmd = bits[0]
bits = bits[1:]
for bit in bits:
# If no command is defined yet, we must still
# have env vars
if cmd is None:
# Look for leading / to indicate command name
if bit.startswith("/"):
cmd = bit
else:
env.append(bit)
else:
# If there's a leading '-' then this is a new
# parameter, otherwise its a value for the prev
# parameter.
if bit.startswith("-"):
args.append(bit)
else:
args[-1] = args[-1] + " " + bit
# We might have to split line argument values...
args = [rewrap_arg(arg) for arg in args]
# Print env + command first
return " \\\n".join(env + [cmd] + args) + "\n"
def rewrap_arg(arg):
ret = []
max_len = 78
while len(arg) > max_len:
split = arg.rfind(",", 0, max_len + 1)
if split == -1:
split = arg.rfind(":", 0, max_len + 1)
if split == -1:
split = arg.rfind(" ", 0, max_len + 1)
if split == -1:
print("cannot find nice place to split '%s' below 80 chars" %
arg, file=sys.stderr)
split = max_len - 1
split = split + 1
ret.append(arg[0:split])
arg = arg[split:]
ret.append(arg)
return "\\\n".join(ret)
def rewrap(filename, in_place, check):
# Read the original file
with open(filename, 'r') as fh:
orig_lines = []
for line in fh:
orig_lines.append(line)
if len(orig_lines) == 0:
return
lines = []
for line in orig_lines:
if line.endswith("\\\n"):
line = line[:-2]
lines.append(line)
# Kill the last new line in the file
lines[-1] = lines[-1].rstrip("\n")
# Reconstruct the master data by joining all lines
# and then split again based on the real desired
# newlines
lines = "".join(lines).split("\n")
# Now each 'lines' entry represents a single command, we
# can process them
new_lines = []
for line in lines:
new_lines.append(rewrap_line(line))
if in_place:
with open(filename, "w") as fh:
for line in new_lines:
print(line, file=fh, end='')
elif check:
orig = "".join(orig_lines)
new = "".join(new_lines)
if new != orig:
diff = subprocess.Popen(["diff", "-u", filename, "-"],
stdin=subprocess.PIPE)
diff.communicate(input=new.encode('utf-8'))
print("Incorrect line wrapping in $file",
file=sys.stderr)
print("Use test-wrap-argv.py to wrap test data files",
file=sys.stderr)
return False
else:
for line in new_lines:
print(line, end='')
return True
parser = argparse.ArgumentParser(description='Test arg line wrapper')
parser.add_argument('--in-place', '-i', action="store_true",
help='modify files in-place')
parser.add_argument('--check', action="store_true",
help='check existing files only')
parser.add_argument('files', nargs="+",
help="filenames to check")
args = parser.parse_args()
errs = False
for filename in args.files:
if not rewrap(filename, args.in_place, args.check):
errs = True
if errs:
sys.exit(1)
sys.exit(0)

View File

@ -1,174 +0,0 @@
#!/usr/bin/env perl
#
# Copyright (C) 2015 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
#
# This script is intended to be passed a list of .args files, used
# to store command line ARGV for the test suites. It will reformat
# them such that there is at most one '-param value' on each line
# of the file. Parameter values that are longer than 80 chars will
# also be split.
#
# If --in-place is supplied as the first parameter of this script,
# the files will be changed in place.
# If --check is the first parameter, the script will return
# a non-zero value if a file is not wrapped correctly.
# Otherwise the rewrapped files are printed to the standard output.
$in_place = 0;
$check = 0;
if (@ARGV[0] eq "--in-place" or @ARGV[0] eq "-i") {
$in_place = 1;
shift @ARGV;
} elsif (@ARGV[0] eq "--check") {
$check = 1;
shift @ARGV;
}
$ret = 0;
foreach my $file (@ARGV) {
if (&rewrap($file) < 0) {
$ret = 1;
}
}
exit $ret;
sub rewrap {
my $file = shift;
# Read the original file
open FILE, "<", $file or die "cannot read $file: $!";
my @orig_lines = <FILE>;
close FILE;
my @lines = @orig_lines;
foreach (@lines) {
# If there is a trailing '\' then kill the new line
if (/\\$/) {
chomp;
$_ =~ s/\\$//;
}
}
# Skip empty files
return unless @lines;
# Kill the last new line in the file
chomp @lines[$#lines];
# Reconstruct the master data by joining all lines
# and then split again based on the real desired
# newlines
@lines = split /\n/, join('', @lines);
# Now each @lines represents a single command, we
# can process them
@lines = map { &rewrap_line($_) } @lines;
if ($in_place) {
open FILE, ">", $file or die "cannot write $file: $!";
foreach my $line (@lines) {
print FILE $line;
}
close FILE;
} elsif ($check) {
my $nl = join('', @lines);
my $ol = join('', @orig_lines);
unless ($nl eq $ol) {
open DIFF, "| diff -u $file -" or die "cannot run diff: $!";
print DIFF $nl;
close DIFF;
print STDERR "Incorrect line wrapping in $file\n";
print STDERR "Use test-wrap-argv.pl to wrap test data files\n";
return -1;
}
} else {
foreach my $line (@lines) {
print $line;
}
}
return 0;
}
sub rewrap_line {
my $line = shift;
my @bits = split / /, join('', $line);
# @bits contains env vars, then the command line
# and then the arguments
my @env;
my $cmd;
my @args;
if ($bits[0] !~ /=/) {
$cmd = shift @bits;
}
foreach my $bit (@bits) {
# If no command is defined yet, we must still
# have env vars
if (!defined $cmd) {
# Look for leading / to indicate command name
if ($bit =~ m,^/,) {
$cmd = $bit;
} else {
push @env, $bit;
}
} else {
# If there's a leading '-' then this is a new
# parameter, otherwise its a value for the prev
# parameter.
if ($bit =~ m,^-,) {
push @args, $bit;
} else {
$args[$#args] .= " " . $bit;
}
}
}
# We might have to split line argument values...
@args = map { &rewrap_arg($_) } @args;
# Print env + command first
return join(" \\\n", @env, $cmd, @args), "\n";
}
sub rewrap_arg {
my $arg = shift;
my @ret;
my $max_len = 78;
while (length($arg) > $max_len) {
my $split = rindex $arg, ",", $max_len;
if ($split == -1) {
$split = rindex $arg, ":", $max_len;
}
if ($split == -1) {
$split = rindex $arg, " ", $max_len;
}
if ($split == -1) {
warn "cannot find nice place to split '$arg' below 80 chars\n";
$split = $max_len - 1;
}
$split++;
push @ret, substr $arg, 0, $split;
$arg = substr $arg, $split;
}
push @ret, $arg;
return join("\\\n", @ret);
}

View File

@ -58,7 +58,7 @@ static size_t testCounter;
static virBitmapPtr testBitmap;
char *progname;
static char *perl;
static char *python;
static int virTestUseTerminalColors(void)
{
@ -419,14 +419,14 @@ virTestRewrapFile(const char *filename)
virStringHasSuffix(filename, ".ldargs")))
return 0;
if (!perl) {
fprintf(stderr, "cannot rewrap %s: unable to find perl in path", filename);
if (!python) {
fprintf(stderr, "cannot rewrap %s: unable to find python in path", filename);
return -1;
}
script = g_strdup_printf("%s/test-wrap-argv.pl", abs_srcdir);
script = g_strdup_printf("%s/test-wrap-argv.py", abs_srcdir);
cmd = virCommandNewArgList(perl, script, "--in-place", filename, NULL);
cmd = virCommandNewArgList(python, script, "--in-place", filename, NULL);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
@ -910,8 +910,8 @@ int virTestMain(int argc,
}
}
/* Find perl early because some tests override PATH */
perl = virFindFileInPath("perl");
/* Find python early because some tests override PATH */
python = virFindFileInPath("python");
ret = (func)();
@ -922,7 +922,7 @@ int virTestMain(int argc,
fprintf(stderr, " %-3zu %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
}
virLogReset();
VIR_FREE(perl);
VIR_FREE(python);
return ret;
}