From: dbs Date: Sun, 30 Jan 2011 05:47:52 +0000 (+0000) Subject: Replace a hard-coded path in Cronscript.pm with a configure variable X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=01b201e842132ea807d1a23f27bf749beeed2cd4;p=evergreen%2Fpines.git 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. git-svn-id: svn://svn.open-ils.org/ILS/trunk@19338 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- diff --git a/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm b/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm deleted file mode 100644 index ab2152b39b..0000000000 --- a/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm +++ /dev/null @@ -1,371 +0,0 @@ -package OpenILS::Utils::Cronscript; - -# --------------------------------------------------------------- -# Copyright (C) 2010 Equinox Software, Inc -# Author: Joe Atzberger -# -# 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 < Default: $self->{default_opts_clean}->{'osrf-config'} - Specify OpenSRF core config file. - - --lock-file Default: $self->{default_opts_clean}->{'lock-file'} - Specify lock file. - -HELP - . $chunk . <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 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 - -=cut - diff --git a/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in b/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in new file mode 100644 index 0000000000..73281fbc60 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Utils/Cronscript.pm.in @@ -0,0 +1,371 @@ +package OpenILS::Utils::Cronscript; + +# --------------------------------------------------------------- +# Copyright (C) 2010 Equinox Software, Inc +# Author: Joe Atzberger +# +# 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 < Default: $self->{default_opts_clean}->{'osrf-config'} + Specify OpenSRF core config file. + + --lock-file Default: $self->{default_opts_clean}->{'lock-file'} + Specify lock file. + +HELP + . $chunk . <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 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 + +=cut + diff --git a/configure.ac b/configure.ac index 3d70cb3488..83e20852fc 100644 --- a/configure.ac +++ b/configure.ac @@ -374,7 +374,8 @@ AC_CONFIG_FILES([Makefile 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;