*.py[co]
config.mak
autom4te.cache
+config.cache
config.log
config.status
config.mak.autogen
#define REF_HEADS (1u << 1)
#define REF_TAGS (1u << 2)
-extern int git_connect(int fd[2], char *url, const char *prog);
+extern pid_t git_connect(int fd[2], char *url, const char *prog);
extern int finish_connect(pid_t pid);
extern int path_match(const char *path, int nr, char **match);
extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
NO_STRCASESTR=@NO_STRCASESTR@
NO_STRLCPY=@NO_STRLCPY@
NO_SETENV=@NO_SETENV@
+NO_ICONV=@NO_ICONV@
AC_SUBST(NO_EXPAT)
#
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
+# Define NO_ICONV if neither libc nor libiconv support iconv.
AC_CHECK_LIB([c], [iconv],
-[NEEDS_LIBICONV=],
-[NEEDS_LIBICONV=YesPlease])
+ [NEEDS_LIBICONV=],
+ AC_CHECK_LIB([iconv], [iconv],
+ [NEEDS_LIBICONV=YesPlease],
+ [NO_ICONV=YesPlease]))
AC_SUBST(NEEDS_LIBICONV)
+AC_SUBST(NO_ICONV)
test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"
#
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
# Define NO_MMAP if you want to avoid mmap.
+#
+# Define NO_ICONV if your libc does not properly support iconv.
+AC_ARG_WITH(iconv,
+AS_HELP_STRING([--without-iconv],
+[if your architecture doesn't properly support iconv])
+AS_HELP_STRING([--with-iconv=PATH],
+[PATH is prefix for libiconv library and headers])
+AS_HELP_STRING([],
+[used only if you need linking with libiconv]),
+GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
close(pipefd[1][0]);
}
+#define MAX_CMD_LEN 1024
+
/*
- * Yeah, yeah, fixme. Need to pass in the heads etc.
+ * This returns 0 if the transport protocol does not need fork(2),
+ * or a process id if it does. Once done, finish the connection
+ * with finish_connect() with the value returned from this function
+ * (it is safe to call finish_connect() with 0 to support the former
+ * case).
+ *
+ * Does not return a negative value on error; it just dies.
*/
-int git_connect(int fd[2], char *url, const char *prog)
+pid_t git_connect(int fd[2], char *url, const char *prog)
{
- char command[1024];
char *host, *path = url;
char *end;
int c;
if (pid < 0)
die("unable to fork");
if (!pid) {
- snprintf(command, sizeof(command), "%s %s", prog,
- sq_quote(path));
+ char command[MAX_CMD_LEN];
+ char *posn = command;
+ int size = MAX_CMD_LEN;
+ int of = 0;
+
+ of |= add_to_string(&posn, &size, prog, 0);
+ of |= add_to_string(&posn, &size, " ", 0);
+ of |= add_to_string(&posn, &size, path, 1);
+
+ if (of)
+ die("command line too long");
+
dup2(pipefd[1][0], 0);
dup2(pipefd[0][1], 1);
close(pipefd[0][0]);
int finish_connect(pid_t pid)
{
+ if (pid == 0)
+ return 0;
+
while (waitpid(pid, NULL, 0) < 0) {
if (errno != EINTR)
return -1;
--- /dev/null
+To syntax highlight git's commit messages, you need to:
+ 1. Copy syntax/gitcommit.vim to vim's syntax directory:
+ $ mkdir -p $HOME/.vim/syntax
+ $ cp syntax/gitcommit.vim $HOME/.vim/syntax
+ 2. Auto-detect the editing of git commit files:
+ $ cat >>$HOME/.vimrc <<'EOF'
+ autocmd BufNewFile,BufRead COMMIT_EDITMSG set filetype=gitcommit
+ EOF
--- /dev/null
+syn region gitLine start=/^#/ end=/$/
+syn region gitCommit start=/^# Updated but not checked in:$/ end=/^#$/ contains=gitHead,gitCommitFile
+syn region gitHead contained start=/^# (.*)/ end=/^#$/
+syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
+syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
+
+syn match gitCommitFile contained /^#\t.*/hs=s+2
+syn match gitChangedFile contained /^#\t.*/hs=s+2
+syn match gitUntrackedFile contained /^#\t.*/hs=s+2
+
+hi def link gitLine Comment
+hi def link gitCommit Comment
+hi def link gitChanged Comment
+hi def link gitHead Comment
+hi def link gitUntracked Comment
+hi def link gitCommitFile Type
+hi def link gitChangedFile Constant
+hi def link gitUntrackedFile Constant
ret = fetch_pack(fd, nr_heads, heads);
close(fd[0]);
close(fd[1]);
- finish_connect(pid);
+ ret |= finish_connect(pid);
if (!ret && nr_heads) {
/* If the heads to pull were given, we should have
}
}
- return ret;
+ return !!ret;
}
'override' => 0,
# => [content-encoding, suffix, program]
'default' => ['x-gzip', 'gz', 'gzip']},
+
+ 'pickaxe' => {
+ 'sub' => \&feature_pickaxe,
+ 'override' => 0,
+ 'default' => [1]},
);
sub gitweb_check_feature {
return ($ctype, $suffix, $command);
}
+# To enable system wide have in $GITWEB_CONFIG
+# $feature{'pickaxe'}{'default'} = [1];
+# To have project specific config enable override in $GITWEB_CONFIG
+# $feature{'pickaxe'}{'override'} = 1;
+# and in project config gitweb.pickaxe = 0|1;
+
+sub feature_pickaxe {
+ my ($val) = git_get_project_config('pickaxe', '--bool');
+
+ if ($val eq 'true') {
+ return (1);
+ } elsif ($val eq 'false') {
+ return (0);
+ }
+
+ return ($_[0]);
+}
+
# rename detection options for git-diff and git-diff-tree
# - default is '-M', with the cost proportional to
# (number of removed files) * (number of new files).
sub git_history_body {
# Warning: assumes constant type (blob or tree) during history
- my ($fd, $refs, $hash_base, $ftype, $extra) = @_;
+ my ($revlist, $from, $to, $refs, $hash_base, $ftype, $extra) = @_;
+
+ $from = 0 unless defined $from;
+ $to = $#{$revlist} unless (defined $to && $to <= $#{$revlist});
print "<table class=\"history\" cellspacing=\"0\">\n";
my $alternate = 0;
- while (my $line = <$fd>) {
- if ($line !~ m/^([0-9a-fA-F]{40})/) {
+ for (my $i = $from; $i <= $to; $i++) {
+ if ($revlist->[$i] !~ m/^([0-9a-fA-F]{40})/) {
next;
}
if (!defined $hash_base) {
$hash_base = git_get_head_hash($project);
}
+ if (!defined $page) {
+ $page = 0;
+ }
my $ftype;
my %co = parse_commit($hash_base);
if (!%co) {
die_error(undef, "Unknown commit object");
}
+
my $refs = git_get_references();
- git_header_html();
- git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base);
- git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
+ my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
+
if (!defined $hash && defined $file_name) {
$hash = git_get_hash_by_path($hash_base, $file_name);
}
if (defined $hash) {
$ftype = git_get_type($hash);
}
- git_print_page_path($file_name, $ftype, $hash_base);
open my $fd, "-|",
- git_cmd(), "rev-list", "--full-history", $hash_base, "--", $file_name;
+ git_cmd(), "rev-list", $limit, "--full-history", $hash_base, "--", $file_name
+ or die_error(undef, "Open git-rev-list-failed");
+ my @revlist = map { chomp; $_ } <$fd>;
+ close $fd
+ or die_error(undef, "Reading git-rev-list failed");
- git_history_body($fd, $refs, $hash_base, $ftype);
+ my $paging_nav = '';
+ if ($page > 0) {
+ $paging_nav .=
+ $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name)},
+ "first");
+ $paging_nav .= " ⋅ " .
+ $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name, page=>$page-1),
+ -accesskey => "p", -title => "Alt-p"}, "prev");
+ } else {
+ $paging_nav .= "first";
+ $paging_nav .= " ⋅ prev";
+ }
+ if ($#revlist >= (100 * ($page+1)-1)) {
+ $paging_nav .= " ⋅ " .
+ $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name, page=>$page+1),
+ -accesskey => "n", -title => "Alt-n"}, "next");
+ } else {
+ $paging_nav .= " ⋅ next";
+ }
+ my $next_link = '';
+ if ($#revlist >= (100 * ($page+1)-1)) {
+ $next_link =
+ $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name, page=>$page+1),
+ -title => "Alt-n"}, "next");
+ }
+
+ git_header_html();
+ git_print_page_nav('history','', $hash_base,$co{'tree'},$hash_base, $paging_nav);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
+ git_print_page_path($file_name, $ftype, $hash_base);
+
+ git_history_body(\@revlist, ($page * 100), $#revlist,
+ $refs, $hash_base, $ftype, $next_link);
- close $fd;
git_footer_html();
}
if (!%co) {
die_error(undef, "Unknown commit object");
}
- # pickaxe may take all resources of your box and run for several minutes
- # with every query - so decide by yourself how public you make this feature :)
+
my $commit_search = 1;
my $author_search = 0;
my $committer_search = 0;
} elsif ($searchtext =~ s/^pickaxe\\://i) {
$commit_search = 0;
$pickaxe_search = 1;
+
+ # pickaxe may take all resources of your box and run for several minutes
+ # with every query - so decide by yourself how public you make this feature
+ my ($have_pickaxe) = gitweb_check_feature('pickaxe');
+ if (!$have_pickaxe) {
+ die_error('403 Permission denied', "Permission denied");
+ }
}
git_header_html();
git_print_page_nav('','', $hash,$co{'tree'},$hash);
ret = peek_remote(fd, flags);
close(fd[0]);
close(fd[1]);
- finish_connect(pid);
- return ret;
+ ret |= finish_connect(pid);
+ return !!ret;
}
return buf;
}
+/*
+ * Append a string to a string buffer, with or without shell quoting.
+ * Return true if the buffer overflowed.
+ */
+int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
+{
+ char *p = *ptrp;
+ int size = *sizep;
+ int oc;
+ int err = 0;
+
+ if (quote)
+ oc = sq_quote_buf(p, size, str);
+ else {
+ oc = strlen(str);
+ memcpy(p, str, (size <= oc) ? size - 1 : oc);
+ }
+
+ if (size <= oc) {
+ err = 1;
+ oc = size - 1;
+ }
+
+ *ptrp += oc;
+ **ptrp = '\0';
+ *sizep -= oc;
+ return err;
+}
+
char *sq_dequote(char *arg)
{
char *dst = arg;
extern size_t sq_quote_buf(char *dst, size_t n, const char *src);
extern char *sq_quote_argv(const char** argv, int count);
+/*
+ * Append a string to a string buffer, with or without shell quoting.
+ * Return true if the buffer overflowed.
+ */
+extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote);
+
/* This unwraps what sq_quote() produces in place, but returns
* NULL if the input does not look like what sq_quote would have
* produced.
#define COMMAND_SIZE 4096
-/*
- * Append a string to a string buffer, with or without shell quoting.
- * Return true if the buffer overflowed.
- */
-static int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
-{
- char *p = *ptrp;
- int size = *sizep;
- int oc;
- int err = 0;
-
- if ( quote ) {
- oc = sq_quote_buf(p, size, str);
- } else {
- oc = strlen(str);
- memcpy(p, str, (oc >= size) ? size-1 : oc);
- }
-
- if ( oc >= size ) {
- err = 1;
- oc = size-1;
- }
-
- *ptrp += oc;
- **ptrp = '\0';
- *sizep -= oc;
- return err;
-}
-
-int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
+int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
char *url, int rmt_argc, char **rmt_argv)
{
char *host;
ret = send_pack(fd[0], fd[1], nr_heads, heads);
close(fd[0]);
close(fd[1]);
- finish_connect(pid);
- return ret;
+ ret |= finish_connect(pid);
+ return !!ret;
}
static unsigned int sha1_file_open_flag = O_NOATIME;
-static unsigned hexval(char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return ~0;
+static inline unsigned int hexval(unsigned int c)
+{
+ static signed char val[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
+ 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
+ -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
+ };
+ return val[c];
}
int get_sha1_hex(const char *hex, unsigned char *sha1)
{
char *trace = getenv("GIT_TRACE");
- if (!trace || !strcmp(trace, "0") || !strcasecmp(trace," false"))
+ if (!trace || !strcmp(trace, "0") || !strcasecmp(trace, "false"))
return 0;
if (!strcmp(trace, "1") || !strcasecmp(trace, "true"))
return STDERR_FILENO;