aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-var.txt2
-rw-r--r--Documentation/git.txt8
-rw-r--r--builtin-var.c4
-rw-r--r--cache.h2
-rwxr-xr-xgit-am.sh5
-rw-r--r--git-sh-setup.sh13
-rwxr-xr-xgit-svn.perl9
-rw-r--r--pager.c6
-rwxr-xr-xt/t7006-pager.sh176
-rwxr-xr-xt/t7006/test-terminal.perl58
10 files changed, 268 insertions, 15 deletions
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index bb981822a..458f3e275 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -8,7 +8,7 @@ git-var - Show a git logical variable
SYNOPSIS
--------
-'git var' [ -l | <variable> ]
+'git var' ( -l | <variable> )
DESCRIPTION
-----------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index cc32ce18d..98b6e1698 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -230,7 +230,10 @@ help ...`.
-p::
--paginate::
- Pipe all output into 'less' (or if set, $PAGER).
+ Pipe all output into 'less' (or if set, $PAGER) if standard
+ output is a terminal. This overrides the `pager.<cmd>`
+ configuration options (see the "Configuration Mechanism" section
+ below).
--no-pager::
Do not pipe git output into a pager.
@@ -402,7 +405,8 @@ people. Here is an example:
------------
Various commands read from the configuration file and adjust
-their operation accordingly.
+their operation accordingly. See linkgit:git-config[1] for a
+list.
Identifier Terminology
diff --git a/builtin-var.c b/builtin-var.c
index 228051819..70fdb4dec 100644
--- a/builtin-var.c
+++ b/builtin-var.c
@@ -6,7 +6,7 @@
#include "cache.h"
#include "exec_cmd.h"
-static const char var_usage[] = "git var [-l | <variable>]";
+static const char var_usage[] = "git var (-l | <variable>)";
static const char *editor(int flag)
{
@@ -20,7 +20,7 @@ static const char *editor(int flag)
static const char *pager(int flag)
{
- const char *pgm = git_pager();
+ const char *pgm = git_pager(1);
if (!pgm)
pgm = "cat";
diff --git a/cache.h b/cache.h
index d478eff1f..d454b7e68 100644
--- a/cache.h
+++ b/cache.h
@@ -775,7 +775,7 @@ extern const char *git_committer_info(int);
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
extern const char *fmt_name(const char *name, const char *email);
extern const char *git_editor(void);
-extern const char *git_pager(void);
+extern const char *git_pager(int stdout_is_tty);
struct checkout {
const char *base_dir;
diff --git a/git-am.sh b/git-am.sh
index ebfbee59d..9df951a59 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -663,10 +663,7 @@ do
[eE]*) git_editor "$dotest/final-commit"
action=again ;;
[vV]*) action=again
- : ${GIT_PAGER=$(git var GIT_PAGER)}
- : ${LESS=-FRSX}
- export LESS
- $GIT_PAGER "$dotest/patch" ;;
+ git_pager "$dotest/patch" ;;
*) action=again ;;
esac
done
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 5e22440ae..7a095665d 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -107,6 +107,19 @@ git_editor() {
eval "$GIT_EDITOR" '"$@"'
}
+git_pager() {
+ if test -t 1
+ then
+ GIT_PAGER=$(git var GIT_PAGER)
+ else
+ GIT_PAGER=cat
+ fi
+ : ${LESS=-FRSX}
+ export LESS
+
+ eval "$GIT_PAGER" '"$@"'
+}
+
sane_grep () {
GREP_OPTIONS= LC_ALL=C grep "$@"
}
diff --git a/git-svn.perl b/git-svn.perl
index 49dd649bc..b7c03b641 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -5465,7 +5465,12 @@ sub git_svn_log_cmd {
# adapted from pager.c
sub config_pager {
- chomp(my $pager = command_oneline(qw(var GIT_PAGER)));
+ if (! -t *STDOUT) {
+ $ENV{GIT_PAGER_IN_USE} = 'false';
+ $pager = undef;
+ return;
+ }
+ chomp($pager = command_oneline(qw(var GIT_PAGER)));
if ($pager eq 'cat') {
$pager = undef;
}
@@ -5473,7 +5478,7 @@ sub config_pager {
}
sub run_pager {
- return unless -t *STDOUT && defined $pager;
+ return unless defined $pager;
pipe my ($rfd, $wfd) or return;
defined(my $pid = fork) or ::fatal "Can't fork: $!";
if (!$pid) {
diff --git a/pager.c b/pager.c
index 2c7e8ecb3..dac358f04 100644
--- a/pager.c
+++ b/pager.c
@@ -48,11 +48,11 @@ static void wait_for_pager_signal(int signo)
raise(signo);
}
-const char *git_pager(void)
+const char *git_pager(int stdout_is_tty)
{
const char *pager;
- if (!isatty(1))
+ if (!stdout_is_tty)
return NULL;
pager = getenv("GIT_PAGER");
@@ -73,7 +73,7 @@ const char *git_pager(void)
void setup_pager(void)
{
- const char *pager = git_pager();
+ const char *pager = git_pager(isatty(1));
if (!pager)
return;
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
new file mode 100755
index 000000000..d9202d5af
--- /dev/null
+++ b/t/t7006-pager.sh
@@ -0,0 +1,176 @@
+#!/bin/sh
+
+test_description='Test automatic use of a pager.'
+
+. ./test-lib.sh
+
+rm -f stdout_is_tty
+test_expect_success 'set up terminal for tests' '
+ if test -t 1
+ then
+ : > stdout_is_tty
+ elif
+ test_have_prereq PERL &&
+ "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
+ sh -c "test -t 1"
+ then
+ : > test_terminal_works
+ fi
+'
+
+if test -e stdout_is_tty
+then
+ test_terminal() { "$@"; }
+ test_set_prereq TTY
+elif test -e test_terminal_works
+then
+ test_terminal() {
+ "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl "$@"
+ }
+ test_set_prereq TTY
+else
+ say no usable terminal, so skipping some tests
+fi
+
+unset GIT_PAGER GIT_PAGER_IN_USE
+git config --unset core.pager
+PAGER='cat > paginated.out'
+export PAGER
+
+test_expect_success 'setup' '
+ test_commit initial
+'
+
+rm -f paginated.out
+test_expect_success TTY 'some commands use a pager' '
+ test_terminal git log &&
+ test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'some commands do not use a pager' '
+ test_terminal git rev-list HEAD &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success 'no pager when stdout is a pipe' '
+ git log | cat &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success 'no pager when stdout is a regular file' '
+ git log > file &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'git --paginate rev-list uses a pager' '
+ test_terminal git --paginate rev-list HEAD &&
+ test -e paginated.out
+'
+
+rm -f file paginated.out
+test_expect_success 'no pager even with --paginate when stdout is a pipe' '
+ git --paginate log | cat &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'no pager with --no-pager' '
+ test_terminal git --no-pager log &&
+ ! test -e paginated.out
+'
+
+# A colored commit log will begin with an appropriate ANSI escape
+# for the first color; the text "commit" comes later.
+colorful() {
+ read firstline < $1
+ ! expr "$firstline" : "^[a-zA-Z]" >/dev/null
+}
+
+rm -f colorful.log colorless.log
+test_expect_success 'tests can detect color' '
+ git log --no-color > colorless.log &&
+ git log --color > colorful.log &&
+ ! colorful colorless.log &&
+ colorful colorful.log
+'
+
+rm -f colorless.log
+git config color.ui auto
+test_expect_success 'no color when stdout is a regular file' '
+ git log > colorless.log &&
+ ! colorful colorless.log
+'
+
+rm -f paginated.out
+git config color.ui auto
+test_expect_success TTY 'color when writing to a pager' '
+ TERM=vt100 test_terminal git log &&
+ colorful paginated.out
+'
+
+rm -f colorful.log
+git config color.ui auto
+test_expect_success 'color when writing to a file intended for a pager' '
+ TERM=vt100 GIT_PAGER_IN_USE=true git log > colorful.log &&
+ colorful colorful.log
+'
+
+unset PAGER GIT_PAGER
+git config --unset core.pager
+test_expect_success 'determine default pager' '
+ less=$(git var GIT_PAGER) &&
+ test -n "$less"
+'
+
+if expr "$less" : '^[a-z]*$' > /dev/null && test_have_prereq TTY
+then
+ test_set_prereq SIMPLEPAGER
+fi
+
+unset PAGER GIT_PAGER
+git config --unset core.pager
+rm -f default_pager_used
+test_expect_success SIMPLEPAGER 'default pager is used by default' '
+ cat > $less <<-EOF &&
+ #!$SHELL_PATH
+ wc > default_pager_used
+ EOF
+ chmod +x $less &&
+ PATH=.:$PATH test_terminal git log &&
+ test -e default_pager_used
+'
+
+unset GIT_PAGER
+git config --unset core.pager
+rm -f PAGER_used
+test_expect_success TTY 'PAGER overrides default pager' '
+ PAGER="wc > PAGER_used" &&
+ export PAGER &&
+ test_terminal git log &&
+ test -e PAGER_used
+'
+
+unset GIT_PAGER
+rm -f core.pager_used
+test_expect_success TTY 'core.pager overrides PAGER' '
+ PAGER=wc &&
+ export PAGER &&
+ git config core.pager "wc > core.pager_used" &&
+ test_terminal git log &&
+ test -e core.pager_used
+'
+
+rm -f GIT_PAGER_used
+test_expect_success TTY 'GIT_PAGER overrides core.pager' '
+ git config core.pager wc &&
+ GIT_PAGER="wc > GIT_PAGER_used" &&
+ export GIT_PAGER &&
+ test_terminal git log &&
+ test -e GIT_PAGER_used
+'
+
+test_done
diff --git a/t/t7006/test-terminal.perl b/t/t7006/test-terminal.perl
new file mode 100755
index 000000000..73ff80937
--- /dev/null
+++ b/t/t7006/test-terminal.perl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use IO::Pty;
+use File::Copy;
+
+# Run @$argv in the background with stdout redirected to $out.
+sub start_child {
+ my ($argv, $out) = @_;
+ my $pid = fork;
+ if (not defined $pid) {
+ die "fork failed: $!"
+ } elsif ($pid == 0) {
+ open STDOUT, ">&", $out;
+ close $out;
+ exec(@$argv) or die "cannot exec '$argv->[0]': $!"
+ }
+ return $pid;
+}
+
+# Wait for $pid to finish.
+sub finish_child {
+ # Simplified from wait_or_whine() in run-command.c.
+ my ($pid) = @_;
+
+ my $waiting = waitpid($pid, 0);
+ if ($waiting < 0) {
+ die "waitpid failed: $!";
+ } elsif ($? & 127) {
+ my $code = $? & 127;
+ warn "died of signal $code";
+ return $code - 128;
+ } else {
+ return $? >> 8;
+ }
+}
+
+sub xsendfile {
+ my ($out, $in) = @_;
+
+ # Note: the real sendfile() cannot read from a terminal.
+
+ # It is unspecified by POSIX whether reads
+ # from a disconnected terminal will return
+ # EIO (as in AIX 4.x, IRIX, and Linux) or
+ # end-of-file. Either is fine.
+ copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
+}
+
+if ($#ARGV < 1) {
+ die "usage: test-terminal program args";
+}
+my $master = new IO::Pty;
+my $slave = $master->slave;
+my $pid = start_child(\@ARGV, $slave);
+close $slave;
+xsendfile(\*STDOUT, $master);
+exit(finish_child($pid));