From: benoit.person@ensimag.fr
To: git@vger.kernel.org
Cc: Celestin Matte <celestin.matte@ensimag.fr>,
Matthieu Moy <matthieu.moy@grenoble-inp.fr>,
Benoit Person <benoit.person@ensimag.fr>
Subject: [PATCH V3 4/4] git-mw: Add preview subcommand into git mw.
Date: Sun, 16 Jun 2013 04:31:33 +0200 [thread overview]
Message-ID: <1371349893-7789-5-git-send-email-benoit.person@ensimag.fr> (raw)
In-Reply-To: <1371349893-7789-1-git-send-email-benoit.person@ensimag.fr>
From: Benoit Person <benoit.person@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.person@ensimag.fr>
Signed-off-by: Matthieu Moy <matthieu.moy@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
next prev parent reply other threads:[~2013-06-16 2:32 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-16 2:31 [PATCH V3 0/4] git-remote-mediawiki: new tool to preview local changes without pushing benoit.person
2013-06-16 2:31 ` [PATCH V3 1/4] git-mw: Introduction of GitMediawiki.pm benoit.person
2013-06-16 20:18 ` Matthieu Moy
2013-06-16 23:41 ` Benoît Person
2013-06-17 7:12 ` Matthieu Moy
2013-06-18 9:06 ` Benoît Person
2013-06-18 10:10 ` Matthieu Moy
2013-06-18 10:54 ` Matthieu Moy
2013-06-16 2:31 ` [PATCH V3 2/4] git-mw: Move some functions from git-remote-mediawiki.perl to GitMediawiki.pm benoit.person
2013-06-16 2:31 ` [PATCH V3 3/4] git-mw: Adding git-mw command benoit.person
2013-06-16 2:31 ` benoit.person [this message]
2013-06-16 20:39 ` [PATCH V3 4/4] git-mw: Add preview subcommand into git mw Matthieu Moy
2013-06-16 9:00 ` [PATCH V3 0/4] git-remote-mediawiki: new tool to preview local changes without pushing Ramkumar Ramachandra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1371349893-7789-5-git-send-email-benoit.person@ensimag.fr \
--to=benoit.person@ensimag.fr \
--cc=celestin.matte@ensimag.fr \
--cc=git@vger.kernel.org \
--cc=matthieu.moy@grenoble-inp.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).