From 4de741b3e1be564233f0de2c6915a859264fe9b0 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Mon, 25 Sep 2006 22:38:16 -0700 Subject: gitweb: tree view: eliminate redundant "blob" Binary and non-binary blobs: The "list" table element of tree view is identical to the "blob" link part of the link table element. I.e. clicking on "blob" is identical to clicking on the entry itself. Thus, eliminate "blob" from being shown -- the user can get identical result by simply clicking on the entry itself. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 66be61933..c7ab3b64c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1600,34 +1600,35 @@ sub git_print_tree_entry { my %base_key = (); $base_key{hash_base} = $hash_base if defined $hash_base; + # The format of a table row is: mode list link. Where mode is + # the mode of the entry, list is the name of the entry, an href, + # and link is the action links of the entry. + print "" . mode_str($t->{'mode'}) . "\n"; if ($t->{'type'} eq "blob") { print "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key), - -class => "list"}, esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blob"); + $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key), + -class => "list"}, esc_html($t->{'name'})) . "\n"; + print ""; if ($have_blame) { - print " | " . - $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blame"); + print $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "blame"); } if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + if ($have_blame) { + print " | "; + } + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, "history"); } print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, - "raw") . - "\n"; + "raw"); + print "\n"; } elsif ($t->{'type'} eq "tree") { print "" . -- cgit v1.2.1 From 0fa105e7f140fc381ea3cbb776465aacefa22265 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Tue, 26 Sep 2006 12:45:37 -0700 Subject: gitweb: Remove redundant "tree" link In "tree" view, remove redundant "tree" link in the tree listing. It is identical to simply clicking on the tree entry itself. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c7ab3b64c..fa8a65a80 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1631,18 +1631,14 @@ sub git_print_tree_entry { print "\n"; } elsif ($t->{'type'} eq "tree") { - print "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, + print ""; + print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}", %base_key)}, - "tree"); + esc_html($t->{'name'})); + print "\n"; + print ""; if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$basedir$t->{'name'}")}, "history"); } -- cgit v1.2.1 From 65910395c08e3dc4be685a9a9f60adfa61c89aa5 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Tue, 26 Sep 2006 16:45:31 -0700 Subject: gitweb: extend blame to show links to diff and previous git_blame2() now has two more columns, "Prev" and "Diff", before the "Commit" column, as follows: Prev Diff Commit Line Data SHA Diff SHA N ... ... The "Prev" column shows the SHA of the parent commit, between which this line changed. Clicking on it shows the blame of the file as of the parent commit, for that line. So clicking repeatedly on "Prev" would show you the blame of that file, from the point of view of the changes of that particular line whose "Prev" you're clicking on. The "Diff" column shows "Diff" which is a link to blobdiff between "Prev" and "Commit" commits _for that line_. So clicking on "Diff" would show you the blobdiff (HTML) between the parent commit and this commit which changed that particular line. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fa8a65a80..e769c8ed6 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2439,7 +2439,7 @@ sub git_blame2 { print < - + HTML while (<$fd>) { /^([0-9a-fA-F]{40}).*?(\d+)\)\s{1}(\s*.*)/; @@ -2447,6 +2447,8 @@ HTML my $rev = substr($full_rev, 0, 8); my $lineno = $2; my $data = $3; + my %pco = parse_commit($full_rev); + my $parent = $pco{'parent'}; if (!defined $last_rev) { $last_rev = $full_rev; @@ -2455,11 +2457,25 @@ HTML $current_color = ++$current_color % $num_colors; } print "\n"; + # Print the Prev link + print "\n"; + # Print the Diff (blobdiff) link + print "\n"; + # Print the Commit link print "\n"; + # Print the Line number print "\n"; + # Print the Data print "\n"; print "\n"; } -- cgit v1.2.1 From 4b02f48372c72b38d2be7484355222f987f3af97 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:54:24 +0200 Subject: gitweb: Strip trailing slashes from $path in git_get_hash_by_path It also removes unused local variable $tree Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index e769c8ed6..4686d9376 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -710,7 +710,7 @@ sub git_get_hash_by_path { my $path = shift || return undef; my $type = shift; - my $tree = $base; + $path =~ s,/+$,,; open my $fd, "-|", git_cmd(), "ls-tree", $base, "--", $path or die_error(undef, "Open git-ls-tree failed"); -- cgit v1.2.1 From dd1ad5f16708e49722ad455dea8076816054391d Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:56:17 +0200 Subject: gitweb: Use "return" instead of "return undef" for some subs Use "return" instead of "return undef" when subroutine can return, or always return, non-scalar (list) value. Other places are left as is. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4686d9376..eaa42b93c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -106,7 +106,7 @@ our %feature = ( sub gitweb_check_feature { my ($name) = @_; - return undef unless exists $feature{$name}; + return unless exists $feature{$name}; my ($sub, $override, @defaults) = ( $feature{$name}{'sub'}, $feature{$name}{'override'}, @@ -781,7 +781,7 @@ sub git_get_projects_list { # 'git%2Fgit.git Linus+Torvalds' # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' - open my ($fd), $projects_list or return undef; + open my ($fd), $projects_list or return; while (my $line = <$fd>) { chomp $line; my ($path, $owner) = split ' ', $line; -- cgit v1.2.1 From 24d0693a68008baacd827b1345c957e871488596 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:57:02 +0200 Subject: gitweb: Split validate_input into validate_pathname and validate_refname Split validate_input subroutine into validate_pathname which is used for $project, $file_name and $file_parent parameters, and validate_refname which is used for $hash, $hash_base, $hash_parent and $hash_parent_base parameters. Reintroduce validation of $file_name and $file_parent parameters, removed in a2f3db2f validate_pathname in addition to what validate_input did checks also for doubled slashes and NUL character. It does not check if input is textual hash, and does not check if all characters are from the following set: [a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]. validate_refname first check if the input is textual hash, then checks if it is valid pathname, then checks for invalid characters (according to git-check-ref-format manpage). It does not check if all charactes are from the [a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%] set. We do not have to validate pathnames we got from git. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 63 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index eaa42b93c..c51313581 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -200,9 +200,10 @@ if (defined $action) { } } +# parameters which are pathnames our $project = $cgi->param('p'); if (defined $project) { - if (!validate_input($project) || + if (!validate_pathname($project) || !(-d "$projectroot/$project") || !(-e "$projectroot/$project/HEAD") || ($export_ok && !(-e "$projectroot/$project/$export_ok")) || @@ -212,38 +213,50 @@ if (defined $project) { } } -# We have to handle those containing any characters: our $file_name = $cgi->param('f'); +if (defined $file_name) { + if (!validate_pathname($file_name)) { + die_error(undef, "Invalid file parameter"); + } +} + our $file_parent = $cgi->param('fp'); +if (defined $file_parent) { + if (!validate_pathname($file_parent)) { + die_error(undef, "Invalid file parent parameter"); + } +} +# parameters which are refnames our $hash = $cgi->param('h'); if (defined $hash) { - if (!validate_input($hash)) { + if (!validate_refname($hash)) { die_error(undef, "Invalid hash parameter"); } } our $hash_parent = $cgi->param('hp'); if (defined $hash_parent) { - if (!validate_input($hash_parent)) { + if (!validate_refname($hash_parent)) { die_error(undef, "Invalid hash parent parameter"); } } our $hash_base = $cgi->param('hb'); if (defined $hash_base) { - if (!validate_input($hash_base)) { + if (!validate_refname($hash_base)) { die_error(undef, "Invalid hash base parameter"); } } our $hash_parent_base = $cgi->param('hpb'); if (defined $hash_parent_base) { - if (!validate_input($hash_parent_base)) { + if (!validate_refname($hash_parent_base)) { die_error(undef, "Invalid hash parent base parameter"); } } +# other parameters our $page = $cgi->param('pg'); if (defined $page) { if ($page =~ m/[^0-9]/) { @@ -273,7 +286,7 @@ sub evaluate_path_info { $project =~ s,/*[^/]*$,,; } # validate project - $project = validate_input($project); + $project = validate_pathname($project); if (!$project || ($export_ok && !-e "$projectroot/$project/$export_ok") || ($strict_export && !project_in_list($project))) { @@ -294,12 +307,12 @@ sub evaluate_path_info { } else { $action ||= "blob_plain"; } - $hash_base ||= validate_input($refname); - $file_name ||= $pathname; + $hash_base ||= validate_refname($refname); + $file_name ||= validate_pathname($pathname); } elsif (defined $refname) { # we got "project.git/branch" $action ||= "shortlog"; - $hash ||= validate_input($refname); + $hash ||= validate_refname($refname); } } evaluate_path_info(); @@ -387,16 +400,34 @@ sub href(%) { ## ====================================================================== ## validation, quoting/unquoting and escaping -sub validate_input { - my $input = shift; +sub validate_pathname { + my $input = shift || return undef; - if ($input =~ m/^[0-9a-fA-F]{40}$/) { - return $input; + # no '.' or '..' as elements of path, i.e. no '.' nor '..' + # at the beginning, at the end, and between slashes. + # also this catches doubled slashes + if ($input =~ m!(^|/)(|\.|\.\.)(/|$)!) { + return undef; } - if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) { + # no null characters + if ($input =~ m!\0!) { return undef; } - if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) { + return $input; +} + +sub validate_refname { + my $input = shift || return undef; + + # textual hashes are O.K. + if ($input =~ m/^[0-9a-fA-F]{40}$/) { + return $input; + } + # it must be correct pathname + $input = validate_pathname($input) + or return undef; + # restrictions on ref name according to git-check-ref-format + if ($input =~ m!(/\.|\.\.|[\000-\040\177 ~^:?*\[]|/$)!) { return undef; } return $input; -- cgit v1.2.1 From f93bff8d4531d19938a9afbdc28b8d8f4dc97b32 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:58:41 +0200 Subject: gitweb: Add git_url subroutine, and use it to quote full URLs Add git_url subroutine, which does what git_param did before commit a2f3db2f5de2a3667b0e038aa65e3e097e642e7d, and is used to quote full URLs, currently only $home_link. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c51313581..093ee604f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -443,6 +443,15 @@ sub esc_param { return $str; } +# quote unsafe chars in whole URL, so some charactrs cannot be quoted +sub esc_url { + my $str = shift; + $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg; + $str =~ s/\+/%2B/g; + $str =~ s/ /\+/g; + return $str; +} + # replace invalid utf8 character with SUBSTITUTION sequence sub esc_html { my $str = shift; @@ -1359,7 +1368,7 @@ EOF "" . "\"git\"" . "\n"; - print $cgi->a({-href => esc_param($home_link)}, $home_link_str) . " / "; + print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; if (defined $project) { print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); if (defined $action) { -- cgit v1.2.1 From ab41dfbfd4f3f9fedac71550027e9813b11abe3d Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Sep 2006 01:59:43 +0200 Subject: gitweb: Quote filename in HTTP Content-Disposition: header Finish work started by commit a2f3db2 (although not documented in commit message) of quoting using quotemeta the filename in HTTP -content_disposition header. Just in case filename contains end of line character. Also use consistent coding style to compute -content_disposition parameter. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 093ee604f..9349fa1cb 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2320,7 +2320,7 @@ sub git_project_index { print $cgi->header( -type => 'text/plain', -charset => 'utf-8', - -content_disposition => qq(inline; filename="index.aux")); + -content_disposition => 'inline; filename="index.aux"'); foreach my $pr (@projects) { if (!exists $pr->{'owner'}) { @@ -2682,7 +2682,7 @@ sub git_blob_plain { print $cgi->header( -type => "$type", -expires=>$expires, - -content_disposition => "inline; filename=\"$save_as\""); + -content_disposition => 'inline; filename="' . quotemeta($save_as) . '"'); undef $/; binmode STDOUT, ':raw'; print <$fd>; @@ -2856,10 +2856,11 @@ sub git_snapshot { my $filename = basename($project) . "-$hash.tar.$suffix"; - print $cgi->header(-type => 'application/x-tar', - -content_encoding => $ctype, - -content_disposition => "inline; filename=\"$filename\"", - -status => '200 OK'); + print $cgi->header( + -type => 'application/x-tar', + -content_encoding => $ctype, + -content_disposition => 'inline; filename="' . quotemeta($filename) . '"', + -status => '200 OK'); my $git_command = git_cmd_str(); open my $fd, "-|", "$git_command tar-tree $hash \'$project\' | $command" or @@ -3169,7 +3170,7 @@ sub git_blobdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => qq(inline; filename=") . quotemeta($file_name) . qq(.patch")); + -content_disposition => 'inline; filename="' . quotemeta($file_name) . '.patch"'); print "X-Git-Url: " . $cgi->self_url() . "\n\n"; @@ -3272,7 +3273,7 @@ sub git_commitdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => qq(inline; filename="$filename")); + -content_disposition => 'inline; filename="' . quotemeta($filename) . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); print < Date: Tue, 26 Sep 2006 18:53:02 -0700 Subject: diff --stat: allow custom diffstat output width. This adds two parameters to "diff --stat". . --stat-width=72 tells that the page should fit on 72-column output. . --stat-name-width=30 tells that the filename part is limited to 30 columns. Signed-off-by: Junio C Hamano --- diff.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++------------------- diff.h | 3 ++ 2 files changed, 96 insertions(+), 38 deletions(-) diff --git a/diff.c b/diff.c index 443e24861..8d299f476 100644 --- a/diff.c +++ b/diff.c @@ -545,21 +545,64 @@ static void diffstat_consume(void *priv, char *line, unsigned long len) x->deleted++; } -static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; -static const char minuses[]= "----------------------------------------------------------------------"; const char mime_boundary_leader[] = "------------"; -static void show_stats(struct diffstat_t* data) +static int scale_linear(int it, int width, int max_change) +{ + /* + * round(width * it / max_change); + */ + return (it * width * 2 + max_change) / (max_change * 2); +} + +static void show_name(const char *prefix, const char *name, int len) +{ + printf(" %s%-*s |", prefix, len, name); +} + +static void show_graph(char ch, int cnt) +{ + if (cnt <= 0) + return; + while (cnt--) + putchar(ch); +} + +static void show_stats(struct diffstat_t* data, struct diff_options *options) { int i, len, add, del, total, adds = 0, dels = 0; - int max, max_change = 0, max_len = 0; + int max_change = 0, max_len = 0; int total_files = data->nr; + int width, name_width; if (data->nr == 0) return; + width = options->stat_width ? options->stat_width : 80; + name_width = options->stat_name_width ? options->stat_name_width : 50; + + /* Sanity: give at least 5 columns to the graph, + * but leave at least 10 columns for the name. + */ + if (width < name_width + 15) { + if (name_width <= 25) + width = name_width + 15; + else + name_width = width - 15; + } + + /* Find the longest filename and max number of changes */ for (i = 0; i < data->nr; i++) { struct diffstat_file *file = data->files[i]; + int change = file->added + file->deleted; + + len = quote_c_style(file->name, NULL, NULL, 0); + if (len) { + char *qname = xmalloc(len + 1); + quote_c_style(file->name, qname, NULL, 0); + free(file->name); + file->name = qname; + } len = strlen(file->name); if (max_len < len) @@ -567,54 +610,53 @@ static void show_stats(struct diffstat_t* data) if (file->is_binary || file->is_unmerged) continue; - if (max_change < file->added + file->deleted) - max_change = file->added + file->deleted; + if (max_change < change) + max_change = change; } + /* Compute the width of the graph part; + * 10 is for one blank at the beginning of the line plus + * " | count " between the name and the graph. + * + * From here on, name_width is the width of the name area, + * and width is the width of the graph area. + */ + name_width = (name_width < max_len) ? name_width : max_len; + if (width < (name_width + 10) + max_change) + width = width - (name_width + 10); + else + width = max_change; + for (i = 0; i < data->nr; i++) { const char *prefix = ""; char *name = data->files[i]->name; int added = data->files[i]->added; int deleted = data->files[i]->deleted; - - if (0 < (len = quote_c_style(name, NULL, NULL, 0))) { - char *qname = xmalloc(len + 1); - quote_c_style(name, qname, NULL, 0); - free(name); - data->files[i]->name = name = qname; - } + int name_len; /* * "scale" the filename */ - len = strlen(name); - max = max_len; - if (max > 50) - max = 50; - if (len > max) { + len = name_width; + name_len = strlen(name); + if (name_width < name_len) { char *slash; prefix = "..."; - max -= 3; - name += len - max; + len -= 3; + name += name_len - len; slash = strchr(name, '/'); if (slash) name = slash; } - len = max; - - /* - * scale the add/delete - */ - max = max_change; - if (max + len > 70) - max = 70 - len; if (data->files[i]->is_binary) { - printf(" %s%-*s | Bin\n", prefix, len, name); + show_name(prefix, name, len); + printf(" Bin\n"); goto free_diffstat_file; } else if (data->files[i]->is_unmerged) { - printf(" %s%-*s | Unmerged\n", prefix, len, name); + show_name(prefix, name, len); + printf(" Unmerged\n"); goto free_diffstat_file; } else if (!data->files[i]->is_renamed && @@ -623,27 +665,32 @@ static void show_stats(struct diffstat_t* data) goto free_diffstat_file; } + /* + * scale the add/delete + */ add = added; del = deleted; total = add + del; adds += add; dels += del; - if (max_change > 0) { - total = (total * max + max_change / 2) / max_change; - add = (add * max + max_change / 2) / max_change; + if (width <= max_change) { + total = scale_linear(total, width, max_change); + add = scale_linear(add, width, max_change); del = total - add; } - printf(" %s%-*s |%5d %.*s%.*s\n", prefix, - len, name, added + deleted, - add, pluses, del, minuses); + show_name(prefix, name, len); + printf("%5d ", added + deleted); + show_graph('+', add); + show_graph('-', del); + putchar('\n'); free_diffstat_file: free(data->files[i]->name); free(data->files[i]); } free(data->files); printf(" %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + total_files, adds, dels); } struct checkdiff_t { @@ -1681,6 +1728,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format |= DIFF_FORMAT_DIFFSTAT; + else if (!strncmp(arg, "--stat-width=", 13)) { + options->stat_width = strtoul(arg + 13, NULL, 10); + options->output_format |= DIFF_FORMAT_DIFFSTAT; + } + else if (!strncmp(arg, "--stat-name-width=", 18)) { + options->stat_name_width = strtoul(arg + 18, NULL, 10); + options->output_format |= DIFF_FORMAT_DIFFSTAT; + } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) @@ -2438,7 +2493,7 @@ void diff_flush(struct diff_options *options) if (check_pair_status(p)) diff_flush_stat(p, options, &diffstat); } - show_stats(&diffstat); + show_stats(&diffstat, options); separator++; } diff --git a/diff.h b/diff.h index b60a02e62..e06d0f418 100644 --- a/diff.h +++ b/diff.h @@ -69,6 +69,9 @@ struct diff_options { const char *stat_sep; long xdl_opts; + int stat_width; + int stat_name_width; + int nr_paths; const char **paths; int *pathlens; -- cgit v1.2.1 From 785f743276991567a36420f069c228e4dc9d0df3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 26 Sep 2006 18:59:41 -0700 Subject: diff --stat: color output. Under --color option, diffstat shows '+' and '-' in the graph the same color as added and deleted lines. Signed-off-by: Junio C Hamano --- diff.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/diff.c b/diff.c index 8d299f476..3fd7a5220 100644 --- a/diff.c +++ b/diff.c @@ -555,17 +555,20 @@ static int scale_linear(int it, int width, int max_change) return (it * width * 2 + max_change) / (max_change * 2); } -static void show_name(const char *prefix, const char *name, int len) +static void show_name(const char *prefix, const char *name, int len, + const char *reset, const char *set) { - printf(" %s%-*s |", prefix, len, name); + printf(" %s%s%-*s%s |", set, prefix, len, name, reset); } -static void show_graph(char ch, int cnt) +static void show_graph(char ch, int cnt, const char *set, const char *reset) { if (cnt <= 0) return; + printf("%s", set); while (cnt--) putchar(ch); + printf("%s", reset); } static void show_stats(struct diffstat_t* data, struct diff_options *options) @@ -574,6 +577,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) int max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; + const char *reset, *set, *add_c, *del_c; if (data->nr == 0) return; @@ -592,6 +596,11 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) } /* Find the longest filename and max number of changes */ + reset = diff_get_color(options->color_diff, DIFF_RESET); + set = diff_get_color(options->color_diff, DIFF_PLAIN); + add_c = diff_get_color(options->color_diff, DIFF_FILE_NEW); + del_c = diff_get_color(options->color_diff, DIFF_FILE_OLD); + for (i = 0; i < data->nr; i++) { struct diffstat_file *file = data->files[i]; int change = file->added + file->deleted; @@ -650,12 +659,12 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) } if (data->files[i]->is_binary) { - show_name(prefix, name, len); + show_name(prefix, name, len, reset, set); printf(" Bin\n"); goto free_diffstat_file; } else if (data->files[i]->is_unmerged) { - show_name(prefix, name, len); + show_name(prefix, name, len, reset, set); printf(" Unmerged\n"); goto free_diffstat_file; } @@ -679,18 +688,18 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) add = scale_linear(add, width, max_change); del = total - add; } - show_name(prefix, name, len); + show_name(prefix, name, len, reset, set); printf("%5d ", added + deleted); - show_graph('+', add); - show_graph('-', del); + show_graph('+', add, add_c, reset); + show_graph('-', del, del_c, reset); putchar('\n'); free_diffstat_file: free(data->files[i]->name); free(data->files[i]); } free(data->files); - printf(" %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + printf("%s %d files changed, %d insertions(+), %d deletions(-)%s\n", + set, total_files, adds, dels, reset); } struct checkdiff_t { -- cgit v1.2.1 From dd4676299dde0a4c6f8a471e6353170f86a78c8a Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Tue, 26 Sep 2006 09:47:43 -0500 Subject: Cleaned up git-daemon virtual hosting support. Standardized on lowercase hostnames from client. Added interpolation values for the IP address, port and canonical hostname of the server as it is contacted and named by the client and passed in via the extended args. Added --listen=host_or_ipaddr option suport. Renamed port variable as "listen_port" correspondingly as well. Documented mutual exclusivity of --inetd option with --user, --group, --listen and --port options. Added compat/inet_pton.c from Paul Vixie as needed. Small memory leaks need to be cleaned up still. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano --- Documentation/git-daemon.txt | 43 +++++++-- Makefile | 3 + compat/inet_pton.c | 220 +++++++++++++++++++++++++++++++++++++++++++ daemon.c | 151 ++++++++++++++++++++++++----- 4 files changed, 389 insertions(+), 28 deletions(-) create mode 100644 compat/inet_pton.c diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index 51d7c94d7..d562232e5 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -8,14 +8,15 @@ git-daemon - A really simple server for git repositories SYNOPSIS -------- [verse] -'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all] +'git-daemon' [--verbose] [--syslog] [--export-all] [--timeout=n] [--init-timeout=n] [--strict-paths] [--base-path=path] [--user-path | --user-path=path] [--interpolated-path=pathtemplate] + [--reuseaddr] [--detach] [--pid-file=file] [--enable=service] [--disable=service] [--allow-override=service] [--forbid-override=service] - [--reuseaddr] [--detach] [--pid-file=file] - [--user=user [--group=group]] [directory...] + [--inetd | [--listen=host_or_ipaddr] [--port=n] [--user=user [--group=group]] + [directory...] DESCRIPTION ----------- @@ -54,8 +55,12 @@ OPTIONS --interpolated-path=pathtemplate:: To support virtual hosting, an interpolated path template can be used to dynamically construct alternate paths. The template - supports %H for the target hostname as supplied by the client, + supports %H for the target hostname as supplied by the client but + converted to all lowercase, %CH for the canonical hostname, + %IP for the server's IP address, %P for the port number, and %D for the absolute path of the named repository. + After interpolation, the path is validated against the directory + whitelist. --export-all:: Allow pulling from all directories that look like GIT repositories @@ -64,9 +69,17 @@ OPTIONS --inetd:: Have the server run as an inetd service. Implies --syslog. + Incompatible with --port, --listen, --user and --group options. + +--listen=host_or_ipaddr:: + Listen on an a specific IP address or hostname. IP addresses can + be either an IPv4 address or an IPV6 address if supported. If IPv6 + is not supported, then --listen=hostname is also not supported and + --listen must be given an IPv4 address. + Incompatible with '--inetd' option. ---port:: - Listen on an alternative port. +--port=n:: + Listen on an alternative port. Incompatible with '--inetd' option. --init-timeout:: Timeout between the moment the connection is established and the @@ -182,6 +195,24 @@ clients, a symlink from `/software` into the appropriate default repository could be made as well. +git-daemon as regular daemon for virtual hosts:: + To set up `git-daemon` as a regular, non-inetd service that + handles repositories for multiple virtual hosts based on + their IP addresses, start the daemon like this: ++ +------------------------------------------------ + git-daemon --verbose --export-all + --interpolated-path=/pub/%IP/%D + /pub/192.168.1.200/software + /pub/10.10.220.23/software +------------------------------------------------ ++ +In this example, the root-level directory `/pub` will contain +a subdirectory for each virtual host IP address supported. +Repositories can still be accessed by hostname though, assuming +they correspond to these IP addresses. + + Author ------ Written by Linus Torvalds , YOSHIFUJI Hideaki diff --git a/Makefile b/Makefile index 28091d6be..e68b4c074 100644 --- a/Makefile +++ b/Makefile @@ -524,6 +524,9 @@ endif ifdef NO_INET_NTOP LIB_OBJS += compat/inet_ntop.o endif +ifdef NO_INET_PTON + LIB_OBJS += compat/inet_pton.o +endif ifdef NO_ICONV ALL_CFLAGS += -DNO_ICONV diff --git a/compat/inet_pton.c b/compat/inet_pton.c new file mode 100644 index 000000000..5704e0d2b --- /dev/null +++ b/compat/inet_pton.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NS_INT16SZ +#define NS_INT16SZ 2 +#endif + +#ifndef NS_INADDRSZ +#define NS_INADDRSZ 4 +#endif + +#ifndef NS_IN6ADDRSZ +#define NS_IN6ADDRSZ 16 +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int new = *tp * 10 + (pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ + +#ifndef NO_IPV6 +static int +inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} +#endif + +/* int + * isc_net_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); +#ifndef NO_IPV6 + case AF_INET6: + return (inet_pton6(src, dst)); +#endif + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} diff --git a/daemon.c b/daemon.c index eb4f3f1e9..69ea35c22 100644 --- a/daemon.c +++ b/daemon.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "pkt-line.h" #include "cache.h" #include "exec_cmd.h" @@ -19,13 +20,15 @@ static int verbose; static int reuseaddr; static const char daemon_usage[] = -"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n" +"git-daemon [--verbose] [--syslog] [--export-all]\n" " [--timeout=n] [--init-timeout=n] [--strict-paths]\n" " [--base-path=path] [--user-path | --user-path=path]\n" " [--interpolated-path=path]\n" " [--reuseaddr] [--detach] [--pid-file=file]\n" " [--[enable|disable|allow-override|forbid-override]=service]\n" -" [--user=user [[--group=group]] [directory...]"; +" [--inetd | [--listen=host_or_ipaddr] [--port=n]\n" +" [--user=user [--group=group]]\n" +" [directory...]"; /* List of acceptable pathname prefixes */ static char **ok_paths; @@ -56,11 +59,17 @@ static unsigned int init_timeout; * Feel free to make dynamic as needed. */ #define INTERP_SLOT_HOST (0) -#define INTERP_SLOT_DIR (1) -#define INTERP_SLOT_PERCENT (2) +#define INTERP_SLOT_CANON_HOST (1) +#define INTERP_SLOT_IP (2) +#define INTERP_SLOT_PORT (3) +#define INTERP_SLOT_DIR (4) +#define INTERP_SLOT_PERCENT (5) static struct interp interp_table[] = { { "%H", 0}, + { "%CH", 0}, + { "%IP", 0}, + { "%P", 0}, { "%D", 0}, { "%%", "%"}, }; @@ -408,9 +417,17 @@ static void parse_extra_args(char *extra_args, int buflen) val = extra_args + 5; vallen = strlen(val) + 1; if (*val) { - char *save = xmalloc(vallen); + char *port; + char *save = xmalloc(vallen); /* FIXME: Leak */ + interp_table[INTERP_SLOT_HOST].value = save; strlcpy(save, val, vallen); + port = strrchr(save, ':'); + if (port) { + *port = 0; + port++; + interp_table[INTERP_SLOT_PORT].value = port; + } } /* On to the next one */ extra_args = val + vallen; @@ -418,6 +435,73 @@ static void parse_extra_args(char *extra_args, int buflen) } } +void fill_in_extra_table_entries(struct interp *itable) +{ + char *hp; + char *canon_host = NULL; + char *ipaddr = NULL; + + /* + * Replace literal host with lowercase-ized hostname. + */ + hp = interp_table[INTERP_SLOT_HOST].value; + for ( ; *hp; hp++) + *hp = tolower(*hp); + + /* + * Locate canonical hostname and its IP address. + */ +#ifndef NO_IPV6 + { + struct addrinfo hints; + struct addrinfo *ai, *ai0; + int gai; + static char addrbuf[HOST_NAME_MAX + 1]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + gai = getaddrinfo(interp_table[INTERP_SLOT_HOST].value, 0, &hints, &ai0); + if (!gai) { + for (ai = ai0; ai; ai = ai->ai_next) { + struct sockaddr_in *sin_addr = (void *)ai->ai_addr; + + canon_host = xstrdup(ai->ai_canonname); + inet_ntop(AF_INET, &sin_addr->sin_addr, + addrbuf, sizeof(addrbuf)); + ipaddr = addrbuf; + break; + } + freeaddrinfo(ai0); + } + } +#else + { + struct hostent *hent; + struct sockaddr_in sa; + char **ap; + static char addrbuf[HOST_NAME_MAX + 1]; + + hent = gethostbyname(interp_table[INTERP_SLOT_HOST].value); + canon_host = xstrdup(hent->h_name); + + ap = hent->h_addr_list; + memset(&sa, 0, sizeof sa); + sa.sin_family = hent->h_addrtype; + sa.sin_port = htons(0); + memcpy(&sa.sin_addr, *ap, hent->h_length); + + inet_ntop(hent->h_addrtype, &sa.sin_addr, + addrbuf, sizeof(addrbuf)); + ipaddr = addrbuf; + } +#endif + + interp_table[INTERP_SLOT_CANON_HOST].value = canon_host; /* FIXME: Leak */ + interp_table[INTERP_SLOT_IP].value = xstrdup(ipaddr); /* FIXME: Leak */ +} + + static int execute(struct sockaddr *addr) { static char line[1000]; @@ -458,8 +542,10 @@ static int execute(struct sockaddr *addr) if (len && line[len-1] == '\n') line[--len] = 0; - if (len != pktlen) + if (len != pktlen) { parse_extra_args(line + len + 1, pktlen - len - 1); + fill_in_extra_table_entries(interp_table); + } for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); @@ -663,23 +749,22 @@ static int set_reuse_addr(int sockfd) #ifndef NO_IPV6 -static int socksetup(int port, int **socklist_p) +static int socksetup(char *listen_addr, int listen_port, int **socklist_p) { int socknum = 0, *socklist = NULL; int maxfd = -1; char pbuf[NI_MAXSERV]; - struct addrinfo hints, *ai0, *ai; int gai; - sprintf(pbuf, "%d", port); + sprintf(pbuf, "%d", listen_port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; - gai = getaddrinfo(NULL, pbuf, &hints, &ai0); + gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); if (gai) die("getaddrinfo() failed: %s\n", gai_strerror(gai)); @@ -733,20 +818,27 @@ static int socksetup(int port, int **socklist_p) #else /* NO_IPV6 */ -static int socksetup(int port, int **socklist_p) +static int socksetup(char *lisen_addr, int listen_port, int **socklist_p) { struct sockaddr_in sin; int sockfd; + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(listen_port); + + if (listen_addr) { + /* Well, host better be an IP address here. */ + if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) + return 0; + } else { + sin.sin_addr.s_addr = htonl(INADDR_ANY); + } + sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) return 0; - memset(&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(port); - if (set_reuse_addr(sockfd)) { close(sockfd); return 0; @@ -855,13 +947,14 @@ static void store_pid(const char *path) fclose(f); } -static int serve(int port, struct passwd *pass, gid_t gid) +static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid) { int socknum, *socklist; - socknum = socksetup(port, &socklist); + socknum = socksetup(listen_addr, listen_port, &socklist); if (socknum == 0) - die("unable to allocate any listen sockets on port %u", port); + die("unable to allocate any listen sockets on host %s port %u", + listen_addr, listen_port); if (pass && gid && (initgroups(pass->pw_name, gid) || setgid (gid) || @@ -873,7 +966,8 @@ static int serve(int port, struct passwd *pass, gid_t gid) int main(int argc, char **argv) { - int port = DEFAULT_GIT_PORT; + int listen_port = 0; + char *listen_addr = NULL; int inetd_mode = 0; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; int detach = 0; @@ -890,12 +984,20 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { char *arg = argv[i]; + if (!strncmp(arg, "--listen=", 9)) { + char *p = arg + 9; + char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1); + while (*p) + *ph++ = tolower(*p++); + *ph = 0; + continue; + } if (!strncmp(arg, "--port=", 7)) { char *end; unsigned long n; n = strtoul(arg+7, &end, 0); if (arg[7] && !*end) { - port = n; + listen_port = n; continue; } } @@ -995,6 +1097,11 @@ int main(int argc, char **argv) if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); + if (inetd_mode && (listen_port || listen_addr)) + die("--listen= and --port= are incompatible with --inetd"); + else if (listen_port == 0) + listen_port = DEFAULT_GIT_PORT; + if (group_name && !user_name) die("--group supplied without --user"); @@ -1043,5 +1150,5 @@ int main(int argc, char **argv) if (pid_file) store_pid(pid_file); - return serve(port, pass, gid); + return serve(listen_addr, listen_port, pass, gid); } -- cgit v1.2.1 From eb30aed7c69190fd648947d54bbb9ebe53c67715 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Wed, 27 Sep 2006 11:16:10 -0500 Subject: Removed memory leaks from interpolation table uses. Clarified that parse_extra_args()s results in interpolation table entries. Removed a few trailing whitespace occurrences. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano --- daemon.c | 52 ++++++++++++++++++++++++++++++++-------------------- interpolate.c | 26 ++++++++++++++++++++++++++ interpolate.h | 3 +++ 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/daemon.c b/daemon.c index 69ea35c22..5335d212c 100644 --- a/daemon.c +++ b/daemon.c @@ -71,7 +71,7 @@ static struct interp interp_table[] = { { "%IP", 0}, { "%P", 0}, { "%D", 0}, - { "%%", "%"}, + { "%%", 0}, }; @@ -405,7 +405,11 @@ static void make_service_overridable(const char *name, int ena) { die("No such service %s", name); } -static void parse_extra_args(char *extra_args, int buflen) +/* + * Separate the "extra args" information as supplied by the client connection. + * Any resulting data is squirrelled away in the given interpolation table. + */ +static void parse_extra_args(struct interp *table, char *extra_args, int buflen) { char *val; int vallen; @@ -417,18 +421,17 @@ static void parse_extra_args(char *extra_args, int buflen) val = extra_args + 5; vallen = strlen(val) + 1; if (*val) { - char *port; - char *save = xmalloc(vallen); /* FIXME: Leak */ - - interp_table[INTERP_SLOT_HOST].value = save; - strlcpy(save, val, vallen); - port = strrchr(save, ':'); + /* Split : at colon. */ + char *host = val; + char *port = strrchr(host, ':'); if (port) { *port = 0; port++; - interp_table[INTERP_SLOT_PORT].value = port; + interp_set_entry(table, INTERP_SLOT_PORT, port); } + interp_set_entry(table, INTERP_SLOT_HOST, host); } + /* On to the next one */ extra_args = val + vallen; } @@ -438,8 +441,6 @@ static void parse_extra_args(char *extra_args, int buflen) void fill_in_extra_table_entries(struct interp *itable) { char *hp; - char *canon_host = NULL; - char *ipaddr = NULL; /* * Replace literal host with lowercase-ized hostname. @@ -466,10 +467,12 @@ void fill_in_extra_table_entries(struct interp *itable) for (ai = ai0; ai; ai = ai->ai_next) { struct sockaddr_in *sin_addr = (void *)ai->ai_addr; - canon_host = xstrdup(ai->ai_canonname); inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); - ipaddr = addrbuf; + interp_set_entry(interp_table, + INTERP_SLOT_CANON_HOST, ai->ai_canonname); + interp_set_entry(interp_table, + INTERP_SLOT_IP, addrbuf); break; } freeaddrinfo(ai0); @@ -483,7 +486,6 @@ void fill_in_extra_table_entries(struct interp *itable) static char addrbuf[HOST_NAME_MAX + 1]; hent = gethostbyname(interp_table[INTERP_SLOT_HOST].value); - canon_host = xstrdup(hent->h_name); ap = hent->h_addr_list; memset(&sa, 0, sizeof sa); @@ -493,12 +495,11 @@ void fill_in_extra_table_entries(struct interp *itable) inet_ntop(hent->h_addrtype, &sa.sin_addr, addrbuf, sizeof(addrbuf)); - ipaddr = addrbuf; + + interp_set_entry(interp_table, INTERP_SLOT_CANON_HOST, hent->h_name); + interp_set_entry(interp_table, INTERP_SLOT_IP, addrbuf); } #endif - - interp_table[INTERP_SLOT_CANON_HOST].value = canon_host; /* FIXME: Leak */ - interp_table[INTERP_SLOT_IP].value = xstrdup(ipaddr); /* FIXME: Leak */ } @@ -542,8 +543,14 @@ static int execute(struct sockaddr *addr) if (len && line[len-1] == '\n') line[--len] = 0; + /* + * Initialize the path interpolation table for this connection. + */ + interp_clear_table(interp_table, ARRAY_SIZE(interp_table)); + interp_set_entry(interp_table, INTERP_SLOT_PERCENT, "%"); + if (len != pktlen) { - parse_extra_args(line + len + 1, pktlen - len - 1); + parse_extra_args(interp_table, line + len + 1, pktlen - len - 1); fill_in_extra_table_entries(interp_table); } @@ -553,7 +560,12 @@ static int execute(struct sockaddr *addr) if (!strncmp("git-", line, 4) && !strncmp(s->name, line + 4, namelen) && line[namelen + 4] == ' ') { - interp_table[INTERP_SLOT_DIR].value = line+namelen+5; + /* + * Note: The directory here is probably context sensitive, + * and might depend on the actual service being performed. + */ + interp_set_entry(interp_table, + INTERP_SLOT_DIR, line + namelen + 5); return run_service(interp_table, s); } } diff --git a/interpolate.c b/interpolate.c index 4570c123d..62701d843 100644 --- a/interpolate.c +++ b/interpolate.c @@ -4,9 +4,35 @@ #include +#include "git-compat-util.h" #include "interpolate.h" +void interp_set_entry(struct interp *table, int slot, char *value) +{ + char *oldval = table[slot].value; + char *newval = value; + + if (oldval) + free(oldval); + + if (value) + newval = xstrdup(value); + + table[slot].value = newval; +} + + +void interp_clear_table(struct interp *table, int ninterps) +{ + int i; + + for (i = 0; i < ninterps; i++) { + interp_set_entry(table, i, NULL); + } +} + + /* * Convert a NUL-terminated string in buffer orig * into the supplied buffer, result, whose length is reslen, diff --git a/interpolate.h b/interpolate.h index d16f9244f..a55fb8e07 100644 --- a/interpolate.h +++ b/interpolate.h @@ -16,6 +16,9 @@ struct interp { char *value; }; +extern void interp_set_entry(struct interp *table, int slot, char *value); +extern void interp_clear_table(struct interp *table, int ninterps); + extern int interpolate(char *result, int reslen, const char *orig, const struct interp *interps, int ninterps); -- cgit v1.2.1 From 709f898dae46b9b035e98cc634fa3ac2492b6cee Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 27 Sep 2006 17:22:03 -0700 Subject: Revert "gitweb: extend blame to show links to diff and previous" This concept is very fine, but it makes blame slow across renames and across branches, so revert it. There is a better way to do this. This reverts commit 03d06a8e26f4fbd37800d1e1125c6ecf4c104466. Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9349fa1cb..0a627846b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2479,7 +2479,7 @@ sub git_blame2 { print <
CommitLineData
PrevDiffCommitLineData
"; + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, file_name=>$file_name)}, + esc_html(substr($parent, 0, 8))); + print ""; + print $cgi->a({-href => href(action=>"blobdiff", file_name=>$file_name, hash_parent_base=>$parent, + hash_base=>$full_rev)}, + esc_html("Diff")); + print "" . $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "" . esc_html($lineno) . "" . esc_html($data) . "
- + HTML while (<$fd>) { /^([0-9a-fA-F]{40}).*?(\d+)\)\s{1}(\s*.*)/; @@ -2487,8 +2487,6 @@ HTML my $rev = substr($full_rev, 0, 8); my $lineno = $2; my $data = $3; - my %pco = parse_commit($full_rev); - my $parent = $pco{'parent'}; if (!defined $last_rev) { $last_rev = $full_rev; @@ -2497,25 +2495,11 @@ HTML $current_color = ++$current_color % $num_colors; } print "\n"; - # Print the Prev link - print "\n"; - # Print the Diff (blobdiff) link - print "\n"; - # Print the Commit link print "\n"; - # Print the Line number print "\n"; - # Print the Data print "\n"; print "\n"; } -- cgit v1.2.1 From 499faeda1bd131f7c3b216c16eebbe30049728d3 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 27 Sep 2006 17:23:25 -0700 Subject: gitweb: Remove excessively redundant entries from git_difftree_body 1) All entries on the left are blobs and clicking on them leads to blobs. No more diff or blob depending on what happened (modified or mode changed) to the file -- this goes to the right, in the "link" column. 2) Remove redundant "blob" from the link column on the right. This can now be had by clicking on the entry itself. This reduces and simplifies the code. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 92 ++++++++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0a627846b..88a8bcdbf 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1732,47 +1732,39 @@ sub git_difftree_body { my $mode_chng = "[new $to_file_type"; $mode_chng .= " with mode: $to_mode_str" if $to_mode_str; $mode_chng .= "]"; - print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; } elsif ($diff{'status'} eq "D") { # deleted my $mode_chng = "[deleted $from_file_type]"; - print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; + "history"); + print "\n"; } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed my $mode_chnge = ""; @@ -1791,42 +1783,29 @@ sub git_difftree_body { $mode_chnge .= "]\n"; } print "\n" . - "\n" . - "\n"; + print "\n"; + print "\n"; } elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied @@ -1846,10 +1825,7 @@ sub git_difftree_body { hash=>$diff{'from_id'}, file_name=>$diff{'from_file'}), -class => "list"}, esc_html($diff{'from_file'})) . " with " . (int $diff{'similarity'}) . "% similarity$mode_chng]\n" . - "\n"; } elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed @@ -1803,8 +1806,11 @@ sub git_difftree_body { } print " | "; } - print $cgi->a({-href => href(action=>"history", - hash_base=>$hash, file_name=>$diff{'file'})}, + print $cgi->a({-href => href(action=>"blame", hash_base=>$hash, + file_name=>$diff{'file'})}, + "blame") . " | "; + print $cgi->a({-href => href(action=>"history", hash_base=>$hash, + file_name=>$diff{'file'})}, "history"); print "\n"; @@ -1830,17 +1836,22 @@ sub git_difftree_body { if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } else { - print " | " . - $cgi->a({-href => href(action=>"blobdiff", - hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, hash_parent_base=>$parent, - file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, - "diff"); + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, + "diff"); } + print " | "; } + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, + file_name=>$diff{'from_file'})}, + "blame") . " | "; + print $cgi->a({-href => href(action=>"history", hash_base=>$parent, + file_name=>$diff{'from_file'})}, + "history"); print "\n"; } # we should not encounter Unmerged (U) or Unknown (X) status -- cgit v1.2.1 From 690d8824c852b6a59deb03f65e330297c587752e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 28 Sep 2006 02:31:25 -0700 Subject: Contributed bash completion support for core Git tools. This is a set of bash completion routines for many of the popular core Git tools. I wrote these routines from scratch after reading the git-compl and git-compl-lib routines available from the gitcompletion package at http://gitweb.hawaga.org.uk/ and found those to be lacking in functionality for some commands. Consequently there may be some similarities but many differences. Since these are completion routines only for tools shipped with core Git and since bash is a popular shell on many of the native core Git platforms (Linux, Mac OS X, Solaris, BSD) including these routines as part of the stock package would probably be convienent for many users. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 324 +++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100755 contrib/completion/git-completion.bash diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash new file mode 100755 index 000000000..d9cb17d0b --- /dev/null +++ b/contrib/completion/git-completion.bash @@ -0,0 +1,324 @@ +# +# bash completion support for core Git. +# +# Copyright (C) 2006 Shawn Pearce +# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). +# +# The contained completion routines provide support for completing: +# +# *) local and remote branch names +# *) local and remote tag names +# *) .git/remotes file names +# *) git 'subcommands' +# *) tree paths within 'ref:path/to/file' expressions +# +# To use these routines: +# +# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). +# 2) Added the following line to your .bashrc: +# source ~/.git-completion.sh +# + +__git_refs () +{ + local cmd i is_hash=y + if [ -d "$1" ]; then + cmd=git-peek-remote + else + cmd=git-ls-remote + fi + for i in $($cmd "$1" 2>/dev/null); do + case "$is_hash,$i" in + y,*) is_hash=n ;; + n,*^{}) is_hash=y ;; + n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; + n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; + n,*) is_hash=y; echo "$i" ;; + esac + done +} + +__git_refs2 () +{ + local cmd i is_hash=y + if [ -d "$1" ]; then + cmd=git-peek-remote + else + cmd=git-ls-remote + fi + for i in $($cmd "$1" 2>/dev/null); do + case "$is_hash,$i" in + y,*) is_hash=n ;; + n,*^{}) is_hash=y ;; + n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;; + n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;; + n,*) is_hash=y; echo "$i:$i" ;; + esac + done +} + +__git_remotes () +{ + local i REVERTGLOB=$(shopt -p nullglob) + shopt -s nullglob + for i in .git/remotes/*; do + echo ${i#.git/remotes/} + done + $REVERTGLOB +} + +__git_complete_file () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + ?*:*) + local pfx ls ref="$(echo "$cur" | sed 's,:.*$,,')" + cur="$(echo "$cur" | sed 's,^.*:,,')" + case "$cur" in + ?*/*) + pfx="$(echo "$cur" | sed 's,/[^/]*$,,')" + cur="$(echo "$cur" | sed 's,^.*/,,')" + ls="$ref:$pfx" + pfx="$pfx/" + ;; + *) + ls="$ref" + ;; + esac + COMPREPLY=($(compgen -P "$pfx" \ + -W "$(git-ls-tree "$ls" \ + | sed '/^100... blob /s,^.* ,, + /^040000 tree /{ + s,^.* ,, + s,$,/, + } + s/^.* //')" \ + -- "$cur")) + ;; + *) + COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur")) + ;; + esac +} + +_git_branch () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs .)" -- "$cur")) +} + +_git_cat_file () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "${COMP_WORDS[0]},$COMP_CWORD" in + git-cat-file*,1) + COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur")) + ;; + git,2) + COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur")) + ;; + *) + __git_complete_file + ;; + esac +} + +_git_checkout () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "-l -b $(__git_refs .)" -- "$cur")) +} + +_git_diff () +{ + __git_complete_file +} + +_git_diff_tree () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "-r -p -M $(__git_refs .)" -- "$cur")) +} + +_git_fetch () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "${COMP_WORDS[0]},$COMP_CWORD" in + git-fetch*,1) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + git,2) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + *) + case "$cur" in + *:*) + cur=$(echo "$cur" | sed 's/^.*://') + COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur")) + ;; + *) + local remote + case "${COMP_WORDS[0]}" in + git-fetch) remote="${COMP_WORDS[1]}" ;; + git) remote="${COMP_WORDS[2]}" ;; + esac + COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur")) + ;; + esac + ;; + esac +} + +_git_ls_remote () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) +} + +_git_ls_tree () +{ + __git_complete_file +} + +_git_log () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + *..*) + local pfx=$(echo "$cur" | sed 's/\.\..*$/../') + cur=$(echo "$cur" | sed 's/^.*\.\.//') + COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs .)" -- "$cur")) + ;; + *) + COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur")) + ;; + esac +} + +_git_merge_base () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur")) +} + +_git_pull () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "${COMP_WORDS[0]},$COMP_CWORD" in + git-pull*,1) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + git,2) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + *) + local remote + case "${COMP_WORDS[0]}" in + git-pull) remote="${COMP_WORDS[1]}" ;; + git) remote="${COMP_WORDS[2]}" ;; + esac + COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur")) + ;; + esac +} + +_git_push () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "${COMP_WORDS[0]},$COMP_CWORD" in + git-push*,1) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + git,2) + COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) + ;; + *) + case "$cur" in + *:*) + local remote + case "${COMP_WORDS[0]}" in + git-push) remote="${COMP_WORDS[1]}" ;; + git) remote="${COMP_WORDS[2]}" ;; + esac + cur=$(echo "$cur" | sed 's/^.*://') + COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur")) + ;; + *) + COMPREPLY=($(compgen -W "$(__git_refs2 .)" -- "$cur")) + ;; + esac + ;; + esac +} + +_git_show () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur")) +} + +_git () +{ + if [ $COMP_CWORD = 1 ]; then + COMPREPLY=($(compgen \ + -W "--version $(git help -a|egrep '^ ')" \ + -- "${COMP_WORDS[COMP_CWORD]}")) + else + case "${COMP_WORDS[1]}" in + branch) _git_branch ;; + cat-file) _git_cat_file ;; + checkout) _git_checkout ;; + diff) _git_diff ;; + diff-tree) _git_diff_tree ;; + fetch) _git_fetch ;; + log) _git_log ;; + ls-remote) _git_ls_remote ;; + ls-tree) _git_ls_tree ;; + pull) _git_pull ;; + push) _git_push ;; + show) _git_show ;; + show-branch) _git_log ;; + whatchanged) _git_log ;; + *) COMPREPLY=() ;; + esac + fi +} + +_gitk () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "--all $(__git_refs .)" -- "$cur")) +} + +complete -o default -o nospace -F _git git +complete -o default -F _gitk gitk +complete -o default -F _git_branch git-branch +complete -o default -o nospace -F _git_cat_file git-cat-file +complete -o default -F _git_checkout git-checkout +complete -o default -o nospace -F _git_diff git-diff +complete -o default -F _git_diff_tree git-diff-tree +complete -o default -o nospace -F _git_fetch git-fetch +complete -o default -o nospace -F _git_log git-log +complete -o default -F _git_ls_remote git-ls-remote +complete -o default -o nospace -F _git_ls_tree git-ls-tree +complete -o default -F _git_merge_base git-merge-base +complete -o default -o nospace -F _git_pull git-pull +complete -o default -o nospace -F _git_push git-push +complete -o default -F _git_show git-show +complete -o default -o nospace -F _git_log git-whatchanged + +# The following are necessary only for Cygwin, and only are needed +# when the user has tab-completed the executable name and consequently +# included the '.exe' suffix. +# +complete -o default -o nospace -F _git_cat_file git-cat-file.exe +complete -o default -o nospace -F _git_diff git-diff.exe +complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe +complete -o default -o nospace -F _git_log git-log.exe +complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe +complete -o default -F _git_merge_base git-merge-base.exe +complete -o default -o nospace -F _git_push git-push.exe +complete -o default -o nospace -F _git_log git-whatchanged.exe -- cgit v1.2.1 From 7b40e7d1ab20aebaac86b4586d48b6b645da57d1 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Mon, 25 Sep 2006 12:08:13 +0100 Subject: svnimport: add support for parsing From: lines for author When commiting a non-signed off contribution you cannot just add a Signed-off-by: from the author as they did not sign it off. But if you then commit it, and necessarily sign it off yourself, the change appears to be yours. In this case it is common to use the following form: Commentry From: originator Signed-of-by: me Now that we have support for parsing Signed-off-by: for author information it makes sense to handle From: as well. This patch adds a new -F which will handle From: lines in the comments. It may be used in combination with -S. Signed-off-by: Andy Whitcroft Signed-off-by: Junio C Hamano --- git-svnimport.perl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/git-svnimport.perl b/git-svnimport.perl index ed628974d..988514e29 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -31,7 +31,7 @@ $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T, - $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S); + $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F); sub usage() { print STDERR <\s*\n/) { + if ($opt_F && $message =~ /From:\s+(.*?)\s+<(.*)>\s*\n/) { ($author_name, $author_email) = ($1, $2); + print "Author from From: $1 <$2>\n" if ($opt_v);; + } elsif ($opt_S && $message =~ /Signed-off-by:\s+(.*?)\s+<(.*)>\s*\n/) { + ($author_name, $author_email) = ($1, $2); + print "Author from Signed-off-by: $1 <$2>\n" if ($opt_v);; } else { $author_name = $committer_name; $author_email = $committer_email; -- cgit v1.2.1 From c08e52486a7b5e38741c8264979a11f0103ec8c4 Mon Sep 17 00:00:00 2001 From: Matthias Lederhofer Date: Fri, 22 Sep 2006 13:12:01 +0200 Subject: format-patch: use cwd as default output directory Signed-off-by: Junio C Hamano --- builtin-log.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-log.c b/builtin-log.c index fbc58bbca..130b53a19 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -270,6 +270,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.extra_headers = extra_headers; + output_directory = prefix; + /* * Parse the arguments before setup_revisions(), or something * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is -- cgit v1.2.1 From 695dffe2efa53b9628e7811dbe33447a8014fd77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 28 Sep 2006 12:00:35 +0200 Subject: daemon: default to 256 for HOST_NAME_MAX if it is not defined Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- daemon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/daemon.c b/daemon.c index 5335d212c..fc3951cf7 100644 --- a/daemon.c +++ b/daemon.c @@ -15,6 +15,10 @@ #include "exec_cmd.h" #include "interpolate.h" +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 256 +#endif + static int log_syslog; static int verbose; static int reuseaddr; -- cgit v1.2.1 From 100690b6e8e9cc3cfe2c1d170192b5505d7a2ea8 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Thu, 28 Sep 2006 20:48:14 +0200 Subject: fix daemon.c compilation for NO_IPV6=1 Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.c b/daemon.c index fc3951cf7..ad8492873 100644 --- a/daemon.c +++ b/daemon.c @@ -834,7 +834,7 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p) #else /* NO_IPV6 */ -static int socksetup(char *lisen_addr, int listen_port, int **socklist_p) +static int socksetup(char *listen_addr, int listen_port, int **socklist_p) { struct sockaddr_in sin; int sockfd; -- cgit v1.2.1 From e92a54d99cb36eab6e29069fe3b135e6e6b24f12 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 28 Sep 2006 12:12:28 -0700 Subject: Clean up approxidate() in preparation for fixes Our approxidate cannot handle simple times like "5 PM yesterday", and to fix that, we will need to add some logic for number handling. This just splits that out into a function of its own (the same way the _real_ date parsing works). Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- date.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/date.c b/date.c index e387dcd39..4ff6604a0 100644 --- a/date.c +++ b/date.c @@ -712,6 +712,15 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num) return end; } +static const char *approxidate_digit(const char *date, struct tm *tm, int *num) +{ + char *end; + unsigned long number = strtoul(date, &end, 10); + + *num = number; + return end; +} + unsigned long approxidate(const char *date) { int number = 0; @@ -731,9 +740,7 @@ unsigned long approxidate(const char *date) break; date++; if (isdigit(c)) { - char *end; - number = strtoul(date-1, &end, 10); - date = end; + date = approxidate_digit(date-1, &tm, &number); continue; } if (isalpha(c)) -- cgit v1.2.1 From 393d340e4f4ae571cd48387c29c85e9ab098b098 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 28 Sep 2006 12:14:27 -0700 Subject: Fix approxidate() to understand more extended numbers You can now say "5:35 PM yesterday", and approxidate() gets the right answer. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- date.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/date.c b/date.c index 4ff6604a0..db4c18543 100644 --- a/date.c +++ b/date.c @@ -598,6 +598,32 @@ static void date_tea(struct tm *tm, int *num) date_time(tm, 17); } +static void date_pm(struct tm *tm, int *num) +{ + int hour = *num; + *num = 0; + + if (hour > 0 && hour < 12) { + tm->tm_hour = hour; + tm->tm_min = 0; + tm->tm_sec = 0; + } + if (tm->tm_hour > 0 && tm->tm_hour < 12) + tm->tm_hour += 12; +} + +static void date_am(struct tm *tm, int *num) +{ + int hour = *num; + *num = 0; + + if (hour > 0 && hour < 12) { + tm->tm_hour = hour; + tm->tm_min = 0; + tm->tm_sec = 0; + } +} + static const struct special { const char *name; void (*fn)(struct tm *, int *); @@ -606,6 +632,8 @@ static const struct special { { "noon", date_noon }, { "midnight", date_midnight }, { "tea", date_tea }, + { "PM", date_pm }, + { "AM", date_am }, { NULL } }; @@ -717,6 +745,18 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) char *end; unsigned long number = strtoul(date, &end, 10); + switch (*end) { + case ':': + case '.': + case '/': + case '-': + if (isdigit(end[1])) { + int match = match_multi_number(number, *end, date, end, tm); + if (match) + return date + match; + } + } + *num = number; return end; } -- cgit v1.2.1 From a28383770ec44357bfce4af834dc09bf14d9410e Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Thu, 28 Sep 2006 21:12:55 +0200 Subject: do not discard constness in interp_set_entry value argument Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- interpolate.c | 4 ++-- interpolate.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interpolate.c b/interpolate.c index 62701d843..5d9d1889f 100644 --- a/interpolate.c +++ b/interpolate.c @@ -8,10 +8,10 @@ #include "interpolate.h" -void interp_set_entry(struct interp *table, int slot, char *value) +void interp_set_entry(struct interp *table, int slot, const char *value) { char *oldval = table[slot].value; - char *newval = value; + char *newval = NULL; if (oldval) free(oldval); diff --git a/interpolate.h b/interpolate.h index a55fb8e07..190a180b5 100644 --- a/interpolate.h +++ b/interpolate.h @@ -16,7 +16,7 @@ struct interp { char *value; }; -extern void interp_set_entry(struct interp *table, int slot, char *value); +extern void interp_set_entry(struct interp *table, int slot, const char *value); extern void interp_clear_table(struct interp *table, int ninterps); extern int interpolate(char *result, int reslen, -- cgit v1.2.1 From 77e565d8f76357781eb6236e031e8e0581de83a9 Mon Sep 17 00:00:00 2001 From: Matthias Lederhofer Date: Thu, 28 Sep 2006 21:55:35 +0200 Subject: git-format-patch: fix bug using -o in subdirectories This was introduced by me in commit v1.4.2.1-gc08e524. Signed-off-by: Matthias Lederhofer Signed-off-by: Junio C Hamano --- builtin-log.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 130b53a19..9d1ceae44 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -270,8 +270,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.extra_headers = extra_headers; - output_directory = prefix; - /* * Parse the arguments before setup_revisions(), or something * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is @@ -350,6 +348,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; + if (!output_directory) + output_directory = prefix; + if (output_directory) { if (use_stdout) die("standard output, or directory, which one?"); -- cgit v1.2.1 From 6dd36acd32476a474a5b7d2ad309a82c84513abe Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:47:50 -0700 Subject: gitweb: "alternate" starts with shade (i.e. 1) When displaying a list of rows (difftree, shortlog, etc), the first entry is now printed shaded, i.e. alternate is initialized to 1, as opposed to non-shaded (alternate initialized to 0). This solves the problem when there is only one row to display -- it is displayed shaded to visually indicate that it is "active", part of a "list", etc. (Compare this to the trivial case of more than one entry, where the rows have alternating shade, thus suggesting being part of a "list" of "active" entries, etc.) Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c86ac1dd8..9550bd74e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1699,7 +1699,7 @@ sub git_difftree_body { print "\n"; print "
PrevDiffCommitLineData
CommitLineData
"; - print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, file_name=>$file_name)}, - esc_html(substr($parent, 0, 8))); - print ""; - print $cgi->a({-href => href(action=>"blobdiff", file_name=>$file_name, hash_parent_base=>$parent, - hash_base=>$full_rev)}, - esc_html("Diff")); - print "" . $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "" . esc_html($lineno) . "" . esc_html($data) . "
" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + print ""; + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, hash_base=>$hash, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})) . - "$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, - hash_base=>$hash, file_name=>$diff{'file'})}, - "blob"); + -class => "list"}, esc_html($diff{'file'})); + print "$mode_chng"; if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } print "" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, + print ""; + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, hash_base=>$parent, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})) . - "$mode_chng" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, - hash_base=>$parent, file_name=>$diff{'file'})}, - "blob") . - " | "; + -class => "list"}, esc_html($diff{'file'})); + print "$mode_chng"; if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); + print " | "; } print $cgi->a({-href => href(action=>"history", hash_base=>$parent, file_name=>$diff{'file'})}, - "history") . - ""; - if ($diff{'to_id'} ne $diff{'from_id'}) { # modified - print $cgi->a({-href => href(action=>"blobdiff", - hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, hash_parent_base=>$parent, - file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})); - } else { # only mode changed - print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, - hash_base=>$hash, file_name=>$diff{'file'}), - -class => "list"}, esc_html($diff{'file'})); - } - print "$mode_chnge" . - $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, - hash_base=>$hash, file_name=>$diff{'file'})}, - "blob"); + print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, + hash_base=>$hash, file_name=>$diff{'file'}), + -class => "list"}, esc_html($diff{'file'})); + print "$mode_chnge"; if ($diff{'to_id'} ne $diff{'from_id'}) { # modified if ($action eq 'commitdiff') { # link to patch $patchno++; - print " | " . - $cgi->a({-href => "#patch$patchno"}, "patch"); + print $cgi->a({-href => "#patch$patchno"}, "patch"); } else { - print " | " . - $cgi->a({-href => href(action=>"blobdiff", - hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, hash_parent_base=>$parent, - file_name=>$diff{'file'})}, - "diff"); + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'file'})}, + "diff"); } + print " | "; } - print " | " . - $cgi->a({-href => href(action=>"history", - hash_base=>$hash, file_name=>$diff{'file'})}, - "history"); + print $cgi->a({-href => href(action=>"history", + hash_base=>$hash, file_name=>$diff{'file'})}, + "history"); print "" . - $cgi->a({-href => href(action=>"blob", hash_base=>$hash, - hash=>$diff{'to_id'}, file_name=>$diff{'to_file'})}, - "blob"); + ""; if ($diff{'to_id'} ne $diff{'from_id'}) { if ($action eq 'commitdiff') { # link to patch -- cgit v1.2.1 From eb51ec9c05e6f4b29567f58102e33c453e1a9a57 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Wed, 27 Sep 2006 17:24:49 -0700 Subject: gitweb: Add history and blame to git_difftree_body() Add blame and history to Deleted files. Add blame and history to Modified or Type changed files. Add blame and history to Renamed or Copied files. This allows us to do blame->commit->blame->commit->blame->... instead of blame->commit->file->blame->commit->file->blame->... which is longer and easier to get wrong. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 88a8bcdbf..c86ac1dd8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1761,9 +1761,12 @@ sub git_difftree_body { print $cgi->a({-href => "#patch$patchno"}, "patch"); print " | "; } + print $cgi->a({-href => href(action=>"blame", hash_base=>$parent, + file_name=>$diff{'file'})}, + "blame") . " | "; print $cgi->a({-href => href(action=>"history", hash_base=>$parent, - file_name=>$diff{'file'})}, - "history"); + file_name=>$diff{'file'})}, + "history"); print "
\n"; - my $alternate = 0; + my $alternate = 1; my $patchno = 0; foreach my $line (@{$difftree}) { my %diff = parse_difftree_raw_line($line); @@ -1993,7 +1993,7 @@ sub git_shortlog_body { $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $commit = $revlist->[$i]; #my $ref = defined $refs ? format_ref_marker($refs, $commit) : ''; @@ -2035,7 +2035,7 @@ sub git_history_body { $to = $#{$revlist} unless (defined $to && $to <= $#{$revlist}); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { if ($revlist->[$i] !~ m/^([0-9a-fA-F]{40})/) { next; @@ -2099,7 +2099,7 @@ sub git_tags_body { $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $taglist->[$i]; my %tag = %$entry; @@ -2159,7 +2159,7 @@ sub git_heads_body { $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); print "
\n"; - my $alternate = 0; + my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; my %tag = %$entry; @@ -2275,7 +2275,7 @@ sub git_project_list { } print "\n" . "\n"; - my $alternate = 0; + my $alternate = 1; foreach my $pr (@projects) { if ($alternate) { print "\n"; @@ -2793,7 +2793,7 @@ sub git_tree { git_print_page_path($file_name, 'tree', $hash_base); print "
\n"; print "
\n"; - my $alternate = 0; + my $alternate = 1; foreach my $line (@entries) { my %t = parse_ls_tree_line($line, -z => 1); @@ -3389,7 +3389,7 @@ sub git_search { git_print_header_div('commit', esc_html($co{'title'}), $hash); print "
\n"; - my $alternate = 0; + my $alternate = 1; if ($commit_search) { $/ = "\0"; open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", $hash or next; -- cgit v1.2.1 From d1d866e9b8d5a6f0dbe490ba3467440bbf87feaf Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:48:40 -0700 Subject: gitweb: Remove redundant "commit" link from shortlog Remove the redundant "commit" link from shortlog. It can be had by simply clicking on the entry title of the row. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 1 - 1 file changed, 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9550bd74e..5ef4d07ca 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2013,7 +2013,6 @@ sub git_shortlog_body { href(action=>"commit", hash=>$commit), $ref); print "\n" . "\n" . -- cgit v1.2.1 From de9272f4bd029d0f331d154b59e64d160e6d1d14 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:49:21 -0700 Subject: gitweb: Factor out gitweb_have_snapshot() Create gitweb_have_snapshot() which returns true of snapshot is available and enabled, else false. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 5ef4d07ca..97b30aa5c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -155,6 +155,13 @@ sub feature_snapshot { return ($ctype, $suffix, $command); } +sub gitweb_have_snapshot { + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + + return $have_snapshot; +} + # To enable system wide have in $GITWEB_CONFIG # $feature{'pickaxe'}{'default'} = [1]; # To have project specific config enable override in $GITWEB_CONFIG @@ -2736,8 +2743,7 @@ sub git_blob { } sub git_tree { - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); - my $have_snapshot = (defined $ctype && defined $suffix); + my $have_snapshot = gitweb_have_snapshot(); if (!defined $hash) { $hash = git_get_head_hash($project); @@ -2813,7 +2819,6 @@ sub git_tree { } sub git_snapshot { - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); my $have_snapshot = (defined $ctype && defined $suffix); if (!$have_snapshot) { @@ -2923,8 +2928,7 @@ sub git_commit { my $refs = git_get_references(); my $ref = format_ref_marker($refs, $co{'id'}); - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); - my $have_snapshot = (defined $ctype && defined $suffix); + my $have_snapshot = gitweb_have_snapshot(); my @views_nav = (); if (defined $file_name && defined $co{'parent'}) { -- cgit v1.2.1 From ba6ef81017a84c2fce822b7ceba74f67dea6919e Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:50:09 -0700 Subject: gitweb: Add snapshot to shortlog Add snapshot to each commit-row of shortlog. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 97b30aa5c..8ad04570a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2021,7 +2021,8 @@ sub git_shortlog_body { print "\n" . "\n" . "\n"; } -- cgit v1.2.1 From a2a3bf7b2baf0ff64c5b5ffc78d54be82d9967f1 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 16:51:43 -0700 Subject: gitweb: Don't use quotemeta on internally generated strings Do not use quotemeta on internally generated strings such as filenames of snapshot, blobs, etc. quotemeta quotes any characters not matching /A-Za-z_0-9/. Which means that we get strings like this: before: linux\-2\.6\.git\-5c2d97cb31fb77981797fec46230ca005b865799\.tar\.gz after: linux-2.6.git-5c2d97cb31fb77981797fec46230ca005b865799.tar.gz This patch fixes this. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8ad04570a..a99e116a4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2660,7 +2660,7 @@ sub git_blob_plain { print $cgi->header( -type => "$type", -expires=>$expires, - -content_disposition => 'inline; filename="' . quotemeta($save_as) . '"'); + -content_disposition => 'inline; filename="' . "$save_as" . '"'); undef $/; binmode STDOUT, ':raw'; print <$fd>; @@ -2835,7 +2835,7 @@ sub git_snapshot { print $cgi->header( -type => 'application/x-tar', -content_encoding => $ctype, - -content_disposition => 'inline; filename="' . quotemeta($filename) . '"', + -content_disposition => 'inline; filename="' . "$filename" . '"', -status => '200 OK'); my $git_command = git_cmd_str(); @@ -2933,7 +2933,6 @@ sub git_commit { my @views_nav = (); if (defined $file_name && defined $co{'parent'}) { - my $parent = $co{'parent'}; push @views_nav, $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame"); @@ -3145,7 +3144,7 @@ sub git_blobdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => 'inline; filename="' . quotemeta($file_name) . '.patch"'); + -content_disposition => 'inline; filename="' . "$file_name" . '.patch"'); print "X-Git-Url: " . $cgi->self_url() . "\n\n"; @@ -3248,7 +3247,7 @@ sub git_commitdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => 'inline; filename="' . quotemeta($filename) . '"'); + -content_disposition => 'inline; filename="' . "$filename" . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); print < Date: Fri, 29 Sep 2006 03:10:44 +0300 Subject: http/ftp: optionally ask curl to not use EPSV command If http.noEPSV config variable is defined and true, or if GIT_CURL_FTP_NO_EPSV environment variable is defined, disable using of EPSV ftp command (PASV will be used instead). This is helpful with some "poor" ftp servers which does not support EPSV mode. Signed-off-by: Sasha Khapyorsky Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 ++++++ git-clone.sh | 4 ++++ git-fetch.sh | 6 +++++- git-ls-remote.sh | 4 ++++ http.c | 12 ++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 98c1f3e2e..84e38911e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -202,6 +202,12 @@ http.lowSpeedLimit, http.lowSpeedTime:: Can be overridden by the 'GIT_HTTP_LOW_SPEED_LIMIT' and 'GIT_HTTP_LOW_SPEED_TIME' environment variables. +http.noEPSV:: + A boolean which disables using of EPSV ftp command by curl. + This can helpful with some "poor" ftp servers which doesn't + support EPSV mode. Can be overridden by the 'GIT_CURL_FTP_NO_EPSV' + environment variable. Default is false (curl will use EPSV). + i18n.commitEncoding:: Character encoding the commit messages are stored in; git itself does not care per se, but this information is necessary e.g. when diff --git a/git-clone.sh b/git-clone.sh index e1b3bf382..3998c55ce 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -31,6 +31,10 @@ clone_dumb_http () { cd "$2" && clone_tmp="$GIT_DIR/clone-tmp" && mkdir -p "$clone_tmp" || exit 1 + if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ + "`git-repo-config --bool http.noEPSV`" = true ]; then + curl_extra_args="${curl_extra_args} --disable-epsv" + fi http_fetch "$1/info/refs" "$clone_tmp/refs" || { echo >&2 "Cannot get remote repository information. Perhaps git-update-server-info needs to be run there?" diff --git a/git-fetch.sh b/git-fetch.sh index 50ad101e8..bcc67ab0b 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -289,6 +289,10 @@ fetch_main () { if [ -n "$GIT_SSL_NO_VERIFY" ]; then curl_extra_args="-k" fi + if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ + "`git-repo-config --bool http.noEPSV`" = true ]; then + noepsv_opt="--disable-epsv" + fi max_depth=5 depth=0 head="ref: $remote_name" @@ -300,7 +304,7 @@ fetch_main () { $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; print "$u"; ' "$head") - head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") + head=$(curl -nsfL $curl_extra_args $noepsv_opt "$remote/$remote_name_quoted") depth=$( expr \( $depth + 1 \) ) done expr "z$head" : "z$_x40\$" >/dev/null || diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 2c0b52122..0f88953f2 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -53,6 +53,10 @@ http://* | https://* | ftp://* ) if [ -n "$GIT_SSL_NO_VERIFY" ]; then curl_extra_args="-k" fi + if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ + "`git-repo-config --bool http.noEPSV`" = true ]; then + curl_extra_args="${curl_extra_args} --disable-epsv" + fi curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" || echo "failed slurping" ;; diff --git a/http.c b/http.c index 6c1937b67..576740fef 100644 --- a/http.c +++ b/http.c @@ -23,6 +23,7 @@ char *ssl_capath = NULL; char *ssl_cainfo = NULL; long curl_low_speed_limit = -1; long curl_low_speed_time = -1; +int curl_ftp_no_epsv = 0; struct curl_slist *pragma_header; @@ -155,6 +156,11 @@ static int http_options(const char *var, const char *value) return 0; } + if (!strcmp("http.noepsv", var)) { + curl_ftp_no_epsv = git_config_bool(var, value); + return 0; + } + /* Fall back on the default ones */ return git_default_config(var, value); } @@ -196,6 +202,9 @@ static CURL* get_curl_handle(void) curl_easy_setopt(result, CURLOPT_USERAGENT, GIT_USER_AGENT); + if (curl_ftp_no_epsv) + curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0); + return result; } @@ -251,6 +260,9 @@ void http_init(void) max_requests = DEFAULT_MAX_REQUESTS; #endif + if (getenv("GIT_CURL_FTP_NO_EPSV")) + curl_ftp_no_epsv = 1; + #ifndef NO_CURL_EASY_DUPHANDLE curl_default = get_curl_handle(); #endif -- cgit v1.2.1 From e46b3c027e7953bccbfe26910ff8c2d43225a17c Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 17:20:23 -0700 Subject: gitweb: Remove redundant "commit" from history Remove redundant "commit" from history -- it can be had by clicking on the title of the commit. This commit makes visualization consistent with shortlog, log, etc. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 1 - 1 file changed, 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a99e116a4..caaa371d0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2071,7 +2071,6 @@ sub git_history_body { href(action=>"commit", hash=>$commit), $ref); print "\n" . "\n" . "\n"; } elsif ($t->{'type'} eq "tree") { @@ -2745,14 +2745,14 @@ sub git_blob { sub git_tree { my $have_snapshot = gitweb_have_snapshot(); + if (!defined $hash_base) { + $hash_base = "HEAD"; + } if (!defined $hash) { - $hash = git_get_head_hash($project); if (defined $file_name) { - my $base = $hash_base || $hash; - $hash = git_get_hash_by_path($base, $file_name, "tree"); - } - if (!defined $hash_base) { - $hash_base = $hash; + $hash = git_get_hash_by_path($hash_base, $file_name, "tree"); + } else { + $hash = $hash_base; } } $/ = "\0"; -- cgit v1.2.1 From 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=1B=2CAi=1B=28Bjar?= Date: Sun, 1 Oct 2006 05:33:05 +0200 Subject: fetch: Misc output cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In particular it removes duplicate information, uses short hashes (as git-log and company) and uses .. for fast forwarding commits and ... for not-fast-forwarding commits (shorter, easier to copy&paste). It also reformat the output as: 1. the ones we store in our local ref (either branches or tags): 1a) fast-forward * refs/heads/origin: fast forward to branch 'master' of ../git/ old..new: 1ad7a06..bc1a580 1b) same (only shown under -v) * refs/heads/next: same as branch 'origin/next' of ../git/ commit: ce47b9f 1c) non-fast-forward, forced * refs/heads/pu: forcing update to non-fast forward branch 'pu' of ../git/ old...new: 7c733a8...5faa935 1d) non-fast-forward, did not update because not forced * refs/heads/po: not updating to non-fast forward branch 'po' of ../git/ old...new: 7c733a8...5faa935 1e) creating a new local ref to store * refs/tags/v1.4.2-rc4: storing tag 'v1.4.2-rc4' of ../git/ tag: 8c7a107 * refs/heads/next: storing branch 'next' of ../git/ commit: f8a20ae 2. the ones we do not store in our local ref (only shown under -v): * fetched branch 'master' of ../git commit: 695dffe * fetched tag 'v1.4.2-rc4' of ../git tag: 8c7a107 Signed-off-by: Santi B.ANijar Signed-off-by: Junio C Hamano --- git-fetch.sh | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/git-fetch.sh b/git-fetch.sh index f1522bd49..85e96a1cc 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -129,22 +129,25 @@ append_fetch_head () { then headc_=$(git-rev-parse --verify "$head_^0") || exit echo "$headc_ $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD" - [ "$verbose" ] && echo >&2 "* committish: $head_" - [ "$verbose" ] && echo >&2 " $note_" else echo "$head_ not-for-merge $note_" >>"$GIT_DIR/FETCH_HEAD" - [ "$verbose" ] && echo >&2 "* non-commit: $head_" - [ "$verbose" ] && echo >&2 " $note_" - fi - if test "$local_name_" != "" - then - # We are storing the head locally. Make sure that it is - # a fast forward (aka "reverse push"). - fast_forward_local "$local_name_" "$head_" "$note_" fi + + update_local_ref "$local_name_" "$head_" "$note_" } -fast_forward_local () { +update_local_ref () { + # If we are storing the head locally make sure that it is + # a fast forward (aka "reverse push"). + + label_=$(git-cat-file -t $2) + newshort_=$(git-rev-parse --short $2) + if test -z "$1" ; then + [ "$verbose" ] && echo >&2 "* fetched $3" + [ "$verbose" ] && echo >&2 " $label_: $newshort_" + return 0 + fi + oldshort_=$(git-rev-parse --short "$1" 2>/dev/null) mkdir -p "$(dirname "$GIT_DIR/$1")" case "$1" in refs/tags/*) @@ -154,13 +157,16 @@ fast_forward_local () { then if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2" then - [ "$verbose" ] && echo >&2 "* $1: same as $3" ||: + [ "$verbose" ] && echo >&2 "* $1: same as $3" + [ "$verbose" ] && echo >&2 " $label_: $newshort_" ||: else echo >&2 "* $1: updating with $3" + echo >&2 " $label_: $newshort_" git-update-ref -m "$rloga: updating tag" "$1" "$2" fi else echo >&2 "* $1: storing $3" + echo >&2 " $label_: $newshort_" git-update-ref -m "$rloga: storing tag" "$1" "$2" fi ;; @@ -178,31 +184,34 @@ fast_forward_local () { if test -n "$verbose" then echo >&2 "* $1: same as $3" + echo >&2 " $label_: $newshort_" fi ;; *,$local) echo >&2 "* $1: fast forward to $3" - echo >&2 " from $local to $2" + echo >&2 " old..new: $oldshort_..$newshort_" git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local" ;; *) false ;; esac || { - echo >&2 "* $1: does not fast forward to $3;" case ",$force,$single_force," in *,t,*) - echo >&2 " forcing update." + echo >&2 "* $1: forcing update to non-fast forward $3" + echo >&2 " old...new: $oldshort_...$newshort_" git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local" ;; *) - echo >&2 " not updating." + echo >&2 "* $1: not updating to non-fast forward $3" + echo >&2 " old...new: $oldshort_...$newshort_" exit 1 ;; esac } else echo >&2 "* $1: storing $3" + echo >&2 " $label_: $newshort_" git-update-ref -m "$rloga: storing head" "$1" "$2" fi ;; -- cgit v1.2.1 From ba0ac36ec5708820e670731001f7ab35351c6c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= Date: Sun, 1 Oct 2006 05:34:17 +0200 Subject: merge and resolve: Output short hashes and .. in "Updating ..." MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- git-merge.sh | 2 +- git-resolve.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git-merge.sh b/git-merge.sh index 5b34b4de9..49c46d55d 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -197,7 +197,7 @@ f,*) ;; ?,1,"$head",*) # Again the most common case of merging one remote. - echo "Updating from $head to $1" + echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)" git-update-index --refresh 2>/dev/null new_head=$(git-rev-parse --verify "$1^0") && git-read-tree -u -v -m $head "$new_head" && diff --git a/git-resolve.sh b/git-resolve.sh index 729ec65dc..36b90e384 100755 --- a/git-resolve.sh +++ b/git-resolve.sh @@ -46,7 +46,7 @@ case "$common" in exit 0 ;; "$head") - echo "Updating from $head to $merge" + echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $merge)" git-read-tree -u -m $head $merge || exit 1 git-update-ref -m "resolve $merge_name: Fast forward" \ HEAD "$merge" "$head" -- cgit v1.2.1
" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); print "" . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . - $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); + $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . " | " . + $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot"); print "
" . - $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype); -- cgit v1.2.1 From 6d81c5a2ea6e0b11fdee87d61d073850c17ce6d8 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 28 Sep 2006 17:21:07 -0700 Subject: gitweb: History: blob and tree are first, then commitdiff, etc Reorder link display in history to be consistent with other list displays: log, shortlog, etc. We now display: blob | commitdiff blob | commitdiff | diff_to_current and tree | commitdiff Instead of the old history format where "blob" and "tree" are between "commitdiff" and "diff_to_current" if present/ applicable. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index caaa371d0..c8557c85c 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2071,8 +2071,8 @@ sub git_history_body { href(action=>"commit", hash=>$commit), $ref); print "" . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . - $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype); + $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype) . " | " . + $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff"); if ($ftype eq 'blob') { my $blob_current = git_get_hash_by_path($hash_base, $file_name); -- cgit v1.2.1 From 5c5b2ea9ab95f71ac155f12d75d1432b5c93c2bb Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 28 Sep 2006 15:07:16 -0700 Subject: diff --stat=width[,name-width]: allow custom diffstat output width. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 7 +++++-- diff.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index b5d976359..7b7b9e8ce 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -10,8 +10,11 @@ --patch-with-raw:: Synonym for "-p --raw". ---stat:: - Generate a diffstat. +--stat[=width[,name-width]]:: + Generate a diffstat. You can override the default + output width for 80-column terminal by "--stat=width". + The width of the filename part can be controlled by + giving another width to it separated by a comma. --summary:: Output a condensed summary of extended header information diff --git a/diff.c b/diff.c index 3fd7a5220..90e084410 100644 --- a/diff.c +++ b/diff.c @@ -1735,15 +1735,32 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--patch-with-raw")) { options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW; } - else if (!strcmp(arg, "--stat")) - options->output_format |= DIFF_FORMAT_DIFFSTAT; - else if (!strncmp(arg, "--stat-width=", 13)) { - options->stat_width = strtoul(arg + 13, NULL, 10); - options->output_format |= DIFF_FORMAT_DIFFSTAT; - } - else if (!strncmp(arg, "--stat-name-width=", 18)) { - options->stat_name_width = strtoul(arg + 18, NULL, 10); + else if (!strncmp(arg, "--stat", 6)) { + char *end; + int width = options->stat_width; + int name_width = options->stat_name_width; + arg += 6; + end = (char *)arg; + + switch (*arg) { + case '-': + if (!strncmp(arg, "-width=", 7)) + width = strtoul(arg + 7, &end, 10); + else if (!strncmp(arg, "-name-width=", 12)) + name_width = strtoul(arg + 12, &end, 10); + break; + case '=': + width = strtoul(arg+1, &end, 10); + if (*end == ',') + name_width = strtoul(end+1, &end, 10); + } + + /* Important! This checks all the error cases! */ + if (*end) + return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; + options->stat_name_width = name_width; + options->stat_width = width; } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; -- cgit v1.2.1 From 3ed74e608a69ce0f10bfad2e4ef6cf99eec04613 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 28 Sep 2006 17:37:39 +0200 Subject: diff --stat: ensure at least one '-' for deletions, and one '+' for additions The number of '-' and '+' is still linear. The idea is that scaled-length := floor(a * length + b) with the following constraints: if length == 1, scaled-length == 1, and the combined length of plusses and minusses should not be larger than the width by a small margin. Thus, a + b == 1 and a * max_plusses + b + a * max_minusses + b = width + 1 The solution is a * x + b = ((width - 1) * (x - 1) + max_change - 1) / (max_change - 1) Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/diff.c b/diff.c index 90e084410..2df085f3c 100644 --- a/diff.c +++ b/diff.c @@ -550,9 +550,12 @@ const char mime_boundary_leader[] = "------------"; static int scale_linear(int it, int width, int max_change) { /* - * round(width * it / max_change); + * make sure that at least one '-' is printed if there were deletions, + * and likewise for '+'. */ - return (it * width * 2 + max_change) / (max_change * 2); + if (max_change < 2) + return it; + return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1); } static void show_name(const char *prefix, const char *name, int len, @@ -684,9 +687,9 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) dels += del; if (width <= max_change) { - total = scale_linear(total, width, max_change); add = scale_linear(add, width, max_change); - del = total - add; + del = scale_linear(del, width, max_change); + total = add + del; } show_name(prefix, name, len, reset, set); printf("%5d ", added + deleted); -- cgit v1.2.1 From 21ff2bdb887c836aab3346bbfa6a3e0251ff6104 Mon Sep 17 00:00:00 2001 From: Robin Rosenberg Date: Fri, 29 Sep 2006 01:28:55 +0200 Subject: Make cvsexportcommit remove files. Signed-off-by: Robin Rosenberg Signed-off-by: Junio C Hamano --- git-cvsexportcommit.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index 99b3dc392..5e23851f8 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -135,7 +135,7 @@ foreach my $f (@files) { if ($fields[4] eq 'M') { push @mfiles, $fields[5]; } - if ($fields[4] eq 'R') { + if ($fields[4] eq 'D') { push @dfiles, $fields[5]; } } -- cgit v1.2.1 From bc1a5807575b2f34538d4158834da6524a4fc1f7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 29 Sep 2006 02:06:24 -0700 Subject: git-diff -B output fix. Geert noticed that complete rewrite diff missed the usual a/ and b/ leading paths. Pickaxe says it never worked, ever. Embarrassing. Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff.c b/diff.c index 2464238cc..17f5a911d 100644 --- a/diff.c +++ b/diff.c @@ -208,7 +208,7 @@ static void emit_rewrite_diff(const char *name_a, diff_populate_filespec(two, 0); lc_a = count_lines(one->data, one->size); lc_b = count_lines(two->data, two->size); - printf("--- %s\n+++ %s\n@@ -", name_a, name_b); + printf("--- a/%s\n+++ b/%s\n@@ -", name_a, name_b); print_line_count(lc_a); printf(" +"); print_line_count(lc_b); -- cgit v1.2.1 From 18b633cafcd43b83d752738fea62f185d4de1b91 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 29 Sep 2006 12:36:13 -0700 Subject: Fix approxidate() to understand 12:34 AM/PM are 00:34 and 12:34 It just simplifies the whole thing to say "hour = (hour % 12) + X" where X is 12 for PM and 0 for AM. It also fixes the "exact date" parsing, which didn't parse AM at all, and as such would do the same "12:30 AM" means "12:30 24-hour-format" bug. Of course, I hope that no exact dates use AM/PM anyway, but since we support the PM format, let's just get it right. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- date.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/date.c b/date.c index db4c18543..182592273 100644 --- a/date.c +++ b/date.c @@ -256,8 +256,12 @@ static int match_alpha(const char *date, struct tm *tm, int *offset) } if (match_string(date, "PM") == 2) { - if (tm->tm_hour > 0 && tm->tm_hour < 12) - tm->tm_hour += 12; + tm->tm_hour = (tm->tm_hour % 12) + 12; + return 2; + } + + if (match_string(date, "AM") == 2) { + tm->tm_hour = (tm->tm_hour % 12) + 0; return 2; } @@ -600,28 +604,30 @@ static void date_tea(struct tm *tm, int *num) static void date_pm(struct tm *tm, int *num) { - int hour = *num; + int hour, n = *num; *num = 0; - if (hour > 0 && hour < 12) { - tm->tm_hour = hour; + hour = tm->tm_hour; + if (n) { + hour = n; tm->tm_min = 0; tm->tm_sec = 0; } - if (tm->tm_hour > 0 && tm->tm_hour < 12) - tm->tm_hour += 12; + tm->tm_hour = (hour % 12) + 12; } static void date_am(struct tm *tm, int *num) { - int hour = *num; + int hour, n = *num; *num = 0; - if (hour > 0 && hour < 12) { - tm->tm_hour = hour; + hour = tm->tm_hour; + if (n) { + hour = n; tm->tm_min = 0; tm->tm_sec = 0; } + tm->tm_hour = (hour % 12); } static const struct special { -- cgit v1.2.1 From 4839bd8a6605e0c9c5c68ddec40d2a1a5ddd57d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= Date: Fri, 29 Sep 2006 20:05:40 +0200 Subject: fetch: Reset remote refs list each time fetch_main is called MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents the fetch of the heads again in the second call of fetch_main. Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- git-fetch.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-fetch.sh b/git-fetch.sh index bcc67ab0b..f1522bd49 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -257,6 +257,7 @@ fi fetch_main () { reflist="$1" refs= + rref= for ref in $reflist do -- cgit v1.2.1 From 6f7ea5fb333554887656f7f6ec683544ec6e3c22 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Fri, 29 Sep 2006 09:57:43 -0700 Subject: gitweb: tree view: hash_base and hash are now context sensitive In tree view, by default, hash_base is HEAD and hash is the entry equivalent. Else the user had selected a hash_base or hash, say by clicking on a revision or commit, in which case those values are used. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c8557c85c..a3c3e7471 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1672,9 +1672,9 @@ sub git_print_tree_entry { "history"); } print " | " . - $cgi->a({-href => href(action=>"blob_plain", - hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, - "raw"); + $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hash_base, + file_name=>"$basedir$t->{'name'}")}, + "raw"); print "