Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Tue, 18 Dec 2007 04:49:42 +0000 (20:49 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Dec 2007 04:49:42 +0000 (20:49 -0800)
* maint:
git-send-email: avoid duplicate message-ids
clone: correctly report http_fetch errors

1  2 
git-clone.sh
git-send-email.perl
diff --combined git-clone.sh
index 68085a3225cb0047ab3c5764472d3d024e467160,036a37e85c7e6c5dcdb53dcd67b30ad0ce946bfa..9a160eea525abae3c27e18217411f0d5f6c69399
@@@ -8,36 -8,15 +8,36 @@@
  # See git-sh-setup why.
  unset CDPATH
  
 +OPTIONS_SPEC="\
 +git-clone [options] [--] <repo> [<dir>]
 +--
 +n,no-checkout        don't create a checkout
 +bare                 create a bare repository
 +naked                create a bare repository
 +l,local              to clone from a local repository
 +no-hardlinks         don't use local hardlinks, always copy
 +s,shared             setup as a shared repository
 +template=            path to the template directory
 +q,quiet              be quiet
 +reference=           reference repository
 +o,origin=            use <name> instead of 'origin' to track upstream
 +u,upload-pack=       path to git-upload-pack on the remote
 +depth=               create a shallow clone of that depth
 +
 +use-separate-remote  compatibility, do not use
 +no-separate-remote   compatibility, do not use"
 +
  die() {
        echo >&2 "$@"
        exit 1
  }
  
  usage() {
 -      die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
 +      exec "$0" -h
  }
  
 +eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
 +
  get_repo_base() {
        (
                cd "`/bin/pwd`" &&
@@@ -56,11 -35,12 +56,12 @@@ f
  
  http_fetch () {
        # $1 = Remote, $2 = Local
-       curl -nsfL $curl_extra_args "$1" >"$2" ||
-               case $? in
-               126|127) exit ;;
-               *)       return $? ;;
-               esac
+       curl -nsfL $curl_extra_args "$1" >"$2"
+       curl_exit_status=$?
+       case $curl_exit_status in
+       126|127) exit ;;
+       *)       return $curl_exit_status ;;
+       esac
  }
  
  clone_dumb_http () {
@@@ -127,57 -107,64 +128,57 @@@ depth
  no_progress=
  local_explicitly_asked_for=
  test -t 1 || no_progress=--no-progress
 -while
 -      case "$#,$1" in
 -      0,*) break ;;
 -      *,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
 -      *,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
 -        no_checkout=yes ;;
 -      *,--na|*,--nak|*,--nake|*,--naked|\
 -      *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
 -      *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
 -        local_explicitly_asked_for=yes
 -        use_local_hardlink=yes ;;
 -      *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
 -      *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
 -        use_local_hardlink=no ;;
 -        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
 -          local_shared=yes; ;;
 -      1,--template) usage ;;
 -      *,--template)
 +
 +while test $# != 0
 +do
 +      case "$1" in
 +      -n|--no-checkout)
 +              no_checkout=yes ;;
 +      --naked|--bare)
 +              bare=yes ;;
 +      -l|--local)
 +              local_explicitly_asked_for=yes
 +              use_local_hardlink=yes
 +              ;;
 +      --no-hardlinks)
 +              use_local_hardlink=no ;;
 +      -s|--shared)
 +              local_shared=yes ;;
 +      --template)
                shift; template="--template=$1" ;;
 -      *,--template=*)
 -        template="$1" ;;
 -      *,-q|*,--quiet) quiet=-q ;;
 -      *,--use-separate-remote) ;;
 -      *,--no-separate-remote)
 +      -q|--quiet)
 +              quiet=-q ;;
 +      --use-separate-remote|--no-separate-remote)
                die "clones are always made with separate-remote layout" ;;
 -      1,--reference) usage ;;
 -      *,--reference)
 +      --reference)
                shift; reference="$1" ;;
 -      *,--reference=*)
 -              reference=`expr "z$1" : 'z--reference=\(.*\)'` ;;
 -      *,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
 -              case "$2" in
 +      -o,--origin)
 +              shift;
 +              case "$1" in
                '')
                    usage ;;
                */*)
 -                  die "'$2' is not suitable for an origin name"
 +                  die "'$1' is not suitable for an origin name"
                esac
 -              git check-ref-format "heads/$2" ||
 -                  die "'$2' is not suitable for a branch name"
 +              git check-ref-format "heads/$1" ||
 +                  die "'$1' is not suitable for a branch name"
                test -z "$origin_override" ||
                    die "Do not give more than one --origin options."
                origin_override=yes
 -              origin="$2"; shift
 +              origin="$1"
                ;;
 -      1,-u|1,--upload-pack) usage ;;
 -      *,-u|*,--upload-pack)
 +      -u|--upload-pack)
                shift
                upload_pack="--upload-pack=$1" ;;
 -      *,--upload-pack=*)
 -              upload_pack=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
 -      1,--depth) usage;;
 -      *,--depth)
 +      --depth)
 +              shift
 +              depth="--depth=$1" ;;
 +      --)
                shift
 -              depth="--depth=$1";;
 -      *,-*) usage ;;
 -      *) break ;;
 +              break ;;
 +      *)
 +              usage ;;
        esac
 -do
        shift
  done
  
  # it is local
  if base=$(get_repo_base "$repo"); then
        repo="$base"
 -      local=yes
 +      if test -z "$depth"
 +      then
 +              local=yes
 +      fi
  fi
  
  dir="$2"
@@@ -232,7 -216,7 +233,7 @@@ cleanup() 
  trap cleanup 0
  mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage
  test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" &&
 -W=$(cd "$GIT_WORK_TREE" && pwd) && export GIT_WORK_TREE="$W"
 +W=$(cd "$GIT_WORK_TREE" && pwd) && GIT_WORK_TREE="$W" && export GIT_WORK_TREE
  if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then
        GIT_DIR="$D"
  else
@@@ -300,8 -284,7 +301,8 @@@ yes
                                      find objects -type f -print | sed -e 1q)
                        # objects directory should not be empty because
                        # we are cloning!
 -                      test -f "$repo/$sample_file" || exit
 +                      test -f "$repo/$sample_file" ||
 +                              die "fatal: cannot clone empty repository"
                        if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
                        then
                                rm -f "$GIT_DIR/objects/sample"
diff --combined git-send-email.perl
index 1d6f46645328dc2520226aba532c4acb86f5ec32,e8354c760be11eec7c0b74b62aeaf4ec95a85d91..248d0350880c17fdcf7cf92afc392bc05dc47825
@@@ -73,22 -73,11 +73,22 @@@ Options
     --signed-off-cc Automatically add email addresses that appear in
                   Signed-off-by: or Cc: lines to the cc: list. Defaults to on.
  
 +   --identity     The configuration identity, a subsection to prioritise over
 +                  the default section.
 +
     --smtp-server  If set, specifies the outgoing SMTP server to use.
 -                  Defaults to localhost.
 +                  Defaults to localhost.  Port number can be specified here with
 +                  hostname:port format or by using --smtp-server-port option.
 +
 +   --smtp-server-port Specify a port on the outgoing SMTP server to connect to.
 +
 +   --smtp-user    The username for SMTP-AUTH.
  
 -   --suppress-from Suppress sending emails to yourself if your address
 -                  appears in a From: line. Defaults to off.
 +   --smtp-pass    The password for SMTP-AUTH.
 +
 +   --smtp-ssl     If set, connects to the SMTP server using SSL.
 +
 +   --suppress-from Suppress sending emails to yourself. Defaults to off.
  
     --thread       Specify that the "In-Reply-To:" header should be set on all
                    emails. Defaults to on.
@@@ -145,7 -134,6 +145,7 @@@ sub format_2822_time 
  
  my $have_email_valid = eval { require Email::Valid; 1 };
  my $smtp;
 +my $auth;
  
  sub unique_email_list(@);
  sub cleanup_compose_files();
@@@ -157,6 -145,7 +157,6 @@@ my $compose_filename = ".msg.$$"
  my (@to,@cc,@initial_cc,@bcclist,@xh,
        $initial_reply_to,$initial_subject,@files,$author,$sender,$compose,$time);
  
 -my $smtp_server;
  my $envelope_sender;
  
  # Example reply to:
@@@ -175,28 -164,24 +175,28 @@@ my ($quiet, $dry_run) = (0, 0)
  
  # Variables with corresponding config settings
  my ($thread, $chain_reply_to, $suppress_from, $signed_off_cc, $cc_cmd);
 +my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_authpass, $smtp_ssl);
 +my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
  
 -my %config_settings = (
 +my %config_bool_settings = (
      "thread" => [\$thread, 1],
      "chainreplyto" => [\$chain_reply_to, 1],
      "suppressfrom" => [\$suppress_from, 0],
      "signedoffcc" => [\$signed_off_cc, 1],
 -    "cccmd" => [\$cc_cmd, ""],
 +    "smtpssl" => [\$smtp_ssl, 0],
  );
  
 -foreach my $setting (keys %config_settings) {
 -    my $config = $repo->config_bool("sendemail.$setting");
 -    ${$config_settings{$setting}->[0]} = (defined $config) ? $config : $config_settings{$setting}->[1];
 -}
 -
 -@bcclist = $repo->config('sendemail.bcc');
 -if (!@bcclist or !$bcclist[0]) {
 -    @bcclist = ();
 -}
 +my %config_settings = (
 +    "smtpserver" => \$smtp_server,
 +    "smtpserverport" => \$smtp_server_port,
 +    "smtpuser" => \$smtp_authuser,
 +    "smtppass" => \$smtp_authpass,
 +    "to" => \@to,
 +    "cccmd" => \$cc_cmd,
 +    "aliasfiletype" => \$aliasfiletype,
 +    "bcc" => \@bcclist,
 +    "aliasesfile" => \@alias_files,
 +);
  
  # Begin by accumulating all the variables (defined above), that we will end up
  # needing, first, from the command line:
@@@ -209,11 -194,6 +209,11 @@@ my $rc = GetOptions("sender|from=s" => 
                    "bcc=s" => \@bcclist,
                    "chain-reply-to!" => \$chain_reply_to,
                    "smtp-server=s" => \$smtp_server,
 +                  "smtp-server-port=s" => \$smtp_server_port,
 +                  "smtp-user=s" => \$smtp_authuser,
 +                  "smtp-pass=s" => \$smtp_authpass,
 +                  "smtp-ssl!" => \$smtp_ssl,
 +                  "identity=s" => \$identity,
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
@@@ -228,43 -208,6 +228,43 @@@ unless ($rc) 
      usage();
  }
  
 +# Now, let's fill any that aren't set in with defaults:
 +
 +sub read_config {
 +      my ($prefix) = @_;
 +
 +      foreach my $setting (keys %config_bool_settings) {
 +              my $target = $config_bool_settings{$setting}->[0];
 +              $$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
 +      }
 +
 +      foreach my $setting (keys %config_settings) {
 +              my $target = $config_settings{$setting};
 +              if (ref($target) eq "ARRAY") {
 +                      unless (@$target) {
 +                              my @values = $repo->config("$prefix.$setting");
 +                              @$target = @values if (@values && defined $values[0]);
 +                      }
 +              }
 +              else {
 +                      $$target = $repo->config("$prefix.$setting") unless (defined $$target);
 +              }
 +      }
 +}
 +
 +# read configuration from [sendemail "$identity"], fall back on [sendemail]
 +$identity = $repo->config("sendemail.identity") unless (defined $identity);
 +read_config("sendemail.$identity") if (defined $identity);
 +read_config("sendemail");
 +
 +# fall back on builtin bool defaults
 +foreach my $setting (values %config_bool_settings) {
 +      ${$setting->[0]} = $setting->[1] unless (defined (${$setting->[0]}));
 +}
 +
 +my ($repoauthor) = $repo->ident_person('author');
 +my ($repocommitter) = $repo->ident_person('committer');
 +
  # Verify the user input
  
  foreach my $entry (@to) {
@@@ -279,7 -222,14 +279,7 @@@ foreach my $entry (@bcclist) 
        die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
  }
  
 -# Now, let's fill any that aren't set in with defaults:
 -
 -my ($repoauthor) = $repo->ident_person('author');
 -my ($repocommitter) = $repo->ident_person('committer');
 -
  my %aliases;
 -my @alias_files = $repo->config('sendemail.aliasesfile');
 -my $aliasfiletype = $repo->config('sendemail.aliasfiletype');
  my %parse_alias = (
        # multiline formats can be supported in the future
        mutt => sub { my $fh = shift; while (<$fh>) {
@@@ -367,13 -317,14 +367,13 @@@ if ($thread && !defined $initial_reply_
        } while (!defined $_);
  
        $initial_reply_to = $_;
 -      $initial_reply_to =~ s/^\s+<?/</;
 -      $initial_reply_to =~ s/>?\s+$/>/;
  }
 -
 -if (!$smtp_server) {
 -      $smtp_server = $repo->config('sendemail.smtpserver');
 +if (defined $initial_reply_to && $_ ne "") {
 +      $initial_reply_to =~ s/^\s*<?/</;
 +      $initial_reply_to =~ s/>?\s*$/>/;
  }
 -if (!$smtp_server) {
 +
 +if (!defined $smtp_server) {
        foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
                if (-x $_) {
                        $smtp_server = $_;
@@@ -560,11 -511,7 +560,11 @@@ sub sanitize_addres
  sub send_message
  {
        my @recipients = unique_email_list(@to);
 -      @cc = (map { sanitize_address($_) } @cc);
 +      @cc = (grep { my $cc = extract_valid_address($_);
 +                    not grep { $cc eq $_ } @recipients
 +                  }
 +             map { sanitize_address($_) }
 +             @cc);
        my $to = join (",\n\t", @recipients);
        @recipients = unique_email_list(@recipients,@cc,@bcclist);
        @recipients = (map { extract_valid_address($_) } @recipients);
                $ccline = "\nCc: $cc";
        }
        my $sanitized_sender = sanitize_address($sender);
-       make_message_id();
+       make_message_id() unless defined($message_id);
  
        my $header = "From: $sanitized_sender
  To: $to${ccline}
@@@ -616,30 -563,8 +616,30 @@@ X-Mailer: git-send-email $gitversio
                print $sm "$header\n$message";
                close $sm or die $?;
        } else {
 -              require Net::SMTP;
 -              $smtp ||= Net::SMTP->new( $smtp_server );
 +
 +              if (!defined $smtp_server) {
 +                      die "The required SMTP server is not properly defined."
 +              }
 +
 +              if ($smtp_ssl) {
 +                      $smtp_server_port ||= 465; # ssmtp
 +                      require Net::SMTP::SSL;
 +                      $smtp ||= Net::SMTP::SSL->new($smtp_server, Port => $smtp_server_port);
 +              }
 +              else {
 +                      require Net::SMTP;
 +                      $smtp ||= Net::SMTP->new((defined $smtp_server_port)
 +                                               ? "$smtp_server:$smtp_server_port"
 +                                               : $smtp_server);
 +              }
 +
 +              if (!$smtp) {
 +                      die "Unable to initialize SMTP properly.  Is there something wrong with your config?";
 +              }
 +
 +              if ((defined $smtp_authuser) && (defined $smtp_authpass)) {
 +                      $auth ||= $smtp->auth( $smtp_authuser, $smtp_authpass ) 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;
        if ($quiet) {
                printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
        } else {
 -              print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n");
 +              print (($dry_run ? "Dry-" : "")."OK. Log says:\n");
                if ($smtp_server !~ m#^/#) {
                        print "Server: $smtp_server\n";
                        print "MAIL FROM:<$raw_from>\n";
                } else {
                        print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
                }
 -              print "From: $sanitized_sender\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
 +              print $header, "\n";
                if ($smtp) {
                        print "Result: ", $smtp->code, ' ',
                                ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
@@@ -718,6 -643,9 +718,9 @@@ foreach my $t (@files) 
                                        }
                                        push @xh, $_;
                                }
+                               elsif (/^Message-Id: (.*)/i) {
+                                       $message_id = $1;
+                               }
                                elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
                                        push @xh, $_;
                                }
                        if (/^(Signed-off-by|Cc): (.*)$/i && $signed_off_cc) {
                                my $c = $2;
                                chomp $c;
 +                              next if ($c eq $sender and $suppress_from);
                                push @cc, $c;
                                printf("(sob) Adding cc: %s from line '%s'\n",
                                        $c, $_) unless $quiet;
        }
        close F;
  
 -      if ($cc_cmd ne "") {
 +      if (defined $cc_cmd) {
                open(F, "$cc_cmd $t |")
                        or die "(cc-cmd) Could not execute '$cc_cmd'";
                while(<F>) {
                        my $c = $_;
                        $c =~ s/^\s*//g;
                        $c =~ s/\n$//g;
 +                      next if ($c eq $sender and $suppress_from);
                        push @cc, $c;
                        printf("(cc-cmd) Adding cc: %s from: '%s'\n",
                                $c, $cc_cmd) unless $quiet;
                        $references = "$message_id";
                }
        }
+       $message_id = undef;
  }
  
  if ($compose) {