Skip to content

Commit f4dc943

Browse files
avargitster
authored andcommitted
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/[email protected] Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 447ed29 commit f4dc943

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

git-send-email.perl

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,10 @@
1919
use 5.008;
2020
use strict;
2121
use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
22-
use POSIX qw/strftime/;
23-
use Term::ReadLine;
2422
use Getopt::Long;
25-
use Text::ParseWords;
26-
use Term::ANSIColor;
27-
use File::Temp qw/ tempdir tempfile /;
28-
use File::Spec::Functions qw(catdir catfile);
2923
use Git::LoadCPAN::Error qw(:try);
30-
use Cwd qw(abs_path cwd);
3124
use Git;
3225
use Git::I18N;
33-
use Net::Domain ();
34-
use Net::SMTP ();
35-
use Git::LoadCPAN::Mail::Address;
3626

3727
Getopt::Long::Configure qw/ pass_through /;
3828

@@ -166,7 +156,6 @@ sub format_2822_time {
166156
);
167157
}
168158

169-
my $have_email_valid = eval { require Email::Valid; 1 };
170159
my $smtp;
171160
my $auth;
172161
my $num_sent = 0;
@@ -192,14 +181,6 @@ sub format_2822_time {
192181

193182
my $repo = eval { Git->repository() };
194183
my @repo = $repo ? ($repo) : ();
195-
my $term = eval {
196-
$ENV{"GIT_SEND_EMAIL_NOTTY"}
197-
? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
198-
: Term::ReadLine->new('git-send-email');
199-
};
200-
if ($@) {
201-
$term = FakeTerm->new("$@: going non-interactive");
202-
}
203184

204185
# Behavior modification variables
205186
my ($quiet, $dry_run) = (0, 0);
@@ -319,9 +300,9 @@ sub do_edit {
319300

320301
# Handle Uncouth Termination
321302
sub signal_handler {
322-
323303
# Make text normal
324-
print color("reset"), "\n";
304+
require Term::ANSIColor;
305+
print Term::ANSIColor::color("reset"), "\n";
325306

326307
# SMTP password masked
327308
system "stty echo";
@@ -602,11 +583,13 @@ sub config_regexp {
602583
}
603584

604585
sub parse_address_line {
586+
require Git::LoadCPAN::Mail::Address;
605587
return map { $_->format } Mail::Address->parse($_[0]);
606588
}
607589

608590
sub split_addrs {
609-
return quotewords('\s*,\s*', 1, @_);
591+
require Text::ParseWords;
592+
return Text::ParseWords::quotewords('\s*,\s*', 1, @_);
610593
}
611594

612595
my %aliases;
@@ -655,10 +638,11 @@ sub parse_sendmail_aliases {
655638
s/\\"/"/g foreach @addr;
656639
$aliases{$alias} = \@addr
657640
}}},
658-
mailrc => sub { my $fh = shift; while (<$fh>) {
641+
mailrc => sub { my $fh = shift; while (<$fh>) {
659642
if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
643+
require Text::ParseWords;
660644
# spaces delimit multiple addresses
661-
$aliases{$1} = [ quotewords('\s+', 0, $2) ];
645+
$aliases{$1} = [ Text::ParseWords::quotewords('\s+', 0, $2) ];
662646
}}},
663647
pine => sub { my $fh = shift; my $f='\t[^\t]*';
664648
for (my $x = ''; defined($x); $x = $_) {
@@ -730,7 +714,8 @@ sub is_format_patch_arg {
730714
opendir my $dh, $f
731715
or die sprintf(__("Failed to opendir %s: %s"), $f, $!);
732716

733-
push @files, grep { -f $_ } map { catfile($f, $_) }
717+
require File::Spec;
718+
push @files, grep { -f $_ } map { File::Spec->catfile($f, $_) }
734719
sort readdir $dh;
735720
closedir $dh;
736721
} elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
@@ -743,7 +728,8 @@ sub is_format_patch_arg {
743728
if (@rev_list_opts) {
744729
die __("Cannot run git format-patch from outside a repository\n")
745730
unless $repo;
746-
push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
731+
require File::Temp;
732+
push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1), @rev_list_opts);
747733
}
748734

749735
@files = handle_backup_files(@files);
@@ -780,9 +766,10 @@ sub get_patch_subject {
780766
if ($compose) {
781767
# Note that this does not need to be secure, but we will make a small
782768
# effort to have it be unique
769+
require File::Temp;
783770
$compose_filename = ($repo ?
784-
tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
785-
tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
771+
File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
772+
File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
786773
open my $c, ">", $compose_filename
787774
or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!);
788775

@@ -889,13 +876,27 @@ sub get_patch_subject {
889876
do_edit(@files);
890877
}
891878
879+
sub term {
880+
my $term = eval {
881+
require Term::ReadLine;
882+
$ENV{"GIT_SEND_EMAIL_NOTTY"}
883+
? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
884+
: Term::ReadLine->new('git-send-email');
885+
};
886+
if ($@) {
887+
$term = FakeTerm->new("$@: going non-interactive");
888+
}
889+
return $term;
890+
}
891+
892892
sub ask {
893893
my ($prompt, %arg) = @_;
894894
my $valid_re = $arg{valid_re};
895895
my $default = $arg{default};
896896
my $confirm_only = $arg{confirm_only};
897897
my $resp;
898898
my $i = 0;
899+
my $term = term();
899900
return defined $default ? $default : undef
900901
unless defined $term->IN and defined fileno($term->IN) and
901902
defined $term->OUT and defined fileno($term->OUT);
@@ -1076,6 +1077,7 @@ sub extract_valid_address {
10761077
return $address if ($address =~ /^($local_part_regexp)$/);
10771078

10781079
$address =~ s/^\s*<(.*)>\s*$/$1/;
1080+
my $have_email_valid = eval { require Email::Valid; 1 };
10791081
if ($have_email_valid) {
10801082
return scalar Email::Valid->address($address);
10811083
}
@@ -1135,7 +1137,8 @@ sub validate_address_list {
11351137
sub make_message_id {
11361138
my $uniq;
11371139
if (!defined $message_id_stamp) {
1138-
$message_id_stamp = strftime("%Y%m%d%H%M%S.$$", gmtime(time));
1140+
require POSIX;
1141+
$message_id_stamp = POSIX::strftime("%Y%m%d%H%M%S.$$", gmtime(time));
11391142
$message_id_serial = 0;
11401143
}
11411144
$message_id_serial++;
@@ -1305,6 +1308,7 @@ sub valid_fqdn {
13051308
sub maildomain_net {
13061309
my $maildomain;
13071310

1311+
require Net::Domain;
13081312
my $domain = Net::Domain::domainname();
13091313
$maildomain = $domain if valid_fqdn($domain);
13101314

@@ -1315,6 +1319,7 @@ sub maildomain_mta {
13151319
my $maildomain;
13161320

13171321
for my $host (qw(mailhost localhost)) {
1322+
require Net::SMTP;
13181323
my $smtp = Net::SMTP->new($host);
13191324
if (defined $smtp) {
13201325
my $domain = $smtp->domain;
@@ -1994,13 +1999,15 @@ sub validate_patch {
19941999

19952000
if ($repo) {
19962001
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
1997-
my $validate_hook = catfile($hooks_path,
2002+
require File::Spec;
2003+
my $validate_hook = File::Spec->catfile($hooks_path,
19982004
'sendemail-validate');
19992005
my $hook_error;
20002006
if (-x $validate_hook) {
2001-
my $target = abs_path($fn);
2007+
require Cwd;
2008+
my $target = Cwd::abs_path($fn);
20022009
# The hook needs a correct cwd and GIT_DIR.
2003-
my $cwd_save = cwd();
2010+
my $cwd_save = Cwd::cwd();
20042011
chdir($repo->wc_path() or $repo->repo_path())
20052012
or die("chdir: $!");
20062013
local $ENV{"GIT_DIR"} = $repo->repo_path();

0 commit comments

Comments
 (0)