* Re: [PATCH 1/5] MSVC: Windows-native implementation for subset of Pthreads API
From: Dmitry Potapov @ 2010-01-13 12:53 UTC (permalink / raw)
To: Johannes Sixt; +Cc: kusmabite, msysgit, git, Andrzej K. Haczewski
In-Reply-To: <201001122213.38287.j6t@kdbg.org>
On Tue, Jan 12, 2010 at 10:13:38PM +0100, Johannes Sixt wrote:
> On Freitag, 8. Januar 2010, Erik Faye-Lund wrote:
> > On Fri, Jan 8, 2010 at 4:32 AM, Dmitry Potapov <dpotapov@gmail.com> wrote:
> > > AFAIK, Win32 API assumes that reading LONG is always atomic, so
> > > the critical section is not really necesary here, but you need
> > > to declare 'waiters' as 'volatile':
> >
> > "Simple reads and writes to properly-aligned 32-bit variables are
> > atomic operations."
> > http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
>
> But then the next sentence is:
>
> "However, access is not guaranteed to be synchronized. If two threads are
> reading and writing from the same variable, you cannot determine if one
> thread will perform its read operation before the other performs its write
> operation."
>
> This goes without saying, IOW, those Microsofties don't know what they write,
> which makes the documentation a bit less trustworthy.
The fact that Microsoft documentation is not written by brightest people
in the world is well known...
>
> Nevertheless, I rewrote the code to use Interlocked* functions, and then read
> the documentation again. InterlockedIncrement reads, for example:
>
> "... This function is atomic with respect to calls to other interlocked
> functions."
I have no clue what the author meant here. Perhaps Microsoft wanted to
reserve the right to implement Interlocked functions using an internal
lock on those architectures that do not have atomic operations. (For
instance, ARMv5 does not have atomic operations).
But any sane implementation of a critical section primitive requires
some operation that is atomic with respect to the user space (or you
kill the performance by calling some syscall in noncontentious case).
For instance, the Linux kernel provides this possibility by providing
__kernel_cmpxchg for ARM, which can be used to implement all other
synchronization primitives such mutexes and conditions. (Or on some
small MMU-less embedded system, disabling interrupts or the scheduler
lock is used). So, any sane implementation should atomic not only in
respect to other Interlock functions but also other synchronization
primitives.
In any case, on x86, it is implemented as _InterlockedIncrement, which
is a built-in function that generates the appropriate assembler instruction.
>
> In particular, it doesn't say that it is atomic WRT reads such as we have
> here:
>
> > >> + /* we're done waiting, so make sure we decrease waiters count */
> > >> + EnterCriticalSection(&cond->waiters_lock);
> > >> + --cond->waiters;
> > >> + LeaveCriticalSection(&cond->waiters_lock);
and these lines should be replaced with
InterlockedDecrement(&cond->waiters)
so it will be safe even on utterly idiotic implementation of Interlocked
functions that uses some internal lock; and as I said earlier on x86,
Interlocked functions are translated in appropriate assembler instructions.
Dmitry
^ permalink raw reply
* [PATCH v2] fast-import: tag may point to any object type
From: Dmitry Potapov @ 2010-01-13 12:35 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git, Junio C Hamano
In-Reply-To: <20100111171454.GO32155@spearce.org>
If you tried to export the official git repository, and then to import it
back then git-fast-import would die complaining that "Mark :1 not a commit".
Accordingly to a generated crash file, Mark 1 is not a commit but a blob,
which is pointed by junio-gpg-pub tag. Because git-tag allows to create such
tags, git-fast-import should import them.
Signed-off-by: Dmitry Potapov <dpotapov@gmail.com>
---
On Mon, Jan 11, 2010 at 09:14:54AM -0800, Shawn O. Pearce wrote:
>
> Your patch is the right idea. But you need to make sure all of
> the branch arms are handled correctly.
>
> That is, if we do this, the get_sha1() on line 2459 should also
> permit non-commit objects, and the lookup_branch() earlier up on
> line 2451 should do "type = OBJ_COMMIT".
Thank you for guideliness. I do not understand this code well.
I hope I got it right this time.
fast-import.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/fast-import.c b/fast-import.c
index cd87049..4fdf809 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2305,6 +2305,7 @@ static void parse_new_tag(void)
struct tag *t;
uintmax_t from_mark = 0;
unsigned char sha1[20];
+ enum object_type type;
/* Obtain the new tag name from the rest of our command */
sp = strchr(command_buf.buf, ' ') + 1;
@@ -2325,19 +2326,20 @@ static void parse_new_tag(void)
s = lookup_branch(from);
if (s) {
hashcpy(sha1, s->sha1);
+ type = OBJ_COMMIT;
} else if (*from == ':') {
struct object_entry *oe;
from_mark = strtoumax(from + 1, NULL, 10);
oe = find_mark(from_mark);
- if (oe->type != OBJ_COMMIT)
- die("Mark :%" PRIuMAX " not a commit", from_mark);
+ type = oe->type;
hashcpy(sha1, oe->sha1);
} else if (!get_sha1(from, sha1)) {
unsigned long size;
char *buf;
+ type = sha1_object_info(sha1, NULL);
buf = read_object_with_reference(sha1,
- commit_type, &size, sha1);
+ typename(type), &size, sha1);
if (!buf || size < 46)
die("Not a valid commit: %s", from);
free(buf);
@@ -2362,7 +2364,7 @@ static void parse_new_tag(void)
"object %s\n"
"type %s\n"
"tag %s\n",
- sha1_to_hex(sha1), commit_type, t->name);
+ sha1_to_hex(sha1), typename(type), t->name);
if (tagger)
strbuf_addf(&new_data,
"tagger %s\n", tagger);
--
1.6.6.137.g1acb
^ permalink raw reply related
* discussion: an option to fail git fetch if a pulled branch tip is not a fast forward of the existing remote tip?
From: Jon Seymour @ 2010-01-13 11:54 UTC (permalink / raw)
To: Git Mailing List
I spent a little while this afternoon debugging an issue where an
upstream publisher had backtracked and published a branch tip which
was not a descendant of a previously published (and fetched) branch
tip. The net result was that the backtracked changes were preserved in
the downstream branch once the 2nd tip was pulled.
Now clearly the upstream developer should not have backtracked. That
said, it would have been nice if I could have easily configured my
porcelain to detect the backtracking condition. An option on git fetch
that implemented something similar to the git push check would have
made this easy to achieve.
Has any consideration been given to such an option? Is there a
well-known alternative pattern for detecting this case?
jon.
^ permalink raw reply
* git-svn doesn't fetch an empty directory with svn:externals
From: Michel Jouvin @ 2010-01-13 11:49 UTC (permalink / raw)
To: git
Hi,
I'm running in a problem when trying to fetch a SVN repository branch that
contains an empty directory with a SVN property svn:externals attached. This
directory is missing in the Git repository/checkout. I was unable to find an
option to have it added. I'd like to get it added to readd the externals using
the trick described in http://kerneltrap.org/mailarchive/git/2007/5/1/245002.
Without it, I have to recreate it in git, add it to .gitignore... which is
painful.
BTW, I didn't find any documentation on empty dirs handling by git-svn. They
seems to be often removed which is not always desirable. Are they options
related to this?
Cheers,
Michel
^ permalink raw reply
* Re: default behaviour for `gitmerge` (no arguments)
From: Johannes Schindelin @ 2010-01-13 11:04 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, Gareth Adams, git
In-Reply-To: <7v6376pc9w.fsf@alter.siamese.dyndns.org>
Hi,
On Wed, 13 Jan 2010, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> >> I wondered why it doesn't hook into interpret_branch_name(), and
> >> instead adds itself to the static substitute_branch_name(); it
> >> forbids the use of the syntax from by callers of strbuf_branchname().
> >
> > I _think_ it was to allow something like
> >
> > git log -g @{u}
> >
> > but frankly, this is so long ago, I do not remember, I reconstructed this
> > reasoning as being the most likely.
>
> That is not the question I was asking.
>
> If you compare substitute_branch_name() and interpret_branch_name() before
> your patch, you will notice that they are _meant_ to do the same thing,
> with different external API, only because many callers in sha1_name.c do
> not use strbuf to hold their names. The primary API is the latter (which
> is extern), and the former (which is static) is merely a helping wrapper
> that is internal to sha1_name.c
So you meant to say that substitute_branch_name() calls
interpret_branch_name(), so the change should be in the latter. (This is
supposed to be the summary of your 4 paragraphs.)
I have no problems with that, except that I do not have the time to do it
myself.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH 0/6] Re: Documentation: warn prominently against merging with dirty trees
From: Petr Baudis @ 2010-01-13 10:44 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Thomas Rast, git
In-Reply-To: <20100111082123.GA23742@progeny.tock>
On Mon, Jan 11, 2010 at 02:21:23AM -0600, Jonathan Nieder wrote:
> Jonathan Nieder (6):
> Documentation: clarify one-line description for merge
I don't think this is an improvement and prefer the original phrasing.
> Documentation: merge: move configuration section to the end
Ack.
I will reply to the other patches in separate mails.
Petr "Pasky" Baudis
^ permalink raw reply
* Re: What to do with patches that should go upstream?
From: Jeenu V @ 2010-01-13 10:34 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzl4inwh1.fsf@alter.siamese.dyndns.org>
On Wed, Jan 13, 2010 at 3:43 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Jeenu V <jeenuv@gmail.com> writes:
>
>> For example, in the following figure,
>>
>> A
>> -O---O-+
>> \ A' B'
>> -O---O---O---O---O---O---O W
>> /
>> -O----O--+
>>
>> W is the current working branch. But there are commits A' and B' which
>> should go upstream. What I wanted to know is the next step from here.
>>
>> 1) Do I switch to A and B, and then cherry pick the commits A' and B'?
>> 2) If I send the patch out to include in upstream, wouldn't it
>> conflict the next time I happen to merge from A or B?
>
> I don't see B in your picture, so I may not be answering the question you
> wanted to ask, or you perhaps asked something other than the question you
> wanted to ask. Having said that, I think you are asking two more-or-less
> independent questions.
Sorry, B was meant to be the branch at the bottom. But anyway I think
I got hints on what I needed. Thank you for your descriptive reply.
--
:J
^ permalink raw reply
* Re: What to do with patches that should go upstream?
From: Junio C Hamano @ 2010-01-13 10:13 UTC (permalink / raw)
To: Jeenu V; +Cc: git
In-Reply-To: <5195c8761001130151q12ac636cnc69513087320195@mail.gmail.com>
Jeenu V <jeenuv@gmail.com> writes:
> For example, in the following figure,
>
> A
> -O---O-+
> \ A' B'
> -O---O---O---O---O---O---O W
> /
> -O----O--+
>
> W is the current working branch. But there are commits A' and B' which
> should go upstream. What I wanted to know is the next step from here.
>
> 1) Do I switch to A and B, and then cherry pick the commits A' and B'?
> 2) If I send the patch out to include in upstream, wouldn't it
> conflict the next time I happen to merge from A or B?
I don't see B in your picture, so I may not be answering the question you
wanted to ask, or you perhaps asked something other than the question you
wanted to ask. Having said that, I think you are asking two more-or-less
independent questions.
Whether you interact with your upstream by sending patches, asking them to
pull, or directly pushing into them, from your problem description, it is
clear that you _only_ want to give change contained in A' and B'. So
there is no room for "how do I" involved in it.
(1) First check out a pristine copy of your upstream, and cherry-pick A'
and B'
$ git checkout upstream ;# or whatever
$ git cherry-pick A'
$ git cherry-pick B'
(2-a) If you are sending patches to interact with your upstream, then
format-patch the two [*1*]
$ git format-patch -2
and send them out.
(2-b) If you are asking for them to pull, publish that to your public
repository and ask. Perhaps...
$ git push $publicURL HEAD:for-upstream
$ mail integrator@upstream.com
Subject: please pull
Please find my two changes at
$publicURL for-upstream
(2-c) If you can push, you push it to whichever branch the others are
expecting you to push to. Perhaps...
$ git push $upstreamURL HEAD:$branch
Now, how to deal with the duplicate copies A' and B' in your private
history is your problem, and it is largely independent from the above.
If your branch W is private and you haven't published, then you would want
to drop the now-obsolete two commits that do not belong to what you wanted
to achieve in that branch by running "rebase -i", perhaps...
$ git rebase -i A'^
... delete lines that correspond to A' and B' and save ...
If your branch W has been published (iow, other people have seen the
commits on it), then you shouldn't be doing rebase. When you merge
upstream to W (but why would you do that in the first place? You
shouldn't be working directly on a branch that you merge random changes
from other people), you _will_ end up having A and A' (and B and B') as
duplicates in your history. You'll need to live with it.
A good news is that git was designed for the Linux kernel community where
patch duplication is the norm, not exception. Over there, it is not
uncommon for a subsystem maintainer to pick up a patch from the mailing
list that falls within his area, while the maintainer at the higher level
than the subsystem maintainer picks up the same patch (perhaps because it
trivially fixes a rather urgent issue) and then later ends up merging with
the subsystem maintainer. When this happens, git notices that the two
sides made exactly the same change and resolves it as a non-conflicting
event when able (and it often is).
[Footnote]
*1* cherry-pick may not seem useful in this case, but it is a courtesy
to your upstream to give them a clean patch; cherry-picking and adjusting
for potential conflicts on top of the pristine upstream before running
format-patch will ensure this.
^ permalink raw reply
* What to do with patches that should go upstream?
From: Jeenu V @ 2010-01-13 9:51 UTC (permalink / raw)
To: git
Hi,
I'd like to know what's the best practice to follow when one discovers
that a change that's been applied on the current branch, has to
actually go upstream. For example, in the following figure,
A
-O---O-+
\ A' B'
-O---O---O---O---O---O---O W
/
-O----O--+
W is the current working branch. But there are commits A' and B' which
should go upstream. What I wanted to know is the next step from here.
1) Do I switch to A and B, and then cherry pick the commits A' and B'?
2) If I send the patch out to include in upstream, wouldn't it
conflict the next time I happen to merge from A or B?
Please suggest.
--
:J
^ permalink raw reply
* Re: default behaviour for `gitmerge` (no arguments)
From: Junio C Hamano @ 2010-01-13 9:47 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Jeff King, Gareth Adams, git
In-Reply-To: <alpine.DEB.1.00.1001131024420.3043@intel-tinevez-2-302>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>> I wondered why it doesn't hook into interpret_branch_name(), and instead
>> adds itself to the static substitute_branch_name(); it forbids the use
>> of the syntax from by callers of strbuf_branchname().
>
> I _think_ it was to allow something like
>
> git log -g @{u}
>
> but frankly, this is so long ago, I do not remember, I reconstructed this
> reasoning as being the most likely.
That is not the question I was asking.
If you compare substitute_branch_name() and interpret_branch_name() before
your patch, you will notice that they are _meant_ to do the same thing,
with different external API, only because many callers in sha1_name.c do
not use strbuf to hold their names. The primary API is the latter (which
is extern), and the former (which is static) is merely a helping wrapper
that is internal to sha1_name.c
But with your patch, they suddenly have different semantics, and the
function that implements the primary API doesn't know anything about
this new @{upstream} syntax.
This discrepancy will affect callers of strbuf_branchname(), e.g.
merge_name() in builtin-merge.c that prepares the "Merge branch nitfol of
remote frotz" message, or delete_branches() in builtin-branch.c.
Note that I am not saying "branch -d @{upstream}" should or should not
work (at least not yet---I haven't thought the issues through). But I
wanted to know if this subtle change in the semantics was a deliberate
choice, and if so wanted to see the reason behind it described clearly.
^ permalink raw reply
* [PATCH 5/7] gitweb: Convert output to using indirect file handle
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-5-git-send-email-warthog9@eaglescrag.net>
This converts the output handling of gitweb to using an indirect
file handle. This is in preparation to add the caching layer. This
is a slight modification to the way I was originally doing it by
passing the output around. This should be a nop and this shouldn't
change the behavior of gitweb. This does leave error reporting
functions (die_error specifically) continuing to output directly
as I want to garauntee those will report their errors regardless of
what may be going on with respect to the rest of the output.
---
gitweb/gitweb.perl | 876 ++++++++++++++++++++++++++--------------------------
1 files changed, 442 insertions(+), 434 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b8f2a67..3b6bc06 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -455,6 +455,13 @@ our %feature = (
'default' => [0]},
);
+# Basic file handler for all of gitweb, there are two of them. The first
+# is the basic text/html file handler which is used for everything other
+# then the binary files, that uses a separate file handler though
+# these are both set to STDOUT for the time being.
+our $output_handler = *STDOUT;
+our $output_handler_bin = *STDOUT;
+
sub gitweb_get_feature {
my ($name) = @_;
return unless exists $feature{$name};
@@ -3091,7 +3098,7 @@ sub insert_file {
my $filename = shift;
open my $fd, '<', $filename;
- print map { to_utf8($_) } <$fd>;
+ print {$output_handler} map { to_utf8($_) } <$fd>;
close $fd;
}
@@ -3208,10 +3215,10 @@ sub git_header_html {
} else {
$content_type = 'text/html';
}
- print $cgi->header(-type=>$content_type, -charset => 'utf-8',
+ print {$output_handler} $cgi->header(-type=>$content_type, -charset => 'utf-8',
-status=> $status, -expires => $expires);
my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
- print <<EOF;
+ print {$output_handler} <<EOF;
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
@@ -3226,16 +3233,16 @@ EOF
# the stylesheet, favicon etc urls won't work correctly with path_info
# unless we set the appropriate base URL
if ($ENV{'PATH_INFO'}) {
- print "<base href=\"".esc_url($base_url)."\" />\n";
+ print {$output_handler} "<base href=\"".esc_url($base_url)."\" />\n";
}
# print out each stylesheet that exist, providing backwards capability
# for those people who defined $stylesheet in a config file
if (defined $stylesheet) {
- print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
+ print {$output_handler} '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
} else {
foreach my $stylesheet (@stylesheets) {
next unless $stylesheet;
- print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
+ print {$output_handler} '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
}
}
if (defined $project) {
@@ -3254,7 +3261,7 @@ EOF
$href_params{'action'} = $type;
$link_attr{'-href'} = href(%href_params);
- print "<link ".
+ print {$output_handler} "<link ".
"rel=\"$link_attr{'-rel'}\" ".
"title=\"$link_attr{'-title'}\" ".
"href=\"$link_attr{'-href'}\" ".
@@ -3264,7 +3271,7 @@ EOF
$href_params{'extra_options'} = '--no-merges';
$link_attr{'-href'} = href(%href_params);
$link_attr{'-title'} .= ' (no merges)';
- print "<link ".
+ print {$output_handler} "<link ".
"rel=\"$link_attr{'-rel'}\" ".
"title=\"$link_attr{'-title'}\" ".
"href=\"$link_attr{'-href'}\" ".
@@ -3273,37 +3280,37 @@ EOF
}
} else {
- printf('<link rel="alternate" title="%s projects list" '.
+ printf( {$output_handler} '<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8" />'."\n",
$site_name, href(project=>undef, action=>"project_index"));
- printf('<link rel="alternate" title="%s projects feeds" '.
+ printf( {$output_handler} '<link rel="alternate" title="%s projects feeds" '.
'href="%s" type="text/x-opml" />'."\n",
$site_name, href(project=>undef, action=>"opml"));
}
if (defined $favicon) {
- print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
+ print {$output_handler} qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
}
- print "</head>\n" .
+ print {$output_handler} "</head>\n" .
"<body>\n";
if (-f $site_header) {
insert_file($site_header);
}
- print "<div class=\"page_header\">\n" .
+ print {$output_handler} "<div class=\"page_header\">\n" .
$cgi->a({-href => esc_url($logo_url),
-title => $logo_label},
qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>));
- print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
+ print {$output_handler} $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
if (defined $project) {
- print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
+ print {$output_handler} $cgi->a({-href => href(action=>"summary")}, esc_html($project));
if (defined $action) {
- print " / $action";
+ print {$output_handler} " / $action";
}
- print "\n";
+ print {$output_handler} "\n";
}
- print "</div>\n";
+ print {$output_handler} "</div>\n";
my $have_search = gitweb_check_feature('search');
if (defined $project && $have_search) {
@@ -3323,7 +3330,7 @@ EOF
if ($use_pathinfo) {
$action .= "/".esc_url($project);
}
- print $cgi->startform(-method => "get", -action => $action) .
+ print {$output_handler} $cgi->startform(-method => "get", -action => $action) .
"<div class=\"search\">\n" .
(!$use_pathinfo &&
$cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
@@ -3346,11 +3353,11 @@ EOF
sub git_footer_html {
my $feed_class = 'rss_logo';
- print "<div class=\"page_footer\">\n";
+ print {$output_handler} "<div class=\"page_footer\">\n";
if (defined $project) {
my $descr = git_get_project_description($project);
if (defined $descr) {
- print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
+ print {$output_handler} "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
}
my %href_params = get_feed_info();
@@ -3361,22 +3368,22 @@ sub git_footer_html {
foreach my $format qw(RSS Atom) {
$href_params{'action'} = lc($format);
- print $cgi->a({-href => href(%href_params),
+ print {$output_handler} $cgi->a({-href => href(%href_params),
-title => "$href_params{'-title'} $format feed",
-class => $feed_class}, $format)."\n";
}
} else {
- print $cgi->a({-href => href(project=>undef, action=>"opml"),
+ print {$output_handler} $cgi->a({-href => href(project=>undef, action=>"opml"),
-class => $feed_class}, "OPML") . " ";
- print $cgi->a({-href => href(project=>undef, action=>"project_index"),
+ print {$output_handler} $cgi->a({-href => href(project=>undef, action=>"project_index"),
-class => $feed_class}, "TXT") . "\n";
}
- print "</div>\n"; # class="page_footer"
+ print {$output_handler} "</div>\n"; # class="page_footer"
if (defined $t0 && gitweb_check_feature('timed')) {
- print "<div id=\"generating_info\">\n";
- print 'This page took '.
+ print {$output_handler} "<div id=\"generating_info\">\n";
+ print {$output_handler} 'This page took '.
'<span id="generating_time" class="time_span">'.
Time::HiRes::tv_interval($t0, [Time::HiRes::gettimeofday()]).
' seconds </span>'.
@@ -3385,26 +3392,26 @@ sub git_footer_html {
$number_of_git_cmds.
'</span> git commands '.
" to generate.\n";
- print "</div>\n"; # class="page_footer"
+ print {$output_handler} "</div>\n"; # class="page_footer"
}
if (-f $site_footer) {
insert_file($site_footer);
}
- print qq!<script type="text/javascript" src="$javascript"></script>\n!;
+ print {$output_handler} qq!<script type="text/javascript" src="$javascript"></script>\n!;
if ($action eq 'blame_incremental') {
- print qq!<script type="text/javascript">\n!.
+ print {$output_handler} qq!<script type="text/javascript">\n!.
qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!.
qq! "!. href() .qq!");\n!.
qq!</script>\n!;
} elsif (gitweb_check_feature('javascript-actions')) {
- print qq!<script type="text/javascript">\n!.
+ print {$output_handler} qq!<script type="text/javascript">\n!.
qq!window.onload = fixLinks;\n!.
qq!</script>\n!;
}
- print "</body>\n" .
+ print {$output_handler} "</body>\n" .
"</html>";
}
@@ -3488,12 +3495,12 @@ sub git_print_page_nav {
$arg{$label}{'_href'} = $link;
}
- print "<div class=\"page_nav\">\n" .
+ print {$output_handler} "<div class=\"page_nav\">\n" .
(join " | ",
map { $_ eq $current ?
$_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
} @navs);
- print "<br/>\n$extra<br/>\n" .
+ print {$output_handler} "<br/>\n$extra<br/>\n" .
"</div>\n";
}
@@ -3534,7 +3541,7 @@ sub git_print_header_div {
$args{'hash'} = $hash if $hash;
$args{'hash_base'} = $hash_base if $hash_base;
- print "<div class=\"header\">\n" .
+ print {$output_handler} "<div class=\"header\">\n" .
$cgi->a({-href => href(%args), -class => "title"},
$title ? $title : $action) .
"\n</div>\n";
@@ -3543,10 +3550,10 @@ sub git_print_header_div {
sub print_local_time {
my %date = @_;
if ($date{'hour_local'} < 6) {
- printf(" (<span class=\"atnight\">%02d:%02d</span> %s)",
+ printf({$output_handler} " (<span class=\"atnight\">%02d:%02d</span> %s)",
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
} else {
- printf(" (%02d:%02d %s)",
+ printf({$output_handler} " (%02d:%02d %s)",
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
}
}
@@ -3559,11 +3566,11 @@ sub git_print_authorship {
my $author = $co->{'author_name'};
my %ad = parse_date($co->{'author_epoch'}, $co->{'author_tz'});
- print "<$tag class=\"author_date\">" .
+ print {$output_handler} "<$tag class=\"author_date\">" .
format_search_author($author, "author", esc_html($author)) .
" [$ad{'rfc2822'}";
- print_local_time(%ad) if ($opts{-localtime});
- print "]" . git_get_avatar($co->{'author_email'}, -pad_before => 1)
+ print {$output_handler} get_local_time(%ad) if ($opts{-localtime});
+ print {$output_handler} "]" . git_get_avatar($co->{'author_email'}, -pad_before => 1)
. "</$tag>\n";
}
@@ -3579,7 +3586,7 @@ sub git_print_authorship_rows {
@people = ('author', 'committer') unless @people;
foreach my $who (@people) {
my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"});
- print "<tr><td>$who</td><td>" .
+ print {$output_handler} "<tr><td>$who</td><td>" .
format_search_author($co->{"${who}_name"}, $who,
esc_html($co->{"${who}_name"})) . " " .
format_search_author($co->{"${who}_email"}, $who,
@@ -3589,8 +3596,8 @@ sub git_print_authorship_rows {
"</td></tr>\n" .
"<tr>" .
"<td></td><td> $wd{'rfc2822'}";
- print_local_time(%wd);
- print "</td>" .
+ print {$output_handler} get_local_time(%wd);
+ print {$output_handler} "</td>" .
"</tr>\n";
}
}
@@ -3600,11 +3607,10 @@ sub git_print_page_path {
my $type = shift;
my $hb = shift;
-
- print "<div class=\"page_path\">";
- print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
+ print {$output_handler} "<div class=\"page_path\">";
+ print {$output_handler} $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
-title => 'tree root'}, to_utf8("[$project]"));
- print " / ";
+ print {$output_handler} " / ";
if (defined $name) {
my @dirname = split '/', $name;
my $basename = pop @dirname;
@@ -3612,25 +3618,25 @@ sub git_print_page_path {
foreach my $dir (@dirname) {
$fullname .= ($fullname ? '/' : '') . $dir;
- print $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
+ print {$output_handler} $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
hash_base=>$hb),
-title => $fullname}, esc_path($dir));
- print " / ";
+ print {$output_handler} " / ";
}
if (defined $type && $type eq 'blob') {
- print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
+ print {$output_handler} $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
hash_base=>$hb),
-title => $name}, esc_path($basename));
} elsif (defined $type && $type eq 'tree') {
- print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
+ print {$output_handler} $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
hash_base=>$hb),
-title => $name}, esc_path($basename));
- print " / ";
+ print {$output_handler} " / ";
} else {
- print esc_path($basename);
+ print {$output_handler} esc_path($basename);
}
}
- print "<br/></div>\n";
+ print {$output_handler} "<br/></div>\n";
}
sub git_print_log {
@@ -3654,7 +3660,7 @@ sub git_print_log {
$signoff = 1;
$empty = 0;
if (! $opts{'-remove_signoff'}) {
- print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
+ print {$output_handler} "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n";
next;
} else {
# remove signoff lines
@@ -3673,12 +3679,12 @@ sub git_print_log {
$empty = 0;
}
- print format_log_line_html($line) . "<br/>\n";
+ print {$output_handler} format_log_line_html($line) . "<br/>\n";
}
if ($opts{'-final_empty_line'}) {
# end with single empty line
- print "<br/>\n" unless $empty;
+ print {$output_handler} "<br/>\n" unless $empty;
}
}
@@ -3751,12 +3757,12 @@ sub git_print_tree_entry {
# the mode of the entry, list is the name of the entry, an href,
# and link is the action links of the entry.
- print "<td class=\"mode\">" . mode_str($t->{'mode'}) . "</td>\n";
+ print {$output_handler} "<td class=\"mode\">" . mode_str($t->{'mode'}) . "</td>\n";
if (exists $t->{'size'}) {
- print "<td class=\"size\">$t->{'size'}</td>\n";
+ print {$output_handler} "<td class=\"size\">$t->{'size'}</td>\n";
}
if ($t->{'type'} eq "blob") {
- print "<td class=\"list\">" .
+ print {$output_handler} "<td class=\"list\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key),
-class => "list"}, esc_path($t->{'name'}));
@@ -3765,71 +3771,71 @@ sub git_print_tree_entry {
if ($link_target) {
my $norm_target = normalize_link_target($link_target, $basedir);
if (defined $norm_target) {
- print " -> " .
+ print {$output_handler} " -> " .
$cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
file_name=>$norm_target),
-title => $norm_target}, esc_path($link_target));
} else {
- print " -> " . esc_path($link_target);
+ print {$output_handler} " -> " . esc_path($link_target);
}
}
}
- print "</td>\n";
- print "<td class=\"link\">";
- print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td class=\"link\">";
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
"blob");
if ($have_blame) {
- print " | " .
+ print {$output_handler} " | " .
$cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
"blame");
}
if (defined $hash_base) {
- print " | " .
+ print {$output_handler} " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")},
"history");
}
- print " | " .
+ print {$output_handler} " | " .
$cgi->a({-href => href(action=>"blob_plain", hash_base=>$hash_base,
file_name=>"$basedir$t->{'name'}")},
"raw");
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} elsif ($t->{'type'} eq "tree") {
- print "<td class=\"list\">";
- print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
+ print {$output_handler} "<td class=\"list\">";
+ print {$output_handler} $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}",
%base_key)},
esc_path($t->{'name'}));
- print "</td>\n";
- print "<td class=\"link\">";
- print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td class=\"link\">";
+ print {$output_handler} $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}",
%base_key)},
"tree");
if (defined $hash_base) {
- print " | " .
+ print {$output_handler} " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
file_name=>"$basedir$t->{'name'}")},
"history");
}
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} else {
# unknown object: we can only present history for it
# (this includes 'commit' object, i.e. submodule support)
- print "<td class=\"list\">" .
+ print {$output_handler} "<td class=\"list\">" .
esc_path($t->{'name'}) .
"</td>\n";
- print "<td class=\"link\">";
+ print {$output_handler} "<td class=\"link\">";
if (defined $hash_base) {
- print $cgi->a({-href => href(action=>"history",
+ print {$output_handler} $cgi->a({-href => href(action=>"history",
hash_base=>$hash_base,
file_name=>"$basedir$t->{'name'}")},
"history");
}
- print "</td>\n";
+ print {$output_handler} "</td>\n";
}
}
@@ -3876,13 +3882,13 @@ sub git_difftree_body {
my ($difftree, $hash, @parents) = @_;
my ($parent) = $parents[0];
my $have_blame = gitweb_check_feature('blame');
- print "<div class=\"list_head\">\n";
+ print {$output_handler} "<div class=\"list_head\">\n";
if ($#{$difftree} > 10) {
- print(($#{$difftree} + 1) . " files changed:\n");
+ print {$output_handler} (($#{$difftree} + 1) . " files changed:\n");
}
- print "</div>\n";
+ print {$output_handler} "</div>\n";
- print "<table class=\"" .
+ print {$output_handler} "<table class=\"" .
(@parents > 1 ? "combined " : "") .
"diff_tree\">\n";
@@ -3890,11 +3896,11 @@ sub git_difftree_body {
my $has_header = @$difftree && @parents > 1 && $action eq 'commitdiff';
if ($has_header) {
# table header
- print "<thead><tr>\n" .
+ print {$output_handler} "<thead><tr>\n" .
"<th></th><th></th>\n"; # filename, patchN link
for (my $i = 0; $i < @parents; $i++) {
my $par = $parents[$i];
- print "<th>" .
+ print {$output_handler} "<th>" .
$cgi->a({-href => href(action=>"commitdiff",
hash=>$hash, hash_parent=>$par),
-title => 'commitdiff to parent number ' .
@@ -3902,7 +3908,7 @@ sub git_difftree_body {
$i+1) .
" </th>\n";
}
- print "</tr></thead>\n<tbody>\n";
+ print {$output_handler} "</tr></thead>\n<tbody>\n";
}
my $alternate = 1;
@@ -3911,9 +3917,9 @@ sub git_difftree_body {
my $diff = parsed_difftree_line($line);
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
@@ -3924,14 +3930,14 @@ sub git_difftree_body {
if (!is_deleted($diff)) {
# file exists in the result (child) commit
- print "<td>" .
+ print {$output_handler} "<td>" .
$cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
file_name=>$diff->{'to_file'},
hash_base=>$hash),
-class => "list"}, esc_path($diff->{'to_file'})) .
"</td>\n";
} else {
- print "<td>" .
+ print {$output_handler} "<td>" .
esc_path($diff->{'to_file'}) .
"</td>\n";
}
@@ -3939,7 +3945,7 @@ sub git_difftree_body {
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print "<td class=\"link\">" .
+ print {$output_handler} "<td class=\"link\">" .
$cgi->a({-href => "#patch$patchno"}, "patch") .
" | " .
"</td>\n";
@@ -3957,9 +3963,9 @@ sub git_difftree_body {
$not_deleted ||= ($status ne 'D');
if ($status eq 'A') {
- print "<td class=\"link\" align=\"right\"> | </td>\n";
+ print {$output_handler} "<td class=\"link\" align=\"right\"> | </td>\n";
} elsif ($status eq 'D') {
- print "<td class=\"link\">" .
+ print {$output_handler} "<td class=\"link\">" .
$cgi->a({-href => href(action=>"blob",
hash_base=>$hash,
hash=>$from_hash,
@@ -3968,11 +3974,11 @@ sub git_difftree_body {
" | </td>\n";
} else {
if ($diff->{'to_id'} eq $from_hash) {
- print "<td class=\"link nochange\">";
+ print {$output_handler} "<td class=\"link nochange\">";
} else {
- print "<td class=\"link\">";
+ print {$output_handler} "<td class=\"link\">";
}
- print $cgi->a({-href => href(action=>"blobdiff",
+ print {$output_handler} $cgi->a({-href => href(action=>"blobdiff",
hash=>$diff->{'to_id'},
hash_parent=>$from_hash,
hash_base=>$hash,
@@ -3984,24 +3990,24 @@ sub git_difftree_body {
}
}
- print "<td class=\"link\">";
+ print {$output_handler} "<td class=\"link\">";
if ($not_deleted) {
- print $cgi->a({-href => href(action=>"blob",
+ print {$output_handler} $cgi->a({-href => href(action=>"blob",
hash=>$diff->{'to_id'},
file_name=>$diff->{'to_file'},
hash_base=>$hash)},
"blob");
- print " | " if ($has_history);
+ print {$output_handler} " | " if ($has_history);
}
if ($has_history) {
- print $cgi->a({-href => href(action=>"history",
+ print {$output_handler} $cgi->a({-href => href(action=>"history",
file_name=>$diff->{'to_file'},
hash_base=>$hash)},
"history");
}
- print "</td>\n";
+ print {$output_handler} "</td>\n";
- print "</tr>\n";
+ print {$output_handler} "</tr>\n";
next; # instead of 'else' clause, to avoid extra indent
}
# else ordinary diff
@@ -4027,51 +4033,51 @@ sub git_difftree_body {
my $mode_chng = "<span class=\"file_status new\">[new $to_file_type";
$mode_chng .= " with mode: $to_mode_str" if $to_mode_str;
$mode_chng .= "]</span>";
- print "<td>";
- print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
+ print {$output_handler} "<td>";
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
hash_base=>$hash, file_name=>$diff->{'file'}),
-class => "list"}, esc_path($diff->{'file'}));
- print "</td>\n";
- print "<td>$mode_chng</td>\n";
- print "<td class=\"link\">";
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td>$mode_chng</td>\n";
+ print {$output_handler} "<td class=\"link\">";
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print $cgi->a({-href => "#patch$patchno"}, "patch");
- print " | ";
+ print {$output_handler} $cgi->a({-href => "#patch$patchno"}, "patch");
+ print {$output_handler} " | ";
}
- print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
hash_base=>$hash, file_name=>$diff->{'file'})},
"blob");
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} elsif ($diff->{'status'} eq "D") { # deleted
my $mode_chng = "<span class=\"file_status deleted\">[deleted $from_file_type]</span>";
- print "<td>";
- print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'from_id'},
+ print {$output_handler} "<td>";
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'from_id'},
hash_base=>$parent, file_name=>$diff->{'file'}),
-class => "list"}, esc_path($diff->{'file'}));
- print "</td>\n";
- print "<td>$mode_chng</td>\n";
- print "<td class=\"link\">";
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td>$mode_chng</td>\n";
+ print {$output_handler} "<td class=\"link\">";
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print $cgi->a({-href => "#patch$patchno"}, "patch");
- print " | ";
+ print {$output_handler} $cgi->a({-href => "#patch$patchno"}, "patch");
+ print {$output_handler} " | ";
}
- print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'from_id'},
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'from_id'},
hash_base=>$parent, file_name=>$diff->{'file'})},
"blob") . " | ";
if ($have_blame) {
- print $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
+ print {$output_handler} $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
file_name=>$diff->{'file'})},
"blame") . " | ";
}
- print $cgi->a({-href => href(action=>"history", hash_base=>$parent,
+ print {$output_handler} $cgi->a({-href => href(action=>"history", hash_base=>$parent,
file_name=>$diff->{'file'})},
"history");
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} elsif ($diff->{'status'} eq "M" || $diff->{'status'} eq "T") { # modified, or type changed
my $mode_chnge = "";
@@ -4089,39 +4095,39 @@ sub git_difftree_body {
}
$mode_chnge .= "]</span>\n";
}
- print "<td>";
- print $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
+ print {$output_handler} "<td>";
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
hash_base=>$hash, file_name=>$diff->{'file'}),
-class => "list"}, esc_path($diff->{'file'}));
- print "</td>\n";
- print "<td>$mode_chnge</td>\n";
- print "<td class=\"link\">";
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td>$mode_chnge</td>\n";
+ print {$output_handler} "<td class=\"link\">";
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print $cgi->a({-href => "#patch$patchno"}, "patch") .
+ print {$output_handler} $cgi->a({-href => "#patch$patchno"}, "patch") .
" | ";
} elsif ($diff->{'to_id'} ne $diff->{'from_id'}) {
# "commit" view and modified file (not onlu mode changed)
- print $cgi->a({-href => href(action=>"blobdiff",
+ print {$output_handler} $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=>"blob", hash=>$diff->{'to_id'},
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
hash_base=>$hash, file_name=>$diff->{'file'})},
"blob") . " | ";
if ($have_blame) {
- print $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
+ print {$output_handler} $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
file_name=>$diff->{'file'})},
"blame") . " | ";
}
- print $cgi->a({-href => href(action=>"history", hash_base=>$hash,
+ print {$output_handler} $cgi->a({-href => href(action=>"history", hash_base=>$hash,
file_name=>$diff->{'file'})},
"history");
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} elsif ($diff->{'status'} eq "R" || $diff->{'status'} eq "C") { # renamed or copied
my %status_name = ('R' => 'moved', 'C' => 'copied');
@@ -4131,7 +4137,7 @@ sub git_difftree_body {
# mode also for directories, so we cannot use $to_mode_str
$mode_chng = sprintf(", mode: %04o", $to_mode_oct & 0777);
}
- print "<td>" .
+ print {$output_handler} "<td>" .
$cgi->a({-href => href(action=>"blob", hash_base=>$hash,
hash=>$diff->{'to_id'}, file_name=>$diff->{'to_file'}),
-class => "list"}, esc_path($diff->{'to_file'})) . "</td>\n" .
@@ -4144,35 +4150,35 @@ sub git_difftree_body {
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print $cgi->a({-href => "#patch$patchno"}, "patch") .
+ print {$output_handler} $cgi->a({-href => "#patch$patchno"}, "patch") .
" | ";
} elsif ($diff->{'to_id'} ne $diff->{'from_id'}) {
# "commit" view and modified file (not only pure rename or copy)
- print $cgi->a({-href => href(action=>"blobdiff",
+ print {$output_handler} $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=>"blob", hash=>$diff->{'to_id'},
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
hash_base=>$parent, file_name=>$diff->{'to_file'})},
"blob") . " | ";
if ($have_blame) {
- print $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
+ print {$output_handler} $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
file_name=>$diff->{'to_file'})},
"blame") . " | ";
}
- print $cgi->a({-href => href(action=>"history", hash_base=>$hash,
+ print {$output_handler} $cgi->a({-href => href(action=>"history", hash_base=>$hash,
file_name=>$diff->{'to_file'})},
"history");
- print "</td>\n";
+ print {$output_handler} "</td>\n";
} # we should not encounter Unmerged (U) or Unknown (X) status
- print "</tr>\n";
+ print {$output_handler} "</tr>\n";
}
- print "</tbody>" if $has_header;
- print "</table>\n";
+ print {$output_handler} "</tbody>" if $has_header;
+ print {$output_handler} "</table>\n";
}
sub git_patchset_body {
@@ -4187,7 +4193,7 @@ sub git_patchset_body {
my $to_name;
my (%from, %to);
- print "<div class=\"patchset\">\n";
+ print {$output_handler} "<div class=\"patchset\">\n";
# skip to first patch
while ($patch_line = <$fd>) {
@@ -4215,7 +4221,7 @@ sub git_patchset_body {
# and parse raw git-diff line if needed
if (is_patch_split($diffinfo, { 'to_file' => $to_name })) {
# this is continuation of a split patch
- print "<div class=\"patch cont\">\n";
+ print {$output_handler} "<div class=\"patch cont\">\n";
} else {
# advance raw git-diff output if needed
$patch_idx++ if defined $diffinfo;
@@ -4227,7 +4233,7 @@ sub git_patchset_body {
# find which patch (using pathname of result) we are at now;
if ($is_combined) {
while ($to_name ne $diffinfo->{'to_file'}) {
- print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+ print {$output_handler} "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
format_diff_cc_simplified($diffinfo, @hash_parents) .
"</div>\n"; # class="patch"
@@ -4244,7 +4250,7 @@ sub git_patchset_body {
# this is first patch for raw difftree line with $patch_idx index
# we index @$difftree array from 0, but number patches from 1
- print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
+ print {$output_handler} "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
}
# git diff header
@@ -4252,25 +4258,25 @@ sub git_patchset_body {
#assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
$patch_number++;
# print "git diff" header
- print format_git_diff_header_line($patch_line, $diffinfo,
+ print {$output_handler} format_git_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
# print extended diff header
- print "<div class=\"diff extended_header\">\n";
+ print {$output_handler} "<div class=\"diff extended_header\">\n";
EXTENDED_HEADER:
while ($patch_line = <$fd>) {
chomp $patch_line;
last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
- print format_extended_diff_header_line($patch_line, $diffinfo,
+ print {$output_handler} format_extended_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
}
- print "</div>\n"; # class="diff extended_header"
+ print {$output_handler} "</div>\n"; # class="diff extended_header"
# from-file/to-file diff header
if (! $patch_line) {
- print "</div>\n"; # class="patch"
+ print {$output_handler} "</div>\n"; # class="patch"
last PATCH;
}
next PATCH if ($patch_line =~ m/^diff /);
@@ -4281,7 +4287,7 @@ sub git_patchset_body {
chomp $patch_line;
#assert($patch_line =~ m/^\+\+\+/) if DEBUG;
- print format_diff_from_to_header($last_patch_line, $patch_line,
+ print {$output_handler} format_diff_from_to_header($last_patch_line, $patch_line,
$diffinfo, \%from, \%to,
@hash_parents);
@@ -4292,11 +4298,11 @@ sub git_patchset_body {
next PATCH if ($patch_line =~ m/^diff /);
- print format_diff_line($patch_line, \%from, \%to);
+ print {$output_handler} format_diff_line($patch_line, \%from, \%to);
}
} continue {
- print "</div>\n"; # class="patch"
+ print {$output_handler} "</div>\n"; # class="patch"
}
# for compact combined (--cc) format, with chunk and patch simpliciaction
@@ -4308,7 +4314,7 @@ sub git_patchset_body {
$diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
# generate anchor for "patch" links in difftree / whatchanged part
- print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+ print {$output_handler} "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
format_diff_cc_simplified($diffinfo, @hash_parents) .
"</div>\n"; # class="patch"
@@ -4317,13 +4323,13 @@ sub git_patchset_body {
if ($patch_number == 0) {
if (@hash_parents > 1) {
- print "<div class=\"diff nodifferences\">Trivial merge</div>\n";
+ print {$output_handler} "<div class=\"diff nodifferences\">Trivial merge</div>\n";
} else {
- print "<div class=\"diff nodifferences\">No differences found</div>\n";
+ print {$output_handler} "<div class=\"diff nodifferences\">No differences found</div>\n";
}
}
- print "</div>\n"; # class="patchset"
+ print {$output_handler} "</div>\n"; # class="patchset"
}
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -4376,9 +4382,9 @@ sub print_sort_th {
$header ||= ucfirst($name);
if ($order eq $name) {
- print "<th>$header</th>\n";
+ print {$output_handler} "<th>$header</th>\n";
} else {
- print "<th>" .
+ print {$output_handler} "<th>" .
$cgi->a({-href => href(-replay=>1, order=>$name),
-class => "header"}, $header) .
"</th>\n";
@@ -4418,20 +4424,20 @@ sub git_project_list_body {
}
}
my $cloud = git_populate_project_tagcloud(\%ctags);
- print git_show_project_tagcloud($cloud, 64);
+ print {$output_handler} git_show_project_tagcloud($cloud, 64);
}
- print "<table class=\"project_list\">\n";
+ print {$output_handler} "<table class=\"project_list\">\n";
unless ($no_header) {
- print "<tr>\n";
+ print {$output_handler} "<tr>\n";
if ($check_forks) {
- print "<th></th>\n";
+ print {$output_handler} "<th></th>\n";
}
- print_sort_th('project', $order, 'Project');
- print_sort_th('descr', $order, 'Description');
- print_sort_th('owner', $order, 'Owner');
- print_sort_th('age', $order, 'Last Change');
- print "<th></th>\n" . # for links
+ print {$output_handler} get_sort_th('project', $order, 'Project');
+ print {$output_handler} get_sort_th('descr', $order, 'Description');
+ print {$output_handler} get_sort_th('owner', $order, 'Owner');
+ print {$output_handler} get_sort_th('age', $order, 'Last Change');
+ print {$output_handler} "<th></th>\n" . # for links
"</tr>\n";
}
my $alternate = 1;
@@ -4451,26 +4457,26 @@ sub git_project_list_body {
}
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
if ($check_forks) {
- print "<td>";
+ print {$output_handler} "<td>";
if ($pr->{'forks'}) {
- print "<!-- $pr->{'forks'} -->\n";
- print $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "+");
+ print {$output_handler} "<!-- $pr->{'forks'} -->\n";
+ print {$output_handler} $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "+");
}
- print "</td>\n";
+ print {$output_handler} "</td>\n";
}
- print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
- -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+ print {$output_handler} "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
+ -class => "list"}, esc_html($pr->{'path'})) ."</td>\n".
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-class => "list", -title => $pr->{'descr_long'}},
esc_html($pr->{'descr'})) . "</td>\n" .
"<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
- print "<td class=\"". age_class($pr->{'age'}) . "\">" .
+ print {$output_handler} "<td class=\"". age_class($pr->{'age'}) . "\">" .
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " .
@@ -4486,14 +4492,14 @@ sub git_project_list_body {
"</tr>\n";
}
if (defined $extra) {
- print "<tr>\n";
+ print {$output_handler} "<tr>\n";
if ($check_forks) {
- print "<td></td>\n";
+ print {$output_handler} "<td></td>\n";
}
- print "<td colspan=\"5\">$extra</td>\n" .
+ print {$output_handler} "<td colspan=\"5\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
sub git_log_body {
@@ -4513,7 +4519,7 @@ sub git_log_body {
"<span class=\"age\">$co{'age_string'}</span>" .
esc_html($co{'title'}) . $ref,
$commit);
- print "<div class=\"title_text\">\n" .
+ print {$output_handler} "<div class=\"title_text\">\n" .
"<div class=\"log_link\">\n" .
$cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") .
" | " .
@@ -4523,16 +4529,16 @@ sub git_log_body {
"<br/>\n" .
"</div>\n";
git_print_authorship(\%co, -tag => 'span');
- print "<br/>\n</div>\n";
+ print {$output_handler} "<br/>\n</div>\n";
- print "<div class=\"log_body\">\n";
+ print {$output_handler} "<div class=\"log_body\">\n";
git_print_log($co{'comment'}, -final_empty_line=> 1);
- print "</div>\n";
+ print {$output_handler} "</div>\n";
}
if ($extra) {
- print "<div class=\"page_nav\">\n";
- print "$extra\n";
- print "</div>\n";
+ print {$output_handler} "<div class=\"page_nav\">\n";
+ print {$output_handler} "$extra\n";
+ print {$output_handler} "</div>\n";
}
}
@@ -4543,41 +4549,41 @@ sub git_shortlog_body {
$from = 0 unless defined $from;
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
- print "<table class=\"shortlog\">\n";
+ print {$output_handler} "<table class=\"shortlog\">\n";
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my %co = %{$commitlist->[$i]};
my $commit = $co{'id'};
my $ref = format_ref_marker($refs, $commit);
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
# git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
- print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ print {$output_handler} "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
format_author_html('td', \%co, 10) . "<td>";
- print format_subject_html($co{'title'}, $co{'title_short'},
+ print {$output_handler} format_subject_html($co{'title'}, $co{'title_short'},
href(action=>"commit", hash=>$commit), $ref);
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" .
$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");
my $snapshot_links = format_snapshot_links($commit);
if (defined $snapshot_links) {
- print " | " . $snapshot_links;
+ print {$output_handler} " | " . $snapshot_links;
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>\n";
}
if (defined $extra) {
- print "<tr>\n" .
+ print {$output_handler} "<tr>\n" .
"<td colspan=\"4\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
sub git_history_body {
@@ -4588,7 +4594,7 @@ sub git_history_body {
$from = 0 unless defined $from;
$to = $#{$commitlist} unless (defined $to && $to <= $#{$commitlist});
- print "<table class=\"history\">\n";
+ print {$output_handler} "<table class=\"history\">\n";
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my %co = %{$commitlist->[$i]};
@@ -4600,18 +4606,18 @@ sub git_history_body {
my $ref = format_ref_marker($refs, $commit);
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
- print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ print {$output_handler} "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
# shortlog: format_author_html('td', \%co, 10)
format_author_html('td', \%co, 15, 3) . "<td>";
# originally git_history used chop_str($co{'title'}, 50)
- print format_subject_html($co{'title'}, $co{'title_short'},
+ print {$output_handler} format_subject_html($co{'title'}, $co{'title_short'},
href(action=>"commit", hash=>$commit), $ref);
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype) . " | " .
$cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
@@ -4621,7 +4627,7 @@ sub git_history_body {
my $blob_parent = git_get_hash_by_path($commit, $file_name);
if (defined $blob_current && defined $blob_parent &&
$blob_current ne $blob_parent) {
- print " | " .
+ print {$output_handler} " | " .
$cgi->a({-href => href(action=>"blobdiff",
hash=>$blob_current, hash_parent=>$blob_parent,
hash_base=>$hash_base, hash_parent_base=>$commit,
@@ -4629,15 +4635,15 @@ sub git_history_body {
"diff to current");
}
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>\n";
}
if (defined $extra) {
- print "<tr>\n" .
+ print {$output_handler} "<tr>\n" .
"<td colspan=\"4\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
sub git_tags_body {
@@ -4646,7 +4652,7 @@ sub git_tags_body {
$from = 0 unless defined $from;
$to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
- print "<table class=\"tags\">\n";
+ print {$output_handler} "<table class=\"tags\">\n";
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my $entry = $taglist->[$i];
@@ -4657,50 +4663,50 @@ sub git_tags_body {
$comment_short = chop_str($comment, 30, 5);
}
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
if (defined $tag{'age'}) {
- print "<td><i>$tag{'age'}</i></td>\n";
+ print {$output_handler} "<td><i>$tag{'age'}</i></td>\n";
} else {
- print "<td></td>\n";
+ print {$output_handler} "<td></td>\n";
}
- print "<td>" .
+ print {$output_handler} "<td>" .
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}),
-class => "list name"}, esc_html($tag{'name'})) .
"</td>\n" .
"<td>";
if (defined $comment) {
- print format_subject_html($comment, $comment_short,
+ print {$output_handler} format_subject_html($comment, $comment_short,
href(action=>"tag", hash=>$tag{'id'}));
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"selflink\">";
if ($tag{'type'} eq "tag") {
- print $cgi->a({-href => href(action=>"tag", hash=>$tag{'id'})}, "tag");
+ print {$output_handler} $cgi->a({-href => href(action=>"tag", hash=>$tag{'id'})}, "tag");
} else {
- print " ";
+ print {$output_handler} " ";
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" . " | " .
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
if ($tag{'reftype'} eq "commit") {
- print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'fullname'})}, "shortlog") .
+ print {$output_handler} " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'fullname'})}, "shortlog") .
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'fullname'})}, "log");
} elsif ($tag{'reftype'} eq "blob") {
- print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
+ print {$output_handler} " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>";
}
if (defined $extra) {
- print "<tr>\n" .
+ print {$output_handler} "<tr>\n" .
"<td colspan=\"5\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
sub git_heads_body {
@@ -4709,19 +4715,19 @@ sub git_heads_body {
$from = 0 unless defined $from;
$to = $#{$headlist} if (!defined $to || $#{$headlist} < $to);
- print "<table class=\"heads\">\n";
+ print {$output_handler} "<table class=\"heads\">\n";
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my $entry = $headlist->[$i];
my %ref = %$entry;
my $curr = $ref{'id'} eq $head;
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
- print "<td><i>$ref{'age'}</i></td>\n" .
+ print {$output_handler} "<td><i>$ref{'age'}</i></td>\n" .
($curr ? "<td class=\"current_head\">" : "<td>") .
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}),
-class => "list name"},esc_html($ref{'name'})) .
@@ -4734,11 +4740,11 @@ sub git_heads_body {
"</tr>";
}
if (defined $extra) {
- print "<tr>\n" .
+ print {$output_handler} "<tr>\n" .
"<td colspan=\"3\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
sub git_search_grep_body {
@@ -4746,7 +4752,7 @@ sub git_search_grep_body {
$from = 0 unless defined $from;
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
- print "<table class=\"commit_search\">\n";
+ print {$output_handler} "<table class=\"commit_search\">\n";
my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my %co = %{$commitlist->[$i]};
@@ -4755,12 +4761,12 @@ sub git_search_grep_body {
}
my $commit = $co{'id'};
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
- print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ print {$output_handler} "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
format_author_html('td', \%co, 15, 5) .
"<td>" .
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
@@ -4780,25 +4786,25 @@ sub git_search_grep_body {
$match = esc_html($match);
$trail = esc_html($trail);
- print "$lead<span class=\"match\">$match</span>$trail<br />";
+ print {$output_handler} "$lead<span class=\"match\">$match</span>$trail<br />";
}
}
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") .
" | " .
$cgi->a({-href => href(action=>"commitdiff", hash=>$co{'id'})}, "commitdiff") .
" | " .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree");
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>\n";
}
if (defined $extra) {
- print "<tr>\n" .
+ print {$output_handler} "<tr>\n" .
"<td colspan=\"3\">$extra</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
## ======================================================================
@@ -4818,11 +4824,11 @@ sub git_project_list {
git_header_html();
if (-f $home_text) {
- print "<div class=\"index_include\">\n";
+ print {$output_handler} "<div class=\"index_include\">\n";
insert_file($home_text);
- print "</div>\n";
+ print {$output_handler} "</div>\n";
}
- print $cgi->startform(-method => "get") .
+ print {$output_handler} $cgi->startform(-method => "get") .
"<p class=\"projsearch\">Search:\n" .
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
"</p>" .
@@ -4852,7 +4858,7 @@ sub git_forks {
sub git_project_index {
my @projects = git_get_projects_list($project);
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => 'text/plain',
-charset => 'utf-8',
-content_disposition => 'inline; filename="index.aux"');
@@ -4869,7 +4875,7 @@ sub git_project_index {
$path =~ s/ /\+/g;
$owner =~ s/ /\+/g;
- print "$path $owner\n";
+ print {$output_handler} "$path $owner\n";
}
}
@@ -4896,12 +4902,12 @@ sub git_summary {
git_header_html();
git_print_page_nav('summary','', $head);
- print "<div class=\"title\"> </div>\n";
- print "<table class=\"projects_list\">\n" .
+ print {$output_handler} "<div class=\"title\"> </div>\n";
+ print {$output_handler} "<table class=\"projects_list\">\n" .
"<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
"<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
if (defined $cd{'rfc2822'}) {
- print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
+ print {$output_handler} "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
}
# use per project git URL list in $projectroot/$project/cloneurl
@@ -4911,7 +4917,7 @@ sub git_summary {
@url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
foreach my $git_url (@url_list) {
next unless $git_url;
- print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
+ print {$output_handler} "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
$url_tag = "";
}
@@ -4920,23 +4926,23 @@ sub git_summary {
if ($show_ctags) {
my $ctags = git_get_project_ctags($project);
my $cloud = git_populate_project_tagcloud($ctags);
- print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
- print "</td>\n<td>" unless %$ctags;
- print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
- print "</td>\n<td>" if %$ctags;
- print git_show_project_tagcloud($cloud, 48);
- print "</td></tr>";
+ print {$output_handler} "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
+ print {$output_handler} "</td>\n<td>" unless %$ctags;
+ print {$output_handler} "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
+ print {$output_handler} "</td>\n<td>" if %$ctags;
+ print {$output_handler} git_show_project_tagcloud($cloud, 48);
+ print {$output_handler} "</td></tr>";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
# If XSS prevention is on, we don't include README.html.
# TODO: Allow a readme in some safe format.
if (!$prevent_xss && -s "$projectroot/$project/README.html") {
- print "<div class=\"title\">readme</div>\n" .
+ print {$output_handler} "<div class=\"title\">readme</div>\n" .
"<div class=\"readme\">\n";
insert_file("$projectroot/$project/README.html");
- print "\n</div>\n"; # class="readme"
+ print {$output_handler} "\n</div>\n"; # class="readme"
}
# we need to request one more than 16 (0..15) to check if
@@ -4985,7 +4991,7 @@ sub git_tag {
}
git_print_header_div('commit', esc_html($tag{'name'}), $hash);
- print "<div class=\"title_text\">\n" .
+ print {$output_handler} "<div class=\"title_text\">\n" .
"<table class=\"object_header\">\n" .
"<tr>\n" .
"<td>object</td>\n" .
@@ -4997,15 +5003,15 @@ sub git_tag {
if (defined($tag{'author'})) {
git_print_authorship_rows(\%tag, 'author');
}
- print "</table>\n\n" .
+ print {$output_handler} "</table>\n\n" .
"</div>\n";
- print "<div class=\"page_body\">";
+ print {$output_handler} "<div class=\"page_body\">";
my $comment = $tag{'comment'};
foreach my $line (@$comment) {
chomp $line;
- print esc_html($line, -nbsp=>1) . "<br/>\n";
+ print {$output_handler} esc_html($line, -nbsp=>1) . "<br/>\n";
}
- print "</div>\n";
+ print {$output_handler} "</div>\n";
git_footer_html();
}
@@ -5056,21 +5062,23 @@ sub git_blame_common {
# incremental blame data returns early
if ($format eq 'data') {
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type=>"text/plain", -charset => "utf-8",
-status=> "200 OK");
local $| = 1; # output autoflush
- print while <$fd>;
+ while (<$fd>) {
+ print {$output_handler} $_;
+ }
close $fd
- or print "ERROR $!\n";
+ or die_error(500, "ERROR $!\n");
- print 'END';
+ print {$output_handler} 'END';
if (defined $t0 && gitweb_check_feature('timed')) {
- print ' '.
+ print {$output_handler} ' '.
Time::HiRes::tv_interval($t0, [Time::HiRes::gettimeofday()]).
' '.$number_of_git_cmds;
}
- print "\n";
+ print {$output_handler} "\n";
return;
}
@@ -5103,20 +5111,20 @@ sub git_blame_common {
# page body
if ($format eq 'incremental') {
- print "<noscript>\n<div class=\"error\"><center><b>\n".
+ print {$output_handler} "<noscript>\n<div class=\"error\"><center><b>\n".
"This page requires JavaScript to run.\n Use ".
$cgi->a({-href => href(action=>'blame',javascript=>0,-replay=>1)},
'this page').
" instead.\n".
"</b></center></div>\n</noscript>\n";
- print qq!<div id="progress_bar" style="width: 100%; background-color: yellow"></div>\n!;
+ print {$output_handler} qq!<div id="progress_bar" style="width: 100%; background-color: yellow"></div>\n!;
}
- print qq!<div class="page_body">\n!;
- print qq!<div id="progress_info">... / ...</div>\n!
+ print {$output_handler} qq!<div class="page_body">\n!;
+ print {$output_handler} qq!<div id="progress_info">... / ...</div>\n!
if ($format eq 'incremental');
- print qq!<table id="blame_table" class="blame" width="100%">\n!.
+ print {$output_handler} qq!<table id="blame_table" class="blame" width="100%">\n!.
#qq!<col width="5.5em" /><col width="2.5em" /><col width="*" />\n!.
qq!<thead>\n!.
qq!<tr><th>Commit</th><th>Line</th><th>Data</th></tr>\n!.
@@ -5137,12 +5145,12 @@ sub git_blame_common {
chomp $line;
$linenr++;
- print qq!<tr id="l$linenr" class="$color_class">!.
+ print {$output_handler} qq!<tr id="l$linenr" class="$color_class">!.
qq!<td class="sha1"><a href=""> </a></td>!.
qq!<td class="linenr">!.
qq!<a class="linenr" href="">$linenr</a></td>!;
- print qq!<td class="pre">! . esc_html($line) . "</td>\n";
- print qq!</tr>\n!;
+ print {$output_handler} qq!<td class="pre">! . esc_html($line) . "</td>\n";
+ print {$output_handler} qq!</tr>\n!;
}
} else { # porcelain, i.e. ordinary blame
@@ -5183,25 +5191,25 @@ sub git_blame_common {
$tr_class .= ' boundary' if (exists $meta->{'boundary'});
$tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
$tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
- print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
+ print {$output_handler} "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
if ($group_size) {
- print "<td class=\"sha1\"";
- print " title=\"". esc_html($author) . ", $date\"";
- print " rowspan=\"$group_size\"" if ($group_size > 1);
- print ">";
- print $cgi->a({-href => href(action=>"commit",
+ print {$output_handler} "<td class=\"sha1\"";
+ print {$output_handler} " title=\"". esc_html($author) . ", $date\"";
+ print {$output_handler} " rowspan=\"$group_size\"" if ($group_size > 1);
+ print {$output_handler} ">";
+ print {$output_handler} $cgi->a({-href => href(action=>"commit",
hash=>$full_rev,
file_name=>$file_name)},
esc_html($short_rev));
if ($group_size >= 2) {
my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
if (@author_initials) {
- print "<br />" .
+ print {$output_handler} "<br />" .
esc_html(join('', @author_initials));
# or join('.', ...)
}
}
- print "</td>\n";
+ print {$output_handler} "</td>\n";
}
# 'previous' <sha1 of parent commit> <filename at commit>
if (exists $meta->{'previous'} &&
@@ -5218,23 +5226,23 @@ sub git_blame_common {
my $blamed = href(action => 'blame',
file_name => $linenr_filename,
hash_base => $linenr_commit);
- print "<td class=\"linenr\">";
- print $cgi->a({ -href => "$blamed#l$orig_lineno",
+ print {$output_handler} "<td class=\"linenr\">";
+ print {$output_handler} $cgi->a({ -href => "$blamed#l$orig_lineno",
-class => "linenr" },
esc_html($lineno));
- print "</td>";
- print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
- print "</tr>\n";
+ print {$output_handler} "</td>";
+ print {$output_handler} "<td class=\"pre\">" . esc_html($data) . "</td>\n";
+ print {$output_handler} "</tr>\n";
} # end while
}
# footer
- print "</tbody>\n".
+ print {$output_handler} "</tbody>\n".
"</table>\n"; # class="blame"
- print "</div>\n"; # class="blame_body"
+ print {$output_handler} "</div>\n"; # class="blame_body"
close $fd
- or print "Reading blob failed\n";
+ or print {$output_handler} "Reading blob failed\n";
git_footer_html();
}
@@ -5317,16 +5325,17 @@ sub git_blob_plain {
my $sandbox = $prevent_xss &&
$type !~ m!^(?:text/plain|image/(?:gif|png|jpeg))$!;
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => $type,
-expires => $expires,
-content_disposition =>
($sandbox ? 'attachment' : 'inline')
. '; filename="' . $save_as . '"');
local $/ = undef;
- binmode STDOUT, ':raw';
- print <$fd>;
- binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+
+ binmode $output_handler_bin, ':raw';
+ print {$output_handler_bin} <$fd>;
+ binmode $output_handler_bin, ':utf8'; # as set at the beginning of gitweb.cgi
close $fd;
}
@@ -5385,18 +5394,18 @@ sub git_blob {
git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
- print "<div class=\"page_nav\">\n" .
+ print {$output_handler} "<div class=\"page_nav\">\n" .
"<br/><br/></div>\n" .
"<div class=\"title\">$hash</div>\n";
}
git_print_page_path($file_name, "blob", $hash_base);
- print "<div class=\"page_body\">\n";
+ print {$output_handler} "<div class=\"page_body\">\n";
if ($mimetype =~ m!^image/!) {
- print qq!<img type="$mimetype"!;
+ print {$output_handler} qq!<img type="$mimetype"!;
if ($file_name) {
- print qq! alt="$file_name" title="$file_name"!;
+ print {$output_handler} qq! alt="$file_name" title="$file_name"!;
}
- print qq! src="! .
+ print {$output_handler} qq! src="! .
href(action=>"blob_plain", hash=>$hash,
hash_base=>$hash_base, file_name=>$file_name) .
qq!" />\n!;
@@ -5406,14 +5415,14 @@ sub git_blob {
chomp $line;
$nr++;
$line = untabify($line);
- printf "<div class=\"pre\"><a id=\"l%i\" href=\"" . href(-replay => 1)
+ printf {$output_handler} "<div class=\"pre\"><a id=\"l%i\" href=\"" . href(-replay => 1)
. "#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
}
}
close $fd
- or print "Reading blob failed.\n";
- print "</div>";
+ or print {$output_handler} "Reading blob failed.\n";
+ print {$output_handler} "</div>";
git_footer_html();
}
@@ -5468,9 +5477,9 @@ sub git_tree {
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";
+ print {$output_handler} "<div class=\"page_nav\">\n";
+ print {$output_handler} "<br/><br/></div>\n";
+ print {$output_handler} "<div class=\"title\">$hash</div>\n";
}
if (defined $file_name) {
$basedir = $file_name;
@@ -5479,16 +5488,16 @@ sub git_tree {
}
git_print_page_path($file_name, 'tree', $hash_base);
}
- print "<div class=\"page_body\">\n";
- print "<table class=\"tree\">\n";
+ print {$output_handler} "<div class=\"page_body\">\n";
+ print {$output_handler} "<table class=\"tree\">\n";
my $alternate = 1;
# '..' (top directory) link if possible
if (defined $hash_base &&
defined $file_name && $file_name =~ m![^/]+$!) {
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
@@ -5496,33 +5505,33 @@ sub git_tree {
$up =~ s!/?[^/]+$!!;
undef $up unless $up;
# based on git_print_tree_entry
- print '<td class="mode">' . mode_str('040000') . "</td>\n";
- print '<td class="size"> </td>'."\n" if $show_sizes;
- print '<td class="list">';
- print $cgi->a({-href => href(action=>"tree",
+ print {$output_handler} '<td class="mode">' . mode_str('040000') . "</td>\n";
+ print {$output_handler} '<td class="size"> </td>'."\n" if $show_sizes;
+ print {$output_handler} '<td class="list">';
+ print {$output_handler} $cgi->a({-href => href(action=>"tree",
hash_base=>$hash_base,
file_name=>$up)},
"..");
- print "</td>\n";
- print "<td class=\"link\"></td>\n";
+ print {$output_handler} "</td>\n";
+ print {$output_handler} "<td class=\"link\"></td>\n";
- print "</tr>\n";
+ print {$output_handler} "</tr>\n";
}
foreach my $line (@entries) {
my %t = parse_ls_tree_line($line, -z => 1, -l => $show_sizes);
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
git_print_tree_entry(\%t, $basedir, $hash_base, $have_blame);
- print "</tr>\n";
+ print {$output_handler} "</tr>\n";
}
- print "</table>\n" .
+ print {$output_handler} "</table>\n" .
"</div>";
git_footer_html();
}
@@ -5599,16 +5608,16 @@ sub git_snapshot {
}
$filename =~ s/(["\\])/\\$1/g;
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => $known_snapshot_formats{$format}{'type'},
-content_disposition => 'inline; filename="' . $filename . '"',
-status => '200 OK');
open my $fd, "-|", $cmd
or die_error(500, "Execute git-archive failed");
- binmode STDOUT, ':raw';
- print <$fd>;
- binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+ binmode $output_handler_bin, ':raw';
+ print {$output_handler_bin} <$fd>;
+ binmode $output_handler_bin, ':utf8'; # as set at the beginning of gitweb.cgi
close $fd;
}
@@ -5759,11 +5768,11 @@ sub git_commit {
} else {
git_print_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash);
}
- print "<div class=\"title_text\">\n" .
+ print {$output_handler} "<div class=\"title_text\">\n" .
"<table class=\"object_header\">\n";
git_print_authorship_rows(\%co);
- print "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n";
- print "<tr>" .
+ print {$output_handler} "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n";
+ print {$output_handler} "<tr>" .
"<td>tree</td>" .
"<td class=\"sha1\">" .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash),
@@ -5774,13 +5783,13 @@ sub git_commit {
"tree");
my $snapshot_links = format_snapshot_links($hash);
if (defined $snapshot_links) {
- print " | " . $snapshot_links;
+ print {$output_handler} " | " . $snapshot_links;
}
- print "</td>" .
+ print {$output_handler} "</td>" .
"</tr>\n";
foreach my $par (@$parents) {
- print "<tr>" .
+ print {$output_handler} "<tr>" .
"<td>parent</td>" .
"<td class=\"sha1\">" .
$cgi->a({-href => href(action=>"commit", hash=>$par),
@@ -5793,12 +5802,12 @@ sub git_commit {
"</td>" .
"</tr>\n";
}
- print "</table>".
+ print {$output_handler} "</table>".
"</div>\n";
- print "<div class=\"page_body\">\n";
+ print {$output_handler} "<div class=\"page_body\">\n";
git_print_log($co{'comment'});
- print "</div>\n";
+ print {$output_handler} "</div>\n";
git_difftree_body(\@difftree, $hash, @$parents);
@@ -5846,7 +5855,7 @@ sub git_object {
die_error(400, "Not enough information to find object");
}
- print $cgi->redirect(-uri => href(action=>$type, -full=>1,
+ print {$output_handler} $cgi->redirect(-uri => href(action=>$type, -full=>1,
hash=>$hash, hash_base=>$hash_base,
file_name=>$file_name),
-status => '302 Found');
@@ -5937,23 +5946,23 @@ sub git_blobdiff {
git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
- print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
- print "<div class=\"title\">$hash vs $hash_parent</div>\n";
+ print {$output_handler} "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
+ print {$output_handler} "<div class=\"title\">$hash vs $hash_parent</div>\n";
}
if (defined $file_name) {
git_print_page_path($file_name, "blob", $hash_base);
} else {
- print "<div class=\"page_path\"></div>\n";
+ print {$output_handler} "<div class=\"page_path\"></div>\n";
}
} elsif ($format eq 'plain') {
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => 'text/plain',
-charset => 'utf-8',
-expires => $expires,
-content_disposition => 'inline; filename="' . "$file_name" . '.patch"');
- print "X-Git-Url: " . $cgi->self_url() . "\n\n";
+ print {$output_handler} "X-Git-Url: " . $cgi->self_url() . "\n\n";
} else {
die_error(400, "Unknown blobdiff format");
@@ -5961,12 +5970,12 @@ sub git_blobdiff {
# patch
if ($format eq 'html') {
- print "<div class=\"page_body\">\n";
+ print {$output_handler} "<div class=\"page_body\">\n";
git_patchset_body($fd, [ \%diffinfo ], $hash_base, $hash_parent_base);
close $fd;
- print "</div>\n"; # class="page_body"
+ print {$output_handler} "</div>\n"; # class="page_body"
git_footer_html();
} else {
@@ -5974,12 +5983,12 @@ sub git_blobdiff {
$line =~ s!a/($hash|$hash_parent)!'a/'.esc_path($diffinfo{'from_file'})!eg;
$line =~ s!b/($hash|$hash_parent)!'b/'.esc_path($diffinfo{'to_file'})!eg;
- print $line;
+ print {$output_handler} $line;
last if $line =~ m!^\+\+\+!;
}
local $/ = undef;
- print <$fd>;
+ print {$output_handler} <$fd>;
close $fd;
}
}
@@ -6142,16 +6151,16 @@ sub git_commitdiff {
git_header_html(undef, $expires);
git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
- print "<div class=\"title_text\">\n" .
+ print {$output_handler} "<div class=\"title_text\">\n" .
"<table class=\"object_header\">\n";
git_print_authorship_rows(\%co);
- print "</table>".
+ print {$output_handler} "</table>".
"</div>\n";
- print "<div class=\"page_body\">\n";
+ print {$output_handler} "<div class=\"page_body\">\n";
if (@{$co{'comment'}} > 1) {
- print "<div class=\"log\">\n";
+ print {$output_handler} "<div class=\"log\">\n";
git_print_log($co{'comment'}, -final_empty_line=> 1, -remove_title => 1);
- print "</div>\n"; # class="log"
+ print {$output_handler} "</div>\n"; # class="log"
}
} elsif ($format eq 'plain') {
@@ -6159,27 +6168,27 @@ sub git_commitdiff {
my $tagname = git_get_rev_name_tags($hash);
my $filename = basename($project) . "-$hash.patch";
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => 'text/plain',
-charset => 'utf-8',
-expires => $expires,
-content_disposition => 'inline; filename="' . "$filename" . '"');
my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
- print "From: " . to_utf8($co{'author'}) . "\n";
- print "Date: $ad{'rfc2822'} ($ad{'tz_local'})\n";
- print "Subject: " . to_utf8($co{'title'}) . "\n";
+ print {$output_handler} "From: " . to_utf8($co{'author'}) . "\n";
+ print {$output_handler} "Date: $ad{'rfc2822'} ($ad{'tz_local'})\n";
+ print {$output_handler} "Subject: " . to_utf8($co{'title'}) . "\n";
- print "X-Git-Tag: $tagname\n" if $tagname;
- print "X-Git-Url: " . $cgi->self_url() . "\n\n";
+ print {$output_handler} "X-Git-Tag: $tagname\n" if $tagname;
+ print {$output_handler} "X-Git-Url: " . $cgi->self_url() . "\n\n";
foreach my $line (@{$co{'comment'}}) {
- print to_utf8($line) . "\n";
+ print {$output_handler} to_utf8($line) . "\n";
}
- print "---\n\n";
+ print {$output_handler} "---\n\n";
} elsif ($format eq 'patch') {
my $filename = basename($project) . "-$hash.patch";
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => 'text/plain',
-charset => 'utf-8',
-expires => $expires,
@@ -6192,24 +6201,24 @@ sub git_commitdiff {
$hash_parent eq '-c' || $hash_parent eq '--cc';
git_difftree_body(\@difftree, $hash,
$use_parents ? @{$co{'parents'}} : $hash_parent);
- print "<br/>\n";
+ print {$output_handler} "<br/>\n";
git_patchset_body($fd, \@difftree, $hash,
$use_parents ? @{$co{'parents'}} : $hash_parent);
close $fd;
- print "</div>\n"; # class="page_body"
+ print {$output_handler} "</div>\n"; # class="page_body"
git_footer_html();
} elsif ($format eq 'plain') {
local $/ = undef;
- print <$fd>;
+ print {$output_handler} <$fd>;
close $fd
- or print "Reading git-diff-tree failed\n";
+ or print {$output_handler} "Reading git-diff-tree failed\n";
} elsif ($format eq 'patch') {
local $/ = undef;
- print <$fd>;
+ print {$output_handler} <$fd>;
close $fd
- or print "Reading git-format-patch failed\n";
+ or print {$output_handler} "Reading git-format-patch failed\n";
}
}
@@ -6312,7 +6321,7 @@ sub git_search {
git_print_page_nav('','', $hash,$co{'tree'},$hash);
git_print_header_div('commit', esc_html($co{'title'}), $hash);
- print "<table class=\"pickaxe search\">\n";
+ print {$output_handler} "<table class=\"pickaxe search\">\n";
my $alternate = 1;
local $/ = "\n";
open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,
@@ -6328,24 +6337,24 @@ sub git_search {
if (defined $set{'commit'}) {
# finish previous commit
if (%co) {
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") .
" | " .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree");
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>\n";
}
if ($alternate) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
$alternate ^= 1;
%co = parse_commit($set{'commit'});
my $author = chop_and_escape_str($co{'author_name'}, 15, 5);
- print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ print {$output_handler} "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
"<td><i>$author</i></td>\n" .
"<td>" .
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
@@ -6354,7 +6363,7 @@ sub git_search {
} elsif (defined $set{'to_id'}) {
next if ($set{'to_id'} =~ m/^0{40}$/);
- print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
+ print {$output_handler} $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
hash=>$set{'to_id'}, file_name=>$set{'to_file'}),
-class => "list"},
"<span class=\"match\">" . esc_path($set{'file'}) . "</span>") .
@@ -6365,23 +6374,23 @@ sub git_search {
# finish last commit (warning: repetition!)
if (%co) {
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") .
" | " .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree");
- print "</td>\n" .
+ print {$output_handler} "</td>\n" .
"</tr>\n";
}
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
if ($searchtype eq 'grep') {
git_print_page_nav('','', $hash,$co{'tree'},$hash);
git_print_header_div('commit', esc_html($co{'title'}), $hash);
- print "<table class=\"grep_search\">\n";
+ print {$output_handler} "<table class=\"grep_search\">\n";
my $alternate = 1;
my $matches = 0;
local $/ = "\n";
@@ -6400,21 +6409,21 @@ sub git_search {
(undef, $file, $lno, $ltext) = split(/:/, $line, 4);
}
if ($file ne $lastfile) {
- $lastfile and print "</td></tr>\n";
+ $lastfile and print {$output_handler} "</td></tr>\n";
if ($alternate++) {
- print "<tr class=\"dark\">\n";
+ print {$output_handler} "<tr class=\"dark\">\n";
} else {
- print "<tr class=\"light\">\n";
+ print {$output_handler} "<tr class=\"light\">\n";
}
- print "<td class=\"list\">".
+ print {$output_handler} "<td class=\"list\">".
$cgi->a({-href => href(action=>"blob", hash=>$co{'hash'},
file_name=>"$file"),
-class => "list"}, esc_path($file));
- print "</td><td>\n";
+ print {$output_handler} "</td><td>\n";
$lastfile = $file;
}
if ($binary) {
- print "<div class=\"binary\">Binary file</div>\n";
+ print {$output_handler} "<div class=\"binary\">Binary file</div>\n";
} else {
$ltext = untabify($ltext);
if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {
@@ -6426,7 +6435,7 @@ sub git_search {
} else {
$ltext = esc_html($ltext, -nbsp=>1);
}
- print "<div class=\"pre\">" .
+ print {$output_handler} "<div class=\"pre\">" .
$cgi->a({-href => href(action=>"blob", hash=>$co{'hash'},
file_name=>"$file").'#l'.$lno,
-class => "linenr"}, sprintf('%4i', $lno))
@@ -6434,16 +6443,16 @@ sub git_search {
}
}
if ($lastfile) {
- print "</td></tr>\n";
+ print {$output_handler} "</td></tr>\n";
if ($matches > 1000) {
- print "<div class=\"diff nodifferences\">Too many matches, listing trimmed</div>\n";
+ print {$output_handler} "<div class=\"diff nodifferences\">Too many matches, listing trimmed</div>\n";
}
} else {
- print "<div class=\"diff nodifferences\">No matches found</div>\n";
+ print {$output_handler} "<div class=\"diff nodifferences\">No matches found</div>\n";
}
close $fd;
- print "</table>\n";
+ print {$output_handler} "</table>\n";
}
git_footer_html();
}
@@ -6451,7 +6460,7 @@ sub git_search {
sub git_search_help {
git_header_html();
git_print_page_nav('','', $hash,$hash,$hash);
- print <<EOT;
+ print {$output_handler} <<EOT;
<p><strong>Pattern</strong> is by default a normal string that is matched precisely (but without
regard to case, except in the case of pickaxe). However, when you check the <em>re</em> checkbox,
the pattern entered is recognized as the POSIX extended
@@ -6463,7 +6472,7 @@ insensitive).</p>
EOT
my $have_grep = gitweb_check_feature('grep');
if ($have_grep) {
- print <<EOT;
+ print {$output_handler} <<EOT;
<dt><b>grep</b></dt>
<dd>All files in the currently selected tree (HEAD unless you are explicitly browsing
a different one) are searched for the given pattern. On large trees, this search can take
@@ -6472,7 +6481,7 @@ due to git-grep peculiarity, currently if regexp mode is turned off, the matches
case-sensitive.</dd>
EOT
}
- print <<EOT;
+ print {$output_handler} <<EOT;
<dt><b>author</b></dt>
<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.</dd>
<dt><b>committer</b></dt>
@@ -6480,7 +6489,7 @@ EOT
EOT
my $have_pickaxe = gitweb_check_feature('pickaxe');
if ($have_pickaxe) {
- print <<EOT;
+ print {$output_handler} <<EOT;
<dt><b>pickaxe</b></dt>
<dd>All commits that caused the string to appear or disappear from any file (changes that
added, removed or "modified" the string) will be listed. This search can take a while and
@@ -6488,7 +6497,7 @@ takes a lot of strain on the server, so please use it wisely. Note that since yo
interested even in changes just changing the case as well, this search is case sensitive.</dd>
EOT
}
- print "</dl>\n";
+ print {$output_handler} "</dl>\n";
git_footer_html();
}
@@ -6535,7 +6544,7 @@ sub git_feed {
$since = Time::ParseDate::parsedate($if_modified, GMT => 1);
}
if (defined $since && $latest_epoch <= $since) {
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => $content_type,
-charset => 'utf-8',
-last_modified => $latest_date{'rfc2822'},
@@ -6543,12 +6552,12 @@ sub git_feed {
return;
}
}
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => $content_type,
-charset => 'utf-8',
-last_modified => $latest_date{'rfc2822'});
} else {
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => $content_type,
-charset => 'utf-8');
}
@@ -6592,13 +6601,13 @@ sub git_feed {
} else {
$alt_url = href(-full=>1, action=>"summary");
}
- print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
+ print {$output_handler} qq!<?xml version="1.0" encoding="utf-8"?>\n!;
if ($format eq 'rss') {
- print <<XML;
+ print {$output_handler} <<XML;
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
XML
- print "<title>$title</title>\n" .
+ print {$output_handler} "<title>$title</title>\n" .
"<link>$alt_url</link>\n" .
"<description>$descr</description>\n" .
"<language>en</language>\n" .
@@ -6608,22 +6617,22 @@ XML
# prefer the logo to the favicon, since RSS
# doesn't allow both
my $img = esc_url($logo || $favicon);
- print "<image>\n" .
+ print {$output_handler} "<image>\n" .
"<url>$img</url>\n" .
"<title>$title</title>\n" .
"<link>$alt_url</link>\n" .
"</image>\n";
}
if (%latest_date) {
- print "<pubDate>$latest_date{'rfc2822'}</pubDate>\n";
- print "<lastBuildDate>$latest_date{'rfc2822'}</lastBuildDate>\n";
+ print {$output_handler} "<pubDate>$latest_date{'rfc2822'}</pubDate>\n";
+ print {$output_handler} "<lastBuildDate>$latest_date{'rfc2822'}</lastBuildDate>\n";
}
- print "<generator>gitweb v.$version/$git_version</generator>\n";
+ print {$output_handler} "<generator>gitweb v.$version/$git_version</generator>\n";
} elsif ($format eq 'atom') {
- print <<XML;
+ print {$output_handler} <<XML;
<feed xmlns="http://www.w3.org/2005/Atom">
XML
- print "<title>$title</title>\n" .
+ print {$output_handler} "<title>$title</title>\n" .
"<subtitle>$descr</subtitle>\n" .
'<link rel="alternate" type="text/html" href="' .
$alt_url . '" />' . "\n" .
@@ -6633,19 +6642,19 @@ XML
# use project owner for feed author
"<author><name>$owner</name></author>\n";
if (defined $favicon) {
- print "<icon>" . esc_url($favicon) . "</icon>\n";
+ print {$output_handler} "<icon>" . esc_url($favicon) . "</icon>\n";
}
if (defined $logo_url) {
# not twice as wide as tall: 72 x 27 pixels
- print "<logo>" . esc_url($logo) . "</logo>\n";
+ print {$output_handler} "<logo>" . esc_url($logo) . "</logo>\n";
}
if (! %latest_date) {
# dummy date to keep the feed valid until commits trickle in:
- print "<updated>1970-01-01T00:00:00Z</updated>\n";
+ print {$output_handler} "<updated>1970-01-01T00:00:00Z</updated>\n";
} else {
- print "<updated>$latest_date{'iso-8601'}</updated>\n";
+ print {$output_handler} "<updated>$latest_date{'iso-8601'}</updated>\n";
}
- print "<generator version='$version/$git_version'>gitweb</generator>\n";
+ print {$output_handler} "<generator version='$version/$git_version'>gitweb</generator>\n";
}
# contents
@@ -6670,7 +6679,7 @@ XML
# print element (entry, item)
my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit);
if ($format eq 'rss') {
- print "<item>\n" .
+ print {$output_handler} "<item>\n" .
"<title>" . esc_html($co{'title'}) . "</title>\n" .
"<author>" . esc_html($co{'author'}) . "</author>\n" .
"<pubDate>$cd{'rfc2822'}</pubDate>\n" .
@@ -6680,22 +6689,22 @@ XML
"<content:encoded>" .
"<![CDATA[\n";
} elsif ($format eq 'atom') {
- print "<entry>\n" .
+ print {$output_handler} "<entry>\n" .
"<title type=\"html\">" . esc_html($co{'title'}) . "</title>\n" .
"<updated>$cd{'iso-8601'}</updated>\n" .
"<author>\n" .
" <name>" . esc_html($co{'author_name'}) . "</name>\n";
if ($co{'author_email'}) {
- print " <email>" . esc_html($co{'author_email'}) . "</email>\n";
+ print {$output_handler} " <email>" . esc_html($co{'author_email'}) . "</email>\n";
}
- print "</author>\n" .
+ print {$output_handler} "</author>\n" .
# use committer for contributor
"<contributor>\n" .
" <name>" . esc_html($co{'committer_name'}) . "</name>\n";
if ($co{'committer_email'}) {
- print " <email>" . esc_html($co{'committer_email'}) . "</email>\n";
+ print {$output_handler} " <email>" . esc_html($co{'committer_email'}) . "</email>\n";
}
- print "</contributor>\n" .
+ print {$output_handler} "</contributor>\n" .
"<published>$cd{'iso-8601'}</published>\n" .
"<link rel=\"alternate\" type=\"text/html\" href=\"$co_url\" />\n" .
"<id>$co_url</id>\n" .
@@ -6703,19 +6712,19 @@ XML
"<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
}
my $comment = $co{'comment'};
- print "<pre>\n";
+ print {$output_handler} "<pre>\n";
foreach my $line (@$comment) {
$line = esc_html($line);
- print "$line\n";
+ print {$output_handler} "$line\n";
}
- print "</pre><ul>\n";
+ print {$output_handler} "</pre><ul>\n";
foreach my $difftree_line (@difftree) {
my %difftree = parse_difftree_raw_line($difftree_line);
next if !$difftree{'from_id'};
my $file = $difftree{'file'} || $difftree{'to_file'};
- print "<li>" .
+ print {$output_handler} "<li>" .
"[" .
$cgi->a({-href => href(-full=>1, action=>"blobdiff",
hash=>$difftree{'to_id'}, hash_parent=>$difftree{'from_id'},
@@ -6723,26 +6732,26 @@ XML
file_name=>$file, file_parent=>$difftree{'from_file'}),
-title => "diff"}, 'D');
if ($have_blame) {
- print $cgi->a({-href => href(-full=>1, action=>"blame",
+ print {$output_handler} $cgi->a({-href => href(-full=>1, action=>"blame",
file_name=>$file, hash_base=>$commit),
-title => "blame"}, 'B');
}
# if this is not a feed of a file history
if (!defined $file_name || $file_name ne $file) {
- print $cgi->a({-href => href(-full=>1, action=>"history",
+ print {$output_handler} $cgi->a({-href => href(-full=>1, action=>"history",
file_name=>$file, hash=>$commit),
-title => "history"}, 'H');
}
$file = esc_path($file);
- print "] ".
+ print {$output_handler} "] ".
"$file</li>\n";
}
if ($format eq 'rss') {
- print "</ul>]]>\n" .
+ print {$output_handler} "</ul>]]>\n" .
"</content:encoded>\n" .
"</item>\n";
} elsif ($format eq 'atom') {
- print "</ul>\n</div>\n" .
+ print {$output_handler} "</ul>\n</div>\n" .
"</content>\n" .
"</entry>\n";
}
@@ -6750,9 +6759,9 @@ XML
# end of feed
if ($format eq 'rss') {
- print "</channel>\n</rss>\n";
+ print {$output_handler} "</channel>\n</rss>\n";
} elsif ($format eq 'atom') {
- print "</feed>\n";
+ print {$output_handler} "</feed>\n";
}
}
@@ -6766,13 +6775,12 @@ sub git_atom {
sub git_opml {
my @list = git_get_projects_list();
-
- print $cgi->header(
+ print {$output_handler} $cgi->header(
-type => 'text/xml',
-charset => 'utf-8',
-content_disposition => 'inline; filename="opml.xml"');
- print <<XML;
+ print {$output_handler} <<XML;
<?xml version="1.0" encoding="utf-8"?>
<opml version="1.0">
<head>
@@ -6797,9 +6805,9 @@ XML
my $path = esc_html(chop_str($proj{'path'}, 25, 5));
my $rss = href('project' => $proj{'path'}, 'action' => 'rss', -full => 1);
my $html = href('project' => $proj{'path'}, 'action' => 'summary', -full => 1);
- print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
+ print {$output_handler} "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
}
- print <<XML;
+ print {$output_handler} <<XML;
</outline>
</body>
</opml>
--
1.6.5.2
^ permalink raw reply related
* [PATCH 6/7] gitweb: add a get function to compliment print_local_time
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-6-git-send-email-warthog9@eaglescrag.net>
This adds a get function for print_local_time so that the basic
function can be used outside of their straight printing operation.
---
gitweb/gitweb.perl | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3b6bc06..3010fe3 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -3548,14 +3548,21 @@ sub git_print_header_div {
}
sub print_local_time {
+ print {$output_handler} get_local_time(@_);
+}
+
+sub get_local_time {
+ my $localtime = "";
my %date = @_;
if ($date{'hour_local'} < 6) {
- printf({$output_handler} " (<span class=\"atnight\">%02d:%02d</span> %s)",
+ $localtime .= sprintf(" (<span class=\"atnight\">%02d:%02d</span> %s)",
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
} else {
- printf({$output_handler} " (%02d:%02d %s)",
+ $localtime .= sprintf(" (%02d:%02d %s)",
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
}
+
+ return $localtime
}
# Outputs the author name and date in long form
--
1.6.5.2
^ permalink raw reply related
* [PATCH 7/7] gitweb: File based caching layer (from git.kernel.org)
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-7-git-send-email-warthog9@eaglescrag.net>
This is a very large patch that implements the file based
caching layer that is used on such large sites as kernel.org and
soon git.fedoraproject.org. This provides a simple, and straight
forward caching mechanism that scales dramatically better than
Gitweb by itself.
The caching layer basically buffers the output that Gitweb would
normally return, and saves that output to a cache file on the local
disk. When the file is requested it attempts to gain a shared lock
on the cache file and cat it out to the client. Should an exclusive
lock be on a file (it's being updated) the code has a choice to either
update in the background and go ahead and show the stale page while
update is being performed, or stall the client(s) until the page
is generated.
There are two forms of stalling involved here, background building
and non-background building, both of which are discussed in the
configuration page.
There are still a few known "issues" with respect to this:
- Code needs to be added to be "browser" aware so
that clients like wget that are trying to get a
binary blob don't obtain a "Generating..." page
- There is an intermittent flushing issue that has yet
to be tracked down
Caching is disabled by default with the $cache_enable variable,
setting this to 1 will enable file based caching. It is expected
that this will be extended to include additional types of caching
(like memcached) in the future and should not be exclusively
considered a binary value.
v4 - warthog9: refactoring to use modified and indirect print
statements as opposed to passing the output around
in memory. This means without caching enabled you
should get exactly the same behavior as if you
never had the caching code at all.
---
gitweb/cache.pm | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gitweb/gitweb.css | 6 +
gitweb/gitweb.perl | 56 ++++++++++-
3 files changed, 343 insertions(+), 2 deletions(-)
create mode 100644 gitweb/cache.pm
diff --git a/gitweb/cache.pm b/gitweb/cache.pm
new file mode 100644
index 0000000..89fa577
--- /dev/null
+++ b/gitweb/cache.pm
@@ -0,0 +1,283 @@
+# gitweb - simple web interface to track changes in git repositories
+#
+# (C) 2006, John 'Warthog9' Hawley <warthog19@eaglescrag.net>
+#
+# This program is licensed under the GPLv2
+
+#
+# Gitweb caching engine
+#
+
+use File::Path qw(make_path remove_tree);
+use Digest::MD5 qw(md5 md5_hex md5_base64);
+use Fcntl ':flock';
+
+sub cache_fetch {
+ my ($action) = @_;
+ my $cacheTime = 0;
+
+ # Deal with cache being disabled
+ if( $cache_enable == 0 ){
+ $output_handler = *STDOUT;
+ $output_handler_bin = *STDOUT;
+ $actions{$action}->();
+ return;
+ }elsif( $cache_enable == 1 ){
+ #obviously we are using file based caching
+
+ if(! -d $cachedir){
+ print "*** Warning ***: Caching enabled but cache directory does not exsist. ($cachedir)\n";
+ mkdir ("cache", 0665) || die "Cannot create cache dir - you will need to manually create";
+ print "Cache directory created successfully\n";
+ }
+
+ our $full_url = "$my_url?". $ENV{'QUERY_STRING'};
+ our $urlhash = md5_hex($full_url);
+ our $fullhashdir = "$cachedir/". substr( $urlhash, 0, 2) ."/";
+
+ my $numdirs = make_path( $fullhashdir, { mode => 0777, error => \my $mkdirerr, } );
+ if( @$mkdirerr ){
+ my $mkdirerrmsg = "";
+ for my $diag (@$mkdirerr) {
+ my ($file, $message) = %$diag;
+ if($file eq '' ){
+ $mkdirerrmsg .= "general error: $message\n";
+ }else{
+ $mkdirerrmsg .= "problem unlinking $file: $message\n";
+ }
+ }
+ die_error(500, "Could not create cache directory | $mkdirerrmsg");
+ }
+ $fullhashpath = "$fullhashdir/". substr( $urlhash, 2 );
+ $fullhashbinpath = "$fullhashpath.bin";
+ } # done dealing with cache enabled / disabled
+
+ if(! -e "$fullhashpath" ){
+ if(! defined(my $childPid = fork()) ){
+ cacheUpdate($action,0);
+ cacheDisplay($action);
+ } elsif ( $childPid == 0 ){
+ #run the updater
+ cacheUpdate($action,1);
+ }else{
+ cacheWaitForUpdate($action);
+ }
+ }else{
+ #if cache is out dated, update
+ #else displayCache();
+ open(cacheFile, '<', "$fullhashpath");
+ stat(cacheFile);
+ close(cacheFile);
+ $cacheTime = get_loadavg() * 60;
+ if( $cacheTime > $maxCacheTime ){
+ $cacheTime = $maxCacheTime;
+ }
+ if( $cacheTime < $minCacheTime ){
+ $cacheTime = $minCacheTime;
+ }
+ if( (stat(_))[9] < (time - $cacheTime) ){
+ if( ! defined(my $childPid = fork()) ){
+ cacheUpdate($action,0);
+ cacheDisplay($action);
+ } elsif ( $childPid == 0 ){
+ #run the updater
+ #print "Running updater\n";
+ cacheUpdate($action,1);
+ }else{
+ #print "Waiting for update\n";
+ cacheWaitForUpdate($action);
+ }
+ } else {
+ cacheDisplay($action);
+ }
+
+
+ }
+
+ #
+ # If all of the caching failes - lets go ahead and press on without it and fall back to 'default'
+ # non-caching behavior. This is the softest of the failure conditions.
+ #
+ #$actions{$action}->();
+}
+
+sub cacheUpdate {
+ my ($action,$areForked) = @_;
+ my $lockingStatus;
+ my $fileData = "";
+
+ if($backgroundCache){
+ open(cacheFileBG, '>:utf8', "$fullhashpath.bg");
+ my $lockStatBG = flock(cacheFileBG,LOCK_EX|LOCK_NB);
+
+ $lockStatus = $lockStatBG;
+ }else{
+ open(cacheFile, '>:utf8', "$fullhashpath");
+ my $lockStat = flock(cacheFile,LOCK_EX|LOCK_NB);
+
+ $lockStatus = $lockStat;
+ }
+ #print "lock status: $lockStat\n";
+
+
+ if (! $lockStatus ){
+ if ( $areForked ){
+ exit(0);
+ }else{
+ return;
+ }
+ }
+
+ if(
+ $action eq "snapshot"
+ ||
+ $action eq "blob_plain"
+ ){
+ open cacheFileBin, '>', $fullhashbinpath or die_error(500, "Could not open bin dump file");
+ $output_handler_bin = *cacheFileBin;
+ }
+
+ $output_handler = *cacheFile;
+
+ if($backgroundCache){
+ open(cacheFile, '>:utf8', "$fullhashpath");
+ $lockStat = flock(cacheFile,LOCK_EX);
+
+ if (! $lockStat ){
+ if ( $areForked ){
+ exit(0);
+ }else{
+ return;
+ }
+ }
+ }
+
+ $actions{$action}->();
+
+ if(
+ $action eq "snapshot"
+ ||
+ $action eq "blob_plain"
+ ){
+ close(cacheFileBin);
+ }
+
+ flock(cacheFile,LOCK_UN);
+ close(cacheFile);
+
+ if($backgroundCache){
+ flock(cacheFileBG,LOCK_UN);
+ close(cacheFileBG);
+ }
+
+ if ( $areForked ){
+ exit(0);
+ } else {
+ return;
+ }
+}
+
+
+sub cacheWaitForUpdate {
+ my ($action) = @_;
+ my $x = 0;
+ my $max = 10;
+ my $lockStat = 0;
+
+ if( $backgroundCache ){
+ if( -e "$fullhashpath" ){
+ open(cacheFile, '<:utf8', "$fullhashpath");
+ $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
+ stat(cacheFile);
+ close(cacheFile);
+
+ if( $lockStat && ( (stat(_))[9] > (time - $maxCacheLife) ) ){
+ cacheDisplay($action);
+ return;
+ }
+ }
+ }
+
+ if(
+ $action eq "atom"
+ ||
+ $action eq "rss"
+ ||
+ $action eq "opml"
+ ){
+ do {
+ sleep 2 if $x > 0;
+ open(cacheFile, '<:utf8', "$fullhashpath");
+ $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
+ close(cacheFile);
+ $x++;
+ $combinedLockStat = $lockStat;
+ } while ((! $combinedLockStat) && ($x < $max));
+
+ if( $x != $max ){
+ cacheDisplay($action);
+ }
+ return;
+ }
+
+ $| = 1;
+
+ print $::cgi->header(-type=>'text/html', -charset => 'utf-8',
+ -status=> 200, -expires => 'never');
+
+ print <<EOF;
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www/w3.porg/TR/html4/strict.dtd">
+<!-- git web w/caching interface version $version, (C) 2006-2010, John 'Warthog9' Hawley <warthog9\@kernel.org> -->
+<!-- git core binaries version $git_version -->
+<head>
+<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
+<meta name="generator" content="gitweb/$version git/$git_version"/>
+<meta name="robots" content="index, nofollow"/>
+<meta http-equiv="refresh" content="0"/>
+<title>$title</title>
+</head>
+<body>
+EOF
+
+ print "Generating..";
+ do {
+ print ".";
+ sleep 2 if $x > 0;
+ open(cacheFile, '<:utf8', "$fullhashpath");
+ $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
+ close(cacheFile);
+ $x++;
+ $combinedLockStat = $lockStat;
+ } while ((! $combinedLockStat) && ($x < $max));
+ print <<EOF;
+</body>
+</html>
+EOF
+ return;
+}
+
+sub cacheDisplay {
+ my ($action) = @_;
+ open(cacheFile, '<:utf8', "$fullhashpath");
+ $lockStat = flock(cacheFile,LOCK_SH|LOCK_NB);
+ if (! $lockStat ){
+ close(cacheFile);
+ cacheWaitForUpdate($action);
+ }
+
+ while( <cacheFile> ){
+ print $_;
+ }
+ if(
+ $action eq "snapshot"
+ ||
+ $action eq "blob_plain"
+ ){
+ open(cacheFileBin, '<', "$fullhashbinpath");
+ binmode STDOUT, ':raw';
+ print <cacheFileBin>;
+ binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+ close(cacheFileBin);
+ }
+ close(cacheFile);
+}
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 50067f2..f809f16 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -67,6 +67,12 @@ div.page_path {
border-width: 0px 0px 1px;
}
+div.cachetime {
+ float: left;
+ margin-right: 10px;
+ color: #555555;
+}
+
div.page_footer {
height: 17px;
padding: 4px 8px;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 3010fe3..3e0fa45 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -235,6 +235,50 @@ our $gitlinkurl_project = '';
# Leave it undefined (or set to 'undef') to turn off load checking.
our $maxload = 300;
+# This enables/disables the caching layer in gitweb. This currently only supports the
+# 'dumb' file based caching layer, primarily used on git.kernel.org. this is reasonably
+# effective but it has the downside of requiring a huge amount of disk space if there
+# are a number of repositories involved. It is not uncommon for git.kernel.org to have
+# on the order of 80G - 120G accumulate over the course of a few months. It is recommended
+# that the cache directory be periodically completely deleted, and this is safe to perform.
+# Suggested mechanism
+# mv $cacheidr $cachedir.flush;mkdir $cachedir;rm -rf $cachedir.flush
+# Value is binary. 0 = disabled (default), 1 = enabled.
+#
+# Values of caching:
+# 1 = 'dumb' file based caching used on git.kernel.org
+our $cache_enable = 0;
+
+# Used to set the minimum cache timeout for the dynamic caching algorithm. Basically
+# if we calculate the cache to be under this number of seconds we set the cache timeout
+# to this minimum.
+# Value is in seconds. 1 = 1 seconds, 60 = 1 minute, 600 = 10 minutes, 3600 = 1 hour
+our $minCacheTime = 20;
+
+# Used to set the maximum cache timeout for the dynamic caching algorithm. Basically
+# if we calculate the cache to exceed this number of seconds we set the cache timeout
+# to this maximum.
+# Value is in seconds. 1 = 1 seconds, 60 = 1 minute, 600 = 10 minutes, 3600 = 1 hour
+our $maxCacheTime = 1200;
+
+# If you need to change the location of the caching directory, override this
+# otherwise this will probably do fine for you
+our $cachedir = 'cache';
+
+# If this is set (to 1) cache will do it's best to always display something instead
+# of making someone wait for the cache to update. This will launch the cacheUpdate
+# into the background and it will lock a <file>.bg file and will only lock the
+# actual cache file when it needs to write into it. In theory this will make
+# gitweb seem more responsive at the price of possibly stale data.
+our $backgroundCache = 1;
+
+# Used to set the maximum cache file life. If a cache files last modify time exceeds
+# this value, it will assume that the data is just too old, and HAS to be regenerated
+# instead of trying to display the existing cache data.
+# Value is in seconds. 1 = 1 seconds, 60 = 1 minute, 600 = 10 minutes, 3600 = 1 hour
+# 18000 = 5 hours
+our $maxCacheLife = 18000;
+
# You define site-wide feature defaults here; override them with
# $GITWEB_CONFIG as necessary.
our %feature = (
@@ -598,6 +642,11 @@ if (defined $maxload && get_loadavg() > $maxload) {
die_error(503, "The load average on the server is too high");
}
+#
+# Includes
+#
+do 'cache.pm';
+
# version of the core git binary
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
$number_of_git_cmds++;
@@ -1004,7 +1053,7 @@ if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
!$project) {
die_error(400, "Project needed");
}
-$actions{$action}->();
+cache_fetch($action);
exit;
## ======================================================================
@@ -3210,7 +3259,9 @@ sub git_header_html {
# support xhtml+xml but choking when it gets what it asked for.
if (defined $cgi->http('HTTP_ACCEPT') &&
$cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ &&
- $cgi->Accept('application/xhtml+xml') != 0) {
+ $cgi->Accept('application/xhtml+xml') != 0
+ &&
+ $cache_enable == 0) {
$content_type = 'application/xhtml+xml';
} else {
$content_type = 'text/html';
@@ -3354,6 +3405,7 @@ sub git_footer_html {
my $feed_class = 'rss_logo';
print {$output_handler} "<div class=\"page_footer\">\n";
+ print {$output_handler} "<div class=\"cachetime\">Cache Last Updated: ". gmtime( time ) ." GMT</div>\n";
if (defined $project) {
my $descr = git_get_project_description($project);
if (defined $descr) {
--
1.6.5.2
^ permalink raw reply related
* [PATCH 4/7] gitweb: Optionally add "git" links in project list page
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-4-git-send-email-warthog9@eaglescrag.net>
From: John 'Warthog9' Hawley <warthog9@kernel.org>
This adds a "git" link for each project in the project list page,
should a common $gitlinkurl_project be defined and not empty. The full
URL of each link is composed of $git_base_url_list[0] and project name.
It is intended for git:// links or that something can reference the git
repository using a smart protocol directly.
This does make the assumption that the git repositories share a common
path, which is no different than the assumption @git_base_url_list makes.
Nothing to date is known to actually make use of introduced link.
Created "git" link follows rel=vcs-* microformat specification:
http://kitenet.net/~joey/rfc/rel-vcs/
Signed-off-by: John 'Warthog9' Hawley <warthog9@kernel.org>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/README | 4 ++++
gitweb/gitweb.perl | 9 +++++++++
2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/gitweb/README b/gitweb/README
index 608b0f8..2ec66e7 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -71,6 +71,7 @@ You can specify the following configuration variables when building GIT:
* GITWEB_BASE_URL
Git base URLs used for URL to where fetch project from, i.e. full
URL is "$git_base_url/$project". Shown on projects summary page.
+ If it begins with "git://" it is also used for $gitlinkurl_base, see below.
Repository URL for project can be also configured per repository; this
takes precedence over URLs composed from base URL and a project name.
Note that you can setup multiple base URLs (for example one for
@@ -204,6 +205,9 @@ not include variables usually directly set during build):
access, and one for http:// "dumb" protocol access). Note that per
repository configuration in 'cloneurl' file, or as values of gitweb.url
project config.
+ * $gitlinkurl_project
+ Boolean (if it is defined and not empty) to add "git" link in
+ projects list, for each project. Full URL is "$git_base_url_list[0]/$project".
* $default_blob_plain_mimetype
Default mimetype for blob_plain (raw) view, if mimetype checking
doesn't result in some other type; by default 'text/plain'.
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f17593f..b8f2a67 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -224,6 +224,11 @@ our %avatar_size = (
# If it is true, exit if gitweb version and git binary version don't match
our $git_versions_must_match = 0;
+# This is a boolean on/off switch to add a "git" link for each project in
+# project list. It uses the first element of @git_base_url_list as the
+# base of the URL. Full URL is "$git_base_url_list[0]/$project".
+our $gitlinkurl_project = '';
+
# Used to set the maximum load that we will still respond to gitweb queries.
# If server load exceed this value then return "503 server busy" error.
# If gitweb cannot determined server load, it is taken to be 0.
@@ -4473,6 +4478,10 @@ sub git_project_list_body {
$cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
$cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') .
+ ($gitlinkurl_project && $git_base_url_list[0] ?
+ " | " . $cgi->a({-href=> $git_base_url_list[0] ."/$pr->{'path'}",
+ -rel=>"vcs-git"}, "git")
+ : '') .
"</td>\n" .
"</tr>\n";
}
--
1.6.5.2
^ permalink raw reply related
* [PATCH 2/7] gitweb: Add option to force version match
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-2-git-send-email-warthog9@eaglescrag.net>
From: John 'Warthog9' Hawley <warthog9@kernel.org>
This adds $git_versions_must_match variable, which is set to true
value checks that we are running on the same version of git that we
shipped with, and if not throw '500 Internal Server Error' error.
What is checked is the version of gitweb (embedded in building
gitweb.cgi), against version of runtime git binary used.
Gitweb can usually run with a mismatched git install. This is more
here to give an obvious warning as to whats going on vs. silently
failing.
By default this feature is turned off.
v3 - warthog9: adjust to use die_error instead of recreating it
v2 - Jakub: Changes to make non-default, and change naming
v1 - warthog9: Initial
Signed-off-by: John 'Warthog9' Hawley <warthog9@kernel.org>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/README | 3 +++
gitweb/gitweb.perl | 28 ++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/gitweb/README b/gitweb/README
index 6c2c8e1..608b0f8 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -233,6 +233,9 @@ not include variables usually directly set during build):
If server load exceed this value then return "503 Service Unavaliable" error.
Server load is taken to be 0 if gitweb cannot determine its value. Set it to
undefined value to turn it off. The default is 300.
+ * $git_versions_must_match
+ If set, gitweb fails with 500 Internal Server Error if the version of gitweb
+ doesn't match version of git binary. The default is false.
Projects list file format
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 0a07d3a..f17593f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -221,6 +221,9 @@ our %avatar_size = (
'double' => 32
);
+# If it is true, exit if gitweb version and git binary version don't match
+our $git_versions_must_match = 0;
+
# Used to set the maximum load that we will still respond to gitweb queries.
# If server load exceed this value then return "503 server busy" error.
# If gitweb cannot determined server load, it is taken to be 0.
@@ -587,6 +590,31 @@ if (defined $maxload && get_loadavg() > $maxload) {
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
$number_of_git_cmds++;
+# Throw an error if git versions does not match, if $git_versions_must_match is true.
+if ($git_versions_must_match &&
+ $git_version ne $version) {
+ my $admin_contact =
+ defined $ENV{'SERVER_ADMIN'} ? ", $ENV{'SERVER_ADMIN'}," : '';
+ my $err_msg = <<EOT;
+Internal Server Error
+<br />
+</div>
+<hr />
+<div class="readme">
+<h1 align="center">*** Warning ***</h1>
+<p>
+This version of gitweb was compiled for <b>@{[esc_html($version)]}</b>,
+however git version <b>@{[esc_html($git_version)]}</b> was found on server,
+and administrator requested strict version checking.
+</p>
+<p>
+Please contact the server administrator${admin_contact} to either configure
+gitweb to allow mismatched versions, or update git or gitweb installation.
+</p>
+EOT
+ die_error(500, $err_msg);
+}
+
$projects_list ||= $projectroot;
# ======================================================================
--
1.6.5.2
^ permalink raw reply related
* [PATCH 3/7] gitweb: Makefile improvements
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-3-git-send-email-warthog9@eaglescrag.net>
From: John 'Warthog9' Hawley <warthog9@kernel.org>
This commit adjust the main Makefile so you can simply run
make gitweb
which in turn calls gitweb/Makefile. This means that in order to
generate gitweb, you can simply run 'make' from gitweb subdirectory:
cd gitweb
make
Targets gitweb/gitweb.cgi and (dependent on JSMIN being defined)
gitweb/gitweb.min.js in main Makefile are preserved for backward
compatibility.
Signed-off-by: John 'Warthog9' Hawley <warthog9@kernel.org>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Makefile | 91 +++++++++++++++++----------------------
gitweb/Makefile | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 169 insertions(+), 51 deletions(-)
create mode 100644 gitweb/Makefile
diff --git a/Makefile b/Makefile
index 4a1e5bc..ffef979 100644
--- a/Makefile
+++ b/Makefile
@@ -280,29 +280,6 @@ pathsep = :
# JavaScript minifier invocation that can function as filter
JSMIN =
-# default configuration for gitweb
-GITWEB_CONFIG = gitweb_config.perl
-GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
-GITWEB_HOME_LINK_STR = projects
-GITWEB_SITENAME =
-GITWEB_PROJECTROOT = /pub/git
-GITWEB_PROJECT_MAXDEPTH = 2007
-GITWEB_EXPORT_OK =
-GITWEB_STRICT_EXPORT =
-GITWEB_BASE_URL =
-GITWEB_LIST =
-GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = gitweb.css
-GITWEB_LOGO = git-logo.png
-GITWEB_FAVICON = git-favicon.png
-ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-else
-GITWEB_JS = gitweb.js
-endif
-GITWEB_SITE_HEADER =
-GITWEB_SITE_FOOTER =
-
export prefix bindir sharedir sysconfdir
CC = gcc
@@ -1509,6 +1486,11 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
chmod +x $@+ && \
mv $@+ $@
+
+.PHONY: gitweb
+gitweb:
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
+
ifdef JSMIN
OTHER_PROGRAMS += gitweb/gitweb.cgi gitweb/gitweb.min.js
gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
@@ -1516,30 +1498,13 @@ else
OTHER_PROGRAMS += gitweb/gitweb.cgi
gitweb/gitweb.cgi: gitweb/gitweb.perl
endif
- $(QUIET_GEN)$(RM) $@ $@+ && \
- sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
- -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
- -e 's|++GIT_BINDIR++|$(bindir)|g' \
- -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
- -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
- -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
- -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
- -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
- -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
- -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
- -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
- -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
- -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
- -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
- -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
- -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
- -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
- -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
- -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
- -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
- $< >$@+ && \
- chmod +x $@+ && \
- mv $@+ $@
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+
+ifdef JSMIN
+gitweb/gitweb.min.js: gitweb/gitweb.js
+ $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+endif # JSMIN
+
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
$(QUIET_GEN)$(RM) $@ $@+ && \
@@ -1566,10 +1531,34 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
mv $@+ $@
endif # NO_PERL
-ifdef JSMIN
-gitweb/gitweb.min.js: gitweb/gitweb.js
- $(QUIET_GEN)$(JSMIN) <$< >$@
-endif # JSMIN
+ifndef NO_PYTHON
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
+ $(QUIET_GEN)$(RM) $@ $@+ && \
+ INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
+ --no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
+ instlibdir` && \
+ sed -e '1{' \
+ -e ' s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
+ -e '}' \
+ -e 's|^import sys.*|&; \\\
+ import os; \\\
+ sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
+ os.environ["GITPYTHONLIB"] or \\\
+ "@@INSTLIBDIR@@"|' \
+ -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
+ $@.py >$@+ && \
+ chmod +x $@+ && \
+ mv $@+ $@
+else # NO_PYTHON
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
+ $(QUIET_GEN)$(RM) $@ $@+ && \
+ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+ -e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \
+ unimplemented.sh >$@+ && \
+ chmod +x $@+ && \
+ mv $@+ $@
+endif # NO_PYTHON
configure: configure.ac
$(QUIET_GEN)$(RM) $@ $<+ && \
diff --git a/gitweb/Makefile b/gitweb/Makefile
new file mode 100644
index 0000000..c9eb1ee
--- /dev/null
+++ b/gitweb/Makefile
@@ -0,0 +1,129 @@
+# The default target of this Makefile is...
+all::
+
+# Define V=1 to have a more verbose compile.
+#
+# Define JSMIN to point to JavaScript minifier that functions as
+# a filter to have gitweb.js minified.
+#
+
+prefix ?= $(HOME)
+bindir ?= $(prefix)/bin
+RM ?= rm -f
+
+# JavaScript minifier invocation that can function as filter
+JSMIN ?=
+
+# default configuration for gitweb
+GITWEB_CONFIG = gitweb_config.perl
+GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
+GITWEB_HOME_LINK_STR = projects
+GITWEB_SITENAME =
+GITWEB_PROJECTROOT = /pub/git
+GITWEB_PROJECT_MAXDEPTH = 2007
+GITWEB_EXPORT_OK =
+GITWEB_STRICT_EXPORT =
+GITWEB_BASE_URL =
+GITWEB_LIST =
+GITWEB_HOMETEXT = indextext.html
+GITWEB_CSS = gitweb.css
+GITWEB_LOGO = git-logo.png
+GITWEB_FAVICON = git-favicon.png
+ifdef JSMIN
+GITWEB_JS = gitweb.min.js
+else
+GITWEB_JS = gitweb.js
+endif
+GITWEB_SITE_HEADER =
+GITWEB_SITE_FOOTER =
+
+# include user config
+-include ../config.mak.autogen
+-include ../config.mak
+
+# determine version
+../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
+ $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
+
+-include ../GIT-VERSION-FILE
+
+### Build rules
+
+SHELL_PATH ?= $(SHELL)
+PERL_PATH ?= /usr/bin/perl
+
+# Shell quote;
+bindir_SQ = $(subst ','\'',$(bindir)) #'
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) #'
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) #'
+
+# Quiet generation (unless V=1)
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET = @
+ QUIET_GEN = $(QUIET)echo ' ' GEN $@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ export V
+ export QUIET
+ export QUIET_GEN
+ export QUIET_SUBDIR0
+ export QUIET_SUBDIR1
+endif
+endif
+
+all:: gitweb.cgi
+
+ifdef JSMIN
+FILES=gitweb.cgi gitweb.min.js
+gitweb.cgi: gitweb.perl gitweb.min.js
+else # !JSMIN
+FILES=gitweb.cgi
+gitweb.cgi: gitweb.perl
+endif # JSMIN
+
+gitweb.cgi:
+ $(QUIET_GEN)$(RM) $@ $@+ && \
+ sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
+ -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
+ -e 's|++GIT_BINDIR++|$(bindir)|g' \
+ -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+ -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
+ -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
+ -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
+ -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+ -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
+ -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
+ -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
+ -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
+ -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
+ -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
+ -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
+ -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
+ -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
+ -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+ -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
+ -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
+ $< >$@+ && \
+ chmod +x $@+ && \
+ mv $@+ $@
+
+ifdef JSMIN
+gitweb.min.js: gitweb.js
+ $(QUIET_GEN)$(JSMIN) <$< >$@
+endif # JSMIN
+
+clean:
+ $(RM) $(FILES)
+
+.PHONY: all clean .FORCE-GIT-VERSION-FILE
--
1.6.5.2
^ permalink raw reply related
* [PATCH 1/7] gitweb: Load checking
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
In-Reply-To: <1263375282-15508-1-git-send-email-warthog9@eaglescrag.net>
From: John 'Warthog9' Hawley <warthog9@kernel.org>
This changes slightly the behavior of gitweb, so that it verifies
that the box isn't inundated with before attempting to serve gitweb.
If the box is overloaded, it basically returns a 503 Server Unavailable
until the load falls below the defined threshold. This helps dramatically
if you have a box that's I/O bound, reaches a certain load and you
don't want gitweb, the I/O hog that it is, increasing the pain the
server is already undergoing.
This behavior is controlled by $maxload configuration variable.
Default is a load of 300, which for most cases should never be hit.
Unset it (set it to undefined value, i.e. undef) to turn off checking.
Currently it requires that '/proc/loadavg' file exists, otherwise the
load check is bypassed (load is taken to be 0). So platforms that do
not implement '/proc/loadavg' currently cannot use this feature.
(provisions are included for additional checks to be added by others)
v3 - warthog9: small additional adjustment to indicate where new load
checking should be added for future improvements
v2 - Jakub: switching to using
v1 - warthog9: Initial creation
Signed-off-by: John 'Warthog9' Hawley <warthog9@kernel.org>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/README | 7 ++++++-
gitweb/gitweb.perl | 45 +++++++++++++++++++++++++++++++++++++++++----
2 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/gitweb/README b/gitweb/README
index e34ee79..6c2c8e1 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -174,7 +174,7 @@ not include variables usually directly set during build):
Base URL for relative URLs in pages generated by gitweb,
(e.g. $logo, $favicon, @stylesheets if they are relative URLs),
needed and used only for URLs with nonempty PATH_INFO via
- <base href="$base_url>. Usually gitweb sets its value correctly,
+ <base href="$base_url">. Usually gitweb sets its value correctly,
and there is no need to set this variable, e.g. to $my_uri or "/".
* $home_link
Target of the home link on top of all pages (the first part of view
@@ -228,6 +228,11 @@ not include variables usually directly set during build):
repositories from launching cross-site scripting (XSS) attacks. Set this
to true if you don't trust the content of your repositories. The default
is false.
+ * $maxload
+ Used to set the maximum load that we will still respond to gitweb queries.
+ If server load exceed this value then return "503 Service Unavaliable" error.
+ Server load is taken to be 0 if gitweb cannot determine its value. Set it to
+ undefined value to turn it off. The default is 300.
Projects list file format
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 7e477af..0a07d3a 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -221,6 +221,12 @@ our %avatar_size = (
'double' => 32
);
+# Used to set the maximum load that we will still respond to gitweb queries.
+# If server load exceed this value then return "503 server busy" error.
+# If gitweb cannot determined server load, it is taken to be 0.
+# Leave it undefined (or set to 'undef') to turn off load checking.
+our $maxload = 300;
+
# You define site-wide feature defaults here; override them with
# $GITWEB_CONFIG as necessary.
our %feature = (
@@ -551,6 +557,32 @@ if (-e $GITWEB_CONFIG) {
do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
}
+# Get loadavg of system, to compare against $maxload.
+# Currently it requires '/proc/loadavg' present to get loadavg;
+# if it is not present it returns 0, which means no load checking.
+sub get_loadavg {
+ if( -e '/proc/loadavg' ){
+ open my $fd, '<', '/proc/loadavg'
+ or return 0;
+ my @load = split(/\s+/, scalar <$fd>);
+ close $fd;
+
+ # The first three columns measure CPU and IO utilization of the last one,
+ # five, and 10 minute periods. The fourth column shows the number of
+ # currently running processes and the total number of processes in the m/n
+ # format. The last column displays the last process ID used.
+ return $load[0] || 0;
+ }
+ # additional checks for load average should go here for things that don't export
+ # /proc/loadavg
+
+ return 0;
+}
+
+if (defined $maxload && get_loadavg() > $maxload) {
+ die_error(503, "The load average on the server is too high");
+}
+
# version of the core git binary
our $git_version = qx("$GIT" --version) =~ m/git version (.*)$/ ? $1 : "unknown";
$number_of_git_cmds++;
@@ -3354,14 +3386,19 @@ sub git_footer_html {
# 500: The server isn't configured properly, or
# an internal error occurred (e.g. failed assertions caused by bugs), or
# an unknown error occurred (e.g. the git binary died unexpectedly).
+# 503: The server is currently unavailable (because it is overloaded,
+# or down for maintenance). Generally, this is a temporary state.
sub die_error {
my $status = shift || 500;
my $error = shift || "Internal server error";
- my %http_responses = (400 => '400 Bad Request',
- 403 => '403 Forbidden',
- 404 => '404 Not Found',
- 500 => '500 Internal Server Error');
+ my %http_responses = (
+ 400 => '400 Bad Request',
+ 403 => '403 Forbidden',
+ 404 => '404 Not Found',
+ 500 => '500 Internal Server Error',
+ 503 => '503 Service Unavailable',
+ );
git_header_html($http_responses{$status});
print <<EOF;
<div class="page_body">
--
1.6.5.2
^ permalink raw reply related
* [PATCH 0/7] Gitweb caching v4
From: John 'Warthog9' Hawley @ 2010-01-13 9:34 UTC (permalink / raw)
To: git
Evening everyone,
This is the latest incarnation of gitweb w/ caching. This is
finally at the point where it should probably start either being
considered for inclusion or mainline, or I need to accept that this
will never get in and more perminantely fork (as is the case with
Fedora where this is going in as gitweb-caching as a parrallel rpm
package).
That said this brings the base up to mainline (again), it updates a
number of elements in the caching engine, and this is a much cleaner
break-out of the tree vs. what I am currently developing against.
v4:
- major re-working of the caching layer to use file handle
redirection instead of buffering output
- other minor improvements
v3:
- various minor re-works based on mailing list feedback,
this series was not sent to the mailing list.
v2:
- Better breakout
- You can actually disable the cache now
- John 'Warthog9' Hawley
John 'Warthog9' Hawley (7):
gitweb: Load checking
gitweb: Add option to force version match
gitweb: Makefile improvements
gitweb: Optionally add "git" links in project list page
gitweb: Convert output to using indirect file handle
gitweb: add a get function to compliment print_local_time
gitweb: File based caching layer (from git.kernel.org)
Makefile | 91 ++---
gitweb/Makefile | 129 +++++++
gitweb/README | 14 +-
gitweb/cache.pm | 283 +++++++++++++++
gitweb/gitweb.css | 6 +
gitweb/gitweb.perl | 1021 ++++++++++++++++++++++++++++++----------------------
6 files changed, 1052 insertions(+), 492 deletions(-)
create mode 100644 gitweb/Makefile
create mode 100644 gitweb/cache.pm
^ permalink raw reply
* Re: default behaviour for `gitmerge` (no arguments)
From: Johannes Schindelin @ 2010-01-13 9:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, Gareth Adams, git
In-Reply-To: <7vwrzmqypn.fsf@alter.siamese.dyndns.org>
Hi,
On Tue, 12 Jan 2010, Junio C Hamano wrote:
> I wondered why it doesn't hook into interpret_branch_name(), and instead
> adds itself to the static substitute_branch_name(); it forbids the use
> of the syntax from by callers of strbuf_branchname().
I _think_ it was to allow something like
git log -g @{u}
but frankly, this is so long ago, I do not remember, I reconstructed this
reasoning as being the most likely.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH 1/2] grep: rip out support for external grep
From: Junio C Hamano @ 2010-01-13 8:59 UTC (permalink / raw)
To: Jay Soffian
Cc: git, Linus Torvalds, Miles Bader, Jeff King, Nguyen Thai Ngoc Duy
In-Reply-To: <76718491001130029i24a4edeyf72ce692429dffa6@mail.gmail.com>
Thanks; I grepped only for EXTERNAL_GREP and ext-grep and forgot about
this one.
^ permalink raw reply
* [PATCH] t7502: test commit.status, --status and --no-status
From: Junio C Hamano @ 2010-01-13 8:58 UTC (permalink / raw)
To: git; +Cc: James P. Howard, II
In-Reply-To: <7vocl1pwf5.fsf@alter.siamese.dyndns.org>
Make sure that the status information:
- is shown as before without configuration nor command line option;
- is shown if commit.status set to true without command line option,
or --status is given;
- is not shown if commit.status set to false without command line option,
or --no-status is given.
Also make sure that the above does not affect the way lines taken from
the custom --template appear in the log message editor.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Junio C Hamano <gitster@pobox.com> writes:
> What's cooking in git.git (Jan 2010, #03; Sun, 10)
> --------------------------------------------------
> ...
> [Stalled]
> * jh/commit-status (2009-12-07) 1 commit
> - [test?] Add commit.status, --status, and --no-status
>
> Needs tests.
I think I have already given ample time for people to react, but ended up
getting tired of waiting for tests to materialize and doing it myself, as
I want to close merge window for 1.7.0-rc0 by the end of next week to
have the final release early next month.
t/t7502-commit.sh | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index fe94552..844fb43 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -267,4 +267,113 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
'
+cat >.git/FAKE_EDITOR <<EOF
+#!$SHELL_PATH
+mv "\$1" "\$1.orig"
+(
+ echo message
+ cat "\$1.orig"
+) >"\$1"
+EOF
+
+echo '## Custom template' >template
+
+clear_config () {
+ (
+ git config --unset-all "$1"
+ case $? in
+ 0|5) exit 0 ;;
+ *) exit 1 ;;
+ esac
+ )
+}
+
+try_commit () {
+ git reset --hard &&
+ echo >>negative &&
+ GIT_EDITOR=.git/FAKE_EDITOR git commit -a $* $use_template &&
+ case "$use_template" in
+ '')
+ ! grep "^## Custom template" .git/COMMIT_EDITMSG ;;
+ *)
+ grep "^## Custom template" .git/COMMIT_EDITMSG ;;
+ esac
+}
+
+try_commit_status_combo () {
+
+ test_expect_success 'commit' '
+ clear_config commit.status &&
+ try_commit "" &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit' '
+ clear_config commit.status &&
+ try_commit "" &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --status' '
+ clear_config commit.status &&
+ try_commit --status &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --no-status' '
+ clear_config commit.status &&
+ try_commit --no-status
+ ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit with commit.status = yes' '
+ clear_config commit.status &&
+ git config commit.status yes &&
+ try_commit "" &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit with commit.status = no' '
+ clear_config commit.status &&
+ git config commit.status no &&
+ try_commit "" &&
+ ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --status with commit.status = yes' '
+ clear_config commit.status &&
+ git config commit.status yes &&
+ try_commit --status &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --no-status with commit.status = yes' '
+ clear_config commit.status &&
+ git config commit.status yes &&
+ try_commit --no-status &&
+ ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --status with commit.status = no' '
+ clear_config commit.status &&
+ git config commit.status no &&
+ try_commit --status &&
+ grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+ test_expect_success 'commit --no-status with commit.status = no' '
+ clear_config commit.status &&
+ git config commit.status no &&
+ try_commit --no-status &&
+ ! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
+ '
+
+}
+
+try_commit_status_combo
+
+use_template="-t template"
+
+try_commit_status_combo
+
test_done
--
1.6.6.292.ge84ea.dirty
^ permalink raw reply related
* Re: [PATCH 1/2] Add `init-db.templatedir` configuration variable.
From: Junio C Hamano @ 2010-01-13 8:50 UTC (permalink / raw)
To: Steven Drake; +Cc: git
In-Reply-To: <alpine.LNX.2.00.1001131719050.22639@vqena.qenxr.bet.am>
Steven Drake <sdrake@xnet.co.nz> writes:
> Include `init.templatedir` as an alias for `init-db.templatedir`.
This describes what the patch adds, which we can read in the diff *if* we
wanted to. The primary job of the first paragraph of the proposed commit
log message is to convince reviewers why it might be worthwhile to read
the diff, and to explain whoever reads "git log" output in the future what
motivated this change to be made.
Your log message doesn't say anything about why it is a good idea to add
this feature, which is much more important to talk about [*1*].
The target _may_ be probably to have this in $HOME/.gitconfig so that your
personal templates in $HOME/.gittemplate/ are used in all repositories you
will create. But you shouldn't make me, anybody who reviews, or readers
of the documentation for that matter, *guess* what problem the new feature
is meant to solve.
IOW, code talks what it itself does, but it often cannot say why it does
what it does, nor why a particular way it does what it does was chosen.
You help your code justify itself by describing the motivation in your
commit log message.
I don't think init-db.templatedir is needed nor wanted.
- People who learn about this configuration will never heard of init-db
(i.e. lack of necessity);
- We have already deprecated init-db and do not advertise in "git help
git"---the longer term direction is to remove it once everybody forgets
about it (i.e. actively undesirable).
By the way, this is probably less useful in /etc/gitconfig, as somebody
who can configure it can customize the system-wide templates with the same
ease. That might also be something you would want to mention in the log.
[Footnote]
*1* I am not saying the commit log message shouldn't talk about what it
does or how it does it. It also is a good thing to do, especially when
the linkage between the motivation and the implementation is not obvious.
^ permalink raw reply
* Re: [PATCH] Add `commit.signoff` configuration variable.
From: Junio C Hamano @ 2010-01-13 8:30 UTC (permalink / raw)
To: Steven Drake; +Cc: git
In-Reply-To: <alpine.LNX.2.00.1001131635510.16395@vqena.qenxr.bet.am>
You need to defend this one better, in fact a *lot* better, than other
ones. See
http://thread.gmane.org/gmane.comp.version-control.git/32503/focus=32522
http://thread.gmane.org/gmane.comp.version-control.git/103939/focus=104207
for starters. Your justifications should address all the points raised in
previous threads.
^ permalink raw reply
* Re: [PATCH 1/2] grep: rip out support for external grep
From: Jay Soffian @ 2010-01-13 8:29 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Miles Bader, Jeff King, Nguyen Thai Ngoc Duy
In-Reply-To: <7v4omqv6tx.fsf_-_@alter.siamese.dyndns.org>
On Wed, Jan 13, 2010 at 1:48 AM, Junio C Hamano <gitster@pobox.com> wrote:
> We still allow people to pass --[no-]ext-grep on the command line,
> but the option is ignored.
Perhaps this squashed in on top? (If gmail's web-interface mangles
this I can resend.)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index a1e36d7..6a96d9d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -645,14 +645,6 @@ color.grep::
`never`), never. When set to `true` or `auto`, use color only
when the output is written to the terminal. Defaults to `false`.
-color.grep.external::
- The string value of this variable is passed to an external 'grep'
- command as a command line option if match highlighting is turned
- on. If set to an empty string, no option is passed at all,
- turning off coloring for external 'grep' calls; this is the default.
- For GNU grep, set it to `--color=always` to highlight matches even
- when a pager is used.
-
color.grep.match::
Use customized color for matches. The value of this variable
may be specified as in color.branch.<slot>. It is passed using
diff --git a/builtin-grep.c b/builtin-grep.c
index 4adb971..3d6ebb5 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -34,8 +34,6 @@ static int grep_config(const char *var, const char
*value, void *cb)
opt->color = git_config_colorbool(var, value, -1);
return 0;
}
- if (!strcmp(var, "color.grep.external"))
- return git_config_string(&(opt->color_external), var, value);
if (!strcmp(var, "color.grep.match")) {
if (!value)
return config_error_nonbool(var);
diff --git a/grep.h b/grep.h
index 75370f6..0c61b00 100644
--- a/grep.h
+++ b/grep.h
@@ -85,7 +85,6 @@ struct grep_opt {
int max_depth;
int funcname;
char color_match[COLOR_MAXLEN];
- const char *color_external;
int regflags;
unsigned pre_context;
unsigned post_context;
^ permalink raw reply related
* Re: [PATCH] Add `format.to` configuration variable.
From: Johannes Sixt @ 2010-01-13 8:20 UTC (permalink / raw)
To: Steven Drake; +Cc: git
In-Reply-To: <alpine.LNX.2.00.1001132054380.24673@vqena.qenxr.bet.am>
You submitted a number of patches in the last hours, but you gave *zero*
motivation for them, i.e., the commit messages lack words about *why* the
changes are good (and what they are good for).
This particular patch lacks documentation, in particular, it's worth to
mention that format.to could be given more than once.
-- Hannes
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox