Merge branch 'cc/trace' into next

* cc/trace:
  Trace into open fd and refactor tracing code.
  t5710: fix two thinkos.
  gitweb: Extend parse_difftree_raw_line to save commit info
  gitweb: Separate printing of git_tree row into git_print_tree_entry
  gitweb: Move git-ls-tree output parsing to parse_ls_tree_line
  use do() instead of require() to include configuration
  gitweb: Remove forgotten call to git_to_hash
  log-tree.c: cleanup a bit append_signoff()
  Remove uneeded #include
  Makefile: fix typo
  unpack-objects: remove unused variable "eof"
  git-fsck-objects: lacking default references should not be fatal
  Check if pack directory exists prior to descending into it
This commit is contained in:
Junio C Hamano
2006-08-31 14:17:00 -07:00
18 changed files with 371 additions and 175 deletions

View File

@@ -260,7 +260,7 @@ LIB_OBJS = \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
write_or_die.o \
write_or_die.o trace.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)
BUILTIN_OBJS = \
@@ -514,7 +514,7 @@ ifdef NO_SETENV
COMPAT_CFLAGS += -DNO_SETENV
COMPAT_OBJS += compat/setenv.o
endif
ifdef NO_SETENV
ifdef NO_UNSETENV
COMPAT_CFLAGS += -DNO_UNSETENV
COMPAT_OBJS += compat/unsetenv.o
endif

View File

@@ -15,7 +15,7 @@ static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];
static unsigned long offset, len, eof;
static unsigned long offset, len;
static SHA_CTX ctx;
/*
@@ -26,8 +26,6 @@ static void * fill(int min)
{
if (min <= len)
return buffer + offset;
if (eof)
die("unable to fill input");
if (min > sizeof(buffer))
die("cannot fill %d bytes", min);
if (offset) {

View File

@@ -401,6 +401,7 @@ extern char git_commit_encoding[MAX_ENCODING_LENGTH];
extern int copy_fd(int ifd, int ofd);
extern void write_or_die(int fd, const void *buf, size_t count);
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
/* Finish off pack transfer receiving end */
extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int);
@@ -426,4 +427,9 @@ extern struct commit *alloc_commit_node(void);
extern struct tag *alloc_tag_node(void);
extern void alloc_report(void);
/* trace.c */
extern int nfvasprintf(char **str, const char *fmt, va_list va);
extern void trace_printf(const char *format, ...);
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
#endif /* CACHE_H */

View File

@@ -97,26 +97,12 @@ int execv_git_cmd(const char **argv)
tmp = argv[0];
argv[0] = git_command;
if (getenv("GIT_TRACE")) {
const char **p = argv;
fputs("trace: exec:", stderr);
while (*p) {
fputc(' ', stderr);
sq_quote_print(stderr, *p);
++p;
}
putc('\n', stderr);
fflush(stderr);
}
trace_argv_printf(argv, -1, "trace: exec:");
/* execve() can only ever return if it fails */
execve(git_command, (char **)argv, environ);
if (getenv("GIT_TRACE")) {
fprintf(stderr, "trace: exec failed: %s\n",
strerror(errno));
fflush(stderr);
}
trace_printf("trace: exec failed: %s\n", strerror(errno));
argv[0] = tmp;
}

View File

@@ -425,8 +425,23 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
static void get_default_heads(void)
{
for_each_ref(fsck_handle_ref);
if (!default_refs)
die("No default references");
/*
* Not having any default heads isn't really fatal, but
* it does mean that "--unreachable" no longer makes any
* sense (since in this case everything will obviously
* be unreachable by definition.
*
* Showing dangling objects is valid, though (as those
* dangling objects are likely lost heads).
*
* So we just print a warning about it, and clear the
* "show_unreachable" flag.
*/
if (!default_refs) {
error("No default references");
show_unreachable = 0;
}
}
static void fsck_object_dir(const char *path)

View File

@@ -38,7 +38,7 @@ case ",$all_into_one," in
pack_objects=
# Redundancy check in all-into-one case is trivial.
existing=`cd "$PACKDIR" && \
existing=`test -d "$PACKDIR" && cd "$PACKDIR" && \
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
;;
esac

25
git.c
View File

@@ -179,17 +179,9 @@ static int handle_alias(int *argcp, const char ***argv)
if (!strcmp(alias_command, new_argv[0]))
die("recursive alias: %s", alias_command);
if (getenv("GIT_TRACE")) {
int i;
fprintf(stderr, "trace: alias expansion: %s =>",
alias_command);
for (i = 0; i < count; ++i) {
fputc(' ', stderr);
sq_quote_print(stderr, new_argv[i]);
}
fputc('\n', stderr);
fflush(stderr);
}
trace_argv_printf(new_argv, count,
"trace: alias expansion: %s =>",
alias_command);
new_argv = xrealloc(new_argv, sizeof(char*) *
(count + *argcp + 1));
@@ -292,16 +284,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
prefix = setup_git_directory();
if (p->option & USE_PAGER)
setup_pager();
if (getenv("GIT_TRACE")) {
int j;
fprintf(stderr, "trace: built-in: git");
for (j = 0; j < argc; ++j) {
fputc(' ', stderr);
sq_quote_print(stderr, argv[j]);
}
putc('\n', stderr);
fflush(stderr);
}
trace_argv_printf(argv, argc, "trace: built-in: git");
exit(p->fn(argc, argv, prefix));
}

View File

@@ -152,7 +152,7 @@ sub feature_snapshot {
our @diff_opts = ('-M'); # taken from git_commit
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
# version of the core git binary
our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
@@ -1027,9 +1027,30 @@ sub parse_difftree_raw_line {
}
}
# 'c512b523472485aef4fff9e57b229d9d243c967f'
#elsif ($line =~ m/^([0-9a-fA-F]{40})$/) {
# $res{'commit'} = $1;
#}
elsif ($line =~ m/^([0-9a-fA-F]{40})$/) {
$res{'commit'} = $1;
}
return wantarray ? %res : \%res;
}
# parse line of git-ls-tree output
sub parse_ls_tree_line ($;%) {
my $line = shift;
my %opts = @_;
my %res;
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
$res{'mode'} = $1;
$res{'type'} = $2;
$res{'hash'} = $3;
if ($opts{'-z'}) {
$res{'name'} = $4;
} else {
$res{'name'} = unquote($4);
}
return wantarray ? %res : \%res;
}
@@ -1454,6 +1475,62 @@ sub git_print_simplified_log {
-remove_title => $remove_title);
}
# print tree entry (row of git_tree), but without encompassing <tr> element
sub git_print_tree_entry {
my ($t, $basedir, $hash_base, $have_blame) = @_;
my %base_key = ();
$base_key{hash_base} = $hash_base if defined $hash_base;
print "<td class=\"mode\">" . mode_str($t->{'mode'}) . "</td>\n";
if ($t->{'type'} eq "blob") {
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key),
-class => "list"}, esc_html($t->{'name'})) .
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
"blob");
if ($have_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,
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") .
"</td>\n";
} elsif ($t->{'type'} eq "tree") {
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
esc_html($t->{'name'})) .
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
"tree");
if (defined $hash_base) {
print " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
file_name=>"$basedir$t->{'name'}")},
"history");
}
print "</td>\n";
}
}
## ......................................................................
## functions printing large fragments of HTML
@@ -2492,14 +2569,13 @@ sub git_tree {
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $hash_base);
git_header_html();
my %base_key = ();
my $base = "";
my $have_blame = gitweb_check_feature('blame');
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
$base_key{hash_base} = $hash_base;
git_print_page_nav('tree','', $hash_base);
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
} else {
undef $hash_base;
print "<div class=\"page_nav\">\n";
print "<br/><br/></div>\n";
print "<div class=\"title\">$hash</div>\n";
@@ -2512,54 +2588,17 @@ sub git_tree {
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
foreach my $line (@entries) {
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
my $t_mode = $1;
my $t_type = $2;
my $t_hash = $3;
my $t_name = validate_input($4);
my %t = parse_ls_tree_line($line, -z => 1);
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
print "<tr class=\"light\">\n";
}
$alternate ^= 1;
print "<td class=\"mode\">" . mode_str($t_mode) . "</td>\n";
if ($t_type eq "blob") {
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key),
-class => "list"}, esc_html($t_name)) .
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t_hash, file_name=>"$base$t_name", %base_key)},
"blob");
if ($have_blame) {
print " | " .
$cgi->a({-href => href(action=>"blame", hash=>$t_hash, file_name=>"$base$t_name", %base_key)},
"blame");
}
print " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
hash=>$t_hash, file_name=>"$base$t_name")},
"history") .
" | " .
$cgi->a({-href => href(action=>"blob_plain",
hash=>$t_hash, file_name=>"$base$t_name")},
"raw") .
"</td>\n";
} elsif ($t_type eq "tree") {
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)},
esc_html($t_name)) .
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"tree", hash=>$t_hash, file_name=>"$base$t_name", %base_key)},
"tree") .
" | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$base$t_name")},
"history") .
"</td>\n";
}
git_print_tree_entry(\%t, $base, $hash_base, $have_blame);
print "</tr>\n";
}
print "</table>\n" .
@@ -2778,10 +2817,6 @@ sub git_blobdiff {
@difftree
or die_error('404 Not Found', "Blob diff not found");
} elsif (defined $hash) { # try to find filename from $hash
if ($hash !~ /[0-9a-fA-F]{40}/) {
$hash = git_to_hash($hash);
}
} elsif (defined $hash &&
$hash =~ /[0-9a-fA-F]{40}/) {
# try to find filename from $hash

View File

@@ -110,7 +110,6 @@ static char *next_arg( char ** );
static void free_generic_messages( message_t * );
static int nfvasprintf( char **str, const char *fmt, va_list va );
static int nfsnprintf( char *buf, int blen, const char *fmt, ... );
@@ -371,21 +370,6 @@ free_generic_messages( message_t *msgs )
}
}
static int
git_vasprintf( char **strp, const char *fmt, va_list ap )
{
int len;
char tmp[1024];
if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = xmalloc( len + 1 )))
return -1;
if (len >= (int)sizeof(tmp))
vsprintf( *strp, fmt, ap );
else
memcpy( *strp, tmp, len + 1 );
return len;
}
static int
nfsnprintf( char *buf, int blen, const char *fmt, ... )
{
@@ -399,15 +383,6 @@ nfsnprintf( char *buf, int blen, const char *fmt, ... )
return ret;
}
static int
nfvasprintf( char **str, const char *fmt, va_list va )
{
int ret = git_vasprintf( str, fmt, va );
if (ret < 0)
die( "Fatal: Out of memory\n");
return ret;
}
static struct {
unsigned char i, j, s[256];
} rs;

View File

@@ -12,10 +12,58 @@ static void show_parents(struct commit *commit, int abbrev)
}
}
/*
* Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
* Signed-off-by: and Acked-by: lines.
*/
static int detect_any_signoff(char *letter, int size)
{
char ch, *cp;
int seen_colon = 0;
int seen_at = 0;
int seen_name = 0;
int seen_head = 0;
cp = letter + size;
while (letter <= --cp && (ch = *cp) == '\n')
continue;
while (letter <= cp) {
ch = *cp--;
if (ch == '\n')
break;
if (!seen_at) {
if (ch == '@')
seen_at = 1;
continue;
}
if (!seen_colon) {
if (ch == '@')
return 0;
else if (ch == ':')
seen_colon = 1;
else
seen_name = 1;
continue;
}
if (('A' <= ch && ch <= 'Z') ||
('a' <= ch && ch <= 'z') ||
ch == '-') {
seen_head = 1;
continue;
}
/* no empty last line doesn't match */
return 0;
}
return seen_head && seen_name;
}
static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
{
int signoff_len = strlen(signoff);
static const char signed_off_by[] = "Signed-off-by: ";
int signoff_len = strlen(signoff);
int has_signoff = 0;
char *cp = buf;
/* Do we have enough space to add it? */
@@ -23,58 +71,26 @@ static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
return at;
/* First see if we already have the sign-off by the signer */
while (1) {
cp = strstr(cp, signed_off_by);
if (!cp)
break;
while ((cp = strstr(cp, signed_off_by))) {
has_signoff = 1;
cp += strlen(signed_off_by);
if ((cp + signoff_len < buf + at) &&
!strncmp(cp, signoff, signoff_len) &&
isspace(cp[signoff_len]))
return at; /* we already have him */
if (cp + signoff_len >= buf + at)
break;
if (strncmp(cp, signoff, signoff_len))
continue;
if (!isspace(cp[signoff_len]))
continue;
/* we already have him */
return at;
}
/* Does the last line already end with "^[-A-Za-z]+: [^@]+@"?
* If not, add a blank line to separate the message from
* the run of Signed-off-by: and Acked-by: lines.
*/
{
char ch;
int seen_colon, seen_at, seen_name, seen_head, not_signoff;
seen_colon = 0;
seen_at = 0;
seen_name = 0;
seen_head = 0;
not_signoff = 0;
cp = buf + at;
while (buf <= --cp && (ch = *cp) == '\n')
;
while (!not_signoff && buf <= cp && (ch = *cp--) != '\n') {
if (!seen_at) {
if (ch == '@')
seen_at = 1;
continue;
}
if (!seen_colon) {
if (ch == '@')
not_signoff = 1;
else if (ch == ':')
seen_colon = 1;
else
seen_name = 1;
continue;
}
if (('A' <= ch && ch <= 'Z') ||
('a' <= ch && ch <= 'z') ||
ch == '-') {
seen_head = 1;
continue;
}
not_signoff = 1;
}
if (not_signoff || !seen_head || !seen_name)
buf[at++] = '\n';
}
if (!has_signoff)
has_signoff = detect_any_signoff(buf, at);
if (!has_signoff)
buf[at++] = '\n';
strcpy(buf + at, signed_off_by);
at += strlen(signed_off_by);

View File

@@ -1,7 +1,6 @@
#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
#include <sys/wait.h>
static const char peek_remote_usage[] =
"git-peek-remote [--exec=upload-pack] [host:]directory";

32
quote.c
View File

@@ -74,6 +74,38 @@ char *sq_quote(const char *src)
return buf;
}
char *sq_quote_argv(const char** argv, int count)
{
char *buf, *to;
int i;
size_t len = 0;
/* Count argv if needed. */
if (count < 0) {
for (count = 0; argv[count]; count++)
; /* just counting */
}
/* Special case: no argv. */
if (!count)
return xcalloc(1,1);
/* Get destination buffer length. */
for (i = 0; i < count; i++)
len += sq_quote_buf(NULL, 0, argv[i]) + 1;
/* Alloc destination buffer. */
to = buf = xmalloc(len + 1);
/* Copy into destination buffer. */
for (i = 0; i < count; ++i) {
*to++ = ' ';
to += sq_quote_buf(to, len, argv[i]);
}
return buf;
}
char *sq_dequote(char *arg)
{
char *dst = arg;

View File

@@ -31,6 +31,7 @@
extern char *sq_quote(const char *src);
extern void sq_quote_print(FILE *stream, const char *src);
extern size_t sq_quote_buf(char *dst, size_t n, const char *src);
extern char *sq_quote_argv(const char** argv, int count);
/* This unwraps what sq_quote() produces in place, but returns
* NULL if the input does not look like what sq_quote would have

View File

@@ -2,7 +2,6 @@
#include "refs.h"
#include "pkt-line.h"
#include "run-command.h"
#include <sys/wait.h>
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";

View File

@@ -58,6 +58,8 @@ test_expect_failure 'creating too deep nesting' \
git clone -l -s D E &&
git clone -l -s E F &&
git clone -l -s F G &&
git clone -l -s G H &&
cd H &&
test_valid_repo'
cd "$base_dir"

View File

@@ -28,7 +28,6 @@ unset GIT_DIR
unset GIT_EXTERNAL_DIFF
unset GIT_INDEX_FILE
unset GIT_OBJECT_DIRECTORY
unset GIT_TRACE
unset SHA1_FILE_DIRECTORIES
unset SHA1_FILE_DIRECTORY
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME

125
trace.c Normal file
View File

@@ -0,0 +1,125 @@
/*
* GIT - The information manager from hell
*
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
* Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
* Copyright (C) 2006 Mike McCormack
* Copyright (C) 2006 Christian Couder
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cache.h"
#include "quote.h"
/* Stolen from "imap-send.c". */
static int git_vasprintf(char **strp, const char *fmt, va_list ap)
{
int len;
char tmp[1024];
if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 ||
!(*strp = xmalloc(len + 1)))
return -1;
if (len >= (int)sizeof(tmp))
vsprintf(*strp, fmt, ap);
else
memcpy(*strp, tmp, len + 1);
return len;
}
/* Stolen from "imap-send.c". */
int nfvasprintf(char **str, const char *fmt, va_list va)
{
int ret = git_vasprintf(str, fmt, va);
if (ret < 0)
die("Fatal: Out of memory\n");
return ret;
}
/* Get a trace file descriptor from GIT_TRACE env variable. */
static int get_trace_fd()
{
char *trace = getenv("GIT_TRACE");
if (!trace || !strcmp(trace, "0") || !strcasecmp(trace," false"))
return 0;
if (!strcmp(trace, "1") || !strcasecmp(trace, "true"))
return STDERR_FILENO;
if (strlen(trace) == 1 && isdigit(*trace))
return atoi(trace);
fprintf(stderr, "What does '%s' for GIT_TRACE means ?\n", trace);
fprintf(stderr, "Defaulting to tracing on stderr...\n");
return STDERR_FILENO;
}
static const char err_msg[] = "Could not trace into fd given by "
"GIT_TRACE environment variable";
void trace_printf(const char *format, ...)
{
char *trace_str;
va_list rest;
int fd = get_trace_fd();
if (!fd)
return;
va_start(rest, format);
nfvasprintf(&trace_str, format, rest);
va_end(rest);
write_or_whine(fd, trace_str, strlen(trace_str), err_msg);
free(trace_str);
}
void trace_argv_printf(const char **argv, int count, const char *format, ...)
{
char *argv_str, *format_str, *trace_str;
size_t argv_len, format_len, trace_len;
va_list rest;
int fd = get_trace_fd();
if (!fd)
return;
/* Get the argv string. */
argv_str = sq_quote_argv(argv, count);
argv_len = strlen(argv_str);
/* Get the formated string. */
va_start(rest, format);
nfvasprintf(&format_str, format, rest);
va_end(rest);
/* Allocate buffer for trace string. */
format_len = strlen(format_str);
trace_len = argv_len + format_len + 1; /* + 1 for \n */
trace_str = xmalloc(trace_len + 1);
/* Copy everything into the trace string. */
strncpy(trace_str, format_str, format_len);
strncpy(trace_str + format_len, argv_str, argv_len);
strcpy(trace_str + trace_len - 1, "\n");
write_or_whine(fd, trace_str, trace_len, err_msg);
free(argv_str);
free(format_str);
free(trace_str);
}

View File

@@ -18,3 +18,28 @@ void write_or_die(int fd, const void *buf, size_t count)
p += written;
}
}
int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
{
const char *p = buf;
ssize_t written;
while (count > 0) {
written = xwrite(fd, p, count);
if (written == 0) {
fprintf(stderr, "%s: disk full?\n", msg);
return 0;
}
else if (written < 0) {
if (errno == EPIPE)
exit(0);
fprintf(stderr, "%s: write error (%s)\n",
msg, strerror(errno));
return 0;
}
count -= written;
p += written;
}
return 1;
}