[Reproducible-commits] [dpkg] 80/105: libdpkg, scripts: Add very basic color support
Niko Tyni
ntyni at moszumanska.debian.org
Mon May 2 13:49:55 UTC 2016
This is an automated email from the git hooks/post-receive script.
ntyni pushed a commit to branch ntyni/reproducible_builds
in repository dpkg.
commit e0c33c729c395dd8592c91723065d723246dab31
Author: Guillem Jover <guillem at debian.org>
Date: Thu Sep 17 18:01:16 2015 +0200
libdpkg, scripts: Add very basic color support
This adds disabled by default color output, that can be enabled with
the new DPKG_COLOR environment variable.
The colors are currently hard-coded ANSI escape sequences, but will be
made configurable eventually.
---
check.am | 1 +
debian/changelog | 3 +
lib/dpkg/Makefile.am | 2 +
lib/dpkg/color.c | 74 ++++++++++++++++++++++++
lib/dpkg/color.h | 87 ++++++++++++++++++++++++++++
lib/dpkg/ehandle.c | 10 +++-
lib/dpkg/libdpkg.map | 5 ++
lib/dpkg/report.c | 11 +++-
man/dpkg-buildpackage.1 | 5 ++
man/dpkg.1 | 5 ++
scripts/Dpkg/Changelog.pm | 6 +-
scripts/Dpkg/ErrorHandling.pm | 129 ++++++++++++++++++++++++++++++++++++++----
scripts/dpkg-buildflags.pl | 10 ++--
13 files changed, 324 insertions(+), 24 deletions(-)
diff --git a/check.am b/check.am
index a2f1779..55b146f 100644
--- a/check.am
+++ b/check.am
@@ -27,6 +27,7 @@ check-local: $(test_data) $(test_programs) $(test_scripts)
[ -z "$(test_tmpdir)" ] || $(MKDIR_P) $(test_tmpdir)
PATH="$(abs_top_builddir)/src:$(abs_top_builddir)/scripts:$(abs_top_builddir)/utils:$(PATH)" \
LC_ALL=C \
+ DPKG_COLORS=never \
$(TEST_ENV_VARS) \
srcdir=$(srcdir) builddir=$(builddir) \
CC=$(CC) \
diff --git a/debian/changelog b/debian/changelog
index 54eb0e3..cc44104 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -71,6 +71,9 @@ dpkg (1.18.5) UNRELEASED; urgency=medium
Prompted by Andrey Utkin <andrey.krieger.utkin at gmail.com>.
* Promote a print to a warning for missing control files in dpkg-deb.
* Use info() instead of print in dpkg-buildpackage and dpkg-genchanges.
+ * Add very basic color support to all dpkg namespaced programs, enabled by
+ setting the environment variable DPKG_COLORS to “auto”, “always” or
+ “never”, the latter being the default.
* Portability:
- Move DPKG_ADMINDIR environment variable name out from update-alternatives
code, to make life easier for non-dpkg-based systems.
diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am
index 2127109..a031b56 100644
--- a/lib/dpkg/Makefile.am
+++ b/lib/dpkg/Makefile.am
@@ -48,6 +48,7 @@ libdpkg_la_SOURCES = \
buffer.c \
c-ctype.c \
cleanup.c \
+ color.c \
command.c \
compress.c \
dbdir.c \
@@ -108,6 +109,7 @@ pkginclude_HEADERS = \
atomic-file.h \
buffer.h \
c-ctype.h \
+ color.h \
command.h \
compress.h \
deb-version.h \
diff --git a/lib/dpkg/color.c b/lib/dpkg/color.c
new file mode 100644
index 0000000..21b8044
--- /dev/null
+++ b/lib/dpkg/color.c
@@ -0,0 +1,74 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * color.c - color support
+ *
+ * Copyright © 2015-2016 Guillem Jover <guillem at debian.org>
+ *
+ * This 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/color.h>
+
+static enum color_mode color_mode = COLOR_MODE_UNKNOWN;
+static bool use_color = false;
+
+bool
+color_set_mode(const char *mode)
+{
+ if (strcmp(mode, "auto") == 0) {
+ color_mode = COLOR_MODE_AUTO;
+ use_color = isatty(STDOUT_FILENO);
+ } else if (strcmp(mode, "always") == 0) {
+ color_mode = COLOR_MODE_ALWAYS;
+ use_color = true;
+ } else {
+ color_mode = COLOR_MODE_NEVER;
+ use_color = false;
+ }
+
+ return use_color;
+}
+
+static bool
+color_enabled(void)
+{
+ const char *mode;
+
+ if (color_mode != COLOR_MODE_UNKNOWN)
+ return use_color;
+
+ mode = getenv("DPKG_COLORS");
+ if (mode == NULL)
+ mode = "never";
+
+ return color_set_mode(mode);
+}
+
+const char *
+color_get(const char *color)
+{
+ if (!color_enabled())
+ return "";
+
+ return color;
+}
diff --git a/lib/dpkg/color.h b/lib/dpkg/color.h
new file mode 100644
index 0000000..5dd3d38
--- /dev/null
+++ b/lib/dpkg/color.h
@@ -0,0 +1,87 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * color.h - color support
+ *
+ * Copyright © 2015-2016 Guillem Jover <guillem at debian.org>
+ *
+ * This 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBDPKG_COLOR_H
+#define LIBDPKG_COLOR_H
+
+#include <stdbool.h>
+
+#include <dpkg/macros.h>
+
+DPKG_BEGIN_DECLS
+
+/**
+ * @defgroup color Color support
+ * @ingroup dpkg-internal
+ * @{
+ */
+
+/* Standard ANSI colors and attributes. */
+#define COLOR_NORMAL ""
+#define COLOR_RESET "\e[0m"
+#define COLOR_BOLD "\e[1m"
+#define COLOR_BLACK "\e[30m"
+#define COLOR_RED "\e[31m"
+#define COLOR_GREEN "\e[32m"
+#define COLOR_YELLOW "\e[33m"
+#define COLOR_BLUE "\e[34m"
+#define COLOR_MAGENTA "\e[35m"
+#define COLOR_CYAN "\e[36m"
+#define COLOR_WHITE "\e[37m"
+#define COLOR_BOLD_BLACK "\e[1;30m"
+#define COLOR_BOLD_RED "\e[1;31m"
+#define COLOR_BOLD_GREEN "\e[1;32m"
+#define COLOR_BOLD_YELLOW "\e[1;33m"
+#define COLOR_BOLD_BLUE "\e[1;34m"
+#define COLOR_BOLD_MAGENTA "\e[1;35m"
+#define COLOR_BOLD_CYAN "\e[1;36m"
+#define COLOR_BOLD_WHITE "\e[1;37m"
+
+/* Current defaults. These might become configurable in the future. */
+#define COLOR_PROG COLOR_BOLD
+#define COLOR_INFO COLOR_GREEN
+#define COLOR_NOTICE COLOR_YELLOW
+#define COLOR_WARN COLOR_BOLD_YELLOW
+#define COLOR_ERROR COLOR_BOLD_RED
+
+enum color_mode {
+ COLOR_MODE_UNKNOWN = -1,
+ COLOR_MODE_NEVER,
+ COLOR_MODE_ALWAYS,
+ COLOR_MODE_AUTO,
+};
+
+bool
+color_set_mode(const char *mode);
+
+const char *
+color_get(const char *color);
+
+static inline const char *
+color_reset(void)
+{
+ return color_get(COLOR_RESET);
+}
+
+/** @} */
+
+DPKG_END_DECLS
+
+#endif /* LIBDPKG_COLOR_H */
diff --git a/lib/dpkg/ehandle.c b/lib/dpkg/ehandle.c
index 683951f..f7dab09 100644
--- a/lib/dpkg/ehandle.c
+++ b/lib/dpkg/ehandle.c
@@ -32,6 +32,7 @@
#include <dpkg/macros.h>
#include <dpkg/i18n.h>
#include <dpkg/progname.h>
+#include <dpkg/color.h>
#include <dpkg/ehandle.h>
/* 6x255 for inserted strings (%.255s &c in fmt; and %s with limited length arg)
@@ -355,7 +356,9 @@ catch_fatal_error(void)
void
print_fatal_error(const char *emsg, const void *data)
{
- fprintf(stderr, _("%s: error: %s\n"), dpkg_get_progname(), emsg);
+ fprintf(stderr, "%s%s:%s %s%s:%s %s\n",
+ color_get(COLOR_PROG), dpkg_get_progname(), color_reset(),
+ color_get(COLOR_ERROR), _("error"), color_reset(), emsg);
}
void
@@ -391,8 +394,9 @@ do_internerr(const char *file, int line, const char *func, const char *fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- fprintf(stderr, _("%s:%s:%d:%s: internal error: %s\n"),
- dpkg_get_progname(), file, line, func, buf);
+ fprintf(stderr, "%s%s:%s:%d:%s:%s %s%s:%s %s\n", color_get(COLOR_PROG),
+ dpkg_get_progname(), file, line, func, color_reset(),
+ color_get(COLOR_ERROR), _("internal error"), color_reset(), buf);
abort();
}
diff --git a/lib/dpkg/libdpkg.map b/lib/dpkg/libdpkg.map
index 8c91ab7..ddf898f 100644
--- a/lib/dpkg/libdpkg.map
+++ b/lib/dpkg/libdpkg.map
@@ -27,6 +27,11 @@ local:
};
LIBDPKG_PRIVATE {
+ # Color handling
+ color_set_mode;
+ color_get;
+ color_reset;
+
# Error handling
push_error_context_jump;
push_error_context_func;
diff --git a/lib/dpkg/report.c b/lib/dpkg/report.c
index a697666..b02e675 100644
--- a/lib/dpkg/report.c
+++ b/lib/dpkg/report.c
@@ -29,6 +29,7 @@
#include <dpkg/macros.h>
#include <dpkg/i18n.h>
#include <dpkg/progname.h>
+#include <dpkg/color.h>
#include <dpkg/report.h>
static int piped_mode = _IOLBF;
@@ -63,7 +64,9 @@ warningv(const char *fmt, va_list args)
warn_count++;
vsnprintf(buf, sizeof(buf), fmt, args);
- fprintf(stderr, _("%s: warning: %s\n"), dpkg_get_progname(), buf);
+ fprintf(stderr, "%s%s:%s %s%s:%s %s\n",
+ color_get(COLOR_PROG), dpkg_get_progname(), color_reset(),
+ color_get(COLOR_WARN), _("warning"), color_reset(), buf);
}
void
@@ -86,7 +89,8 @@ notice(const char *fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- fprintf(stderr, "%s: %s\n", dpkg_get_progname(), buf);
+ fprintf(stderr, "%s%s:%s %s\n",
+ color_get(COLOR_PROG), dpkg_get_progname(), color_reset(), buf);
}
void
@@ -99,5 +103,6 @@ info(const char *fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- printf("%s: %s\n", dpkg_get_progname(), buf);
+ printf("%s%s:%s %s\n",
+ color_get(COLOR_PROG), dpkg_get_progname(), color_reset(), buf);
}
diff --git a/man/dpkg-buildpackage.1 b/man/dpkg-buildpackage.1
index 13770ba..b96b753 100644
--- a/man/dpkg-buildpackage.1
+++ b/man/dpkg-buildpackage.1
@@ -388,6 +388,11 @@ If set, it will be used as the active build profile(s) for the package
being built (since dpkg 1.17.2).
It is a space separated list of profile names.
Overridden by the \fB\-P\fP option.
+.TP
+.B DPKG_COLORS
+Sets the color mode (since dpkg 1.18.5).
+The currently accepted values are: \fBauto\fP, \fBalways\fP and
+\fBnever\fP (default).
.SS Reliance on exported environment flags
Even if \fBdpkg\-buildpackage\fP exports some variables, \fBdebian/rules\fP
diff --git a/man/dpkg.1 b/man/dpkg.1
index cdfbe2b..2992359 100644
--- a/man/dpkg.1
+++ b/man/dpkg.1
@@ -850,6 +850,11 @@ The program \fBdpkg\fP will execute when starting a new interactive shell.
Sets the number of columns \fBdpkg\fP should use when displaying formatted
text.
Currently only used by \fB\-\-list\fP.
+.TP
+.B DPKG_COLORS
+Sets the color mode (since dpkg 1.18.5).
+The currently accepted values are: \fBauto\fP, \fBalways\fP and
+\fBnever\fP (default).
.SS Internal environment
.TP
.B DPKG_SHELL_REASON
diff --git a/scripts/Dpkg/Changelog.pm b/scripts/Dpkg/Changelog.pm
index 60d71aa..b4ed0f5 100644
--- a/scripts/Dpkg/Changelog.pm
+++ b/scripts/Dpkg/Changelog.pm
@@ -37,7 +37,7 @@ use warnings;
our $VERSION = '1.00';
use Dpkg::Gettext;
-use Dpkg::ErrorHandling qw(:DEFAULT report);
+use Dpkg::ErrorHandling qw(:DEFAULT report REPORT_WARN);
use Dpkg::Control;
use Dpkg::Control::Changelog;
use Dpkg::Control::Fields;
@@ -166,9 +166,9 @@ sub get_parse_errors {
my $res = '';
foreach my $e (@{$self->{parse_errors}}) {
if ($e->[3]) {
- $res .= report(g_('warning'), g_("%s(l%s): %s\nLINE: %s"), @$e);
+ $res .= report(REPORT_WARN, g_("%s(l%s): %s\nLINE: %s"), @$e);
} else {
- $res .= report(g_('warning'), g_('%s(l%s): %s'), @$e);
+ $res .= report(REPORT_WARN, g_('%s(l%s): %s'), @$e);
}
}
return $res;
diff --git a/scripts/Dpkg/ErrorHandling.pm b/scripts/Dpkg/ErrorHandling.pm
index a77fe19..cdf3c5a 100644
--- a/scripts/Dpkg/ErrorHandling.pm
+++ b/scripts/Dpkg/ErrorHandling.pm
@@ -18,6 +18,15 @@ use warnings;
our $VERSION = '0.02';
our @EXPORT_OK = qw(
+ REPORT_PROGNAME
+ REPORT_COMMAND
+ REPORT_STATUS
+ REPORT_INFO
+ REPORT_NOTICE
+ REPORT_WARN
+ REPORT_ERROR
+ report_pretty
+ report_color
report
);
our @EXPORT = qw(
@@ -34,12 +43,71 @@ our @EXPORT = qw(
);
use Exporter qw(import);
+use Term::ANSIColor;
use Dpkg ();
use Dpkg::Gettext;
my $quiet_warnings = 0;
my $info_fh = \*STDOUT;
+my $use_color = 0;
+
+sub setup_color
+{
+ my $mode = $ENV{'DPKG_COLORS'} // 'never';
+
+ if ($mode eq 'auto') {
+ ## no critic (InputOutput::ProhibitInteractiveTest)
+ $use_color = 1 if -t *STDOUT or -t *STDERR;
+ } elsif ($mode eq 'always') {
+ $use_color = 1;
+ } else {
+ $use_color = 0;
+ }
+}
+
+setup_color();
+
+use constant {
+ REPORT_PROGNAME => 1,
+ REPORT_COMMAND => 2,
+ REPORT_STATUS => 3,
+ REPORT_INFO => 4,
+ REPORT_NOTICE => 5,
+ REPORT_WARN => 6,
+ REPORT_ERROR => 7,
+};
+
+my %report_mode = (
+ REPORT_PROGNAME() => {
+ color => 'bold',
+ },
+ REPORT_COMMAND() => {
+ color => 'bold magenta',
+ },
+ REPORT_STATUS() => {
+ color => 'clear',
+ # We do not translate this name because the untranslated output is
+ # part of the interface.
+ name => 'status',
+ },
+ REPORT_INFO() => {
+ color => 'green',
+ name => g_('info'),
+ },
+ REPORT_NOTICE() => {
+ color => 'yellow',
+ name => g_('notice'),
+ },
+ REPORT_WARN() => {
+ color => 'bold yellow',
+ name => g_('warning'),
+ },
+ REPORT_ERROR() => {
+ color => 'bold red',
+ name => g_('error'),
+ },
+);
sub report_options
{
@@ -53,50 +121,91 @@ sub report_options
}
}
+sub report_name
+{
+ my $type = shift;
+
+ return $report_mode{$type}{name} // '';
+}
+
+sub report_color
+{
+ my $type = shift;
+
+ return $report_mode{$type}{color} // 'clear';
+}
+
+sub report_pretty
+{
+ my ($msg, $color) = @_;
+
+ if ($use_color) {
+ return colored($msg, $color);
+ } else {
+ return $msg;
+ }
+}
+
+sub _progname_prefix
+{
+ return report_pretty("$Dpkg::PROGNAME: ", report_color(REPORT_PROGNAME));
+}
+
+sub _typename_prefix
+{
+ my $type = shift;
+
+ return report_pretty(report_name($type), report_color($type));
+}
+
sub report(@)
{
my ($type, $msg) = (shift, shift);
$msg = sprintf($msg, @_) if (@_);
- return "$Dpkg::PROGNAME: $type: $msg\n";
+
+ my $progname = _progname_prefix();
+ my $typename = _typename_prefix($type);
+
+ return "$progname$typename: $msg\n";
}
sub info($;@)
{
- print { $info_fh } report(g_('info'), @_) if (!$quiet_warnings);
+ print { $info_fh } report(REPORT_INFO, @_) if not $quiet_warnings;
}
sub notice
{
- warn report(g_('notice'), @_) if not $quiet_warnings;
+ warn report(REPORT_NOTICE, @_) if not $quiet_warnings;
}
sub warning($;@)
{
- warn report(g_('warning'), @_) if (!$quiet_warnings);
+ warn report(REPORT_WARN, @_) if not $quiet_warnings;
}
sub syserr($;@)
{
my $msg = shift;
- die report(g_('error'), "$msg: $!", @_);
+ die report(REPORT_ERROR, "$msg: $!", @_);
}
sub error($;@)
{
- die report(g_('error'), @_);
+ die report(REPORT_ERROR, @_);
}
sub errormsg($;@)
{
- print { *STDERR } report(g_('error'), @_);
+ print { *STDERR } report(REPORT_ERROR, @_);
}
sub printcmd
{
my (@cmd) = @_;
- print { *STDERR } " @cmd\n";
+ print { *STDERR } report_pretty(" @cmd\n", report_color(REPORT_COMMAND));
}
sub subprocerr(@)
@@ -123,8 +232,8 @@ sub usageerr(@)
my ($msg) = (shift);
$msg = sprintf($msg, @_) if (@_);
- warn "$Dpkg::PROGNAME: $msg\n\n";
- warn "$printforhelp\n";
+ warn report(REPORT_ERROR, $msg);
+ warn "\n$printforhelp\n";
exit(2);
}
diff --git a/scripts/dpkg-buildflags.pl b/scripts/dpkg-buildflags.pl
index 0f90d37..b696b08 100755
--- a/scripts/dpkg-buildflags.pl
+++ b/scripts/dpkg-buildflags.pl
@@ -23,7 +23,7 @@ use warnings;
use Dpkg ();
use Dpkg::Gettext;
-use Dpkg::ErrorHandling qw(:DEFAULT report);
+use Dpkg::ErrorHandling qw(:DEFAULT report REPORT_STATUS);
use Dpkg::Build::Env;
use Dpkg::BuildFlags;
use Dpkg::Vendor qw(get_current_vendor);
@@ -155,12 +155,12 @@ if ($action eq 'list') {
my @envvars = Dpkg::Build::Env::list_accessed();
for my $envvar (@envvars) {
if (exists $ENV{$envvar}) {
- printf report('status', 'environment variable %s=%s',
+ printf report(REPORT_STATUS, 'environment variable %s=%s',
$envvar, $ENV{$envvar});
}
}
my $vendor = Dpkg::Vendor::get_current_vendor() || 'undefined';
- print report('status', "vendor is $vendor");
+ print report(REPORT_STATUS, "vendor is $vendor");
# Then the resulting features:
foreach my $area (sort $build_flags->get_feature_areas()) {
my $fs;
@@ -168,13 +168,13 @@ if ($action eq 'list') {
foreach my $feature (sort keys %features) {
$fs .= sprintf(' %s=%s', $feature, $features{$feature} ? 'yes' : 'no');
}
- print report('status', "$area features:$fs");
+ print report(REPORT_STATUS, "$area features:$fs");
}
# Then the resulting values (with their origin):
foreach my $flag ($build_flags->list()) {
my $value = $build_flags->get($flag);
my $origin = $build_flags->get_origin($flag);
my $maintainer = $build_flags->is_maintainer_modified($flag) ? '+maintainer' : '';
- print report('status', "$flag [$origin$maintainer]: $value");
+ print report(REPORT_STATUS, "$flag [$origin$maintainer]: $value");
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/dpkg.git
More information about the Reproducible-commits
mailing list