Skip to content
Commits on Source (10)
diffoscope (129) UNRELEASED; urgency=medium
* WIP (generated upon release).
-- Chris Lamb <lamby@debian.org> Fri, 25 Oct 2019 09:42:10 +0100
diffoscope (129) unstable; urgency=medium
* Call R's "deparse" function to ensure that we do not error out and revert
to a binary diff when processing .rdb files with internal "vector" types as
they do not automatically coerce to strings.
* Add the ability to pass Python bytestrings to external commands and
pass our long script to parse R .rdb files using this new method over a
long command-line argument
* Use Rscript's --vanilla option over --no-environ as this also enables
--no-save, --no-restore, --no-site-file and --no-init-file.
* Improve command-line error messages:
- Split out formatting into a separate utility function.
- Truncate very long lines when displaying them as an external source
of data.
- When printing an error from a command, format the command for the user.
* Use "exit code" over "return code" when referring to UNIX error codes in
displayed differences.
-- Chris Lamb <lamby@debian.org> Mon, 28 Oct 2019 11:15:18 +0000
diffoscope (128) unstable; urgency=medium
......
......@@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
VERSION = "128"
VERSION = "129"
......@@ -32,7 +32,7 @@ import binascii
HEADER = binascii.a2b_hex("580a000000020003")
DUMP_RDB = r"""
DUMP_RDB = rb"""
hideOutput = lazyLoad(commandArgs(TRUE));
for (x in ls(all.names = TRUE, sorted = TRUE)) {
......@@ -42,8 +42,10 @@ for (x in ls(all.names = TRUE, sorted = TRUE)) {
if (typeof(obj) == "environment") {
cat("\n{\n", sep = "");
for (y in ls(obj, all.names = TRUE, sorted = TRUE))
cat(sprintf(" \"%s\" = \"%s\"\n", y, get(y, envir = obj)), sep = "");
for (y in ls(obj, all.names = TRUE, sorted = TRUE)) {
obj2 = get(y, envir = obj);
cat(sprintf(" \"%s\" = \"%s\"\n", y, deparse(obj2)), sep = "");
}
cat("}\n");
} else {
for (line in deparse(obj))
......@@ -109,7 +111,7 @@ class RdsReader(Command):
def cmdline(self):
return [
'Rscript',
'--no-environ',
'--vanilla',
'-e',
'args <- commandArgs(TRUE); readRDS(args[1])',
self.path,
......@@ -138,7 +140,10 @@ class RdbReader(Command):
@tool_required('Rscript')
def cmdline(self):
return ['Rscript', '--no-environ', '-e', DUMP_RDB, self.path]
return ['Rscript', '--vanilla', '-', self.path]
def input(self):
return DUMP_RDB
class RdbFile(File):
......
......@@ -22,6 +22,8 @@ import logging
import shlex
import subprocess
from ...utils import format_cmdline
logger = logging.getLogger(__name__)
......@@ -47,6 +49,7 @@ class Command(metaclass=abc.ABCMeta):
shell=False,
close_fds=True,
env=self.env(),
input=self.input(),
stdin=self._stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
......@@ -65,16 +68,9 @@ class Command(metaclass=abc.ABCMeta):
def cmdline(self):
raise NotImplementedError()
def shell_cmdline(self):
def fn(x):
if x == self.path:
return '{}'
x = repr(x)
if ' ' not in x:
x = x[1:-1]
return x
return ' '.join(fn(x) for x in self.cmdline())
def shell_cmdline(self, *args, **kwargs):
kwargs.setdefault('replace', (self.path,))
return format_cmdline(self.cmdline(), *args, **kwargs)
def env(self):
return None # inherit parent environment by default
......@@ -89,6 +85,9 @@ class Command(metaclass=abc.ABCMeta):
def terminate(self):
pass
def input(self):
pass
def _read_stderr(self):
if self.MASK_STDERR:
return ""
......
......@@ -30,6 +30,7 @@ from diffoscope.exc import (
ContainerExtractionError,
)
from diffoscope.tools import tool_required
from diffoscope.utils import format_cmdline
from diffoscope.config import Config
from diffoscope.profiling import profile
from diffoscope.difference import Difference
......@@ -451,7 +452,6 @@ class File(metaclass=abc.ABCMeta):
)
except subprocess.CalledProcessError as e:
difference = self.compare_bytes(other, source=source)
cmd = ' '.join(e.cmd)
if difference is None:
return None
......@@ -480,8 +480,10 @@ class File(metaclass=abc.ABCMeta):
suffix = '{} [...]'.format(suffix[:max_len])
difference.add_comment(
"Command `{}` exited with return code {}.{}".format(
cmd, e.returncode, suffix or " (No output)"
"Command `{}` exited with exit code {}.{}".format(
format_cmdline(e.cmd),
e.returncode,
suffix or " (No output)",
)
)
except RequiredToolNotFound as e:
......
......@@ -280,7 +280,7 @@ class Difference:
if 'source' not in kwargs:
source_cmd = command1 or command2
kwargs['source'] = source_cmd.shell_cmdline()
kwargs['source'] = source_cmd.shell_cmdline(truncate=120)
try:
difference = Difference.from_feeder(
......
# -*- coding: utf-8 -*-
#
# diffoscope: in-depth comparison of files, archives, and directories
#
# Copyright © 2019 Chris Lamb <lamby@debian.org>
#
# diffoscope is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# diffoscope 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
def format_cmdline(cmd, replace=(), truncate=None):
def fn(x):
if x in replace:
return '{}'
x = repr(x)
if ' ' not in x:
x = x[1:-1]
return x
result = ' '.join(fn(x) for x in cmd)
if truncate is not None and len(result) > truncate:
result = result[: truncate + 4] + " […]"
return result