git-remote-mediawiki: change the name of a variable
[gitweb.git] / contrib / mw-to-git / git-remote-mediawiki.perl
index 9c14c1f88d3a8f23df54db2adc7985eb00722c12..1fcdf2db305ea7d93d624801c401f0899ac7d188 100755 (executable)
 
 use strict;
 use MediaWiki::API;
+use Git;
 use DateTime::Format::ISO8601;
+use warnings;
 
 # By default, use UTF-8 to communicate with Git and the user
-binmode STDERR, ":utf8";
-binmode STDOUT, ":utf8";
+binmode STDERR, ":encoding(UTF-8)";
+binmode STDOUT, ":encoding(UTF-8)";
 
 use URI::Escape;
 use IPC::Open2;
 
-use warnings;
-
 # Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced
 use constant SLASH_REPLACEMENT => "%2F";
 
@@ -91,6 +91,9 @@
        $fetch_strategy = "by_page";
 }
 
+# Remember the timestamp corresponding to a revision id.
+my %basetimestamps;
+
 # Dumb push: don't update notes and mediawiki ref to reflect the last push.
 #
 # Configurable with mediawiki.dumbPush, or per-remote with
 $dumb_push = ($dumb_push eq "true");
 
 my $wiki_name = $url;
-$wiki_name =~ s/[^\/]*:\/\///;
+$wiki_name =~ s{[^/]*://}{};
 # If URL is like http://user:password@example.com/, we clearly don't
 # want the password in $wiki_name. While we're there, also remove user
 # and '@' sign, to avoid author like MWUser@HTTPUser@host.com
        if (defined($cmd[0])) {
                # Line not blank
                if ($cmd[0] eq "capabilities") {
-                       die("Too many arguments for capabilities") unless (!defined($cmd[1]));
+                       die("Too many arguments for capabilities\n") unless (!defined($cmd[1]));
                        mw_capabilities();
                } elsif ($cmd[0] eq "list") {
-                       die("Too many arguments for list") unless (!defined($cmd[2]));
+                       die("Too many arguments for list\n") unless (!defined($cmd[2]));
                        mw_list($cmd[1]);
                } elsif ($cmd[0] eq "import") {
-                       die("Invalid arguments for import") unless ($cmd[1] ne "" && !defined($cmd[2]));
+                       die("Invalid arguments for import\n") unless ($cmd[1] ne "" && !defined($cmd[2]));
                        mw_import($cmd[1]);
                } elsif ($cmd[0] eq "option") {
-                       die("Too many arguments for option") unless ($cmd[1] ne "" && $cmd[2] ne "" && !defined($cmd[3]));
+                       die("Too many arguments for option\n") unless ($cmd[1] ne "" && $cmd[2] ne "" && !defined($cmd[3]));
                        mw_option($cmd[1],$cmd[2]);
                } elsif ($cmd[0] eq "push") {
                        mw_push($cmd[1]);
 
 ########################## Functions ##############################
 
-## credential API management (generic functions)
-
-sub credential_read {
-       my %credential;
-       my $reader = shift;
-       my $op = shift;
-       while (<$reader>) {
-               my ($key, $value) = /([^=]*)=(.*)/;
-               if (not defined $key) {
-                       die "ERROR receiving response from git credential $op:\n$_\n";
-               }
-               $credential{$key} = $value;
-       }
-       return %credential;
-}
-
-sub credential_write {
-       my $credential = shift;
-       my $writer = shift;
-       # url overwrites other fields, so it must come first
-       print $writer "url=$credential->{url}\n" if exists $credential->{url};
-       while (my ($key, $value) = each(%$credential) ) {
-               if (length $value && $key ne 'url') {
-                       print $writer "$key=$value\n";
-               }
-       }
-}
-
-sub credential_run {
-       my $op = shift;
-       my $credential = shift;
-       my $pid = open2(my $reader, my $writer, "git credential $op");
-       credential_write($credential, $writer);
-       print $writer "\n";
-       close($writer);
-
-       if ($op eq "fill") {
-               %$credential = credential_read($reader, $op);
-       } else {
-               if (<$reader>) {
-                       die "ERROR while running git credential $op:\n$_";
-               }
-       }
-       close($reader);
-       waitpid($pid, 0);
-       my $child_exit_status = $? >> 8;
-       if ($child_exit_status != 0) {
-               die "'git credential $op' failed with code $child_exit_status.";
-       }
-}
-
 # MediaWiki API instance, created lazily.
 my $mediawiki;
 
@@ -217,31 +169,51 @@ sub mw_connect_maybe {
        $mediawiki = MediaWiki::API->new;
        $mediawiki->{config}->{api_url} = "$url/api.php";
        if ($wiki_login) {
-               my %credential = (url => $url);
-               $credential{username} = $wiki_login;
-               $credential{password} = $wiki_passwd;
-               credential_run("fill", \%credential);
+               my %credential = (
+                       'url' => $url,
+                       'username' => $wiki_login,
+                       'password' => $wiki_passwd
+               );
+               Git::credential(\%credential);
                my $request = {lgname => $credential{username},
                               lgpassword => $credential{password},
                               lgdomain => $wiki_domain};
                if ($mediawiki->login($request)) {
-                       credential_run("approve", \%credential);
+                       Git::credential(\%credential, 'approve');
                        print STDERR "Logged in mediawiki user \"$credential{username}\".\n";
                } else {
                        print STDERR "Failed to log in mediawiki user \"$credential{username}\" on $url\n";
                        print STDERR "  (error " .
                                $mediawiki->{error}->{code} . ': ' .
                                $mediawiki->{error}->{details} . ")\n";
-                       credential_run("reject", \%credential);
+                       Git::credential(\%credential, 'reject');
                        exit 1;
                }
        }
+       return;
+}
+
+sub fatal_mw_error {
+       my $action = shift;
+       print STDERR "fatal: could not $action.\n";
+       print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
+       if ($url =~ /^https/) {
+               print STDERR "fatal: make sure '$url/api.php' is a valid page\n";
+               print STDERR "fatal: and the SSL certificate is correct.\n";
+       } else {
+               print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
+       }
+       print STDERR "fatal: (error " .
+           $mediawiki->{error}->{code} . ': ' .
+           $mediawiki->{error}->{details} . ")\n";
+       exit 1;
 }
 
 ## Functions for listing pages on the remote wiki
 sub get_mw_tracked_pages {
        my $pages = shift;
        get_mw_page_list(\@tracked_pages, $pages);
+       return;
 }
 
 sub get_mw_page_list {
@@ -257,6 +229,7 @@ sub get_mw_page_list {
                get_mw_first_pages(\@slice, $pages);
                @some_pages = @some_pages[51..$#some_pages];
        }
+       return;
 }
 
 sub get_mw_tracked_categories {
@@ -274,11 +247,12 @@ sub get_mw_tracked_categories {
                        cmtitle => $category,
                        cmlimit => 'max' } )
                        || die $mediawiki->{error}->{code} . ': '
-                               . $mediawiki->{error}->{details};
+                               . $mediawiki->{error}->{details} . "\n";
                foreach my $page (@{$mw_pages}) {
                        $pages->{$page->{title}} = $page;
                }
        }
+       return;
 }
 
 sub get_mw_all_pages {
@@ -290,14 +264,12 @@ sub get_mw_all_pages {
                aplimit => 'max'
        });
        if (!defined($mw_pages)) {
-               print STDERR "fatal: could not get the list of wiki pages.\n";
-               print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
-               print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
-               exit 1;
+               fatal_mw_error("get the list of wiki pages");
        }
        foreach my $page (@{$mw_pages}) {
                $pages->{$page->{title}} = $page;
        }
+       return;
 }
 
 # queries the wiki for a set of pages. Meant to be used within a loop
@@ -316,10 +288,7 @@ sub get_mw_first_pages {
                titles => $titles,
        });
        if (!defined($mw_pages)) {
-               print STDERR "fatal: could not query the list of wiki pages.\n";
-               print STDERR "fatal: '$url' does not appear to be a mediawiki\n";
-               print STDERR "fatal: make sure '$url/api.php' is a valid page.\n";
-               exit 1;
+               fatal_mw_error("query the list of wiki pages");
        }
        while (my ($id, $page) = each(%{$mw_pages->{query}->{pages}})) {
                if ($id < 0) {
@@ -328,6 +297,7 @@ sub get_mw_first_pages {
                        $pages->{$page->{title}} = $page;
                }
        }
+       return;
 }
 
 # Get the list of pages to be fetched according to configuration.
@@ -396,11 +366,12 @@ sub get_all_mediafiles {
        foreach my $page (@{$mw_pages}) {
                $pages->{$page->{title}} = $page;
        }
+       return;
 }
 
 sub get_linked_mediafiles {
        my $pages = shift;
-       my @titles = map $_->{title}, values(%{$pages});
+       my @titles = map { $_->{title} } values(%{$pages});
 
        # The query is split in small batches because of the MW API limit of
        # the number of links to be returned (500 links max).
@@ -428,11 +399,13 @@ sub get_linked_mediafiles {
                while (my ($id, $page) = each(%{$result->{query}->{pages}})) {
                        my @media_titles;
                        if (defined($page->{links})) {
-                               my @link_titles = map $_->{title}, @{$page->{links}};
+                               my @link_titles
+                                   = map { $_->{title} } @{$page->{links}};
                                push(@media_titles, @link_titles);
                        }
                        if (defined($page->{images})) {
-                               my @image_titles = map $_->{title}, @{$page->{images}};
+                               my @image_titles
+                                   = map { $_->{title} } @{$page->{images}};
                                push(@media_titles, @image_titles);
                        }
                        if (@media_titles) {
@@ -442,6 +415,7 @@ sub get_linked_mediafiles {
 
                @titles = @titles[($batch+1)..$#titles];
        }
+       return;
 }
 
 sub get_mw_mediafile_for_page_revision {
@@ -480,14 +454,14 @@ sub get_mw_mediafile_for_page_revision {
 }
 
 sub download_mw_mediafile {
-       my $url = shift;
+       my $download_url = shift;
 
-       my $response = $mediawiki->{ua}->get($url);
+       my $response = $mediawiki->{ua}->get($download_url);
        if ($response->code == 200) {
                return $response->decoded_content;
        } else {
                print STDERR "Error downloading mediafile from :\n";
-               print STDERR "URL: $url\n";
+               print STDERR "URL: $download_url\n";
                print STDERR "Server response: " . $response->code . " " . $response->message . "\n";
                exit 1;
        }
@@ -511,9 +485,6 @@ sub get_last_local_revision {
        return $lastrevision_number;
 }
 
-# Remember the timestamp corresponding to a revision id.
-my %basetimestamps;
-
 # Get the last remote revision without taking in account which pages are
 # tracked or not. This function makes a single request to the wiki thus
 # avoid a loop onto all tracked pages. This is useful for the fetch-by-rev
@@ -593,7 +564,7 @@ sub mediawiki_smudge {
 
 sub mediawiki_clean_filename {
        my $filename = shift;
-       $filename =~ s/@{[SLASH_REPLACEMENT]}/\//g;
+       $filename =~ s{@{[SLASH_REPLACEMENT]}}{/}g;
        # [, ], |, {, and } are forbidden by MediaWiki, even URL-encoded.
        # Do a variant of URL-encoding, i.e. looks like URL-encoding,
        # but with _ added to prevent MediaWiki from thinking this is
@@ -607,7 +578,7 @@ sub mediawiki_clean_filename {
 
 sub mediawiki_smudge_filename {
        my $filename = shift;
-       $filename =~ s/\//@{[SLASH_REPLACEMENT]}/g;
+       $filename =~ s{/}{@{[SLASH_REPLACEMENT]}}g;
        $filename =~ s/ /_/g;
        # Decode forbidden characters encoded in mediawiki_clean_filename
        $filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf("%c", hex($1))/ge;
@@ -617,6 +588,7 @@ sub mediawiki_smudge_filename {
 sub literal_data {
        my ($content) = @_;
        print STDOUT "data ", bytes::length($content), "\n", $content;
+       return;
 }
 
 sub literal_data_raw {
@@ -626,7 +598,8 @@ sub literal_data_raw {
        utf8::downgrade($content);
        binmode STDOUT, ":raw";
        print STDOUT "data ", bytes::length($content), "\n", $content;
-       binmode STDOUT, ":utf8";
+       binmode STDOUT, ":encoding(UTF-8)";
+       return;
 }
 
 sub mw_capabilities {
@@ -638,6 +611,7 @@ sub mw_capabilities {
        print STDOUT "list\n";
        print STDOUT "push\n";
        print STDOUT "\n";
+       return;
 }
 
 sub mw_list {
@@ -646,11 +620,13 @@ sub mw_list {
        print STDOUT "? refs/heads/master\n";
        print STDOUT "\@refs/heads/master HEAD\n";
        print STDOUT "\n";
+       return;
 }
 
 sub mw_option {
        print STDERR "remote-helper command 'option $_[0]' not yet implemented\n";
        print STDOUT "unsupported\n";
+       return;
 }
 
 sub fetch_mw_revisions_for_page {
@@ -772,6 +748,7 @@ sub import_file_revision {
        print STDOUT "N inline :$n\n";
        literal_data("mediawiki_revision: " . $commit{mw_revision});
        print STDOUT "\n\n";
+       return;
 }
 
 # parse a sequence of
@@ -784,14 +761,15 @@ sub get_more_refs {
        my @refs;
        while (1) {
                my $line = <STDIN>;
-               if ($line =~ m/^$cmd (.*)$/) {
+               if ($line =~ /^$cmd (.*)$/) {
                        push(@refs, $1);
                } elsif ($line eq "\n") {
                        return @refs;
                } else {
-                       die("Invalid command in a '$cmd' batch: ". $_);
+                       die("Invalid command in a '$cmd' batch: $_\n");
                }
        }
+       return;
 }
 
 sub mw_import {
@@ -801,6 +779,7 @@ sub mw_import {
                mw_import_ref($ref);
        }
        print STDOUT "done\n";
+       return;
 }
 
 sub mw_import_ref {
@@ -844,6 +823,7 @@ sub mw_import_ref {
                # thrown saying that HEAD is referring to unknown object 0000000000000000000
                # and the clone fails.
        }
+       return;
 }
 
 sub mw_import_ref_by_pages {
@@ -855,7 +835,7 @@ sub mw_import_ref_by_pages {
        my ($n, @revisions) = fetch_mw_revisions(\@pages, $fetch_from);
 
        @revisions = sort {$a->{revid} <=> $b->{revid}} @revisions;
-       my @revision_ids = map $_->{revid}, @revisions;
+       my @revision_ids = map { $_->{revid} } @revisions;
 
        return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash);
 }
@@ -898,7 +878,7 @@ sub mw_import_revids {
                my $result = $mediawiki->api($query);
 
                if (!$result) {
-                       die "Failed to retrieve modified page for revision $pagerevid";
+                       die "Failed to retrieve modified page for revision $pagerevid\n";
                }
 
                if (defined($result->{query}->{badrevids}->{$pagerevid})) {
@@ -907,7 +887,7 @@ sub mw_import_revids {
                }
 
                if (!defined($result->{query}->{pages})) {
-                       die "Invalid revision $pagerevid.";
+                       die "Invalid revision $pagerevid.\n";
                }
 
                my @result_pages = values(%{$result->{query}->{pages}});
@@ -1018,7 +998,7 @@ sub mw_upload_file {
                        }, {
                                skip_encoding => 1
                        } ) || die $mediawiki->{error}->{code} . ':'
-                                . $mediawiki->{error}->{details};
+                                . $mediawiki->{error}->{details} . "\n";
                        my $last_file_page = $mediawiki->get_page({title => $path});
                        $newrevid = $last_file_page->{revid};
                        print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n";
@@ -1098,7 +1078,7 @@ sub mw_push_file {
                                # Other errors. Shouldn't happen => just die()
                                die 'Fatal: Error ' .
                                    $mediawiki->{error}->{code} .
-                                   ' from mediwiki: ' . $mediawiki->{error}->{details};
+                                   ' from mediwiki: ' . $mediawiki->{error}->{details} . "\n";
                        }
                }
                $newrevid = $result->{edit}->{newrevid};
@@ -1120,7 +1100,7 @@ sub mw_push {
        my $pushed;
        for my $refspec (@refsspecs) {
                my ($force, $local, $remote) = $refspec =~ /^(\+)?([^:]*):([^:]*)$/
-                   or die("Invalid refspec for push. Expected <src>:<dst> or +<src>:<dst>");
+                   or die("Invalid refspec for push. Expected <src>:<dst> or +<src>:<dst>\n");
                if ($force) {
                        print STDERR "Warning: forced push not allowed on a MediaWiki.\n";
                }
@@ -1150,6 +1130,7 @@ sub mw_push {
                print STDERR "  git pull --rebase\n";
                print STDERR "\n";
        }
+       return;
 }
 
 sub mw_push_revision {
@@ -1186,12 +1167,12 @@ sub mw_push_revision {
                my @local_ancestry = split(/\n/, run_git("rev-list --boundary --parents $local ^$parsed_sha1"));
                my %local_ancestry;
                foreach my $line (@local_ancestry) {
-                       if (my ($child, $parents) = $line =~ m/^-?([a-f0-9]+) ([a-f0-9 ]+)/) {
-                               foreach my $parent (split(' ', $parents)) {
+                       if (my ($child, $parents) = $line =~ /^-?([a-f0-9]+) ([a-f0-9 ]+)/) {
+                               foreach my $parent (split(/ /, $parents)) {
                                        $local_ancestry{$parent} = $child;
                                }
-                       } elsif (!$line =~ m/^([a-f0-9]+)/) {
-                               die "Unexpected output from git rev-list: $line";
+                       } elsif (!$line =~ /^([a-f0-9]+)/) {
+                               die "Unexpected output from git rev-list: $line\n";
                        }
                }
                while ($parsed_sha1 ne $HEAD_sha1) {
@@ -1208,10 +1189,10 @@ sub mw_push_revision {
                # history (linearized with --first-parent)
                print STDERR "Warning: no common ancestor, pushing complete history\n";
                my $history = run_git("rev-list --first-parent --children $local");
-               my @history = split('\n', $history);
+               my @history = split(/\n/, $history);
                @history = @history[1..$#history];
                foreach my $line (reverse @history) {
-                       my @commit_info_split = split(/ |\n/, $line);
+                       my @commit_info_split = split(/[ \n]/, $line);
                        push(@commit_pairs, \@commit_info_split);
                }
        }
@@ -1245,7 +1226,7 @@ sub mw_push_revision {
                                return error_non_fast_forward($remote);
                        }
                        if ($status ne "ok") {
-                               die("Unknown error from mw_push_file()");
+                               die("Unknown error from mw_push_file()\n");
                        }
                }
                unless ($dumb_push) {
@@ -1267,8 +1248,8 @@ sub get_allowed_file_extensions {
                siprop => 'fileextensions'
                };
        my $result = $mediawiki->api($query);
-       my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}};
-       my %hashFile = map {$_ => 1}@file_extensions;
+       my @file_extensions = map { $_->{ext}} @{$result->{query}->{fileextensions}};
+       my %hashFile = map { $_ => 1 } @file_extensions;
 
        return %hashFile;
 }
@@ -1290,7 +1271,7 @@ sub get_mw_namespace_id {
                # Look at configuration file, if the record for that namespace is
                # already cached. Namespaces are stored in form:
                # "Name_of_namespace:Id_namespace", ex.: "File:6".
-               my @temp = split(/[\n]/, run_git("config --get-all remote."
+               my @temp = split(/\n/, run_git("config --get-all remote."
                                                . $remotename .".namespaceCache"));
                chomp(@temp);
                foreach my $ns (@temp) {
@@ -1352,7 +1333,8 @@ sub get_mw_namespace_id {
 }
 
 sub get_mw_namespace_id_for_page {
-       if (my ($namespace) = $_[0] =~ /^([^:]*):/) {
+       my $namespace = shift;
+       if ($namespace =~ /^([^:]*):/) {
                return get_mw_namespace_id($namespace);
        } else {
                return;