From: Benoit Person <benoit.person@xxxxxxxxxx> 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.person@xxxxxxxxxx> Signed-off-by: Matthieu Moy <matthieu.moy@xxxxxxxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html