send-email: lazily load modules for a big speedup
Optimize the time git-send-email takes to do even the simplest of
things (such as serving up "-h") from around ~150ms to ~80ms-~90ms by
lazily loading the modules it requires.
Before this change Devel::TraceUse would report 99/97 used modules
under NO_GETTEXT=[|Y], respectively. Now it's 52/37. It now takes ~15s
to run t9001-send-email.sh, down from ~20s.
Changing File::Spec::Functions::{catdir,catfile} to invoking class
methods on File::Spec itself is idiomatic. See [1] for a more
elaborate explanation, the resulting code behaves the same way, just
without the now-pointless function wrapper.
1. http://lore.kernel.org/git/8735u8mmj9.fsf@evledraar.gmail.com
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
			
			
				maint
			
			
		
							parent
							
								
									447ed29c0d
								
							
						
					
					
						commit
						f4dc9432fd
					
				|  | @ -19,20 +19,10 @@ | ||||||
| use 5.008; | use 5.008; | ||||||
| use strict; | use strict; | ||||||
| use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : (); | use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : (); | ||||||
| use POSIX qw/strftime/; |  | ||||||
| use Term::ReadLine; |  | ||||||
| use Getopt::Long; | use Getopt::Long; | ||||||
| use Text::ParseWords; |  | ||||||
| use Term::ANSIColor; |  | ||||||
| use File::Temp qw/ tempdir tempfile /; |  | ||||||
| use File::Spec::Functions qw(catdir catfile); |  | ||||||
| use Git::LoadCPAN::Error qw(:try); | use Git::LoadCPAN::Error qw(:try); | ||||||
| use Cwd qw(abs_path cwd); |  | ||||||
| use Git; | use Git; | ||||||
| use Git::I18N; | use Git::I18N; | ||||||
| use Net::Domain (); |  | ||||||
| use Net::SMTP (); |  | ||||||
| use Git::LoadCPAN::Mail::Address; |  | ||||||
|  |  | ||||||
| Getopt::Long::Configure qw/ pass_through /; | Getopt::Long::Configure qw/ pass_through /; | ||||||
|  |  | ||||||
|  | @ -166,7 +156,6 @@ sub format_2822_time { | ||||||
| 		       ); | 		       ); | ||||||
| } | } | ||||||
|  |  | ||||||
| my $have_email_valid = eval { require Email::Valid; 1 }; |  | ||||||
| my $smtp; | my $smtp; | ||||||
| my $auth; | my $auth; | ||||||
| my $num_sent = 0; | my $num_sent = 0; | ||||||
|  | @ -192,14 +181,6 @@ my (@config_bcc, @getopt_bcc); | ||||||
|  |  | ||||||
| my $repo = eval { Git->repository() }; | my $repo = eval { Git->repository() }; | ||||||
| my @repo = $repo ? ($repo) : (); | my @repo = $repo ? ($repo) : (); | ||||||
| my $term = eval { |  | ||||||
| 	$ENV{"GIT_SEND_EMAIL_NOTTY"} |  | ||||||
| 		? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT) |  | ||||||
| 		: Term::ReadLine->new('git-send-email'); |  | ||||||
| }; |  | ||||||
| if ($@) { |  | ||||||
| 	$term = FakeTerm->new("$@: going non-interactive"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| # Behavior modification variables | # Behavior modification variables | ||||||
| my ($quiet, $dry_run) = (0, 0); | my ($quiet, $dry_run) = (0, 0); | ||||||
|  | @ -319,9 +300,9 @@ my %config_path_settings = ( | ||||||
|  |  | ||||||
| # Handle Uncouth Termination | # Handle Uncouth Termination | ||||||
| sub signal_handler { | sub signal_handler { | ||||||
|  |  | ||||||
| 	# Make text normal | 	# Make text normal | ||||||
| 	print color("reset"), "\n"; | 	require Term::ANSIColor; | ||||||
|  | 	print Term::ANSIColor::color("reset"), "\n"; | ||||||
|  |  | ||||||
| 	# SMTP password masked | 	# SMTP password masked | ||||||
| 	system "stty echo"; | 	system "stty echo"; | ||||||
|  | @ -602,11 +583,13 @@ my ($repoauthor, $repocommitter); | ||||||
| } | } | ||||||
|  |  | ||||||
| sub parse_address_line { | sub parse_address_line { | ||||||
|  | 	require Git::LoadCPAN::Mail::Address; | ||||||
| 	return map { $_->format } Mail::Address->parse($_[0]); | 	return map { $_->format } Mail::Address->parse($_[0]); | ||||||
| } | } | ||||||
|  |  | ||||||
| sub split_addrs { | sub split_addrs { | ||||||
| 	return quotewords('\s*,\s*', 1, @_); | 	require Text::ParseWords; | ||||||
|  | 	return Text::ParseWords::quotewords('\s*,\s*', 1, @_); | ||||||
| } | } | ||||||
|  |  | ||||||
| my %aliases; | my %aliases; | ||||||
|  | @ -655,10 +638,11 @@ my %parse_alias = ( | ||||||
| 			s/\\"/"/g foreach @addr; | 			s/\\"/"/g foreach @addr; | ||||||
| 			$aliases{$alias} = \@addr | 			$aliases{$alias} = \@addr | ||||||
| 		}}}, | 		}}}, | ||||||
| 	mailrc => sub { my $fh = shift; while (<$fh>) { | 	mailrc => sub {	my $fh = shift; while (<$fh>) { | ||||||
| 		if (/^alias\s+(\S+)\s+(.*?)\s*$/) { | 		if (/^alias\s+(\S+)\s+(.*?)\s*$/) { | ||||||
|  | 			require Text::ParseWords; | ||||||
| 			# spaces delimit multiple addresses | 			# spaces delimit multiple addresses | ||||||
| 			$aliases{$1} = [ quotewords('\s+', 0, $2) ]; | 			$aliases{$1} = [ Text::ParseWords::quotewords('\s+', 0, $2) ]; | ||||||
| 		}}}, | 		}}}, | ||||||
| 	pine => sub { my $fh = shift; my $f='\t[^\t]*'; | 	pine => sub { my $fh = shift; my $f='\t[^\t]*'; | ||||||
| 	        for (my $x = ''; defined($x); $x = $_) { | 	        for (my $x = ''; defined($x); $x = $_) { | ||||||
|  | @ -730,7 +714,8 @@ while (defined(my $f = shift @ARGV)) { | ||||||
| 		opendir my $dh, $f | 		opendir my $dh, $f | ||||||
| 			or die sprintf(__("Failed to opendir %s: %s"), $f, $!); | 			or die sprintf(__("Failed to opendir %s: %s"), $f, $!); | ||||||
|  |  | ||||||
| 		push @files, grep { -f $_ } map { catfile($f, $_) } | 		require File::Spec; | ||||||
|  | 		push @files, grep { -f $_ } map { File::Spec->catfile($f, $_) } | ||||||
| 				sort readdir $dh; | 				sort readdir $dh; | ||||||
| 		closedir $dh; | 		closedir $dh; | ||||||
| 	} elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) { | 	} elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) { | ||||||
|  | @ -743,7 +728,8 @@ while (defined(my $f = shift @ARGV)) { | ||||||
| if (@rev_list_opts) { | if (@rev_list_opts) { | ||||||
| 	die __("Cannot run git format-patch from outside a repository\n") | 	die __("Cannot run git format-patch from outside a repository\n") | ||||||
| 		unless $repo; | 		unless $repo; | ||||||
| 	push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts); | 	require File::Temp; | ||||||
|  | 	push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1), @rev_list_opts); | ||||||
| } | } | ||||||
|  |  | ||||||
| @files = handle_backup_files(@files); | @files = handle_backup_files(@files); | ||||||
|  | @ -780,9 +766,10 @@ sub get_patch_subject { | ||||||
| if ($compose) { | if ($compose) { | ||||||
| 	# Note that this does not need to be secure, but we will make a small | 	# Note that this does not need to be secure, but we will make a small | ||||||
| 	# effort to have it be unique | 	# effort to have it be unique | ||||||
|  | 	require File::Temp; | ||||||
| 	$compose_filename = ($repo ? | 	$compose_filename = ($repo ? | ||||||
| 		tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) : | 		File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) : | ||||||
| 		tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1]; | 		File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1]; | ||||||
| 	open my $c, ">", $compose_filename | 	open my $c, ">", $compose_filename | ||||||
| 		or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!); | 		or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!); | ||||||
|  |  | ||||||
|  | @ -889,6 +876,19 @@ EOT3 | ||||||
| 	do_edit(@files); | 	do_edit(@files); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | sub term { | ||||||
|  | 	my $term = eval { | ||||||
|  | 		require Term::ReadLine; | ||||||
|  | 		$ENV{"GIT_SEND_EMAIL_NOTTY"} | ||||||
|  | 			? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT) | ||||||
|  | 			: Term::ReadLine->new('git-send-email'); | ||||||
|  | 	}; | ||||||
|  | 	if ($@) { | ||||||
|  | 		$term = FakeTerm->new("$@: going non-interactive"); | ||||||
|  | 	} | ||||||
|  | 	return $term; | ||||||
|  | } | ||||||
|  |  | ||||||
| sub ask { | sub ask { | ||||||
| 	my ($prompt, %arg) = @_; | 	my ($prompt, %arg) = @_; | ||||||
| 	my $valid_re = $arg{valid_re}; | 	my $valid_re = $arg{valid_re}; | ||||||
|  | @ -896,6 +896,7 @@ sub ask { | ||||||
| 	my $confirm_only = $arg{confirm_only}; | 	my $confirm_only = $arg{confirm_only}; | ||||||
| 	my $resp; | 	my $resp; | ||||||
| 	my $i = 0; | 	my $i = 0; | ||||||
|  | 	my $term = term(); | ||||||
| 	return defined $default ? $default : undef | 	return defined $default ? $default : undef | ||||||
| 		unless defined $term->IN and defined fileno($term->IN) and | 		unless defined $term->IN and defined fileno($term->IN) and | ||||||
| 		       defined $term->OUT and defined fileno($term->OUT); | 		       defined $term->OUT and defined fileno($term->OUT); | ||||||
|  | @ -1076,6 +1077,7 @@ sub extract_valid_address { | ||||||
| 	return $address if ($address =~ /^($local_part_regexp)$/); | 	return $address if ($address =~ /^($local_part_regexp)$/); | ||||||
|  |  | ||||||
| 	$address =~ s/^\s*<(.*)>\s*$/$1/; | 	$address =~ s/^\s*<(.*)>\s*$/$1/; | ||||||
|  | 	my $have_email_valid = eval { require Email::Valid; 1 }; | ||||||
| 	if ($have_email_valid) { | 	if ($have_email_valid) { | ||||||
| 		return scalar Email::Valid->address($address); | 		return scalar Email::Valid->address($address); | ||||||
| 	} | 	} | ||||||
|  | @ -1135,7 +1137,8 @@ my ($message_id_stamp, $message_id_serial); | ||||||
| sub make_message_id { | sub make_message_id { | ||||||
| 	my $uniq; | 	my $uniq; | ||||||
| 	if (!defined $message_id_stamp) { | 	if (!defined $message_id_stamp) { | ||||||
| 		$message_id_stamp = strftime("%Y%m%d%H%M%S.$$", gmtime(time)); | 		require POSIX; | ||||||
|  | 		$message_id_stamp = POSIX::strftime("%Y%m%d%H%M%S.$$", gmtime(time)); | ||||||
| 		$message_id_serial = 0; | 		$message_id_serial = 0; | ||||||
| 	} | 	} | ||||||
| 	$message_id_serial++; | 	$message_id_serial++; | ||||||
|  | @ -1305,6 +1308,7 @@ sub valid_fqdn { | ||||||
| sub maildomain_net { | sub maildomain_net { | ||||||
| 	my $maildomain; | 	my $maildomain; | ||||||
|  |  | ||||||
|  | 	require Net::Domain; | ||||||
| 	my $domain = Net::Domain::domainname(); | 	my $domain = Net::Domain::domainname(); | ||||||
| 	$maildomain = $domain if valid_fqdn($domain); | 	$maildomain = $domain if valid_fqdn($domain); | ||||||
|  |  | ||||||
|  | @ -1315,6 +1319,7 @@ sub maildomain_mta { | ||||||
| 	my $maildomain; | 	my $maildomain; | ||||||
|  |  | ||||||
| 	for my $host (qw(mailhost localhost)) { | 	for my $host (qw(mailhost localhost)) { | ||||||
|  | 		require Net::SMTP; | ||||||
| 		my $smtp = Net::SMTP->new($host); | 		my $smtp = Net::SMTP->new($host); | ||||||
| 		if (defined $smtp) { | 		if (defined $smtp) { | ||||||
| 			my $domain = $smtp->domain; | 			my $domain = $smtp->domain; | ||||||
|  | @ -1994,13 +1999,15 @@ sub validate_patch { | ||||||
|  |  | ||||||
| 	if ($repo) { | 	if ($repo) { | ||||||
| 		my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks'); | 		my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks'); | ||||||
| 		my $validate_hook = catfile($hooks_path, | 		require File::Spec; | ||||||
|  | 		my $validate_hook = File::Spec->catfile($hooks_path, | ||||||
| 					    'sendemail-validate'); | 					    'sendemail-validate'); | ||||||
| 		my $hook_error; | 		my $hook_error; | ||||||
| 		if (-x $validate_hook) { | 		if (-x $validate_hook) { | ||||||
| 			my $target = abs_path($fn); | 			require Cwd; | ||||||
|  | 			my $target = Cwd::abs_path($fn); | ||||||
| 			# The hook needs a correct cwd and GIT_DIR. | 			# The hook needs a correct cwd and GIT_DIR. | ||||||
| 			my $cwd_save = cwd(); | 			my $cwd_save = Cwd::cwd(); | ||||||
| 			chdir($repo->wc_path() or $repo->repo_path()) | 			chdir($repo->wc_path() or $repo->repo_path()) | ||||||
| 				or die("chdir: $!"); | 				or die("chdir: $!"); | ||||||
| 			local $ENV{"GIT_DIR"} = $repo->repo_path(); | 			local $ENV{"GIT_DIR"} = $repo->repo_path(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Ævar Arnfjörð Bjarmason
						Ævar Arnfjörð Bjarmason