[open-ils-commits] r19338 - in trunk: . Open-ILS/src/perlmods/OpenILS/Utils (dbs)

svn at svn.open-ils.org svn at svn.open-ils.org
Sun Jan 30 00:47:55 EST 2011


Author: dbs
Date: 2011-01-30 00:47:52 -0500 (Sun, 30 Jan 2011)
New Revision: 19338

Added:
   trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in
Removed:
   trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm
Modified:
   trunk/configure.ac
Log:
Replace a hard-coded path in Cronscript.pm with a configure variable

As much as possible, we need to avoid hard-coded paths if we
ever want to be packagable.


Deleted: trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm	2011-01-30 05:22:04 UTC (rev 19337)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm	2011-01-30 05:47:52 UTC (rev 19338)
@@ -1,371 +0,0 @@
-package OpenILS::Utils::Cronscript;
-
-# ---------------------------------------------------------------
-# Copyright (C) 2010 Equinox Software, Inc
-# Author: Joe Atzberger <jatzberger at esilibrary.com>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# ---------------------------------------------------------------
-
-# The purpose of this module is to consolidate the common aspects
-# of various cron tasks that all need the same things:
-#    ~ non-duplicative processing, i.e. lockfiles and lockfile checking
-#    ~ opensrf_core.xml file location 
-#    ~ common options like help and debug
-
-use strict;
-use warnings;
-
-use Getopt::Long qw(:DEFAULT GetOptionsFromArray);
-use OpenSRF::System;
-use OpenSRF::AppSession;
-use OpenSRF::Utils::JSON;
-use OpenSRF::EX qw(:try);
-use OpenILS::Utils::Fieldmapper;
-use OpenILS::Utils::Lockfile;
-use OpenILS::Utils::CStoreEditor q/:funcs/;
-
-use File::Basename qw/fileparse/;
-
-use Data::Dumper;
-use Carp;
-
-our @extra_opts = (     # additional keys are stored here
-    # 'addlopt'
-);
-
-our $debug = 0;
-
-sub _default_self {
-    return {
-    #   opts       => {},
-    #   opts_clean => {},
-    #   default_opts_clean => {},
-        default_opts       => {
-            'lock-file=s'   => OpenILS::Utils::Lockfile::default_filename,
-            'osrf-config=s' => '/openils/conf/opensrf_core.xml',   # TODO: packaging needs a make variable like @@EG_CONF_DIR@@
-            'debug'         => 0,
-            'verbose+'      => 0,
-            'help'          => 0,
-          # 'internal_var'  => 'XYZ',
-        },
-    #   lockfile => undef,
-    #   session => undef,
-    #   bootstrapped => 0,
-    #   got_options => 0,
-        auto_get_options_4_bootstrap => 1,
-    };
-}
-
-sub is_clean {
-    my $key = shift   or  return 1;
-    $key =~ /[=:].*$/ and return 0;
-    $key =~ /[+!]$/   and return 0;
-    return 1;
-}
-
-sub clean {
-    my $key = shift or return;
-    $key =~ s/[=:].*$//;
-    $key =~ s/[+!]$//;
-    return $key;
-}
-
-sub fuzzykey {                      # when you know the hash you want from, but not the exact key
-    my $self = shift or return;
-    my $key  = shift or return;
-    my $target = @_ ? shift : 'opts_clean';
-    foreach (map {clean($_)} keys %{$self->{default_opts}}) {  # TODO: cache
-        $key eq $_ and return $self->{$target}->{$_};
-    }
-}
-
-# MyGetOptions
-# A wrapper around GetOptions
-# {opts} does two things for GetOptions (see Getopt::Long)
-#  (1) maps command-line options to the *other* variables where values are stored (in opts_clean)
-#  (2) provides hashspace for the rest of the arbitrary options from the command-line
-#
-# TODO: allow more options to be passed here, maybe mimic Getopt::Long::GetOptions style
-#
-# If an arrayref argument is passed, then @ARGV will NOT be touched.
-# Instead, the array will be passed to GetOptionsFromArray.
-#
-
-sub MyGetOptions {
-    my $self = shift;
-    my $arrayref = @_ ? shift : undef;
-    if ($arrayref and ref($arrayref) ne 'ARRAY') {
-        carp "MyGetOptions argument is not an array ref.  Expect GetOptionsFromArray to explode";
-    }
-    $self->{got_options} and carp "MyGetOptions called after options were already retrieved previously";
-    my @keys = sort {is_clean($b) <=> is_clean($a)} keys %{$self->{default_opts}};
-    $debug and print "KEYS: ", join(", ", @keys), "\n";
-    foreach (@keys) {
-        my $clean = clean($_);
-        my $place = $self->{default_opts_clean}->{$clean};
-        $self->{opts_clean}->{$clean} = $place;  # prepopulate default
-        # $self->{opts}->{$_} = $self->{opts_clean}->{$clean};                 # pointer for GetOptions
-        $self->{opts}->{$_} = sub {
-            my $opt = shift;
-            my $val = shift;
-            ref ( $self->{opts_clean}->{$opt} ) and ref($self->{opts_clean}->{$opt}) eq 'SCALAR'
-            and ${$self->{opts_clean}->{$opt}} = $val;  # set the referent's value
-            $self->{opts_clean}->{$opt} = $val;     # burn the map, stick the value there
-        };                 # pointer for GetOptions
-    }
-    $arrayref  ? GetOptionsFromArray($arrayref, $self->{opts}, @keys)
-               : GetOptions(                    $self->{opts}, @keys) ;
-   
-    foreach (@keys) {
-        delete $self->{opts}->{$_};     # now remove the mappings from (1) so we just have (2)
-    }
-    $self->clean_mirror('opts');        # populate clean_opts w/ cleaned versions of (2), plus everything else
-
-    print $self->help() and exit if $self->{opts_clean}->{help};
-    $self->new_lockfile();
-    $self->{got_options}++;
-    return wantarray ? %{$self->{opts_clean}} : $self->{opts_clean};
-}
-
-sub new_lockfile {
-    my $self = shift;
-    $debug and $OpenILS::Utils::Lockfile::debug = $debug;
-    unless ($self->{opts_clean}->{nolockfile} || $self->{default_opts_clean}->{nolockfile}) {
-        $self->{lockfile_obj} = OpenILS::Utils::Lockfile->new($self->first_defined('lock-file'));
-        $self->{lockfile}     = $self->{lockfile_obj}->filename;
-    }
-}
-
-sub first_defined {
-    my $self = shift;
-    my $key  = shift or return;
-    foreach (qw(opts_clean opts default_opts_clean default_opts)) {
-        defined $self->{$_}->{$key} and return $self->{$_}->{$key};
-    }
-    return;
-}
-
-sub clean_mirror {
-    my $self  = shift;
-    my $dirty = @_ ? shift : 'default_opts';
-    foreach (keys %{$self->{$dirty}}) {
-        defined $self->{$dirty}->{$_} or next;
-        $self->{$dirty . '_clean'}->{clean($_)} = $self->{$dirty}->{$_};
-    }
-}
-
-sub new {
-    my $class = shift;
-    my $self  = _default_self;
-    bless ($self, $class);
-    $self->init(@_);
-    $debug and print "new ",  __PACKAGE__, " obj: ", Dumper($self);
-    return $self;
-}
-
-sub add_and_purge {
-    my $self = shift;
-    my $key  = shift;
-    my $val  = shift;
-    my $clean = clean($key);
-    my @others = grep {/$clean/ and $_ ne $key} keys %{$self->{default_opts}};
-    unless (@others) {
-        $debug and print "unique key $key => $val\n";
-        $self->{default_opts}->{$key} = $val;   # no purge, just add
-        return;
-    }
-    foreach (@others) {
-        $debug and print "variant of $key => $_\n";
-        if ($key ne $clean) {    # if it is a dirtier key, delete the clean one
-            delete $self->{default_opts}->{$_};
-            $self->{default_opts}->{$key} = $val;
-        } else {                 # else update the dirty one
-            $self->{default_opts}->{$_} = $val;
-        }
-    }
-}
-
-sub init {      # not INIT
-    my $self = shift;
-    my $opts  = @_ ? shift : {};    # user can specify more default options to constructor
-# TODO: check $opts is hashref; then check verbose/debug first.  maybe check negations e.g. "no-verbose" ?
-    @extra_opts = keys %$opts;
-    foreach (@extra_opts) {        # add any other keys w/ default values
-        $debug and print "init() adding option $_, default value: $opts->{$_}\n";
-        $self->add_and_purge($_, $opts->{$_});
-    }
-    $self->clean_mirror;
-    return $self;
-}
-
-sub usage {
-    # my $self = shift;
-    return "\nUSAGE: $0 [OPTIONS]";
-}
-
-sub options_help {
-    my $self = shift;
-    my $chunk = @_ ? shift : '';
-    return <<HELP
-
-COMMON OPTIONS:
-    --osrf-config </path/to/config_file>  Default: $self->{default_opts_clean}->{'osrf-config'}
-                 Specify OpenSRF core config file.
-
-    --lock-file </path/to/file_name>      Default: $self->{default_opts_clean}->{'lock-file'}
-                 Specify lock file.     
-
-HELP
-    . $chunk . <<HELP;
-    --debug      Print server responses to STDOUT for debugging
-    --verbose    Set verbosity
-    --help       Show this help message
-HELP
-}
-
-sub help {
-    my $self = shift;
-    return $self->usage() . "\n" . $self->options_help(@_) . $self->example();
-}
-
-sub example {
-    return "\n\nEXAMPLES:\n\n    $0 --osrf-config /my/other/opensrf_core.xml\n";
-}
-
-# the proper order is: MyGetOptions, bootstrap, session.
-# But the latter subs will check to see if they need to call the preceeding one(s).  
-
-sub session {
-    my $self = shift or return;
-    $self->{bootstrapped} or $self->bootstrap();
-    @_ or croak "session() called without required argument (app_name, e.g. 'open-ils.acq')";
-    return ($self->{session} ||= OpenSRF::AppSession->create(@_));
-}
-
-sub bootstrap {
-    my $self = shift or return;
-    if ($self->{auto_get_options_4_bootstrap} and not $self->{got_options}) {
-        $debug and print "Automatically calling MyGetOptions before bootstrap\n";
-        $self->MyGetOptions();
-    }
-    try {
-        $debug and print "bootstrap lock-file  : ", $self->first_defined('lock-file'), "\n";
-        $debug and print "bootstrap osrf-config: ", $self->first_defined('osrf-config'), "\n";
-        OpenSRF::System->bootstrap_client(config_file => $self->first_defined('osrf-config'));
-        Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
-        $self->{bootstrapped} = 1;
-    } otherwise {
-        $self->{bootstrapped} = 0;
-        warn shift;
-    };
-}
-
-sub editor_init {
-    my $self = shift or return;
-    OpenILS::Utils::CStoreEditor::init();   # no return value to check
-    $self->{editor_inited} = 1;
-}
-
-sub editor {
-    my $self = shift or return;
-    $self->{bootstrapped}  or $self->bootstrap();
-    $self->{editor_inited} or $self->editor_init();
-    return new_editor(@_);
-}
-
-1;
-__END__
-
-=pod
-
-=head1 NAME
-
-OpenILS::Utils::Cronscript - Consolidated options handling for any script (not just cron, really)
-
-=head1 SYNOPSIS
-
-    use OpenILS::Utils::Cronscript;
-
-    my %defaults = (
-        'min=i'      => 0,          # keys are Getopt::Long style options
-        'max=i'      => 999,        # values are default values
-        'user=s'     => 'admin',
-        'password=s' => '',
-        'nolockfile' => 1,
-    };
-
-    my $core = OpenILS::Utils::Cronscript->new(\%defaults);
-    my $opts = $core->MyGetOptions();   # options now in, e.g.: $opts->{max}
-    $core->bootstrap;
-
-Or if you don't need any additional options and just want to get a session going:
-    
-    use OpenILS::Utils::Cronscript;
-    my $session = OpenILS::Utils::Cronscript->new()->session('open-ils.acq');
-
-=head1 DESCRIPTION
-
-There are a few main problems when writing a new script for Evergreen. 
-
-=head2 Initialization
-
-The runtime 
-environment for the application requires a lot of initialization, but during normal operation it
-has already occured (when Evergreen was started).  So most of the EG code never has to deal with 
-this problem, but standalone scripts do.  The timing and sequence of requisite events is important and not obvious.
-
-=head2 Common Options, Consistent Options
-
-We need several common options for each script that accesses the database or
-uses EG data objects and methods.  Logically, these options often deal with initialization.  They
-should take the B<exact> same form(s) for each script and should not be 
-dependent on the local author to copy and paste them from some reference source.  We really don't want to encourage (let alone force)
-admins to use C<--config>, C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in different scripts, with different
-default handling, help descriptions and error messages (or lack thereof).
-
-This suggests broader problem of UI consistency and uniformity, also partially addressed by this module.
-
-=head2 Lockfiles
-
-A lockfile is necessary for a script that wants to prevent possible simultaneous execution.  For example, consider a script 
-that is scheduled to run frequently, but that experiences occasional high load: you wouldn't want crontab to start running
-it again if the first instance had not yet finished.  
-
-But the code for creating, writing to, checking for, reading and cleaning up a lockfile for the script bloats what might otherwise be a terse 
-method call.  Conscript handles lockfile generation and removal automatically.
-
-=head1 OPTIONS
-
-The common options (and default values) are:
-
-    'lock-file=s'   => OpenILS::Utils::Lockfile::default_filename,
-    'osrf-config=s' => '/openils/conf/opensrf_core.xml',
-    'debug'         => 0,
-    'verbose+'      => 0,
-    'help'          => 0,
-
-=head1 TODO 
-
-More docs here.
-
-=head1 SEE ALSO
-
-    Getopt::Long
-    OpenILS::Utils::Lockfile
-    oils_header.pl
-
-=head1 AUTHOR
-
-Joe Atzberger <jatzberger at esilibrary.com>
-
-=cut
-

Copied: trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in (from rev 19331, trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm)
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in	                        (rev 0)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in	2011-01-30 05:47:52 UTC (rev 19338)
@@ -0,0 +1,371 @@
+package OpenILS::Utils::Cronscript;
+
+# ---------------------------------------------------------------
+# Copyright (C) 2010 Equinox Software, Inc
+# Author: Joe Atzberger <jatzberger at esilibrary.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# ---------------------------------------------------------------
+
+# The purpose of this module is to consolidate the common aspects
+# of various cron tasks that all need the same things:
+#    ~ non-duplicative processing, i.e. lockfiles and lockfile checking
+#    ~ opensrf_core.xml file location 
+#    ~ common options like help and debug
+
+use strict;
+use warnings;
+
+use Getopt::Long qw(:DEFAULT GetOptionsFromArray);
+use OpenSRF::System;
+use OpenSRF::AppSession;
+use OpenSRF::Utils::JSON;
+use OpenSRF::EX qw(:try);
+use OpenILS::Utils::Fieldmapper;
+use OpenILS::Utils::Lockfile;
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+
+use File::Basename qw/fileparse/;
+
+use Data::Dumper;
+use Carp;
+
+our @extra_opts = (     # additional keys are stored here
+    # 'addlopt'
+);
+
+our $debug = 0;
+
+sub _default_self {
+    return {
+    #   opts       => {},
+    #   opts_clean => {},
+    #   default_opts_clean => {},
+        default_opts       => {
+            'lock-file=s'   => OpenILS::Utils::Lockfile::default_filename,
+            'osrf-config=s' => '@sysconfdir@/opensrf_core.xml',
+            'debug'         => 0,
+            'verbose+'      => 0,
+            'help'          => 0,
+          # 'internal_var'  => 'XYZ',
+        },
+    #   lockfile => undef,
+    #   session => undef,
+    #   bootstrapped => 0,
+    #   got_options => 0,
+        auto_get_options_4_bootstrap => 1,
+    };
+}
+
+sub is_clean {
+    my $key = shift   or  return 1;
+    $key =~ /[=:].*$/ and return 0;
+    $key =~ /[+!]$/   and return 0;
+    return 1;
+}
+
+sub clean {
+    my $key = shift or return;
+    $key =~ s/[=:].*$//;
+    $key =~ s/[+!]$//;
+    return $key;
+}
+
+sub fuzzykey {                      # when you know the hash you want from, but not the exact key
+    my $self = shift or return;
+    my $key  = shift or return;
+    my $target = @_ ? shift : 'opts_clean';
+    foreach (map {clean($_)} keys %{$self->{default_opts}}) {  # TODO: cache
+        $key eq $_ and return $self->{$target}->{$_};
+    }
+}
+
+# MyGetOptions
+# A wrapper around GetOptions
+# {opts} does two things for GetOptions (see Getopt::Long)
+#  (1) maps command-line options to the *other* variables where values are stored (in opts_clean)
+#  (2) provides hashspace for the rest of the arbitrary options from the command-line
+#
+# TODO: allow more options to be passed here, maybe mimic Getopt::Long::GetOptions style
+#
+# If an arrayref argument is passed, then @ARGV will NOT be touched.
+# Instead, the array will be passed to GetOptionsFromArray.
+#
+
+sub MyGetOptions {
+    my $self = shift;
+    my $arrayref = @_ ? shift : undef;
+    if ($arrayref and ref($arrayref) ne 'ARRAY') {
+        carp "MyGetOptions argument is not an array ref.  Expect GetOptionsFromArray to explode";
+    }
+    $self->{got_options} and carp "MyGetOptions called after options were already retrieved previously";
+    my @keys = sort {is_clean($b) <=> is_clean($a)} keys %{$self->{default_opts}};
+    $debug and print "KEYS: ", join(", ", @keys), "\n";
+    foreach (@keys) {
+        my $clean = clean($_);
+        my $place = $self->{default_opts_clean}->{$clean};
+        $self->{opts_clean}->{$clean} = $place;  # prepopulate default
+        # $self->{opts}->{$_} = $self->{opts_clean}->{$clean};                 # pointer for GetOptions
+        $self->{opts}->{$_} = sub {
+            my $opt = shift;
+            my $val = shift;
+            ref ( $self->{opts_clean}->{$opt} ) and ref($self->{opts_clean}->{$opt}) eq 'SCALAR'
+            and ${$self->{opts_clean}->{$opt}} = $val;  # set the referent's value
+            $self->{opts_clean}->{$opt} = $val;     # burn the map, stick the value there
+        };                 # pointer for GetOptions
+    }
+    $arrayref  ? GetOptionsFromArray($arrayref, $self->{opts}, @keys)
+               : GetOptions(                    $self->{opts}, @keys) ;
+   
+    foreach (@keys) {
+        delete $self->{opts}->{$_};     # now remove the mappings from (1) so we just have (2)
+    }
+    $self->clean_mirror('opts');        # populate clean_opts w/ cleaned versions of (2), plus everything else
+
+    print $self->help() and exit if $self->{opts_clean}->{help};
+    $self->new_lockfile();
+    $self->{got_options}++;
+    return wantarray ? %{$self->{opts_clean}} : $self->{opts_clean};
+}
+
+sub new_lockfile {
+    my $self = shift;
+    $debug and $OpenILS::Utils::Lockfile::debug = $debug;
+    unless ($self->{opts_clean}->{nolockfile} || $self->{default_opts_clean}->{nolockfile}) {
+        $self->{lockfile_obj} = OpenILS::Utils::Lockfile->new($self->first_defined('lock-file'));
+        $self->{lockfile}     = $self->{lockfile_obj}->filename;
+    }
+}
+
+sub first_defined {
+    my $self = shift;
+    my $key  = shift or return;
+    foreach (qw(opts_clean opts default_opts_clean default_opts)) {
+        defined $self->{$_}->{$key} and return $self->{$_}->{$key};
+    }
+    return;
+}
+
+sub clean_mirror {
+    my $self  = shift;
+    my $dirty = @_ ? shift : 'default_opts';
+    foreach (keys %{$self->{$dirty}}) {
+        defined $self->{$dirty}->{$_} or next;
+        $self->{$dirty . '_clean'}->{clean($_)} = $self->{$dirty}->{$_};
+    }
+}
+
+sub new {
+    my $class = shift;
+    my $self  = _default_self;
+    bless ($self, $class);
+    $self->init(@_);
+    $debug and print "new ",  __PACKAGE__, " obj: ", Dumper($self);
+    return $self;
+}
+
+sub add_and_purge {
+    my $self = shift;
+    my $key  = shift;
+    my $val  = shift;
+    my $clean = clean($key);
+    my @others = grep {/$clean/ and $_ ne $key} keys %{$self->{default_opts}};
+    unless (@others) {
+        $debug and print "unique key $key => $val\n";
+        $self->{default_opts}->{$key} = $val;   # no purge, just add
+        return;
+    }
+    foreach (@others) {
+        $debug and print "variant of $key => $_\n";
+        if ($key ne $clean) {    # if it is a dirtier key, delete the clean one
+            delete $self->{default_opts}->{$_};
+            $self->{default_opts}->{$key} = $val;
+        } else {                 # else update the dirty one
+            $self->{default_opts}->{$_} = $val;
+        }
+    }
+}
+
+sub init {      # not INIT
+    my $self = shift;
+    my $opts  = @_ ? shift : {};    # user can specify more default options to constructor
+# TODO: check $opts is hashref; then check verbose/debug first.  maybe check negations e.g. "no-verbose" ?
+    @extra_opts = keys %$opts;
+    foreach (@extra_opts) {        # add any other keys w/ default values
+        $debug and print "init() adding option $_, default value: $opts->{$_}\n";
+        $self->add_and_purge($_, $opts->{$_});
+    }
+    $self->clean_mirror;
+    return $self;
+}
+
+sub usage {
+    # my $self = shift;
+    return "\nUSAGE: $0 [OPTIONS]";
+}
+
+sub options_help {
+    my $self = shift;
+    my $chunk = @_ ? shift : '';
+    return <<HELP
+
+COMMON OPTIONS:
+    --osrf-config </path/to/config_file>  Default: $self->{default_opts_clean}->{'osrf-config'}
+                 Specify OpenSRF core config file.
+
+    --lock-file </path/to/file_name>      Default: $self->{default_opts_clean}->{'lock-file'}
+                 Specify lock file.     
+
+HELP
+    . $chunk . <<HELP;
+    --debug      Print server responses to STDOUT for debugging
+    --verbose    Set verbosity
+    --help       Show this help message
+HELP
+}
+
+sub help {
+    my $self = shift;
+    return $self->usage() . "\n" . $self->options_help(@_) . $self->example();
+}
+
+sub example {
+    return "\n\nEXAMPLES:\n\n    $0 --osrf-config /my/other/opensrf_core.xml\n";
+}
+
+# the proper order is: MyGetOptions, bootstrap, session.
+# But the latter subs will check to see if they need to call the preceeding one(s).  
+
+sub session {
+    my $self = shift or return;
+    $self->{bootstrapped} or $self->bootstrap();
+    @_ or croak "session() called without required argument (app_name, e.g. 'open-ils.acq')";
+    return ($self->{session} ||= OpenSRF::AppSession->create(@_));
+}
+
+sub bootstrap {
+    my $self = shift or return;
+    if ($self->{auto_get_options_4_bootstrap} and not $self->{got_options}) {
+        $debug and print "Automatically calling MyGetOptions before bootstrap\n";
+        $self->MyGetOptions();
+    }
+    try {
+        $debug and print "bootstrap lock-file  : ", $self->first_defined('lock-file'), "\n";
+        $debug and print "bootstrap osrf-config: ", $self->first_defined('osrf-config'), "\n";
+        OpenSRF::System->bootstrap_client(config_file => $self->first_defined('osrf-config'));
+        Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
+        $self->{bootstrapped} = 1;
+    } otherwise {
+        $self->{bootstrapped} = 0;
+        warn shift;
+    };
+}
+
+sub editor_init {
+    my $self = shift or return;
+    OpenILS::Utils::CStoreEditor::init();   # no return value to check
+    $self->{editor_inited} = 1;
+}
+
+sub editor {
+    my $self = shift or return;
+    $self->{bootstrapped}  or $self->bootstrap();
+    $self->{editor_inited} or $self->editor_init();
+    return new_editor(@_);
+}
+
+1;
+__END__
+
+=pod
+
+=head1 NAME
+
+OpenILS::Utils::Cronscript - Consolidated options handling for any script (not just cron, really)
+
+=head1 SYNOPSIS
+
+    use OpenILS::Utils::Cronscript;
+
+    my %defaults = (
+        'min=i'      => 0,          # keys are Getopt::Long style options
+        'max=i'      => 999,        # values are default values
+        'user=s'     => 'admin',
+        'password=s' => '',
+        'nolockfile' => 1,
+    };
+
+    my $core = OpenILS::Utils::Cronscript->new(\%defaults);
+    my $opts = $core->MyGetOptions();   # options now in, e.g.: $opts->{max}
+    $core->bootstrap;
+
+Or if you don't need any additional options and just want to get a session going:
+    
+    use OpenILS::Utils::Cronscript;
+    my $session = OpenILS::Utils::Cronscript->new()->session('open-ils.acq');
+
+=head1 DESCRIPTION
+
+There are a few main problems when writing a new script for Evergreen. 
+
+=head2 Initialization
+
+The runtime 
+environment for the application requires a lot of initialization, but during normal operation it
+has already occured (when Evergreen was started).  So most of the EG code never has to deal with 
+this problem, but standalone scripts do.  The timing and sequence of requisite events is important and not obvious.
+
+=head2 Common Options, Consistent Options
+
+We need several common options for each script that accesses the database or
+uses EG data objects and methods.  Logically, these options often deal with initialization.  They
+should take the B<exact> same form(s) for each script and should not be 
+dependent on the local author to copy and paste them from some reference source.  We really don't want to encourage (let alone force)
+admins to use C<--config>, C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in different scripts, with different
+default handling, help descriptions and error messages (or lack thereof).
+
+This suggests broader problem of UI consistency and uniformity, also partially addressed by this module.
+
+=head2 Lockfiles
+
+A lockfile is necessary for a script that wants to prevent possible simultaneous execution.  For example, consider a script 
+that is scheduled to run frequently, but that experiences occasional high load: you wouldn't want crontab to start running
+it again if the first instance had not yet finished.  
+
+But the code for creating, writing to, checking for, reading and cleaning up a lockfile for the script bloats what might otherwise be a terse 
+method call.  Conscript handles lockfile generation and removal automatically.
+
+=head1 OPTIONS
+
+The common options (and default values) are:
+
+    'lock-file=s'   => OpenILS::Utils::Lockfile::default_filename,
+    'osrf-config=s' => '/openils/conf/opensrf_core.xml',
+    'debug'         => 0,
+    'verbose+'      => 0,
+    'help'          => 0,
+
+=head1 TODO 
+
+More docs here.
+
+=head1 SEE ALSO
+
+    Getopt::Long
+    OpenILS::Utils::Lockfile
+    oils_header.pl
+
+=head1 AUTHOR
+
+Joe Atzberger <jatzberger at esilibrary.com>
+
+=cut
+

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2011-01-30 05:22:04 UTC (rev 19337)
+++ trunk/configure.ac	2011-01-30 05:47:52 UTC (rev 19338)
@@ -374,7 +374,8 @@
 		 Open-ILS/updates/Makefile
 		 Open-ILS/xul/staff_client/Makefile
 		 Open-ILS/src/extras/eg_config
-		 Open-ILS/src/extras/fast-extract],
+		 Open-ILS/src/extras/fast-extract
+         Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm],
 		[
 			if test -e "./Open-ILS/src/extras/eg_config"; then chmod 755 Open-ILS/src/extras/eg_config; fi;
 			if test -e "./Open-ILS/src/extras/fast-extract"; then chmod 755 Open-ILS/src/extras/fast-extract; fi;



More information about the open-ils-commits mailing list