Merge branch 'jn/maint-fix-pager'
* jn/maint-fix-pager: tests: Fix race condition in t7006-pager t7006-pager: if stdout is not a terminal, make a new one tests: Add tests for automatic use of pager am: Fix launching of pager git svn: Fix launching of pager git.1: Clarify the behavior of the --paginate option Make 'git var GIT_PAGER' always print the configured pager Fix 'git var' usage synopsismaint
						commit
						52ebb06f14
					
				|  | @ -8,7 +8,7 @@ git-var - Show a git logical variable | ||||||
|  |  | ||||||
| SYNOPSIS | SYNOPSIS | ||||||
| -------- | -------- | ||||||
| 'git var' [ -l | <variable> ] | 'git var' ( -l | <variable> ) | ||||||
|  |  | ||||||
| DESCRIPTION | DESCRIPTION | ||||||
| ----------- | ----------- | ||||||
|  |  | ||||||
|  | @ -230,7 +230,10 @@ help ...`. | ||||||
|  |  | ||||||
| -p:: | -p:: | ||||||
| --paginate:: | --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:: | --no-pager:: | ||||||
| 	Do not pipe git output into a 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 | 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 | Identifier Terminology | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
| #include "cache.h" | #include "cache.h" | ||||||
| #include "exec_cmd.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) | static const char *editor(int flag) | ||||||
| { | { | ||||||
|  | @ -20,7 +20,7 @@ static const char *editor(int flag) | ||||||
|  |  | ||||||
| static const char *pager(int flag) | static const char *pager(int flag) | ||||||
| { | { | ||||||
| 	const char *pgm = git_pager(); | 	const char *pgm = git_pager(1); | ||||||
|  |  | ||||||
| 	if (!pgm) | 	if (!pgm) | ||||||
| 		pgm = "cat"; | 		pgm = "cat"; | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										2
									
								
								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_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 *fmt_name(const char *name, const char *email); | ||||||
| extern const char *git_editor(void); | extern const char *git_editor(void); | ||||||
| extern const char *git_pager(void); | extern const char *git_pager(int stdout_is_tty); | ||||||
|  |  | ||||||
| struct checkout { | struct checkout { | ||||||
| 	const char *base_dir; | 	const char *base_dir; | ||||||
|  |  | ||||||
|  | @ -663,10 +663,7 @@ do | ||||||
| 		[eE]*) git_editor "$dotest/final-commit" | 		[eE]*) git_editor "$dotest/final-commit" | ||||||
| 		       action=again ;; | 		       action=again ;; | ||||||
| 		[vV]*) action=again | 		[vV]*) action=again | ||||||
| 		       : ${GIT_PAGER=$(git var GIT_PAGER)} | 		       git_pager "$dotest/patch" ;; | ||||||
| 		       : ${LESS=-FRSX} |  | ||||||
| 		       export LESS |  | ||||||
| 		       $GIT_PAGER "$dotest/patch" ;; |  | ||||||
| 		*)     action=again ;; | 		*)     action=again ;; | ||||||
| 		esac | 		esac | ||||||
| 	    done | 	    done | ||||||
|  |  | ||||||
|  | @ -107,6 +107,19 @@ git_editor() { | ||||||
| 	eval "$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 () { | sane_grep () { | ||||||
| 	GREP_OPTIONS= LC_ALL=C grep "$@" | 	GREP_OPTIONS= LC_ALL=C grep "$@" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5465,7 +5465,12 @@ sub git_svn_log_cmd { | ||||||
|  |  | ||||||
| # adapted from pager.c | # adapted from pager.c | ||||||
| sub config_pager { | 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') { | 	if ($pager eq 'cat') { | ||||||
| 		$pager = undef; | 		$pager = undef; | ||||||
| 	} | 	} | ||||||
|  | @ -5473,7 +5478,7 @@ sub config_pager { | ||||||
| } | } | ||||||
|  |  | ||||||
| sub run_pager { | sub run_pager { | ||||||
| 	return unless -t *STDOUT && defined $pager; | 	return unless defined $pager; | ||||||
| 	pipe my ($rfd, $wfd) or return; | 	pipe my ($rfd, $wfd) or return; | ||||||
| 	defined(my $pid = fork) or ::fatal "Can't fork: $!"; | 	defined(my $pid = fork) or ::fatal "Can't fork: $!"; | ||||||
| 	if (!$pid) { | 	if (!$pid) { | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								pager.c
								
								
								
								
							
							
						
						
									
										6
									
								
								pager.c
								
								
								
								
							|  | @ -48,11 +48,11 @@ static void wait_for_pager_signal(int signo) | ||||||
| 	raise(signo); | 	raise(signo); | ||||||
| } | } | ||||||
|  |  | ||||||
| const char *git_pager(void) | const char *git_pager(int stdout_is_tty) | ||||||
| { | { | ||||||
| 	const char *pager; | 	const char *pager; | ||||||
|  |  | ||||||
| 	if (!isatty(1)) | 	if (!stdout_is_tty) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	pager = getenv("GIT_PAGER"); | 	pager = getenv("GIT_PAGER"); | ||||||
|  | @ -73,7 +73,7 @@ const char *git_pager(void) | ||||||
|  |  | ||||||
| void setup_pager(void) | void setup_pager(void) | ||||||
| { | { | ||||||
| 	const char *pager = git_pager(); | 	const char *pager = git_pager(isatty(1)); | ||||||
|  |  | ||||||
| 	if (!pager) | 	if (!pager) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  | @ -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)); | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano