Merge branch 'master' of https://github.com/jgoodman/Freeside
[freeside.git] / rt / lib / RT.pm
index ec2e6cc..0f0c79a 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -83,12 +83,56 @@ RT - Request Tracker
 
 =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
@@ -137,8 +181,8 @@ up logging|/InitLogging>, and L<loads plugins|/InitPlugins>.
 =cut
 
 sub Init {
-
-    my @arg = @_;
+    shift if @_%2; # code is inconsistent about calling as method
+    my %args = (@_);
 
     CheckPerlRequirements();
 
@@ -147,8 +191,8 @@ sub Init {
     #Get a database connection
     ConnectToDatabase();
     InitSystemObjects();
-    InitClasses();
-    InitLogging(@arg);
+    InitClasses(%args);
+    InitLogging(%args);
     InitPlugins();
     RT::I18N->Init;
     RT->Config->PostLoadCheck;
@@ -220,7 +264,7 @@ sub InitLogging {
             my ($package, $filename, $line) = caller($frame);
 
             $p{'message'} =~ s/(?:\r*\n)+$//;
-            return "[". gmtime(time) ."] [". $p{'level'} ."]: "
+            return "[$$] [". gmtime(time) ."] [". $p{'level'} ."]: "
                 . $p{'message'} ." ($filename:$line)\n";
         };
 
@@ -239,9 +283,9 @@ sub InitLogging {
 
             $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";
             }
         };
 
@@ -316,9 +360,20 @@ sub InitLogging {
     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 = @_;
+    return if $arg{'NoSignalHandlers'};
 
 # Signal handlers
 ## This is the default handling of warnings and die'ings in the code
@@ -326,32 +381,33 @@ sub InitSignalHandlers {
 ## Mason).  It will log all problems through the standard logging
 ## mechanism (see above).
 
-    unless ( $arg{'NoSignalHandlers'} ) {
-
-        $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;
-            }
-        };
-
-        #When we call die, trap it and log->crit with the value of the die.
-
-        $SIG{__DIE__}  = sub {
-            # if we are not in eval and perl is not parsing code
-            # then rollback transactions and log RT error
-            unless ($^S || !defined $^S ) {
-                $RT::Handle->Rollback(1) if $RT::Handle;
-                $RT::Logger->crit("$_[0]") if $RT::Logger;
-            }
-            die $_[0];
-        };
-
-    }
+    $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;
+        }
+        # Return value is used only by RT::Test to filter warnings from
+        # reaching the Test::NoWarnings catcher.  If Log::Dispatch::log() ever
+        # starts returning 'IGNORE', we'll need to switch to something more
+        # clever.  I don't expect that to happen.
+        return 'IGNORE';
+    };
+
+#When we call die, trap it and log->crit with the value of the die.
+
+    $SIG{__DIE__}  = sub {
+        # if we are not in eval and perl is not parsing code
+        # then rollback transactions and log RT error
+        unless ($^S || !defined $^S ) {
+            $RT::Handle->Rollback(1) if $RT::Handle;
+            $RT::Logger->crit("$_[0]") if $RT::Logger;
+        }
+        die $_[0];
+    };
 }
 
 
@@ -425,6 +481,7 @@ sub InitClasses {
     require RT::Approval;
     require RT::Lifecycle;
     require RT::Link;
+    require RT::Links;
     require RT::Article;
     require RT::Articles;
     require RT::Class;
@@ -688,11 +745,21 @@ sub InitPlugins {
 sub InstallMode {
     my $self = shift;
     if (@_) {
-         $_INSTALL_MODE = shift;
-         if($_INSTALL_MODE) {
-             require RT::CurrentUser;
-            $SystemUser = RT::CurrentUser->new();
-         }
+        my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity;
+        if ($_[0] and $integrity) {
+            # Trying to turn install mode on but we have a good DB!
+            require Carp;
+            $RT::Logger->error(
+                Carp::longmess("Something tried to turn on InstallMode but we have DB integrity!")
+            );
+        }
+        else {
+            $_INSTALL_MODE = shift;
+            if($_INSTALL_MODE) {
+                require RT::CurrentUser;
+               $SystemUser = RT::CurrentUser->new();
+            }
+        }
     }
     return $_INSTALL_MODE;
 }
@@ -745,7 +812,7 @@ sub CanonicalizeGeneratedPaths {
 =head2 AddJavaScript
 
 helper method to add js files to C<JSFiles> config.
-to add extra css files, you can add the following line
+to add extra js files, you can add the following line
 in the plugin's main file:
 
     RT->AddJavaScript( 'foo.js', 'bar.js' );