[Bps-public-commit] rt-extension-commentoncreate branch, master, updated. 1.00-5-ge9d2db1

? sunnavy sunnavy at bestpractical.com
Fri Jun 11 17:06:04 EDT 2021


The branch, master has been updated
       via  e9d2db1957db72b1d8eecdb1bcfb876193cbfb83 (commit)
       via  06206579fbe153c4422246b67a464c181e311816 (commit)
       via  23746c976f5974242e87d41a439525bbba985ff8 (commit)
       via  22228e33aed89da5f66833edd54259e7d8e87b42 (commit)
       via  774adcf93ce9c3a146df7e45dd2141dbbb994f90 (commit)
      from  ecfdb9093590e20c222a7ab6c5a7a6c530326467 (commit)

Summary of changes:
 Changes                                            |   8 +-
 MANIFEST                                           |   1 -
 META.yml                                           |   6 +-
 README                                             |   6 +-
 .../Ticket/Create.html/AfterMessageBox             |  13 +-
 inc/Module/Install.pm                              |  35 +-
 inc/Module/Install/Base.pm                         |   2 +-
 inc/Module/Install/Can.pm                          |  13 +-
 inc/Module/Install/Fetch.pm                        |   2 +-
 inc/Module/Install/Include.pm                      |   2 +-
 inc/Module/Install/Makefile.pm                     |   2 +-
 inc/Module/Install/Metadata.pm                     |   2 +-
 inc/Module/Install/RTx.pm                          |  81 +-
 inc/Module/Install/RTx/Runtime.pm                  |  80 ++
 inc/Module/Install/ReadmeFromPod.pm                |  76 +-
 inc/Module/Install/Win32.pm                        |   2 +-
 inc/Module/Install/WriteAll.pm                     |   2 +-
 inc/YAML/Tiny.pm                                   | 872 +++++++++++++++++++++
 lib/RT/Extension/CommentOnCreate.pm                |   8 +-
 19 files changed, 1136 insertions(+), 77 deletions(-)
 create mode 100644 inc/Module/Install/RTx/Runtime.pm
 create mode 100644 inc/YAML/Tiny.pm

- Log -----------------------------------------------------------------
commit 774adcf93ce9c3a146df7e45dd2141dbbb994f90
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Jun 12 04:30:14 2021 +0800

    Update M:I

diff --git a/MANIFEST b/MANIFEST
index 2ebc084..d2d2a25 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -13,7 +13,6 @@ inc/Module/Install/RTx.pm
 inc/Module/Install/RTx/Runtime.pm
 inc/Module/Install/Win32.pm
 inc/Module/Install/WriteAll.pm
-inc/unicore/Name.pm
 inc/YAML/Tiny.pm
 lib/RT/Extension/CommentOnCreate.pm
 Makefile.PL
diff --git a/META.yml b/META.yml
index df93a1f..1623f3d 100644
--- a/META.yml
+++ b/META.yml
@@ -8,7 +8,7 @@ configure_requires:
   ExtUtils::MakeMaker: 6.59
 distribution_type: module
 dynamic_config: 1
-generated_by: 'Module::Install version 1.12'
+generated_by: 'Module::Install version 1.19'
 license: gpl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -23,5 +23,5 @@ requires:
 resources:
   license: http://opensource.org/licenses/gpl-license.php
 version: '1.00'
-x_module_install_rtx_version: '0.36'
+x_module_install_rtx_version: '0.42'
 x_requires_rt: 4.0.7
diff --git a/inc/Module/Install.pm b/inc/Module/Install.pm
index 5460dd5..7ba98c2 100644
--- a/inc/Module/Install.pm
+++ b/inc/Module/Install.pm
@@ -31,7 +31,7 @@ BEGIN {
 	# This is not enforced yet, but will be some time in the next few
 	# releases once we can make sure it won't clash with custom
 	# Module::Install extensions.
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 
 	# Storage for the pseudo-singleton
 	$MAIN    = undef;
@@ -244,6 +244,8 @@ sub new {
 	}
 	return $args{_self} if $args{_self};
 
+	$base_path = VMS::Filespec::unixify($base_path) if $^O eq 'VMS';
+
 	$args{dispatch} ||= 'Admin';
 	$args{prefix}   ||= 'inc';
 	$args{author}   ||= ($^O eq 'VMS' ? '_author' : '.author');
@@ -322,7 +324,7 @@ sub find_extensions {
 	my ($self, $path) = @_;
 
 	my @found;
-	File::Find::find( sub {
+	File::Find::find( {no_chdir => 1, wanted => sub {
 		my $file = $File::Find::name;
 		return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is;
 		my $subpath = $1;
@@ -336,7 +338,7 @@ sub find_extensions {
 		# correctly.  Otherwise, root through the file to locate the case-preserved
 		# version of the package name.
 		if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
-			my $content = Module::Install::_read($subpath . '.pm');
+			my $content = Module::Install::_read($File::Find::name);
 			my $in_pod  = 0;
 			foreach ( split /\n/, $content ) {
 				$in_pod = 1 if /^=\w/;
@@ -351,7 +353,7 @@ sub find_extensions {
 		}
 
 		push @found, [ $file, $pkg ];
-	}, $path ) if -d $path;
+	}}, $path ) if -d $path;
 
 	@found;
 }
@@ -373,24 +375,14 @@ sub _caller {
 	return $call;
 }
 
-# Done in evals to avoid confusing Perl::MinimumVersion
-eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _read {
 	local *FH;
 	open( FH, '<', $_[0] ) or die "open($_[0]): $!";
+	binmode FH;
 	my $string = do { local $/; <FH> };
 	close FH or die "close($_[0]): $!";
 	return $string;
 }
-END_NEW
-sub _read {
-	local *FH;
-	open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
-	my $string = do { local $/; <FH> };
-	close FH or die "close($_[0]): $!";
-	return $string;
-}
-END_OLD
 
 sub _readperl {
 	my $string = Module::Install::_read($_[0]);
@@ -411,26 +403,15 @@ sub _readpod {
 	return $string;
 }
 
-# Done in evals to avoid confusing Perl::MinimumVersion
-eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _write {
 	local *FH;
 	open( FH, '>', $_[0] ) or die "open($_[0]): $!";
+	binmode FH;
 	foreach ( 1 .. $#_ ) {
 		print FH $_[$_] or die "print($_[0]): $!";
 	}
 	close FH or die "close($_[0]): $!";
 }
-END_NEW
-sub _write {
-	local *FH;
-	open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
-	foreach ( 1 .. $#_ ) {
-		print FH $_[$_] or die "print($_[0]): $!";
-	}
-	close FH or die "close($_[0]): $!";
-}
-END_OLD
 
 # _version is for processing module versions (eg, 1.03_05) not
 # Perl versions (eg, 5.8.1).
diff --git a/inc/Module/Install/Base.pm b/inc/Module/Install/Base.pm
index f9bf5de..9fa42c2 100644
--- a/inc/Module/Install/Base.pm
+++ b/inc/Module/Install/Base.pm
@@ -4,7 +4,7 @@ package Module::Install::Base;
 use strict 'vars';
 use vars qw{$VERSION};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 }
 
 # Suspend handler for "redefined" warnings
diff --git a/inc/Module/Install/Can.pm b/inc/Module/Install/Can.pm
index b4e5e3b..d65c753 100644
--- a/inc/Module/Install/Can.pm
+++ b/inc/Module/Install/Can.pm
@@ -8,7 +8,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -121,6 +121,15 @@ END_C
 # Can we locate a (the) C compiler
 sub can_cc {
 	my $self   = shift;
+
+	if ($^O eq 'VMS') {
+		require ExtUtils::CBuilder;
+		my $builder = ExtUtils::CBuilder->new(
+		quiet => 1,
+		);
+		return $builder->have_compiler;
+	}
+
 	my @chunks = split(/ /, $Config::Config{cc}) or return;
 
 	# $Config{cc} may contain args; try to find out the program part
@@ -151,4 +160,4 @@ if ( $^O eq 'cygwin' ) {
 
 __END__
 
-#line 236
+#line 245
diff --git a/inc/Module/Install/Fetch.pm b/inc/Module/Install/Fetch.pm
index 54f14fb..3072b08 100644
--- a/inc/Module/Install/Fetch.pm
+++ b/inc/Module/Install/Fetch.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/Include.pm b/inc/Module/Install/Include.pm
index 7224cff..13fdcd0 100644
--- a/inc/Module/Install/Include.pm
+++ b/inc/Module/Install/Include.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/Makefile.pm b/inc/Module/Install/Makefile.pm
index 81cddd5..13a4464 100644
--- a/inc/Module/Install/Makefile.pm
+++ b/inc/Module/Install/Makefile.pm
@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/Metadata.pm b/inc/Module/Install/Metadata.pm
index 2c66b1e..11bf971 100644
--- a/inc/Module/Install/Metadata.pm
+++ b/inc/Module/Install/Metadata.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/RTx.pm b/inc/Module/Install/RTx.pm
index 73e7245..2dd9489 100644
--- a/inc/Module/Install/RTx.pm
+++ b/inc/Module/Install/RTx.pm
@@ -6,9 +6,10 @@ use strict;
 use warnings;
 no warnings 'once';
 
+use Term::ANSIColor qw(:constants);
 use Module::Install::Base;
 use base 'Module::Install::Base';
-our $VERSION = '0.36';
+our $VERSION = '0.42';
 
 use FindBin;
 use File::Glob     ();
@@ -37,6 +38,13 @@ sub RTx {
     }
     $self->add_metadata("x_module_install_rtx_version", $VERSION );
 
+    my $installdirs = $ENV{INSTALLDIRS};
+    for ( @ARGV ) {
+        if ( /INSTALLDIRS=(.*)/ ) {
+            $installdirs = $1;
+        }
+    }
+
     # Try to find RT.pm
     my @prefixes = qw( /opt /usr/local /home /usr /sw /usr/share/request-tracker4);
     $ENV{RTHOME} =~ s{/RT\.pm$}{} if defined $ENV{RTHOME};
@@ -46,7 +54,7 @@ sub RTx {
         my @look = @INC;
         unshift @look, grep {defined and -d $_} @try;
         push @look, grep {defined and -d $_}
-            map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
+            map { ( "$_/rt5/lib", "$_/lib/rt5", "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
         last if eval {local @INC = @look; require RT; $RT::LocalLibPath};
 
         warn
@@ -69,9 +77,31 @@ sub RTx {
         $self->requires_rt('4.0.0');
     }
 
+    my $package = $name;
+    $package =~ s/-/::/g;
+    if ( $RT::CORED_PLUGINS{$package} ) {
+        my ($base_version) = $RT::VERSION =~ /(\d+\.\d+\.\d+)/;
+        die RED, <<"EOT";
+
+**** Error: Your installed version of RT ($RT::VERSION) already
+            contains this extension in core, so you don't need to
+            install it.
+
+            Check https://docs.bestpractical.com/rt/$base_version/RT_Config.html
+            to configure it.
+
+EOT
+    }
+
     # Installation locations
     my %path;
-    $path{$_} = $RT::LocalPluginPath . "/$name/$_"
+    my $plugin_path;
+    if ( $installdirs && $installdirs eq 'vendor' ) {
+        $plugin_path = $RT::PluginPath;
+    } else {
+        $plugin_path = $RT::LocalPluginPath;
+    }
+    $path{$_} = $plugin_path . "/$name/$_"
         foreach @DIRS;
 
     # Copy RT 4.2.0 static files into NoAuth; insufficient for
@@ -85,7 +115,7 @@ sub RTx {
     my %index = map { $_ => 1 } @INDEX_DIRS;
     $self->no_index( directory => $_ ) foreach grep !$index{$_}, @DIRS;
 
-    my $args = join ', ', map "q($_)", map { ($_, $path{$_}) }
+    my $args = join ', ', map "q($_)", map { ($_, "\$(DESTDIR)$path{$_}") }
         sort keys %path;
 
     printf "%-10s => %s\n", $_, $path{$_} for sort keys %path;
@@ -100,11 +130,29 @@ lexicons ::
 .
     }
 
+    my $remove_files;
+    if( $extra_args->{'remove_files'} ){
+        $self->include('Module::Install::RTx::Remove');
+        our @remove_files;
+        eval { require "etc/upgrade/remove_files" }
+          or print "No remove file located, no files to remove\n";
+        $remove_files = join ",", map {"q(\$(DESTDIR)$plugin_path/$name/$_)"} @remove_files;
+    }
+
     $self->include('Module::Install::RTx::Runtime') if $self->admin;
     $self->include_deps( 'YAML::Tiny', 0 ) if $self->admin;
     my $postamble = << ".";
 install ::
 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxPlugin()"
+.
+
+    if( $remove_files ){
+        $postamble .= << ".";
+\t\$(NOECHO) \$(PERL) -MModule::Install::RTx::Remove -e \"RTxRemove([$remove_files])\"
+.
+    }
+
+    $postamble .= << ".";
 \t\$(NOECHO) \$(PERL) -MExtUtils::Install -e \"install({$args})\"
 .
 
@@ -123,7 +171,7 @@ install ::
         $has_etc{acl}++;
     }
     if ( -e 'etc/initialdata' ) { $has_etc{initialdata}++; }
-    if ( grep { /\d+\.\d+(\.\d+)?.*$/ } glob('etc/upgrade/*.*') ) {
+    if ( grep { /\d+\.\d+\.\d+.*$/ } glob('etc/upgrade/*.*.*') ) {
         $has_etc{upgrade}++;
     }
 
@@ -131,6 +179,7 @@ install ::
     if ( $path{lib} ) {
         $self->makemaker_args( INSTALLSITELIB => $path{'lib'} );
         $self->makemaker_args( INSTALLARCHLIB => $path{'lib'} );
+        $self->makemaker_args( INSTALLVENDORLIB => $path{'lib'} )
     } else {
         $self->makemaker_args( PM => { "" => "" }, );
     }
@@ -139,6 +188,13 @@ install ::
     $self->makemaker_args( INSTALLSITEMAN3DIR => "$RT::LocalPath/man/man3" );
     $self->makemaker_args( INSTALLSITEARCH => "$RT::LocalPath/man" );
 
+    # INSTALLDIRS=vendor should install manpages into /usr/share/man.
+    # That is the default path in most distributions. Need input from
+    # Redhat, Centos etc.
+    $self->makemaker_args( INSTALLVENDORMAN1DIR => "/usr/share/man/man1" );
+    $self->makemaker_args( INSTALLVENDORMAN3DIR => "/usr/share/man/man3" );
+    $self->makemaker_args( INSTALLVENDORARCH => "/usr/share/man" );
+
     if (%has_etc) {
         print "For first-time installation, type 'make initdb'.\n";
         my $initdb = '';
@@ -184,7 +240,7 @@ sub requires_rt {
     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
 
     if ($sorted[-1] eq $version) {
-        die <<"EOT";
+        die RED, <<"EOT";
 
 **** Error: This extension requires RT $version. Your installed version
             of RT ($RT::VERSION) is too old.
@@ -210,12 +266,12 @@ sub requires_rt_plugin {
         unshift @INC, $path;
     } else {
         my $name = $self->name;
-        warn <<"EOT";
+        my $msg = <<"EOT";
 
 **** Warning: $name requires that the $plugin plugin be installed and
               enabled; it does not appear to be installed.
-
 EOT
+        warn RED, $msg, RESET, "\n";
     }
     $self->requires(@_);
 }
@@ -225,9 +281,8 @@ sub rt_too_new {
     my $name = $self->name;
     $msg ||= <<EOT;
 
-**** Error: Your installed version of RT (%s) is too new; this extension
-            only works with versions older than %s.
-
+**** Warning: Your installed version of RT (%s) is too new; this extension
+              has not been tested on your version of RT and may not work as expected.
 EOT
     $self->add_metadata("x_rt_too_new", $version) if $self->is_admin;
 
@@ -235,7 +290,7 @@ EOT
     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
 
     if ($sorted[0] eq $version) {
-        die sprintf($msg,$RT::VERSION,$version);
+        warn RED, sprintf($msg,$RT::VERSION), RESET, "\n";
     }
 }
 
@@ -258,4 +313,4 @@ sub _load_rt_handle {
 
 __END__
 
-#line 390
+#line 484
diff --git a/inc/Module/Install/RTx/Runtime.pm b/inc/Module/Install/RTx/Runtime.pm
new file mode 100644
index 0000000..ae07502
--- /dev/null
+++ b/inc/Module/Install/RTx/Runtime.pm
@@ -0,0 +1,80 @@
+#line 1
+package Module::Install::RTx::Runtime;
+
+use base 'Exporter';
+our @EXPORT = qw/RTxDatabase RTxPlugin/;
+
+use strict;
+use File::Basename ();
+
+sub _rt_runtime_load {
+    require RT;
+
+    eval { RT::LoadConfig(); };
+    if (my $err = $@) {
+        die $err unless $err =~ /^RT couldn't load RT config file/m;
+        my $warn = <<EOT;
+This usually means that your current user cannot read the file.  You
+will likely need to run this installation step as root, or some user
+with more permissions.
+EOT
+        $err =~ s/This usually means.*/$warn/s;
+        die $err;
+    }
+}
+
+sub RTxDatabase {
+    my ($action, $name, $version) = @_;
+
+    _rt_runtime_load();
+
+    require RT::System;
+    my $has_upgrade = RT::System->can('AddUpgradeHistory');
+
+    my $lib_path = File::Basename::dirname($INC{'RT.pm'});
+    my @args = (
+        "-I.",
+        "-Ilib",
+        "-I$RT::LocalLibPath",
+        "-I$lib_path",
+        "$RT::SbinPath/rt-setup-database",
+        "--action"      => $action,
+        ($action eq 'upgrade' ? () : ("--datadir"     => "etc")),
+        (($action eq 'insert') ? ("--datafile"    => "etc/initialdata") : ()),
+        "--dba"         => $RT::DatabaseAdmin || $RT::DatabaseUser,
+        "--prompt-for-dba-password" => '',
+        ($has_upgrade ? ("--package" => $name, "--ext-version" => $version) : ()),
+    );
+    # If we're upgrading against an RT which isn't at least 4.2 (has
+    # AddUpgradeHistory) then pass --package.  Upgrades against later RT
+    # releases will pick up --package from AddUpgradeHistory.
+    if ($action eq 'upgrade' and not $has_upgrade) {
+        push @args, "--package" => $name;
+    }
+
+    print "$^X @args\n";
+    (system($^X, @args) == 0) or die "...returned with error: $?\n";
+}
+
+sub RTxPlugin {
+    my ($name) = @_;
+
+    _rt_runtime_load();
+    require YAML::Tiny;
+    my $data = YAML::Tiny::LoadFile('META.yml');
+    my $name = $data->{name};
+
+    my @enabled = RT->Config->Get('Plugins');
+    for my $required (@{$data->{x_requires_rt_plugins} || []}) {
+        next if grep {$required eq $_} @enabled;
+
+        warn <<"EOT";
+
+**** Warning: $name requires that the $required plugin be installed and
+              enabled; it is not currently in \@Plugins.
+
+EOT
+    }
+}
+
+1;
diff --git a/inc/Module/Install/ReadmeFromPod.pm b/inc/Module/Install/ReadmeFromPod.pm
index b5e03c3..3738232 100644
--- a/inc/Module/Install/ReadmeFromPod.pm
+++ b/inc/Module/Install/ReadmeFromPod.pm
@@ -7,12 +7,41 @@ use warnings;
 use base qw(Module::Install::Base);
 use vars qw($VERSION);
 
-$VERSION = '0.22';
+$VERSION = '0.30';
+
+{
+
+    # these aren't defined until after _require_admin is run, so
+    # define them so prototypes are available during compilation.
+    sub io;
+    sub capture(&;@);
+
+#line 28
+
+    my $done = 0;
+
+    sub _require_admin {
+
+	# do this once to avoid redefinition warnings from IO::All
+	return if $done;
+
+	require IO::All;
+	IO::All->import( '-binary' );
+
+	require Capture::Tiny;
+	Capture::Tiny->import ( 'capture' );
+
+	return;
+    }
+
+}
 
 sub readme_from {
   my $self = shift;
   return unless $self->is_admin;
 
+  _require_admin;
+
   # Input file
   my $in_file  = shift || $self->_all_from
     or die "Can't determine file to make readme_from";
@@ -50,6 +79,8 @@ sub readme_from {
     $out_file = $self->_readme_htm($in_file, $out_file, $options);
   } elsif ($format eq 'man') {
     $out_file = $self->_readme_man($in_file, $out_file, $options);
+  } elsif ($format eq 'md') {
+    $out_file = $self->_readme_md($in_file, $out_file, $options);
   } elsif ($format eq 'pdf') {
     $out_file = $self->_readme_pdf($in_file, $out_file, $options);
   }
@@ -67,10 +98,10 @@ sub _readme_txt {
   $out_file ||= 'README';
   require Pod::Text;
   my $parser = Pod::Text->new( @$options );
-  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
   $parser->output_fh( *$out_fh );
   $parser->parse_file( $in_file );
-  close $out_fh;
   return $out_file;
 }
 
@@ -79,11 +110,14 @@ sub _readme_htm {
   my ($self, $in_file, $out_file, $options) = @_;
   $out_file ||= 'README.htm';
   require Pod::Html;
-  Pod::Html::pod2html(
-    "--infile=$in_file",
-    "--outfile=$out_file",
-    @$options,
-  );
+  my ($o) = capture {
+    Pod::Html::pod2html(
+      "--infile=$in_file",
+      "--outfile=-",
+      @$options,
+    );
+  };
+  io->file($out_file)->print($o);
   # Remove temporary files if needed
   for my $file ('pod2htmd.tmp', 'pod2htmi.tmp') {
     if (-e $file) {
@@ -99,7 +133,10 @@ sub _readme_man {
   $out_file ||= 'README.1';
   require Pod::Man;
   my $parser = Pod::Man->new( @$options );
-  $parser->parse_from_file($in_file, $out_file);
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
+  $parser->output_fh( *$out_fh );
+  $parser->parse_file( $in_file );
   return $out_file;
 }
 
@@ -111,11 +148,20 @@ sub _readme_pdf {
     or die "Could not generate $out_file because pod2pdf could not be found\n";
   my $parser = App::pod2pdf->new( @$options );
   $parser->parse_from_file($in_file);
-  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
-  select $out_fh;
-  $parser->output;
-  select STDOUT;
-  close $out_fh;
+  my ($o) = capture { $parser->output };
+  io->file($out_file)->print($o);
+  return $out_file;
+}
+
+sub _readme_md {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README.md';
+  require Pod::Markdown;
+  my $parser = Pod::Markdown->new( @$options );
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
+  $parser->output_fh( *$out_fh );
+  $parser->parse_file( $in_file );
   return $out_file;
 }
 
@@ -134,5 +180,5 @@ sub _all_from {
 
 __END__
 
-#line 254
+#line 316
 
diff --git a/inc/Module/Install/Win32.pm b/inc/Module/Install/Win32.pm
index e48c32d..f7aa615 100644
--- a/inc/Module/Install/Win32.pm
+++ b/inc/Module/Install/Win32.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/WriteAll.pm b/inc/Module/Install/WriteAll.pm
index 409ef40..2db861a 100644
--- a/inc/Module/Install/WriteAll.pm
+++ b/inc/Module/Install/WriteAll.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.12';
+	$VERSION = '1.19';
 	@ISA     = qw{Module::Install::Base};
 	$ISCORE  = 1;
 }
diff --git a/inc/YAML/Tiny.pm b/inc/YAML/Tiny.pm
new file mode 100644
index 0000000..fb157a6
--- /dev/null
+++ b/inc/YAML/Tiny.pm
@@ -0,0 +1,872 @@
+#line 1
+use 5.008001; # sane UTF-8 support
+use strict;
+use warnings;
+package YAML::Tiny; # git description: v1.72-7-g8682f63
+# XXX-INGY is 5.8.1 too old/broken for utf8?
+# XXX-XDG Lancaster consensus was that it was sufficient until
+# proven otherwise
+
+our $VERSION = '1.73';
+
+#####################################################################
+# The YAML::Tiny API.
+#
+# These are the currently documented API functions/methods and
+# exports:
+
+use Exporter;
+our @ISA       = qw{ Exporter  };
+our @EXPORT    = qw{ Load Dump };
+our @EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
+
+###
+# Functional/Export API:
+
+sub Dump {
+    return YAML::Tiny->new(@_)->_dump_string;
+}
+
+# XXX-INGY Returning last document seems a bad behavior.
+# XXX-XDG I think first would seem more natural, but I don't know
+# that it's worth changing now
+sub Load {
+    my $self = YAML::Tiny->_load_string(@_);
+    if ( wantarray ) {
+        return @$self;
+    } else {
+        # To match YAML.pm, return the last document
+        return $self->[-1];
+    }
+}
+
+# XXX-INGY Do we really need freeze and thaw?
+# XXX-XDG I don't think so.  I'd support deprecating them.
+BEGIN {
+    *freeze = \&Dump;
+    *thaw   = \&Load;
+}
+
+sub DumpFile {
+    my $file = shift;
+    return YAML::Tiny->new(@_)->_dump_file($file);
+}
+
+sub LoadFile {
+    my $file = shift;
+    my $self = YAML::Tiny->_load_file($file);
+    if ( wantarray ) {
+        return @$self;
+    } else {
+        # Return only the last document to match YAML.pm,
+        return $self->[-1];
+    }
+}
+
+
+###
+# Object Oriented API:
+
+# Create an empty YAML::Tiny object
+# XXX-INGY Why do we use ARRAY object?
+# NOTE: I get it now, but I think it's confusing and not needed.
+# Will change it on a branch later, for review.
+#
+# XXX-XDG I don't support changing it yet.  It's a very well-documented
+# "API" of YAML::Tiny.  I'd support deprecating it, but Adam suggested
+# we not change it until YAML.pm's own OO API is established so that
+# users only have one API change to digest, not two
+sub new {
+    my $class = shift;
+    bless [ @_ ], $class;
+}
+
+# XXX-INGY It probably doesn't matter, and it's probably too late to
+# change, but 'read/write' are the wrong names. Read and Write
+# are actions that take data from storage to memory
+# characters/strings. These take the data to/from storage to native
+# Perl objects, which the terms dump and load are meant. As long as
+# this is a legacy quirk to YAML::Tiny it's ok, but I'd prefer not
+# to add new {read,write}_* methods to this API.
+
+sub read_string {
+    my $self = shift;
+    $self->_load_string(@_);
+}
+
+sub write_string {
+    my $self = shift;
+    $self->_dump_string(@_);
+}
+
+sub read {
+    my $self = shift;
+    $self->_load_file(@_);
+}
+
+sub write {
+    my $self = shift;
+    $self->_dump_file(@_);
+}
+
+
+
+
+#####################################################################
+# Constants
+
+# Printed form of the unprintable characters in the lowest range
+# of ASCII characters, listed by ASCII ordinal position.
+my @UNPRINTABLE = qw(
+    0    x01  x02  x03  x04  x05  x06  a
+    b    t    n    v    f    r    x0E  x0F
+    x10  x11  x12  x13  x14  x15  x16  x17
+    x18  x19  x1A  e    x1C  x1D  x1E  x1F
+);
+
+# Printable characters for escapes
+my %UNESCAPES = (
+    0 => "\x00", z => "\x00", N    => "\x85",
+    a => "\x07", b => "\x08", t    => "\x09",
+    n => "\x0a", v => "\x0b", f    => "\x0c",
+    r => "\x0d", e => "\x1b", '\\' => '\\',
+);
+
+# XXX-INGY
+# I(ngy) need to decide if these values should be quoted in
+# YAML::Tiny or not. Probably yes.
+
+# These 3 values have special meaning when unquoted and using the
+# default YAML schema. They need quotes if they are strings.
+my %QUOTE = map { $_ => 1 } qw{
+    null true false
+};
+
+# The commented out form is simpler, but overloaded the Perl regex
+# engine due to recursion and backtracking problems on strings
+# larger than 32,000ish characters. Keep it for reference purposes.
+# qr/\"((?:\\.|[^\"])*)\"/
+my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
+my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
+# unquoted re gets trailing space that needs to be stripped
+my $re_capture_unquoted_key  = qr/([^:]+(?::+\S(?:[^:]*|.*?(?=:)))*)(?=\s*\:(?:\s+|$))/;
+my $re_trailing_comment      = qr/(?:\s+\#.*)?/;
+my $re_key_value_separator   = qr/\s*:(?:\s+(?:\#.*)?|$)/;
+
+
+
+
+
+#####################################################################
+# YAML::Tiny Implementation.
+#
+# These are the private methods that do all the work. They may change
+# at any time.
+
+
+###
+# Loader functions:
+
+# Create an object from a file
+sub _load_file {
+    my $class = ref $_[0] ? ref shift : shift;
+
+    # Check the file
+    my $file = shift or $class->_error( 'You did not specify a file name' );
+    $class->_error( "File '$file' does not exist" )
+        unless -e $file;
+    $class->_error( "'$file' is a directory, not a file" )
+        unless -f _;
+    $class->_error( "Insufficient permissions to read '$file'" )
+        unless -r _;
+
+    # Open unbuffered with strict UTF-8 decoding and no translation layers
+    open( my $fh, "<:unix:encoding(UTF-8)", $file );
+    unless ( $fh ) {
+        $class->_error("Failed to open file '$file': $!");
+    }
+
+    # flock if available (or warn if not possible for OS-specific reasons)
+    if ( _can_flock() ) {
+        flock( $fh, Fcntl::LOCK_SH() )
+            or warn "Couldn't lock '$file' for reading: $!";
+    }
+
+    # slurp the contents
+    my $contents = eval {
+        use warnings FATAL => 'utf8';
+        local $/;
+        <$fh>
+    };
+    if ( my $err = $@ ) {
+        $class->_error("Error reading from file '$file': $err");
+    }
+
+    # close the file (release the lock)
+    unless ( close $fh ) {
+        $class->_error("Failed to close file '$file': $!");
+    }
+
+    $class->_load_string( $contents );
+}
+
+# Create an object from a string
+sub _load_string {
+    my $class  = ref $_[0] ? ref shift : shift;
+    my $self   = bless [], $class;
+    my $string = $_[0];
+    eval {
+        unless ( defined $string ) {
+            die \"Did not provide a string to load";
+        }
+
+        # Check if Perl has it marked as characters, but it's internally
+        # inconsistent.  E.g. maybe latin1 got read on a :utf8 layer
+        if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
+            die \<<'...';
+Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
+Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
+...
+        }
+
+        # Ensure Unicode character semantics, even for 0x80-0xff
+        utf8::upgrade($string);
+
+        # Check for and strip any leading UTF-8 BOM
+        $string =~ s/^\x{FEFF}//;
+
+        # Check for some special cases
+        return $self unless length $string;
+
+        # Split the file into lines
+        my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
+                split /(?:\015{1,2}\012|\015|\012)/, $string;
+
+        # Strip the initial YAML header
+        @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
+
+        # A nibbling parser
+        my $in_document = 0;
+        while ( @lines ) {
+            # Do we have a document header?
+            if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
+                # Handle scalar documents
+                shift @lines;
+                if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
+                    push @$self,
+                        $self->_load_scalar( "$1", [ undef ], \@lines );
+                    next;
+                }
+                $in_document = 1;
+            }
+
+            if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
+                # A naked document
+                push @$self, undef;
+                while ( @lines and $lines[0] !~ /^---/ ) {
+                    shift @lines;
+                }
+                $in_document = 0;
+
+            # XXX The final '-+$' is to look for -- which ends up being an
+            # error later.
+            } elsif ( ! $in_document && @$self ) {
+                # only the first document can be explicit
+                die \"YAML::Tiny failed to classify the line '$lines[0]'";
+            } elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
+                # An array at the root
+                my $document = [ ];
+                push @$self, $document;
+                $self->_load_array( $document, [ 0 ], \@lines );
+
+            } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
+                # A hash at the root
+                my $document = { };
+                push @$self, $document;
+                $self->_load_hash( $document, [ length($1) ], \@lines );
+
+            } else {
+                # Shouldn't get here.  @lines have whitespace-only lines
+                # stripped, and previous match is a line with any
+                # non-whitespace.  So this clause should only be reachable via
+                # a perlbug where \s is not symmetric with \S
+
+                # uncoverable statement
+                die \"YAML::Tiny failed to classify the line '$lines[0]'";
+            }
+        }
+    };
+    my $err = $@;
+    if ( ref $err eq 'SCALAR' ) {
+        $self->_error(${$err});
+    } elsif ( $err ) {
+        $self->_error($err);
+    }
+
+    return $self;
+}
+
+sub _unquote_single {
+    my ($self, $string) = @_;
+    return '' unless length $string;
+    $string =~ s/\'\'/\'/g;
+    return $string;
+}
+
+sub _unquote_double {
+    my ($self, $string) = @_;
+    return '' unless length $string;
+    $string =~ s/\\"/"/g;
+    $string =~
+        s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
+         {(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
+    return $string;
+}
+
+# Load a YAML scalar string to the actual Perl scalar
+sub _load_scalar {
+    my ($self, $string, $indent, $lines) = @_;
+
+    # Trim trailing whitespace
+    $string =~ s/\s*\z//;
+
+    # Explitic null/undef
+    return undef if $string eq '~';
+
+    # Single quote
+    if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
+        return $self->_unquote_single($1);
+    }
+
+    # Double quote.
+    if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
+        return $self->_unquote_double($1);
+    }
+
+    # Special cases
+    if ( $string =~ /^[\'\"!&]/ ) {
+        die \"YAML::Tiny does not support a feature in line '$string'";
+    }
+    return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
+    return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
+
+    # Regular unquoted string
+    if ( $string !~ /^[>|]/ ) {
+        die \"YAML::Tiny found illegal characters in plain scalar: '$string'"
+            if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
+                $string =~ /:(?:\s|$)/;
+        $string =~ s/\s+#.*\z//;
+        return $string;
+    }
+
+    # Error
+    die \"YAML::Tiny failed to find multi-line scalar content" unless @$lines;
+
+    # Check the indent depth
+    $lines->[0]   =~ /^(\s*)/;
+    $indent->[-1] = length("$1");
+    if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
+        die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+    }
+
+    # Pull the lines
+    my @multiline = ();
+    while ( @$lines ) {
+        $lines->[0] =~ /^(\s*)/;
+        last unless length($1) >= $indent->[-1];
+        push @multiline, substr(shift(@$lines), $indent->[-1]);
+    }
+
+    my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
+    my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
+    return join( $j, @multiline ) . $t;
+}
+
+# Load an array
+sub _load_array {
+    my ($self, $array, $indent, $lines) = @_;
+
+    while ( @$lines ) {
+        # Check for a new document
+        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+            while ( @$lines and $lines->[0] !~ /^---/ ) {
+                shift @$lines;
+            }
+            return 1;
+        }
+
+        # Check the indent level
+        $lines->[0] =~ /^(\s*)/;
+        if ( length($1) < $indent->[-1] ) {
+            return 1;
+        } elsif ( length($1) > $indent->[-1] ) {
+            die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+        }
+
+        if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
+            # Inline nested hash
+            my $indent2 = length("$1");
+            $lines->[0] =~ s/-/ /;
+            push @$array, { };
+            $self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
+
+        } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
+            shift @$lines;
+            unless ( @$lines ) {
+                push @$array, undef;
+                return 1;
+            }
+            if ( $lines->[0] =~ /^(\s*)\-/ ) {
+                my $indent2 = length("$1");
+                if ( $indent->[-1] == $indent2 ) {
+                    # Null array entry
+                    push @$array, undef;
+                } else {
+                    # Naked indenter
+                    push @$array, [ ];
+                    $self->_load_array(
+                        $array->[-1], [ @$indent, $indent2 ], $lines
+                    );
+                }
+
+            } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
+                push @$array, { };
+                $self->_load_hash(
+                    $array->[-1], [ @$indent, length("$1") ], $lines
+                );
+
+            } else {
+                die \"YAML::Tiny failed to classify line '$lines->[0]'";
+            }
+
+        } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
+            # Array entry with a value
+            shift @$lines;
+            push @$array, $self->_load_scalar(
+                "$2", [ @$indent, undef ], $lines
+            );
+
+        } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
+            # This is probably a structure like the following...
+            # ---
+            # foo:
+            # - list
+            # bar: value
+            #
+            # ... so lets return and let the hash parser handle it
+            return 1;
+
+        } else {
+            die \"YAML::Tiny failed to classify line '$lines->[0]'";
+        }
+    }
+
+    return 1;
+}
+
+# Load a hash
+sub _load_hash {
+    my ($self, $hash, $indent, $lines) = @_;
+
+    while ( @$lines ) {
+        # Check for a new document
+        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+            while ( @$lines and $lines->[0] !~ /^---/ ) {
+                shift @$lines;
+            }
+            return 1;
+        }
+
+        # Check the indent level
+        $lines->[0] =~ /^(\s*)/;
+        if ( length($1) < $indent->[-1] ) {
+            return 1;
+        } elsif ( length($1) > $indent->[-1] ) {
+            die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+        }
+
+        # Find the key
+        my $key;
+
+        # Quoted keys
+        if ( $lines->[0] =~
+            s/^\s*$re_capture_single_quoted$re_key_value_separator//
+        ) {
+            $key = $self->_unquote_single($1);
+        }
+        elsif ( $lines->[0] =~
+            s/^\s*$re_capture_double_quoted$re_key_value_separator//
+        ) {
+            $key = $self->_unquote_double($1);
+        }
+        elsif ( $lines->[0] =~
+            s/^\s*$re_capture_unquoted_key$re_key_value_separator//
+        ) {
+            $key = $1;
+            $key =~ s/\s+$//;
+        }
+        elsif ( $lines->[0] =~ /^\s*\?/ ) {
+            die \"YAML::Tiny does not support a feature in line '$lines->[0]'";
+        }
+        else {
+            die \"YAML::Tiny failed to classify line '$lines->[0]'";
+        }
+
+        if ( exists $hash->{$key} ) {
+            warn "YAML::Tiny found a duplicate key '$key' in line '$lines->[0]'";
+        }
+
+        # Do we have a value?
+        if ( length $lines->[0] ) {
+            # Yes
+            $hash->{$key} = $self->_load_scalar(
+                shift(@$lines), [ @$indent, undef ], $lines
+            );
+        } else {
+            # An indent
+            shift @$lines;
+            unless ( @$lines ) {
+                $hash->{$key} = undef;
+                return 1;
+            }
+            if ( $lines->[0] =~ /^(\s*)-/ ) {
+                $hash->{$key} = [];
+                $self->_load_array(
+                    $hash->{$key}, [ @$indent, length($1) ], $lines
+                );
+            } elsif ( $lines->[0] =~ /^(\s*)./ ) {
+                my $indent2 = length("$1");
+                if ( $indent->[-1] >= $indent2 ) {
+                    # Null hash entry
+                    $hash->{$key} = undef;
+                } else {
+                    $hash->{$key} = {};
+                    $self->_load_hash(
+                        $hash->{$key}, [ @$indent, length($1) ], $lines
+                    );
+                }
+            }
+        }
+    }
+
+    return 1;
+}
+
+
+###
+# Dumper functions:
+
+# Save an object to a file
+sub _dump_file {
+    my $self = shift;
+
+    require Fcntl;
+
+    # Check the file
+    my $file = shift or $self->_error( 'You did not specify a file name' );
+
+    my $fh;
+    # flock if available (or warn if not possible for OS-specific reasons)
+    if ( _can_flock() ) {
+        # Open without truncation (truncate comes after lock)
+        my $flags = Fcntl::O_WRONLY()|Fcntl::O_CREAT();
+        sysopen( $fh, $file, $flags )
+            or $self->_error("Failed to open file '$file' for writing: $!");
+
+        # Use no translation and strict UTF-8
+        binmode( $fh, ":raw:encoding(UTF-8)");
+
+        flock( $fh, Fcntl::LOCK_EX() )
+            or warn "Couldn't lock '$file' for reading: $!";
+
+        # truncate and spew contents
+        truncate $fh, 0;
+        seek $fh, 0, 0;
+    }
+    else {
+        open $fh, ">:unix:encoding(UTF-8)", $file;
+    }
+
+    # serialize and spew to the handle
+    print {$fh} $self->_dump_string;
+
+    # close the file (release the lock)
+    unless ( close $fh ) {
+        $self->_error("Failed to close file '$file': $!");
+    }
+
+    return 1;
+}
+
+# Save an object to a string
+sub _dump_string {
+    my $self = shift;
+    return '' unless ref $self && @$self;
+
+    # Iterate over the documents
+    my $indent = 0;
+    my @lines  = ();
+
+    eval {
+        foreach my $cursor ( @$self ) {
+            push @lines, '---';
+
+            # An empty document
+            if ( ! defined $cursor ) {
+                # Do nothing
+
+            # A scalar document
+            } elsif ( ! ref $cursor ) {
+                $lines[-1] .= ' ' . $self->_dump_scalar( $cursor );
+
+            # A list at the root
+            } elsif ( ref $cursor eq 'ARRAY' ) {
+                unless ( @$cursor ) {
+                    $lines[-1] .= ' []';
+                    next;
+                }
+                push @lines, $self->_dump_array( $cursor, $indent, {} );
+
+            # A hash at the root
+            } elsif ( ref $cursor eq 'HASH' ) {
+                unless ( %$cursor ) {
+                    $lines[-1] .= ' {}';
+                    next;
+                }
+                push @lines, $self->_dump_hash( $cursor, $indent, {} );
+
+            } else {
+                die \("Cannot serialize " . ref($cursor));
+            }
+        }
+    };
+    if ( ref $@ eq 'SCALAR' ) {
+        $self->_error(${$@});
+    } elsif ( $@ ) {
+        $self->_error($@);
+    }
+
+    join '', map { "$_\n" } @lines;
+}
+
+sub _has_internal_string_value {
+    my $value = shift;
+    my $b_obj = B::svref_2object(\$value);  # for round trip problem
+    return $b_obj->FLAGS & B::SVf_POK();
+}
+
+sub _dump_scalar {
+    my $string = $_[1];
+    my $is_key = $_[2];
+    # Check this before checking length or it winds up looking like a string!
+    my $has_string_flag = _has_internal_string_value($string);
+    return '~'  unless defined $string;
+    return "''" unless length  $string;
+    if (Scalar::Util::looks_like_number($string)) {
+        # keys and values that have been used as strings get quoted
+        if ( $is_key || $has_string_flag ) {
+            return qq['$string'];
+        }
+        else {
+            return $string;
+        }
+    }
+    if ( $string =~ /[\x00-\x09\x0b-\x0d\x0e-\x1f\x7f-\x9f\'\n]/ ) {
+        $string =~ s/\\/\\\\/g;
+        $string =~ s/"/\\"/g;
+        $string =~ s/\n/\\n/g;
+        $string =~ s/[\x85]/\\N/g;
+        $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
+        $string =~ s/([\x7f-\x9f])/'\x' . sprintf("%X",ord($1))/ge;
+        return qq|"$string"|;
+    }
+    if ( $string =~ /(?:^[~!@#%&*|>?:,'"`{}\[\]]|^-+$|\s|:\z)/ or
+        $QUOTE{$string}
+    ) {
+        return "'$string'";
+    }
+    return $string;
+}
+
+sub _dump_array {
+    my ($self, $array, $indent, $seen) = @_;
+    if ( $seen->{refaddr($array)}++ ) {
+        die \"YAML::Tiny does not support circular references";
+    }
+    my @lines  = ();
+    foreach my $el ( @$array ) {
+        my $line = ('  ' x $indent) . '-';
+        my $type = ref $el;
+        if ( ! $type ) {
+            $line .= ' ' . $self->_dump_scalar( $el );
+            push @lines, $line;
+
+        } elsif ( $type eq 'ARRAY' ) {
+            if ( @$el ) {
+                push @lines, $line;
+                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
+            } else {
+                $line .= ' []';
+                push @lines, $line;
+            }
+
+        } elsif ( $type eq 'HASH' ) {
+            if ( keys %$el ) {
+                push @lines, $line;
+                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
+            } else {
+                $line .= ' {}';
+                push @lines, $line;
+            }
+
+        } else {
+            die \"YAML::Tiny does not support $type references";
+        }
+    }
+
+    @lines;
+}
+
+sub _dump_hash {
+    my ($self, $hash, $indent, $seen) = @_;
+    if ( $seen->{refaddr($hash)}++ ) {
+        die \"YAML::Tiny does not support circular references";
+    }
+    my @lines  = ();
+    foreach my $name ( sort keys %$hash ) {
+        my $el   = $hash->{$name};
+        my $line = ('  ' x $indent) . $self->_dump_scalar($name, 1) . ":";
+        my $type = ref $el;
+        if ( ! $type ) {
+            $line .= ' ' . $self->_dump_scalar( $el );
+            push @lines, $line;
+
+        } elsif ( $type eq 'ARRAY' ) {
+            if ( @$el ) {
+                push @lines, $line;
+                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
+            } else {
+                $line .= ' []';
+                push @lines, $line;
+            }
+
+        } elsif ( $type eq 'HASH' ) {
+            if ( keys %$el ) {
+                push @lines, $line;
+                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
+            } else {
+                $line .= ' {}';
+                push @lines, $line;
+            }
+
+        } else {
+            die \"YAML::Tiny does not support $type references";
+        }
+    }
+
+    @lines;
+}
+
+
+
+#####################################################################
+# DEPRECATED API methods:
+
+# Error storage (DEPRECATED as of 1.57)
+our $errstr    = '';
+
+# Set error
+sub _error {
+    require Carp;
+    $errstr = $_[1];
+    $errstr =~ s/ at \S+ line \d+.*//;
+    Carp::croak( $errstr );
+}
+
+# Retrieve error
+my $errstr_warned;
+sub errstr {
+    require Carp;
+    Carp::carp( "YAML::Tiny->errstr and \$YAML::Tiny::errstr is deprecated" )
+        unless $errstr_warned++;
+    $errstr;
+}
+
+
+
+
+#####################################################################
+# Helper functions. Possibly not needed.
+
+
+# Use to detect nv or iv
+use B;
+
+# XXX-INGY Is flock YAML::Tiny's responsibility?
+# Some platforms can't flock :-(
+# XXX-XDG I think it is.  When reading and writing files, we ought
+# to be locking whenever possible.  People (foolishly) use YAML
+# files for things like session storage, which has race issues.
+my $HAS_FLOCK;
+sub _can_flock {
+    if ( defined $HAS_FLOCK ) {
+        return $HAS_FLOCK;
+    }
+    else {
+        require Config;
+        my $c = \%Config::Config;
+        $HAS_FLOCK = grep { $c->{$_} } qw/d_flock d_fcntl_can_lock d_lockf/;
+        require Fcntl if $HAS_FLOCK;
+        return $HAS_FLOCK;
+    }
+}
+
+
+# XXX-INGY Is this core in 5.8.1? Can we remove this?
+# XXX-XDG Scalar::Util 1.18 didn't land until 5.8.8, so we need this
+#####################################################################
+# Use Scalar::Util if possible, otherwise emulate it
+
+use Scalar::Util ();
+BEGIN {
+    local $@;
+    if ( eval { Scalar::Util->VERSION(1.18); } ) {
+        *refaddr = *Scalar::Util::refaddr;
+    }
+    else {
+        eval <<'END_PERL';
+# Scalar::Util failed to load or too old
+sub refaddr {
+    my $pkg = ref($_[0]) or return undef;
+    if ( !! UNIVERSAL::can($_[0], 'can') ) {
+        bless $_[0], 'Scalar::Util::Fake';
+    } else {
+        $pkg = undef;
+    }
+    "$_[0]" =~ /0x(\w+)/;
+    my $i = do { no warnings 'portable'; hex $1 };
+    bless $_[0], $pkg if defined $pkg;
+    $i;
+}
+END_PERL
+    }
+}
+
+delete $YAML::Tiny::{refaddr};
+
+1;
+
+# XXX-INGY Doc notes I'm putting up here. Changing the doc when it's wrong
+# but leaving grey area stuff up here.
+#
+# I would like to change Read/Write to Load/Dump below without
+# changing the actual API names.
+#
+# It might be better to put Load/Dump API in the SYNOPSIS instead of the
+# dubious OO API.
+#
+# null and bool explanations may be outdated.
+
+__END__
+
+#line 1487

commit 22228e33aed89da5f66833edd54259e7d8e87b42
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Jun 12 04:32:13 2021 +0800

    Update copyright year

diff --git a/README b/README
index bb3d475..c2cc754 100644
--- a/README
+++ b/README
@@ -48,7 +48,7 @@ BUGS
         L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-CommentOnCreate>.
 
 LICENSE AND COPYRIGHT
-    This software is Copyright (c) 2014 by Best Practical Solutions
+    This software is Copyright (c) 2014-2021 by Best Practical Solutions
 
     This is free software, licensed under:
 
diff --git a/lib/RT/Extension/CommentOnCreate.pm b/lib/RT/Extension/CommentOnCreate.pm
index 46053fd..45172f7 100644
--- a/lib/RT/Extension/CommentOnCreate.pm
+++ b/lib/RT/Extension/CommentOnCreate.pm
@@ -70,7 +70,7 @@ or via the web at
 
 =head1 LICENSE AND COPYRIGHT
 
-This software is Copyright (c) 2014 by Best Practical Solutions
+This software is Copyright (c) 2014-2021 by Best Practical Solutions
 
 This is free software, licensed under:
 

commit 23746c976f5974242e87d41a439525bbba985ff8
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Jun 12 04:32:42 2021 +0800

    Update default path to "rt5"

diff --git a/README b/README
index c2cc754..9eda33b 100644
--- a/README
+++ b/README
@@ -8,7 +8,7 @@ INSTALLATION
     make install
         May need root permissions
 
-    Edit your /opt/rt4/etc/RT_SiteConfig.pm
+    Edit your /opt/rt5/etc/RT_SiteConfig.pm
         If you are using RT 4.2 or greater, add this line:
 
             Plugin('RT::Extension::CommentOnCreate');
@@ -21,7 +21,7 @@ INSTALLATION
         line.
 
     Clear your mason cache
-            rm -rf /opt/rt4/var/mason_data/obj
+            rm -rf /opt/rt5/var/mason_data/obj
 
     Restart your webserver
 
diff --git a/lib/RT/Extension/CommentOnCreate.pm b/lib/RT/Extension/CommentOnCreate.pm
index 45172f7..5da2a71 100644
--- a/lib/RT/Extension/CommentOnCreate.pm
+++ b/lib/RT/Extension/CommentOnCreate.pm
@@ -23,7 +23,7 @@ RT::Extension::CommentOnCreate - Adds an optional Comment box to Ticket Creation
 
 May need root permissions
 
-=item Edit your F</opt/rt4/etc/RT_SiteConfig.pm>
+=item Edit your F</opt/rt5/etc/RT_SiteConfig.pm>
 
 If you are using RT 4.2 or greater, add this line:
 
@@ -37,7 +37,7 @@ or add C<RT::Extension::CommentOnCreate> to your existing C<@Plugins> line.
 
 =item Clear your mason cache
 
-    rm -rf /opt/rt4/var/mason_data/obj
+    rm -rf /opt/rt5/var/mason_data/obj
 
 =item Restart your webserver
 

commit 06206579fbe153c4422246b67a464c181e311816
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Jun 12 04:58:34 2021 +0800

    Support rt5 themes

diff --git a/html/Callbacks/RT-Extension-CommentOnCreate/Ticket/Create.html/AfterMessageBox b/html/Callbacks/RT-Extension-CommentOnCreate/Ticket/Create.html/AfterMessageBox
index 1e88ec1..a557063 100644
--- a/html/Callbacks/RT-Extension-CommentOnCreate/Ticket/Create.html/AfterMessageBox
+++ b/html/Callbacks/RT-Extension-CommentOnCreate/Ticket/Create.html/AfterMessageBox
@@ -45,9 +45,20 @@
 %# those contributions and any derivatives thereof.
 %# 
 %# END BPS TAGGED BLOCK }}}
+% if ( RT::Handle::cmp_version($RT::VERSION, '5.0.0') >= 0 ) {
+</div>
+<div class="form-row">
+  <div class="label col-auto">
+    <&|/l&>Include an optional Comment below</&>:
+  </div>
+</div>
+<div class="form-group">
+% } else {
 </td></tr>
-<tr><td colspan="6">Include an optional Comment below</td></tr>
+<tr><td colspan="6"><&|/l&>Include an optional Comment below</&>:</td></tr>
 <tr><td colspan="6">
+% }
+
 % if (exists $ARGS{CommentContent}) {
 <& /Elements/MessageBox, Name => 'CommentContent',
                          Default => $ARGS{CommentContent},

commit e9d2db1957db72b1d8eecdb1bcfb876193cbfb83
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Sat Jun 12 05:02:49 2021 +0800

    Prep 1.01 release

diff --git a/Changes b/Changes
index 4559128..23b8712 100644
--- a/Changes
+++ b/Changes
@@ -1,6 +1,12 @@
 Revision history for RT-Extension-CommentOnCreate
 
-0.05 2014-02-06
+1.01 2021-06-11
+  - Add RT 5 support
+
+1.00 2014-12-15
+  - Fix "Use of uninitialized value" warnings
+
+0.06 2014-02-06
   - POD error
 
 0.05 2014-02-06
diff --git a/META.yml b/META.yml
index 1623f3d..04edc2c 100644
--- a/META.yml
+++ b/META.yml
@@ -22,6 +22,6 @@ requires:
   perl: 5.8.3
 resources:
   license: http://opensource.org/licenses/gpl-license.php
-version: '1.00'
+version: '1.01'
 x_module_install_rtx_version: '0.42'
 x_requires_rt: 4.0.7
diff --git a/lib/RT/Extension/CommentOnCreate.pm b/lib/RT/Extension/CommentOnCreate.pm
index 5da2a71..565877c 100644
--- a/lib/RT/Extension/CommentOnCreate.pm
+++ b/lib/RT/Extension/CommentOnCreate.pm
@@ -1,6 +1,6 @@
 package RT::Extension::CommentOnCreate;
 
-our $VERSION = '1.00';
+our $VERSION = '1.01';
 
 use warnings;
 use strict;

-----------------------------------------------------------------------


More information about the Bps-public-commit mailing list