#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
package RT;
+use Encode ();
use File::Spec ();
use Cwd ();
=head1 SYNOPSIS
-A fully featured request tracker package
+A fully featured request tracker package.
+
+This documentation describes the point-of-entry for RT's Perl API. To learn
+more about what RT is and what it can do for you, visit
+L<https://bestpractical.com/rt>.
=head1 DESCRIPTION
=head2 INITIALIZATION
+If you're using RT's Perl libraries, you need to initialize RT before using any
+of the modules.
+
+You have the option of handling the timing of config loading and the actual
+init sequence yourself with:
+
+ use RT;
+ BEGIN {
+ RT->LoadConfig;
+ RT->Init;
+ }
+
+or you can let RT do it all:
+
+ use RT -init;
+
+This second method is particular useful when writing one-liners to interact with RT:
+
+ perl -MRT=-init -e '...'
+
+The first method is necessary if you need to delay or conditionalize
+initialization or if you want to fiddle with C<< RT->Config >> between loading
+the config files and initializing the RT environment.
+
+=cut
+
+{
+ my $DID_IMPORT_INIT;
+ sub import {
+ my $class = shift;
+ my $action = shift || '';
+
+ if ($action eq "-init" and not $DID_IMPORT_INIT) {
+ $class->LoadConfig;
+ $class->Init;
+ $DID_IMPORT_INIT = 1;
+ }
+ }
+}
+
=head2 LoadConfig
Load RT's config file. First, the site configuration file
=cut
sub Init {
-
- my @arg = @_;
+ shift if @_%2; # code is inconsistent about calling as method
+ my %args = (@_);
CheckPerlRequirements();
#Get a database connection
ConnectToDatabase();
InitSystemObjects();
- InitClasses();
- InitLogging(@arg);
+ InitClasses(%args);
+ InitLogging(%args);
InitPlugins();
RT::I18N->Init;
RT->Config->PostLoadCheck;
$frame++ while caller($frame) && caller($frame) =~ /^Log::/;
my ($package, $filename, $line) = caller($frame);
+ # Encode to bytes, so we don't send wide characters
+ $p{message} = Encode::encode("UTF-8", $p{message});
+
$p{'message'} =~ s/(?:\r*\n)+$//;
- return "[". gmtime(time) ."] [". $p{'level'} ."]: "
+ return "[$$] [". gmtime(time) ."] [". $p{'level'} ."]: "
. $p{'message'} ." ($filename:$line)\n";
};
$frame++ while caller($frame) && caller($frame) =~ /^Log::/;
my ($package, $filename, $line) = caller($frame);
- # syswrite() cannot take utf8; turn it off here.
- Encode::_utf8_off($p{message});
+ # Encode to bytes, so we don't send wide characters
+ $p{message} = Encode::encode("UTF-8", $p{message});
$p{message} =~ s/(?:\r*\n)+$//;
if ($p{level} eq 'debug') {
- return "$p{message}\n";
+ return "[$$] $p{message} ($filename:$line)\n";
} else {
- return "$p{message} ($filename:$line)\n";
+ return "[$$] $p{message}\n";
}
};
InitSignalHandlers(%arg);
}
+{ # Work around bug in Log::Dispatch < 2.30, wherein the short forms
+ # of ->warn, ->err, and ->crit do not usefully propagate out, unlike
+ # ->warning, ->error, and ->critical
+ package Log::Dispatch;
+ no warnings 'redefine';
+ sub warn { shift->warning(@_) }
+ sub err { shift->error(@_) }
+ sub crit { shift->critical(@_) }
+}
+
sub InitSignalHandlers {
my %arg = @_;
## mechanism (see above).
$SIG{__WARN__} = sub {
- # The 'wide character' warnings has to be silenced for now, at least
- # until HTML::Mason offers a sane way to process both raw output and
- # unicode strings.
# use 'goto &foo' syntax to hide ANON sub from stack
- if( index($_[0], 'Wide character in ') != 0 ) {
- unshift @_, $RT::Logger, qw(level warning message);
- goto &Log::Dispatch::log;
- }
+ unshift @_, $RT::Logger, qw(level warning message);
+ goto &Log::Dispatch::log;
};
#When we call die, trap it and log->crit with the value of the die.
my @tmp_inc;
my $added;
for (@INC) {
- if ( Cwd::realpath($_) eq $RT::LocalLibPath) {
+ my $realpath = Cwd::realpath($_);
+ next unless defined $realpath;
+ if ( $realpath eq $RT::LocalLibPath) {
push @tmp_inc, $_, @lib_dirs;
$added = 1;
} else {