git-remote-mediawiki: send "File:" attachments to a remote wiki

The current version of the git-remote-mediawiki supports only import and export of plain wiki pages. This patch adds the functionality to export file attachments (i.e. the content of the File: MediaWiki namespace), which are also exposed by MediaWiki API. This requires a recent version of MediaWiki::API (Version 0.37 works. Version 0.34 doesn't). Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr> Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr> Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

NGUYEN Kim Thuat committed Jun 27, 2012 at 11:10 UTC b3d985959869d3f2fb1901639326eb64c2e3f726
1 file changed +90 -8
contrib/mw-to-git/git-remote-mediawiki
+90 -8
@@ -348,8 +348,12 @@ sub get_mw_pages {
348 return values(%pages);
349 }
350
351 +# usage: $out = run_git("command args");
352 +# $out = run_git("command args", "raw"); # don't interpret output as UTF-8.
353 sub run_git {
352 - open(my $git, "-|:encoding(UTF-8)", "git " . $_[0]);
354 + my $args = shift;
355 + my $encoding = (shift || "encoding(UTF-8)");
356 + open(my $git, "-|:$encoding", "git " . $args);
357 my $res = do { local $/; <$git> };
358 close($git);
359
@@ -705,6 +709,63 @@ sub error_non_fast_forward {
709 return 0;
710 }
711
712 +sub mw_upload_file {
713 + my $complete_file_name = shift;
714 + my $new_sha1 = shift;
715 + my $extension = shift;
716 + my $file_deleted = shift;
717 + my $summary = shift;
718 + my $newrevid;
719 + my $path = "File:" . $complete_file_name;
720 + my %hashFiles = get_allowed_file_extensions();
721 + if (!exists($hashFiles{$extension})) {
722 + print STDERR "$complete_file_name is not a permitted file on this wiki.\n";
723 + print STDERR "Check the configuration of file uploads in your mediawiki.\n";
724 + return $newrevid;
725 + }
726 + # Deleting and uploading a file requires a priviledged user
727 + if ($file_deleted) {
728 + mw_connect_maybe();
729 + my $query = {
730 + action => 'delete',
731 + title => $path,
732 + reason => $summary
733 + };
734 + if (!$mediawiki->edit($query)) {
735 + print STDERR "Failed to delete file on remote wiki\n";
736 + print STDERR "Check your permissions on the remote site. Error code:\n";
737 + print STDERR $mediawiki->{error}->{code} . ':' . $mediawiki->{error}->{details};
738 + exit 1;
739 + }
740 + } else {
741 + # Don't let perl try to interpret file content as UTF-8 => use "raw"
742 + my $content = run_git("cat-file blob $new_sha1", "raw");
743 + if ($content ne "") {
744 + mw_connect_maybe();
745 + $mediawiki->{config}->{upload_url} =
746 + "$url/index.php/Special:Upload";
747 + $mediawiki->edit({
748 + action => 'upload',
749 + filename => $complete_file_name,
750 + comment => $summary,
751 + file => [undef,
752 + $complete_file_name,
753 + Content => $content],
754 + ignorewarnings => 1,
755 + }, {
756 + skip_encoding => 1
757 + } ) || die $mediawiki->{error}->{code} . ':'
758 + . $mediawiki->{error}->{details};
759 + my $last_file_page = $mediawiki->get_page({title => $path});
760 + $newrevid = $last_file_page->{revid};
761 + print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
762 + } else {
763 + print STDERR "Empty file $complete_file_name not pushed.\n";
764 + }
765 + }
766 + return $newrevid;
767 +}
768 +
769 sub mw_push_file {
770 my $diff_info = shift;
771 # $diff_info contains a string in this format:
@@ -717,7 +778,8 @@ sub mw_push_file {
778 my $summary = shift;
779 # MediaWiki revision number. Keep the previous one by default,
780 # in case there's no edit to perform.
720 - my $newrevid = shift;
781 + my $oldrevid = shift;
782 + my $newrevid;
783
784 my $new_sha1 = $diff_info_split[3];
785 my $old_sha1 = $diff_info_split[2];
@@ -725,9 +787,11 @@ sub mw_push_file {
787 my $page_deleted = ($new_sha1 eq NULL_SHA1);
788 $complete_file_name = mediawiki_clean_filename($complete_file_name);
789
728 - if (substr($complete_file_name,-3) eq ".mw") {
729 - my $title = substr($complete_file_name,0,-3);
730 -
790 + my ($title, $extension) = $complete_file_name =~ /^(.*)\.([^\.]*)$/;
791 + if (!defined($extension)) {
792 + $extension = "";
793 + }
794 + if ($extension eq "mw") {
795 my $file_content;
796 if ($page_deleted) {
797 # Deleting a page usually requires
@@ -745,7 +809,7 @@ sub mw_push_file {
809 action => 'edit',
810 summary => $summary,
811 title => $title,
748 - basetimestamp => $basetimestamps{$newrevid},
812 + basetimestamp => $basetimestamps{$oldrevid},
813 text => mediawiki_clean($file_content, $page_created),
814 }, {
815 skip_encoding => 1 # Helps with names with accentuated characters
@@ -757,7 +821,7 @@ sub mw_push_file {
821 $mediawiki->{error}->{code} .
822 ' from mediwiki: ' . $mediawiki->{error}->{details} .
823 ".\n";
760 - return ($newrevid, "non-fast-forward");
824 + return ($oldrevid, "non-fast-forward");
825 } else {
826 # Other errors. Shouldn't happen => just die()
827 die 'Fatal: Error ' .
@@ -768,8 +832,11 @@ sub mw_push_file {
832 $newrevid = $result->{edit}->{newrevid};
833 print STDERR "Pushed file: $new_sha1 - $title\n";
834 } else {
771 - print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n"
835 + $newrevid = mw_upload_file($complete_file_name, $new_sha1,
836 + $extension, $page_deleted,
837 + $summary);
838 }
839 + $newrevid = ($newrevid or $oldrevid);
840 return ($newrevid, "ok");
841 }
842
@@ -906,3 +973,18 @@ sub mw_push_revision {
973 print STDOUT "ok $remote\n";
974 return 1;
975 }
976 +
977 +sub get_allowed_file_extensions {
978 + mw_connect_maybe();
979 +
980 + my $query = {
981 + action => 'query',
982 + meta => 'siteinfo',
983 + siprop => 'fileextensions'
984 + };
985 + my $result = $mediawiki->api($query);
986 + my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
987 + my %hashFile = map {$_ => 1}@file_extensions;
988 +
989 + return %hashFile;
990 +}