Add output_pipeline subroutine, which allows to use list form of pipeline; instead of open my $fh, "-|", "cmd_1 option | cmd_2 argument" we can now write my $fh = output_pipeline(['cmd_1', 'option'], ['cmd_2', 'argument']); which allows to avoid troubles with shell quoting, and avoid spawning shell. Code is based on snippet http://www.perlmonks.org/?node_id=246397 simplified a bit. It is then used in git_snapshot subroutine, where we sometimes open pipeline from git-archive to compressor. While at it, ensure that snapshot saved as <basename>.<suffix> uncompresses to <basename>/ NOTE: this commit prepares way for adding syntax highlighting support using external filter (external tool), like GNU Source-highlight or Andre Simon's Highlight. Signed-off-by: Jakub Narebski <jnareb@xxxxxxxxx> --- This patch is an RFC, and doesn't really meant to be applied. I'd like opinion on this code from resident Perl experts. It should work, though; it was rudimentarly tested. gitweb/gitweb.perl | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 40 insertions(+), 12 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a5df2fe..ba97a7b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1455,6 +1455,35 @@ sub git_cmd_str { return join(' ', git_cmd()); } +# my $fh = output_pipeline(['cmd_1', 'option'], ['cmd_2', 'argument']); +# is equivalent to (is the "list form" of) the following +# open my $fh, "-|", "cmd_1 option | cmd_2 argument" +# +# Based on http://www.perlmonks.org/?node_id=246397 +# +sub output_pipeline { + my @commands_list = @_; + exit unless @commands_list; + + my $pid = open(my $fh, "-|"); + #die "Couldn't fork: $!" unless defined $pid; + + if ($pid) { # parent + return $fh; + } + + # child + COMMAND: + while (my $command = pop @commands_list) { + my $pid = @commands_list ? open(STDIN, "-|") : -1; + #die "Couldn't fork: $!" unless defined $pid; + + next COMMAND unless ($pid); # parent + exec @$command; # child + #die "Couldn't exec \"@$command\": $!"; + } +} + # get HEAD ref of given project as hash sub git_get_head_hash { my $project = shift; @@ -4545,27 +4574,26 @@ sub git_snapshot { $hash = git_get_head_hash($project); } - my $git_command = git_cmd_str(); my $name = $project; - $name =~ s,([^/])/*\.git$,$1,; + $name =~ s,([^/])/*\.git$,$1,; # strip '.git' or '/.git' $name = basename($name); - my $filename = to_utf8($name); - $name =~ s/\047/\047\\\047\047/g; - my $cmd; - $filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}"; - $cmd = "$git_command archive " . - "--format=$known_snapshot_formats{$format}{'format'} " . - "--prefix=\'$name\'/ $hash"; + $name = to_utf8($name); # or only for filename, not prefix? + $name .= "-$hash"; + + my @cmds = ([git_cmd(), "archive", + "--format=$known_snapshot_formats{$format}{'format'}", + "--prefix=$name/", $hash]); if (exists $known_snapshot_formats{$format}{'compressor'}) { - $cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}}; + push @cmds, $known_snapshot_formats{$format}{'compressor'}; } print $cgi->header( -type => $known_snapshot_formats{$format}{'type'}, - -content_disposition => 'inline; filename="' . "$filename" . '"', + -content_disposition => 'inline; filename="' . + "$filename$known_snapshot_formats{$format}{'suffix'}" . '"', -status => '200 OK'); - open my $fd, "-|", $cmd + my $fd = output_pipeline(@cmds) or die_error(undef, "Execute git-archive failed"); binmode STDOUT, ':raw'; print <$fd>; -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html