Add color output to zfs diff.

This adds support to color zfs diff (in the style of git diff)
conditional on the ZFS_COLOR environment variable.

Signed-off-by: Ethan Coe-Renner <coerenner1@llnl.gov>
This commit is contained in:
Ethan Coe-Renner 2022-12-12 15:30:51 -08:00 committed by Tony Hutter
parent 0e72f5fb83
commit 9ef565a185
4 changed files with 60 additions and 8 deletions

View File

@ -151,13 +151,15 @@ int zfs_ioctl_fd(int fd, unsigned long request, struct zfs_cmd *zc);
* List of colors to use * List of colors to use
*/ */
#define ANSI_RED "\033[0;31m" #define ANSI_RED "\033[0;31m"
#define ANSI_GREEN "\033[0;32m"
#define ANSI_YELLOW "\033[0;33m" #define ANSI_YELLOW "\033[0;33m"
#define ANSI_BLUE "\033[0;34m"
#define ANSI_RESET "\033[0m" #define ANSI_RESET "\033[0m"
#define ANSI_BOLD "\033[1m" #define ANSI_BOLD "\033[1m"
void color_start(char *color); void color_start(const char *color);
void color_end(void); void color_end(void);
int printf_color(char *color, char *format, ...); int printf_color(const char *color, char *format, ...);
/* /*
* These functions are used by the ZFS libraries and cmd/zpool code, but are * These functions are used by the ZFS libraries and cmd/zpool code, but are

View File

@ -45,6 +45,7 @@
#include <pthread.h> #include <pthread.h>
#include <sys/zfs_ioctl.h> #include <sys/zfs_ioctl.h>
#include <libzfs.h> #include <libzfs.h>
#include <libzutil.h>
#include "libzfs_impl.h" #include "libzfs_impl.h"
#define ZDIFF_SNAPDIR "/.zfs/snapshot/" #define ZDIFF_SNAPDIR "/.zfs/snapshot/"
@ -55,6 +56,10 @@
#define ZDIFF_REMOVED '-' #define ZDIFF_REMOVED '-'
#define ZDIFF_RENAMED "R" #define ZDIFF_RENAMED "R"
#define ZDIFF_ADDED_COLOR ANSI_GREEN
#define ZDIFF_MODIFIED_COLOR ANSI_YELLOW
#define ZDIFF_REMOVED_COLOR ANSI_RED
#define ZDIFF_RENAMED_COLOR ANSI_BLUE
/* /*
* Given a {dsname, object id}, get the object path * Given a {dsname, object id}, get the object path
@ -129,6 +134,25 @@ stream_bytes(FILE *fp, const char *string)
} }
} }
/*
* Takes the type of change (like `print_file`), outputs the appropriate color
*/
static const char *
type_to_color(char type)
{
if (type == '+')
return (ZDIFF_ADDED_COLOR);
else if (type == '-')
return (ZDIFF_REMOVED_COLOR);
else if (type == 'M')
return (ZDIFF_MODIFIED_COLOR);
else if (type == 'R')
return (ZDIFF_RENAMED_COLOR);
else
return (NULL);
}
static char static char
get_what(mode_t what) get_what(mode_t what)
{ {
@ -176,6 +200,8 @@ static void
print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new, print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
zfs_stat_t *isb) zfs_stat_t *isb)
{ {
if (isatty(fileno(fp)))
color_start(ZDIFF_RENAMED_COLOR);
if (di->timestamped) if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t", (void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0], (longlong_t)isb->zs_ctime[0],
@ -187,12 +213,18 @@ print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
(void) fputs(di->scripted ? "\t" : " -> ", fp); (void) fputs(di->scripted ? "\t" : " -> ", fp);
print_cmn(fp, di, new); print_cmn(fp, di, new);
(void) fputc('\n', fp); (void) fputc('\n', fp);
if (isatty(fileno(fp)))
color_end();
} }
static void static void
print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file, print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
zfs_stat_t *isb) zfs_stat_t *isb)
{ {
if (isatty(fileno(fp)))
color_start(ZDIFF_MODIFIED_COLOR);
if (di->timestamped) if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t", (void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0], (longlong_t)isb->zs_ctime[0],
@ -202,12 +234,17 @@ print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
(void) fprintf(fp, "%c\t", get_what(isb->zs_mode)); (void) fprintf(fp, "%c\t", get_what(isb->zs_mode));
print_cmn(fp, di, file); print_cmn(fp, di, file);
(void) fprintf(fp, "\t(%+d)\n", delta); (void) fprintf(fp, "\t(%+d)\n", delta);
if (isatty(fileno(fp)))
color_end();
} }
static void static void
print_file(FILE *fp, differ_info_t *di, char type, const char *file, print_file(FILE *fp, differ_info_t *di, char type, const char *file,
zfs_stat_t *isb) zfs_stat_t *isb)
{ {
if (isatty(fileno(fp)))
color_start(type_to_color(type));
if (di->timestamped) if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t", (void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0], (longlong_t)isb->zs_ctime[0],
@ -217,6 +254,9 @@ print_file(FILE *fp, differ_info_t *di, char type, const char *file,
(void) fprintf(fp, "%c\t", get_what(isb->zs_mode)); (void) fprintf(fp, "%c\t", get_what(isb->zs_mode));
print_cmn(fp, di, file); print_cmn(fp, di, file);
(void) fputc('\n', fp); (void) fputc('\n', fp);
if (isatty(fileno(fp)))
color_end();
} }
static int static int

View File

@ -2082,22 +2082,26 @@ use_color(void)
* color_end(); * color_end();
*/ */
void void
color_start(char *color) color_start(const char *color)
{ {
if (use_color()) if (use_color()) {
printf("%s", color); fputs(color, stdout);
fflush(stdout);
}
} }
void void
color_end(void) color_end(void)
{ {
if (use_color()) if (use_color()) {
printf(ANSI_RESET); fputs(ANSI_RESET, stdout);
fflush(stdout);
}
} }
/* printf() with a color. If color is NULL, then do a normal printf. */ /* printf() with a color. If color is NULL, then do a normal printf. */
int int
printf_color(char *color, char *format, ...) printf_color(const char *color, char *format, ...)
{ {
va_list aptr; va_list aptr;
int rc; int rc;

View File

@ -704,6 +704,12 @@ command will be undone if the share is ever unshared (like via a reboot).
.El .El
. .
.Sh ENVIRONMENT VARIABLES .Sh ENVIRONMENT VARIABLES
.Bl -tag -width "ZFS_COLOR"
.It Sy ZFS_COLOR
Use ANSI color in
.Nm zfs Cm diff
output.
.El
.Bl -tag -width "ZFS_MOUNT_HELPER" .Bl -tag -width "ZFS_MOUNT_HELPER"
.It Sy ZFS_MOUNT_HELPER .It Sy ZFS_MOUNT_HELPER
Cause Cause