#!/usr/bin/perl
# Copyright (C) 2007, Steve Frécinaux <code@istique.net>
# License: GPL v2 or later

use strict;
use warnings;
use Getopt::Long qw(:config posix_default gnu_getopt);
use Term::ReadKey qw/ReadMode ReadLine/;

# Use WWW::Mechanize if available and display a gentle message otherwise.
BEGIN {
	eval { require WWW::Mechanize; import WWW::Mechanize };
	die <<ERROR if $@;
The module WWW::Mechanize is required by git-send-pastebin but is currently
not available. You can install it using cpan WWW::Mechanize.
ERROR
}

my $url = "http://paste.lisp.org/new/webkit";
my $mech = WWW::Mechanize->new(agent => "git-send-pastebin/0.0");

sub add_attachment {
	my $username = shift;
	my $patch = shift;
	my $description = shift;
	my $comment = shift;
	my $request = shift;

	$mech->get("$url");
	die "Can't get attachment form: ", $mech->res->status_line
		unless $mech->success;

	my $form = $mech->form_number(1);

	my $title = $request ? "$description, r?" : $description;

	$form->value('channel', '#webkit');
	$form->value('username', $username);
	$form->value('title', $title);
	$form->value('captcha', 'lisp');
	$form->value('colorize', 'C++');
	$form->value('text', "$comment\n\n$patch");

	$mech->submit;

	die "Attachment failed: ", $mech->res->status_line
		unless $mech->success;

	#die "Error while attaching patch. Aborting\n"
		#unless $mech->title =~ /Changes Submitted/i;
}

sub read_repo_config {
	my $key = shift;
	my $type = shift || 'str';
	my $default = shift || '';

	my $arg = 'git-repo-config';
	$arg .= " --$type" unless $type eq 'str';

	chop (my $val = `$arg --get pastebin.$key`);
	
	return $default if $?;
	return $val eq 'true' if ($type eq 'bool');
	return $val;
}

sub usage {
	my $exitcode = shift || 0;
	my $fd = $exitcode ? \*STDERR : \*STDOUT;
	print $fd "Usage: git-send-pastebin [options] <bugid> <since>[..<until>]\n";
	exit $exitcode;
}

my $username = read_repo_config 'username';
my $request = 0;
my $cherry = 0;
my $numbered = read_repo_config 'numbered', 'bool', 0;
my $start_number = read_repo_config 'startnumber', 'int', 1;
my $dry_run = 0;
my $help = 0;

# Parse options
GetOptions("username|u=s" => \$username,
	   "request|r" => \$request,
	   "cherry|c" => \$cherry,
	   "numbered|n" => \$numbered,
	   "start-number" => \$start_number,
	   "dry-run" => \$dry_run,
	   "help|h|?" => \$help);

exec 'man', 1, 'git-send-pastebin' if $help;

# Get revisions to build patch from. Do the same way git-format-patch does.
my @revisions;
open REVPARSE, '-|', 'git-rev-parse', ('--revs-only', @ARGV)
	or die "Cannot call git-rev-parse: $!";
chop (@revisions = <REVPARSE>);
close REVPARSE;

if (@revisions eq 0) {
	print STDERR "No revision specified!\n";
	usage 1;
}

if($cherry eq 0) {
	if (@revisions eq 1) {
		$revisions[0] =~ s/^\^?/^/;
		push @revisions, 'HEAD';
	}

	# Get revision list
	open REVLIST, '-|', "git-rev-list", @revisions
		or die "Cannot call git-rev-list: $!";
	chop (@revisions = reverse <REVLIST>);
	close REVLIST;
}

die "No patch to send\n" if @revisions eq 0;

print STDERR "Attaching patches...\n";
my $i = $start_number;
my $n = @revisions - 1 + $i;
for my $rev (@revisions) {
	#my $description = $numbered ? "[$i/$n]" : '[PATCH]';
	my $description = $numbered ? "[$i/$n] " : '';
	my $comment = '';

	open COMMIT, '-|', "git-cat-file commit $rev";
	# skip headers
	while (<COMMIT>) {
		chop;
		last if $_ eq "";
	}
	chop ($description .= <COMMIT>);
	chop ($comment = join "", <COMMIT>) unless eof COMMIT;
	close COMMIT;

	$comment .= "\n---\n" unless $comment eq '';
	$comment .= `git-diff-tree --stat --no-commit-id $rev`;
	my $patch = `git-diff-tree -p $rev`;
	
	print STDERR "  - $description\n";

	#FIXME: should be made to annotate the original paste
	add_attachment $username, $patch, $description, $comment, $request unless $dry_run;

	$i++;
}
print "Done.\n"
