Merge branch 'maint'

* maint:
  Start preparing for 1.5.1.3
  Sanitize @to recipients.
  git-svn: Ignore usernames in URLs in find_by_url
  Document --dry-run and envelope-sender for git-send-email.
  Allow users to optionally specify their envelope sender.
  Ensure clean addresses are always used with Net::SMTP
  Validate @recipients before using it for sendmail and Net::SMTP.
  Perform correct quoting of recipient names.
  Change the scope of the $cc variable as it is not needed outside of send_message.
  Debugging cleanup improvements
  Prefix Dry- to the message status to denote dry-runs.
  Document --dry-run parameter to send-email.
  git-svn: Don't rely on $_ after making a function call
  Fix handle leak in write_tree
  Actually handle some-low memory conditions

Conflicts:

	RelNotes
	git-send-email.perl
This commit is contained in:
Junio C Hamano
2007-04-25 23:31:45 -07:00
7 changed files with 111 additions and 33 deletions

View File

@ -0,0 +1,38 @@
GIT v1.5.1.3 Release Notes (draft)
==========================
Fixes since v1.5.1.2
--------------------
* Bugfixes
- git-add tried to optimize by finding common leading
directories across its arguments but botched, causing very
confused behaviour.
- unofficial rpm.spec file shipped with git was letting
ETC_GITCONFIG set to /usr/etc/gitconfig. Tweak the official
Makefile to make it harder for distro people to make the
same mistake, by setting the variable to /etc/gitconfig if
prefix is set to /usr.
- git-svn inconsistently stripped away username from the URL
only when svnsync_props was in use.
- git-send-email was not quoting recipient names that have
period '.' in them. Also it did not allow overriding
envelope sender, which made it impossible to send patches to
certain subscriber-only lists.
- built-in write_tree() routine had a sequence that renamed a
file that is still open, which some systems did not like.
- when memory is very tight, sliding mmap code to read
packfiles incorrectly closed the fd that was still being
used to read the pack.
---
exec >/var/tmp/1
O=v1.5.1.2-23-gbf7af11
echo O=`git describe refs/heads/maint`
git shortlog --no-merges $O..refs/heads/maint

View File

@ -85,6 +85,15 @@ The --cc option must be repeated for each user you want on the cc list.
Do not add the From: address to the cc: list, if it shows up in a From: Do not add the From: address to the cc: list, if it shows up in a From:
line. line.
--dry-run::
Do everything except actually send the emails.
--envelope-sender::
Specify the envelope sender used to send the emails.
This is useful if your default address is not the address that is
subscribed to a list. If you use the sendmail binary, you must have
suitable privileges for the -f parameter.
--to:: --to::
Specify the primary recipient of the emails generated. Specify the primary recipient of the emails generated.
Generally, this will be the upstream maintainer of the Generally, this will be the upstream maintainer of the

View File

@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
die("git-write-tree: error building trees"); die("git-write-tree: error building trees");
if (0 <= newfd) { if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr) if (!write_cache(newfd, active_cache, active_nr)
&& !close(newfd)) && !close(newfd)) {
commit_lock_file(lock_file); commit_lock_file(lock_file);
newfd = -1;
}
} }
/* Not being able to write is fine -- we are only interested /* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller * in updating the cache-tree part, and if the next caller
@ -55,6 +57,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
else else
hashcpy(sha1, active_cache_tree->sha1); hashcpy(sha1, active_cache_tree->sha1);
if (0 <= newfd)
close(newfd);
rollback_lock_file(lock_file); rollback_lock_file(lock_file);
return 0; return 0;

View File

@ -164,13 +164,13 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
extern uintmax_t gitstrtoumax(const char *, char **, int); extern uintmax_t gitstrtoumax(const char *, char **, int);
#endif #endif
extern void release_pack_memory(size_t); extern void release_pack_memory(size_t, int);
static inline char* xstrdup(const char *str) static inline char* xstrdup(const char *str)
{ {
char *ret = strdup(str); char *ret = strdup(str);
if (!ret) { if (!ret) {
release_pack_memory(strlen(str) + 1); release_pack_memory(strlen(str) + 1, -1);
ret = strdup(str); ret = strdup(str);
if (!ret) if (!ret)
die("Out of memory, strdup failed"); die("Out of memory, strdup failed");
@ -184,7 +184,7 @@ static inline void *xmalloc(size_t size)
if (!ret && !size) if (!ret && !size)
ret = malloc(1); ret = malloc(1);
if (!ret) { if (!ret) {
release_pack_memory(size); release_pack_memory(size, -1);
ret = malloc(size); ret = malloc(size);
if (!ret && !size) if (!ret && !size)
ret = malloc(1); ret = malloc(1);
@ -203,7 +203,7 @@ static inline void *xrealloc(void *ptr, size_t size)
if (!ret && !size) if (!ret && !size)
ret = realloc(ptr, 1); ret = realloc(ptr, 1);
if (!ret) { if (!ret) {
release_pack_memory(size); release_pack_memory(size, -1);
ret = realloc(ptr, size); ret = realloc(ptr, size);
if (!ret && !size) if (!ret && !size)
ret = realloc(ptr, 1); ret = realloc(ptr, 1);
@ -219,7 +219,7 @@ static inline void *xcalloc(size_t nmemb, size_t size)
if (!ret && (!nmemb || !size)) if (!ret && (!nmemb || !size))
ret = calloc(1, 1); ret = calloc(1, 1);
if (!ret) { if (!ret) {
release_pack_memory(nmemb * size); release_pack_memory(nmemb * size, -1);
ret = calloc(nmemb, size); ret = calloc(nmemb, size);
if (!ret && (!nmemb || !size)) if (!ret && (!nmemb || !size))
ret = calloc(1, 1); ret = calloc(1, 1);
@ -236,7 +236,7 @@ static inline void *xmmap(void *start, size_t length,
if (ret == MAP_FAILED) { if (ret == MAP_FAILED) {
if (!length) if (!length)
return NULL; return NULL;
release_pack_memory(length); release_pack_memory(length, fd);
ret = mmap(start, length, prot, flags, fd, offset); ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED) if (ret == MAP_FAILED)
die("Out of memory? mmap failed: %s", strerror(errno)); die("Out of memory? mmap failed: %s", strerror(errno));

View File

@ -77,6 +77,10 @@ Options:
--quiet Make git-send-email less verbose. One line per email --quiet Make git-send-email less verbose. One line per email
should be all that is output. should be all that is output.
--dry-run Do everything except actually send the emails.
--envelope-sender Specify the envelope sender used to send the emails.
EOT EOT
exit(1); exit(1);
} }
@ -137,6 +141,7 @@ my (@to,@cc,@initial_cc,@bcclist,@xh,
my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc, my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc,
$dry_run) = (1, 0, 0, 0, 0); $dry_run) = (1, 0, 0, 0, 0);
my $smtp_server; my $smtp_server;
my $envelope_sender;
# Example reply to: # Example reply to:
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>'; #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@ -175,6 +180,7 @@ my $rc = GetOptions("from=s" => \$from,
"suppress-from" => \$suppress_from, "suppress-from" => \$suppress_from,
"no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc, "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
"dry-run" => \$dry_run, "dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
); );
unless ($rc) { unless ($rc) {
@ -268,6 +274,7 @@ sub expand_aliases {
} }
@to = expand_aliases(@to); @to = expand_aliases(@to);
@to = (map { sanitize_address_rfc822($_) } @to);
@initial_cc = expand_aliases(@initial_cc); @initial_cc = expand_aliases(@initial_cc);
@bcclist = expand_aliases(@bcclist); @bcclist = expand_aliases(@bcclist);
@ -377,7 +384,7 @@ if (@files) {
} }
# Variables we set as part of the loop over files # Variables we set as part of the loop over files
our ($message_id, $cc, %mail, $subject, $reply_to, $references, $message); our ($message_id, %mail, $subject, $reply_to, $references, $message);
sub extract_valid_address { sub extract_valid_address {
my $address = shift; my $address = shift;
@ -418,7 +425,6 @@ sub make_message_id
$cc = "";
$time = time - scalar $#files; $time = time - scalar $#files;
sub unquote_rfc2047 { sub unquote_rfc2047 {
@ -430,26 +436,37 @@ sub unquote_rfc2047 {
return "$_"; return "$_";
} }
# If an address contains a . in the name portion, the name must be quoted.
sub sanitize_address_rfc822
{
my ($recipient) = @_;
my ($recipient_name) = ($recipient =~ /^(.*?)\s+</);
if ($recipient_name && $recipient_name =~ /\./ && $recipient_name !~ /^".*"$/) {
my ($name, $addr) = ($recipient =~ /^(.*?)(\s+<.*)/);
$recipient = "\"$name\"$addr";
}
return $recipient;
}
sub send_message sub send_message
{ {
my @recipients = unique_email_list(@to); my @recipients = unique_email_list(@to);
@cc = (map { sanitize_address_rfc822($_) } @cc);
my $to = join (",\n\t", @recipients); my $to = join (",\n\t", @recipients);
@recipients = unique_email_list(@recipients,@cc,@bcclist); @recipients = unique_email_list(@recipients,@cc,@bcclist);
@recipients = (map { extract_valid_address($_) } @recipients);
my $date = format_2822_time($time++); my $date = format_2822_time($time++);
my $gitversion = '@@GIT_VERSION@@'; my $gitversion = '@@GIT_VERSION@@';
if ($gitversion =~ m/..GIT_VERSION../) { if ($gitversion =~ m/..GIT_VERSION../) {
$gitversion = Git::version(); $gitversion = Git::version();
} }
my ($author_name) = ($from =~ /^(.*?)\s+</); my $cc = join(", ", unique_email_list(@cc));
if ($author_name && $author_name =~ /\./ && $author_name !~ /^".*"$/) {
my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/);
$from = "\"$name\"$addr";
}
my $ccline = ""; my $ccline = "";
if ($cc ne '') { if ($cc ne '') {
$ccline = "\nCc: $cc"; $ccline = "\nCc: $cc";
} }
$from = sanitize_address_rfc822($from);
my $header = "From: $from my $header = "From: $from
To: $to${ccline} To: $to${ccline}
Subject: $subject Subject: $subject
@ -466,22 +483,27 @@ X-Mailer: git-send-email $gitversion
$header .= join("\n", @xh) . "\n"; $header .= join("\n", @xh) . "\n";
} }
my @sendmail_parameters = ('-i', @recipients);
my $raw_from = $from;
$raw_from = $envelope_sender if (defined $envelope_sender);
$raw_from = extract_valid_address($raw_from);
unshift (@sendmail_parameters,
'-f', $raw_from) if(defined $envelope_sender);
if ($dry_run) { if ($dry_run) {
# We don't want to send the email. # We don't want to send the email.
} elsif ($smtp_server =~ m#^/#) { } elsif ($smtp_server =~ m#^/#) {
my $pid = open my $sm, '|-'; my $pid = open my $sm, '|-';
defined $pid or die $!; defined $pid or die $!;
if (!$pid) { if (!$pid) {
exec($smtp_server,'-i', exec($smtp_server, @sendmail_parameters) or die $!;
map { extract_valid_address($_) }
@recipients) or die $!;
} }
print $sm "$header\n$message"; print $sm "$header\n$message";
close $sm or die $?; close $sm or die $?;
} else { } else {
require Net::SMTP; require Net::SMTP;
$smtp ||= Net::SMTP->new( $smtp_server ); $smtp ||= Net::SMTP->new( $smtp_server );
$smtp->mail( $from ) or die $smtp->message; $smtp->mail( $raw_from ) or die $smtp->message;
$smtp->to( @recipients ) or die $smtp->message; $smtp->to( @recipients ) or die $smtp->message;
$smtp->data or die $smtp->message; $smtp->data or die $smtp->message;
$smtp->datasend("$header\n$message") or die $smtp->message; $smtp->datasend("$header\n$message") or die $smtp->message;
@ -489,13 +511,15 @@ X-Mailer: git-send-email $gitversion
$smtp->ok or die "Failed to send $subject\n".$smtp->message; $smtp->ok or die "Failed to send $subject\n".$smtp->message;
} }
if ($quiet) { if ($quiet) {
printf "Sent %s\n", $subject; printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
} else { } else {
print "OK. Log says:\nDate: $date\n"; print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n");
if ($smtp) { if ($smtp_server !~ m#^/#) {
print "Server: $smtp_server\n"; print "Server: $smtp_server\n";
print "MAIL FROM:<$raw_from>\n";
print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n";
} else { } else {
print "Sendmail: $smtp_server\n"; print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
} }
print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n"; print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
if ($smtp) { if ($smtp) {
@ -590,7 +614,6 @@ foreach my $t (@files) {
$message = "From: $author_not_sender\n\n$message"; $message = "From: $author_not_sender\n\n$message";
} }
$cc = join(", ", unique_email_list(@cc));
send_message(); send_message();

View File

@ -771,19 +771,19 @@ sub cmt_metadata {
sub working_head_info { sub working_head_info {
my ($head, $refs) = @_; my ($head, $refs) = @_;
my ($fh, $ctx) = command_output_pipe('rev-list', $head); my ($fh, $ctx) = command_output_pipe('rev-list', $head);
while (<$fh>) { while (my $hash = <$fh>) {
chomp; chomp($hash);
my ($url, $rev, $uuid) = cmt_metadata($_); my ($url, $rev, $uuid) = cmt_metadata($hash);
if (defined $url && defined $rev) { if (defined $url && defined $rev) {
if (my $gs = Git::SVN->find_by_url($url)) { if (my $gs = Git::SVN->find_by_url($url)) {
my $c = $gs->rev_db_get($rev); my $c = $gs->rev_db_get($rev);
if ($c && $c eq $_) { if ($c && $c eq $hash) {
close $fh; # break the pipe close $fh; # break the pipe
return ($url, $rev, $uuid, $gs); return ($url, $rev, $uuid, $gs);
} }
} }
} }
unshift @$refs, $_ if $refs; unshift @$refs, $hash if $refs;
} }
command_close_pipe($fh, $ctx); command_close_pipe($fh, $ctx);
(undef, undef, undef, undef); (undef, undef, undef, undef);
@ -1064,7 +1064,10 @@ sub init_remote_config {
sub find_by_url { # repos_root and, path are optional sub find_by_url { # repos_root and, path are optional
my ($class, $full_url, $repos_root, $path) = @_; my ($class, $full_url, $repos_root, $path) = @_;
return undef unless defined $full_url; return undef unless defined $full_url;
remove_username($full_url);
remove_username($repos_root) if defined $repos_root;
my $remotes = read_all_remotes(); my $remotes = read_all_remotes();
if (defined $full_url && defined $repos_root && !defined $path) { if (defined $full_url && defined $repos_root && !defined $path) {
$path = $full_url; $path = $full_url;
@ -1072,6 +1075,7 @@ sub find_by_url { # repos_root and, path are optional
} }
foreach my $repo_id (keys %$remotes) { foreach my $repo_id (keys %$remotes) {
my $u = $remotes->{$repo_id}->{url} or next; my $u = $remotes->{$repo_id}->{url} or next;
remove_username($u);
next if defined $repos_root && $repos_root ne $u; next if defined $repos_root && $repos_root ne $u;
my $fetch = $remotes->{$repo_id}->{fetch} || {}; my $fetch = $remotes->{$repo_id}->{fetch} || {};

View File

@ -549,7 +549,7 @@ static void scan_windows(struct packed_git *p,
} }
} }
static int unuse_one_window(struct packed_git *current) static int unuse_one_window(struct packed_git *current, int keep_fd)
{ {
struct packed_git *p, *lru_p = NULL; struct packed_git *p, *lru_p = NULL;
struct pack_window *lru_w = NULL, *lru_l = NULL; struct pack_window *lru_w = NULL, *lru_l = NULL;
@ -565,7 +565,7 @@ static int unuse_one_window(struct packed_git *current)
lru_l->next = lru_w->next; lru_l->next = lru_w->next;
else { else {
lru_p->windows = lru_w->next; lru_p->windows = lru_w->next;
if (!lru_p->windows && lru_p != current) { if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
close(lru_p->pack_fd); close(lru_p->pack_fd);
lru_p->pack_fd = -1; lru_p->pack_fd = -1;
} }
@ -577,10 +577,10 @@ static int unuse_one_window(struct packed_git *current)
return 0; return 0;
} }
void release_pack_memory(size_t need) void release_pack_memory(size_t need, int fd)
{ {
size_t cur = pack_mapped; size_t cur = pack_mapped;
while (need >= (cur - pack_mapped) && unuse_one_window(NULL)) while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
; /* nothing */ ; /* nothing */
} }
@ -713,7 +713,7 @@ unsigned char* use_pack(struct packed_git *p,
win->len = (size_t)len; win->len = (size_t)len;
pack_mapped += win->len; pack_mapped += win->len;
while (packed_git_limit < pack_mapped while (packed_git_limit < pack_mapped
&& unuse_one_window(p)) && unuse_one_window(p, p->pack_fd))
; /* nothing */ ; /* nothing */
win->base = xmmap(NULL, win->len, win->base = xmmap(NULL, win->len,
PROT_READ, MAP_PRIVATE, PROT_READ, MAP_PRIVATE,