From: Benoit Person <benoit.per...@ensimag.fr>

Add the subcommand to 'git-mw.perl'.
Add a new constant in GitMediawiki.pm 'HTTP_CODE_PAGE_NOT_FOUND'.

Signed-off-by: Benoit Person <benoit.per...@ensimag.fr>
Signed-off-by: Matthieu Moy <matthieu....@grenoble-inp.fr>

---

changes from V2:
  - Remove the --blob option, distinction between files and blobs is now 
    automatic.
  - Add a --verbose option to output more information on what's going on.
  - Rewrote the doc and the commit message.
  - Rewrote of the template retrieving code (see 'get_template' sub).
  - Use a configuration variable to define the content ID search in the
    template. Default value set as 'bodyContent' since it seems more standard
    than 'mw-content-text'.
  - Final content is now saved as utf-8 to solve encoding issues.
  - Perlcritic changes:
    - All 'print's specify their output streams.
    --> Same useless warnings left in git-remote-mediawiki.perl after 
célestin's 
        work and git-mw.perl after this patch :) .

 contrib/mw-to-git/GitMediawiki.pm |   3 +-
 contrib/mw-to-git/git-mw.perl     | 303 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 304 insertions(+), 2 deletions(-)

diff --git a/contrib/mw-to-git/GitMediawiki.pm 
b/contrib/mw-to-git/GitMediawiki.pm
index beae6d0..d1f2c41 100644
--- a/contrib/mw-to-git/GitMediawiki.pm
+++ b/contrib/mw-to-git/GitMediawiki.pm
@@ -19,7 +19,7 @@ require Exporter;
 
 # Methods which can be called as standalone functions as well:
 @EXPORT_OK = qw(clean_filename smudge_filename connect_maybe
-                               EMPTY HTTP_CODE_OK);
+                               EMPTY HTTP_CODE_OK HTTP_CODE_PAGE_NOT_FOUND);
 }
 
 # Mediawiki filenames can contain forward slashes. This variable decides by 
which pattern they should be replaced
@@ -30,6 +30,7 @@ use constant EMPTY => q{};
 
 # HTTP codes
 use constant HTTP_CODE_OK => 200;
+use constant HTTP_CODE_PAGE_NOT_FOUND => 404;
 
 sub clean_filename {
        my $filename = shift;
diff --git a/contrib/mw-to-git/git-mw.perl b/contrib/mw-to-git/git-mw.perl
index 320c00e..0b83108 100644
--- a/contrib/mw-to-git/git-mw.perl
+++ b/contrib/mw-to-git/git-mw.perl
@@ -12,10 +12,41 @@ use strict;
 use warnings;
 
 use Getopt::Long;
+use URI::URL qw(url);
+use LWP::UserAgent;
+use HTML::TreeBuilder;
+
+use Git;
+use MediaWiki::API;
+use GitMediawiki qw(smudge_filename connect_maybe
+                                       EMPTY HTTP_CODE_PAGE_NOT_FOUND);
+
+# By default, use UTF-8 to communicate with Git and the user
+binmode STDERR, ':encoding(UTF-8)';
+binmode STDOUT, ':encoding(UTF-8)';
+
+#preview parameters
+my $file_name = EMPTY;
+my $remote_name = EMPTY;
+my $preview_file_name = EMPTY;
+my $autoload = 0;
+my $verbose = 0;
+sub file {
+       $file_name = shift;
+       return $file_name;
+}
 
 my %commands = (
        'help' =>
-               [\&help, {}, \&help]
+               [\&help, {}, \&help],
+       'preview' =>
+               [\&preview, {
+                       '<>' => \&file,
+                       'output|o=s' => \$preview_file_name,
+                       'remote|r=s' => \$remote_name,
+                       'autoload|a' => \$autoload,
+                       'verbose|v'  => \$verbose
+               }, \&preview_help]
 );
 
 # Search for sub-command
@@ -33,6 +64,275 @@ GetOptions( %{$cmd->[1]},
 # Launch command
 &{$cmd->[0]};
 
+############################# Preview Functions 
################################
+
+# @TODO : add documentation for verbose option
+sub preview_help {
+       print {*STDOUT} <<'END';
+USAGE: git mw preview [--remote|-r <remote name>] [--autoload|-a]
+                      [--output|-o <output filename>] [--verbose|-v]
+                      <blob> | <filename>
+
+DESCRIPTION:
+Preview is an utiliy to preview local content of a mediawiki repo as if it was
+pushed on the remote.
+
+For that, preview searches for the remote name of the current branch's upstream
+if --remote is not set. If that remote is not found or if it is not a 
mediawiki,
+it lists all mediawiki remotes configured and asks you to replay your command
+with the --remote option set properly.
+
+Then, it searches for a file named 'filename'. If it's not found in the current
+dir, it will assume it's a blob.
+
+The content retrieved in the file (or in the blob) will then be parsed by the
+distant mediawiki and combined with a template retrieved from the mediawiki.
+
+Finally, preview will save the HTML result in a file. and autoload it in your
+default web browser if the option --autoload is present.
+
+OPTIONS:
+       -r <remote name>, --remote <remote name>
+               If the remote is a mediawiki, the template and the parse engine 
used for
+               the preview will be those of that remote.
+               If not, a list of valid remotes will be shown.
+
+       -a, --autoload
+               Try to load the HTML output in a new tab (or new window) of 
your default
+               web browser.
+
+       -o <output filename>, --output <output filename>
+               Change the HTML output filename. Default filename is based on 
the input
+               filename with its extension replaced by '.html'.
+
+       -v, --verbose
+               Show more information on what's going on under the hood.
+END
+       exit;
+}
+
+sub preview {
+       my $wiki;
+       my ($remote_url, $wiki_page_name);
+       my ($content, $content_tree, $template, $html_tree, $mw_content_text);
+       my $file_content;
+       my $template_content_id = 'bodyContent';
+
+       # file_name argumeent is mandatory
+       if (!defined $file_name) {
+               die "File not set, see `git mw help` \n";
+       }
+
+       v_print("### SELECTING REMOTE ###\n");
+
+       if ($remote_name eq EMPTY) {
+               # Search current branch upstream branch remote
+               my $current_branch = git_cmd_try {
+                       Git::command_oneline('symbolic-ref', '--short', 'HEAD') 
}
+                       "%s failed w/ code %d";
+               $remote_name = Git::config("branch.${current_branch}.remote");
+
+               if ($remote_name) {
+                       $remote_url = mediawiki_remote_url_maybe($remote_name);
+               }
+
+               # Search all possibles mediawiki remotes
+               if (! $remote_url) {
+                       my @remotes = git_cmd_try {
+                               Git::command('remote'); }
+                               "%s failed w/ code %d";
+
+                       my @valid_remotes = ();
+                       foreach my $remote (@remotes) {
+                               $remote_url = 
mediawiki_remote_url_maybe($remote);
+                               if ($remote_url) {
+                                       push(@valid_remotes, $remote);
+                               }
+                       }
+
+                       if ($#valid_remotes == 0) {
+                               print {*STDERR} "Can not find any mediawiki 
remote in this repo. \n";
+                               exit 1;
+                       } else {
+                               print {*STDERR} "There are multiple mediawiki 
remotes, which of:\n";
+                               foreach my $remote (@remotes) {
+                                       print {*STDERR} "\t${remote}\n";
+                               }
+                               print {*STDERR} "do you want ? Use the -r 
option to specify the remote\n";
+                       }
+
+                       exit 0;
+               }
+       } else {
+               # Check remote name
+               my @remotes = git_cmd_try {
+                       Git::command('remote') }
+                       "%s failed w/ code %d";
+               my $found_remote = 0;
+               foreach my $remote (@remotes) {
+                       if ($remote eq $remote_name) {
+                               $found_remote = 1;
+                               last;
+                       }
+               }
+               if (!$found_remote) {
+                       die "${remote_name} is not a remote\n";
+               }
+
+               # Find remote url
+               $remote_url = mediawiki_remote_url_maybe($remote_name);
+               if (! $remote_url) {
+                       die "the remote you selected is not a mediawiki 
remote\n";
+               }
+       }
+       v_print("selected remote:\n\tname: ${remote_name}\n\turl: 
${remote_url}\n");
+
+       # Create and connect to the wiki if necessary
+       $wiki = connect_maybe($wiki, $remote_name, $remote_url);
+
+       # Read file content
+       if (! -e $file_name) {
+               $file_content = git_cmd_try {
+                       Git::command('cat-file', 'blob', $file_name); }
+                       "%s failed w/ code %d";
+
+               if ($file_name =~ /(.+):(.+)/) {
+                       $file_name = $2;
+               }
+       } else {
+               open my $read_fh, "<", $file_name
+                       or die "could not open ${file_name}: $!\n";
+               $file_content = do { local $/ = undef; <$read_fh> };
+               close $read_fh
+                       or die "unable to close: $!\n";
+       }
+
+       # Transform file_name into a mediawiki page name
+       $wiki_page_name = smudge_filename($file_name);
+       $wiki_page_name =~ s/\.[^.]+$//;
+
+       # Default preview_file_name is file_name with .html ext
+       if ($preview_file_name eq EMPTY) {
+               $preview_file_name = $file_name;
+               $preview_file_name =~ s/\.[^.]+$/.html/;
+       }
+
+       v_print("### Retrieving template\n");
+       $template = get_template($remote_url, $wiki_page_name);
+
+       v_print("### Parsing & merging contents\n");
+       # Parsing template page
+       $html_tree = HTML::TreeBuilder->new;
+       $html_tree->parse($template);
+
+       # Load new content
+       $content = $wiki->api({
+               action => 'parse',
+               text => $file_content,
+               title => $wiki_page_name
+       }, {
+               skip_encoding => 1
+       }) or die "No response from distant mediawiki\n";
+       $content = $content->{'parse'}->{'text'}->{'*'};
+       $content_tree = HTML::TreeBuilder->new;
+       $content_tree->parse($content);
+
+       # Replace old content with new one
+       $template_content_id = Git::config('mediawiki.IDContent')
+               || $template_content_id;
+       v_print("Using '${template_content_id}' as the content ID\n");
+       $mw_content_text = $html_tree->look_down('id', $template_content_id);
+       if (!defined $mw_content_text) {
+               print {*STDERR} <<"CONFIG";
+Could not combine the new parsed content with the template. You might want to
+configure `mediawiki.IDContent` in your config:
+       git config --add mediawiki.IDContent <your_template_content_element_id>
+CONFIG
+       }
+       $mw_content_text->delete_content();
+       $mw_content_text->push_content($content_tree);
+
+       # Transform relative links into absolute ones
+       for (@{ $html_tree->extract_links() }) {
+               my ($link, $element, $attr) = @{ $_ };
+               my $url = url($link)->canonical;
+               $element->attr($attr, URI->new_abs($url, $remote_url));
+       }
+
+       # Save the preview file
+       open(my $save_fh, '>:encoding(UTF-8)', $preview_file_name)
+               or die "Could not open: $!\n";
+       print {$save_fh} $html_tree->as_HTML;
+       close($save_fh)
+               or die "Could not close: $!\n";
+
+       # Auto-loading in browser
+       v_print("### Results\n");
+       if ($autoload) {
+               v_print("Launching browser w/ file: ${preview_file_name}");
+               system('git', 'web--browse', $preview_file_name);
+       } else {
+               print {*STDERR} "Preview file saved as: ${preview_file_name}\n";
+       }
+
+       exit;
+}
+
+sub mediawiki_remote_url_maybe {
+       my $remote = shift;
+
+       # Find remote url
+       my $remote_url = Git::config("remote.${remote}.url");
+       if ($remote_url =~ s/mediawiki::(.*)/$1/) {
+               return url($remote_url)->canonical;
+       }
+
+       return;
+}
+
+sub get_template {
+       my $url = shift;
+       my $page_name = shift;
+       my ($req, $res, $code, $url_after);
+
+       $req = LWP::UserAgent->new;
+       if ($verbose) {
+               $req->show_progress(1);
+       }
+
+       $res = $req->get("${url}/index.php?title=${page_name}");
+       if (!$res->is_success) {
+               $code = $res->code;
+               $url_after = $res->request()->uri(); # resolve all redirections
+               if ($code == HTTP_CODE_PAGE_NOT_FOUND) {
+                       if ($verbose) {
+                               print {*STDERR} <<"WARNING";
+Warning: Failed to retrieve '$page_name'. Create it on the mediawiki if you 
want
+all the links to work properly.
+Trying to use the mediawiki homepage as a fallback template ...
+WARNING
+                       }
+
+                       # LWP automatically redirects GET request
+                       $res = $req->get("${url}/index.php");
+                       if (!$res->is_success) {
+                               $url_after = $res->request()->uri(); # resolve 
all redirections
+                               die "Failed to get homepage @ ${url_after} w/ 
code ${code}\n";
+                       }
+               } else {
+                       die "Failed to get '${page_name}' @ ${url_after} w/ 
code ${code}\n";
+               }
+       }
+
+       return $res->decoded_content;
+}
+
+sub v_print {
+       if ($verbose) {
+               print {*STDERR} @_;
+       }
+}
+
 ############################## Help Functions 
##################################
 
 sub help {
@@ -41,6 +341,7 @@ usage: git mw <command> <args>
 
 git mw commands are:
     help        Display help information about git mw
+    preview    Parse and render local file into HTML
 END
        exit;
 }
\ No newline at end of file
-- 
1.8.3.GIT

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to