Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Thu, 26 Apr 2007 06:31:45 +0000 (23:31 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 26 Apr 2007 06:31:45 +0000 (23:31 -0700)
* 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

Documentation/RelNotes-1.5.1.3.txt [new file with mode: 0644]
Documentation/git-send-email.txt
builtin-write-tree.c
git-compat-util.h
git-send-email.perl
git-svn.perl
sha1_file.c
diff --git a/Documentation/RelNotes-1.5.1.3.txt b/Documentation/RelNotes-1.5.1.3.txt
new file mode 100644 (file)
index 0000000..9a4b069
--- /dev/null
@@ -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
index 682313e95dc9b96d3cc14f33554ad82bcede9a56..795db873fcda3b9248e56b3662a95f726b7a20cd 100644 (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:
        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::
        Specify the primary recipient of the emails generated.
        Generally, this will be the upstream maintainer of the
index c88bbd1b9be0fe2c033e2fe9daef0a8a2dae03a5..391de53972ebf77d2e08f1b405969e065bd8b371 100644 (file)
@@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
                        die("git-write-tree: error building trees");
                if (0 <= newfd) {
                        if (!write_cache(newfd, active_cache, active_nr)
-                                       && !close(newfd))
+                                       && !close(newfd)) {
                                commit_lock_file(lock_file);
+                               newfd = -1;
+                       }
                }
                /* Not being able to write is fine -- we are only interested
                 * 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
                hashcpy(sha1, active_cache_tree->sha1);
 
+       if (0 <= newfd)
+               close(newfd);
        rollback_lock_file(lock_file);
 
        return 0;
index 0b6d74d4d7ca0df726dd0464951a5e0f045c8715..2c84016ac9942eb62c24d143a551c8f1c8f48bb6 100644 (file)
@@ -164,13 +164,13 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
 extern uintmax_t gitstrtoumax(const char *, char **, int);
 #endif
 
-extern void release_pack_memory(size_t);
+extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
 {
        char *ret = strdup(str);
        if (!ret) {
-               release_pack_memory(strlen(str) + 1);
+               release_pack_memory(strlen(str) + 1, -1);
                ret = strdup(str);
                if (!ret)
                        die("Out of memory, strdup failed");
@@ -184,7 +184,7 @@ static inline void *xmalloc(size_t size)
        if (!ret && !size)
                ret = malloc(1);
        if (!ret) {
-               release_pack_memory(size);
+               release_pack_memory(size, -1);
                ret = malloc(size);
                if (!ret && !size)
                        ret = malloc(1);
@@ -203,7 +203,7 @@ static inline void *xrealloc(void *ptr, size_t size)
        if (!ret && !size)
                ret = realloc(ptr, 1);
        if (!ret) {
-               release_pack_memory(size);
+               release_pack_memory(size, -1);
                ret = realloc(ptr, size);
                if (!ret && !size)
                        ret = realloc(ptr, 1);
@@ -219,7 +219,7 @@ static inline void *xcalloc(size_t nmemb, size_t size)
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
        if (!ret) {
-               release_pack_memory(nmemb * size);
+               release_pack_memory(nmemb * size, -1);
                ret = calloc(nmemb, size);
                if (!ret && (!nmemb || !size))
                        ret = calloc(1, 1);
@@ -236,7 +236,7 @@ static inline void *xmmap(void *start, size_t length,
        if (ret == MAP_FAILED) {
                if (!length)
                        return NULL;
-               release_pack_memory(length);
+               release_pack_memory(length, fd);
                ret = mmap(start, length, prot, flags, fd, offset);
                if (ret == MAP_FAILED)
                        die("Out of memory? mmap failed: %s", strerror(errno));
index d6b15480dc1e211f0653ff54963889464dad3573..a6e3e026199a8d5ce763360c60ee0491f14820a5 100755 (executable)
@@ -77,6 +77,10 @@ sub usage {
    --quiet       Make git-send-email less verbose.  One line per email
                   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
        exit(1);
 }
@@ -137,6 +141,7 @@ sub format_2822_time {
 my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc,
        $dry_run) = (1, 0, 0, 0, 0);
 my $smtp_server;
+my $envelope_sender;
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -175,6 +180,7 @@ sub format_2822_time {
                    "suppress-from" => \$suppress_from,
                    "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
                    "dry-run" => \$dry_run,
+                   "envelope-sender=s" => \$envelope_sender,
         );
 
 unless ($rc) {
@@ -268,6 +274,7 @@ sub expand_aliases {
 }
 
 @to = expand_aliases(@to);
+@to = (map { sanitize_address_rfc822($_) } @to);
 @initial_cc = expand_aliases(@initial_cc);
 @bcclist = expand_aliases(@bcclist);
 
@@ -377,7 +384,7 @@ sub expand_aliases {
 }
 
 # 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 {
        my $address = shift;
@@ -418,7 +425,6 @@ sub make_message_id
 
 
 
-$cc = "";
 $time = time - scalar $#files;
 
 sub unquote_rfc2047 {
@@ -430,26 +436,37 @@ sub unquote_rfc2047 {
        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
 {
        my @recipients = unique_email_list(@to);
+       @cc = (map { sanitize_address_rfc822($_) } @cc);
        my $to = join (",\n\t", @recipients);
        @recipients = unique_email_list(@recipients,@cc,@bcclist);
+       @recipients = (map { extract_valid_address($_) } @recipients);
        my $date = format_2822_time($time++);
        my $gitversion = '@@GIT_VERSION@@';
        if ($gitversion =~ m/..GIT_VERSION../) {
            $gitversion = Git::version();
        }
 
-       my ($author_name) = ($from =~ /^(.*?)\s+</);
-       if ($author_name && $author_name =~ /\./ && $author_name !~ /^".*"$/) {
-               my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/);
-               $from = "\"$name\"$addr";
-       }
+       my $cc = join(", ", unique_email_list(@cc));
        my $ccline = "";
        if ($cc ne '') {
                $ccline = "\nCc: $cc";
        }
+       $from = sanitize_address_rfc822($from);
        my $header = "From: $from
 To: $to${ccline}
 Subject: $subject
@@ -466,22 +483,27 @@ sub send_message
                $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) {
                # We don't want to send the email.
        } elsif ($smtp_server =~ m#^/#) {
                my $pid = open my $sm, '|-';
                defined $pid or die $!;
                if (!$pid) {
-                       exec($smtp_server,'-i',
-                            map { extract_valid_address($_) }
-                            @recipients) or die $!;
+                       exec($smtp_server, @sendmail_parameters) or die $!;
                }
                print $sm "$header\n$message";
                close $sm or die $?;
        } else {
                require Net::SMTP;
                $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->data or die $smtp->message;
                $smtp->datasend("$header\n$message") or die $smtp->message;
@@ -489,13 +511,15 @@ sub send_message
                $smtp->ok or die "Failed to send $subject\n".$smtp->message;
        }
        if ($quiet) {
-               printf "Sent %s\n", $subject;
+               printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
        } else {
-               print "OK. Log says:\nDate: $date\n";
-               if ($smtp) {
+               print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n");
+               if ($smtp_server !~ m#^/#) {
                        print "Server: $smtp_server\n";
+                       print "MAIL FROM:<$raw_from>\n";
+                       print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n";
                } 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";
                if ($smtp) {
@@ -590,7 +614,6 @@ sub send_message
                $message = "From: $author_not_sender\n\n$message";
        }
 
-       $cc = join(", ", unique_email_list(@cc));
 
        send_message();
 
index 077d6b3a134fcb6c8f74f1473cbb9d36bdb7c6f9..7b5f8ab3be6639e682dc6b0d5a53412f1078ba54 100755 (executable)
@@ -771,19 +771,19 @@ sub cmt_metadata {
 sub working_head_info {
        my ($head, $refs) = @_;
        my ($fh, $ctx) = command_output_pipe('rev-list', $head);
-       while (<$fh>) {
-               chomp;
-               my ($url, $rev, $uuid) = cmt_metadata($_);
+       while (my $hash = <$fh>) {
+               chomp($hash);
+               my ($url, $rev, $uuid) = cmt_metadata($hash);
                if (defined $url && defined $rev) {
                        if (my $gs = Git::SVN->find_by_url($url)) {
                                my $c = $gs->rev_db_get($rev);
-                               if ($c && $c eq $_) {
+                               if ($c && $c eq $hash) {
                                        close $fh; # break the pipe
                                        return ($url, $rev, $uuid, $gs);
                                }
                        }
                }
-               unshift @$refs, $_ if $refs;
+               unshift @$refs, $hash if $refs;
        }
        command_close_pipe($fh, $ctx);
        (undef, undef, undef, undef);
@@ -1064,7 +1064,10 @@ sub init_remote_config {
 
 sub find_by_url { # repos_root and, path are optional
        my ($class, $full_url, $repos_root, $path) = @_;
+
        return undef unless defined $full_url;
+       remove_username($full_url);
+       remove_username($repos_root) if defined $repos_root;
        my $remotes = read_all_remotes();
        if (defined $full_url && defined $repos_root && !defined $path) {
                $path = $full_url;
@@ -1072,6 +1075,7 @@ sub find_by_url { # repos_root and, path are optional
        }
        foreach my $repo_id (keys %$remotes) {
                my $u = $remotes->{$repo_id}->{url} or next;
+               remove_username($u);
                next if defined $repos_root && $repos_root ne $u;
 
                my $fetch = $remotes->{$repo_id}->{fetch} || {};
index 06426640eae9db23a0e68e28b74402662fc4da87..32244d704e1c747780aed461bb78cf4a72199f18 100644 (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 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;
                else {
                        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);
                                lru_p->pack_fd = -1;
                        }
@@ -577,10 +577,10 @@ static int unuse_one_window(struct packed_git *current)
        return 0;
 }
 
-void release_pack_memory(size_t need)
+void release_pack_memory(size_t need, int fd)
 {
        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 */
 }
 
@@ -713,7 +713,7 @@ unsigned char* use_pack(struct packed_git *p,
                        win->len = (size_t)len;
                        pack_mapped += win->len;
                        while (packed_git_limit < pack_mapped
-                               && unuse_one_window(p))
+                               && unuse_one_window(p, p->pack_fd))
                                ; /* nothing */
                        win->base = xmmap(NULL, win->len,
                                PROT_READ, MAP_PRIVATE,