#! /usr/bin/env @MST_ROOT@/bin/perl

# --8<--8<--8<--8<--
#
# Copyright (C) 2006 Smithsonian Astrophysical Observatory
#
# This file is part of mst_envs
#
# mst_envs 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.
#
# mst_envs 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
#       Free Software Foundation, Inc.
#       51 Franklin Street, Fifth Floor
#       Boston, MA  02110-1301, USA
#
# -->8-->8-->8-->8--

require 5.10.0;

use strict;
use warnings;

use Getopt::Long;
use File::Spec;

# may not have Text::Glob when bootstrapping the whole MST
# environment, as it needs to run with Core modules only.
my $have_TextGlob    = eval { require Text::Glob; 1 };


use if defined($ENV{MST_ENVS_TEST_PERLLIBDIR}),
    lib => $ENV{MST_ENVS_TEST_PERLLIBDIR};

use MST_Env;

our $VERSION = '@VERSION@';

my %EXPORT;

my %shell_set_var = (
	       ksh => { export => { set => q[export %key='%val'],
				    unset => q[unset %key],
				  },
			local  => {
				   set    => q[%key='%val'],
				   unset  => q[unset %key]
				  },
		      },

	       sh => { export => { set => q[export %key; %key='%val'],
				   unset => q[unset %key],
				  },
			local  => {
				   set    => q[%key='%val'],
				   unset  => q[unset %key]
				  },
		      },

	       csh => { export => { set => q[setenv %key '%val'],
				   unset => q[unsetenv %key],
				  },
			local  => {
				   set    => q[set %key = '%val'],
				   unset  => q[unset %key]
				  },
		      },

	      );

$shell_set_var{bash} = $shell_set_var{ksh};
$shell_set_var{tcsh} = $shell_set_var{csh};

eval { main() };

if ( $@ )
{
    my $error = $@;

    print STDERR "mst_envs: $_\n" foreach split /\n/, $error;
    exit 1;
}

exit 0;

sub main
{
    my %opt = opts();

    # use $0 to set @MST_ROOT_VAR@ if not set. assume this is in @MST_SIMUL_ROOT_VAL@/bin/mst_envs
    if ( ! defined $ENV{@MST_ROOT_VAR@} ) {

	my ( $volume, $directories, $file ) = File::Spec->splitpath( File::Spec->rel2abs( $0 ));
	$directories =~ s{/$}{};

	my $@MST_ROOT_VAR@ = '';

	( $ENV{@MST_ROOT_VAR@} = $directories ) =~ s{@MST_SIMUL_ROOT_VAL@/bin}{};

	die( "error deducing @MST_ROOT_VAR@ from $0\n" )
	  unless -f "$ENV{@MST_ROOT_VAR@}/bin/perl";
    }


    my %MST_Env = MST::envs( $opt{define} );


    if ( @{ $opt{env} } )
    {
	$EXPORT{$_} = $MST_Env{$_}
	  foreach grep { exists $MST_Env{$_} } @{ $opt{env} };
    }

    elsif ( ( ! $opt{envs} && ! $opt{path} ) ||
	    ( $opt{envs} && $opt{path} ) )
    {
	%EXPORT = %MST_Env;
    }

    elsif ( $opt{envs} )
    {
	my %stuff = %MST_Env;
	delete $stuff{PATH};
	%EXPORT = %stuff;
    }

    elsif ( $opt{path} )
    {
	$EXPORT{PATH} = $MST_Env{PATH};
    }

    if ( $have_TextGlob ) {
        if ( @{ $opt{exclude} } ) {

            delete @EXPORT{
                grep {
                    my $key = $_;
                    grep { Text::Glob::match_glob( $_, $key ) }
                      @{ $opt{exclude} }
                } keys %EXPORT
              }

        }
    }

    my @cmds;


    my $set = $shell_set_var{$opt{shell}}{ $opt{export} ? 'export' : 'local' };

    while ( my ( $key, $val ) = each %EXPORT ) {

	$key = $opt{pfx} . $key;

	my $tpl = $set->{ defined $val ? 'set' : 'unset' };

	( my $cmd = $tpl ) =~ s/%key/$key/g;
	$cmd =~ s/%val/$val/g;

	push @cmds, $cmd;

    }

    print join( ";\n", @cmds ), "\n";
}


sub opts
{

    my %opt = (
	       append => 0,
	       export => 1,
	       fullpath => 1,
	       ldlibrarypath => 0,
	       ldrunpath => 1,
	       help => 0,
	       pfx => '',
	       sysarch => 0,
	       env => [],
	       define => {},
	       ignore_errors => 0,
	       exclude => [],
	      );

    eval {
        local $SIG{ __WARN__ } = sub { die $_[0] };

	GetOptions ( \%opt,
		     qw/
			append
			csh
			env=s@
			envs
			exclude=s@
			export!
			fullpath!
			help
			ignore_errors|ignore-errors
			ksh
			ldlibrarypath!
			ldrunpath!
			path
			pfx|prefix=s
			prepend
			sh
			shell=s
			sysarch!
			usage
			version
			define|D=s%
			/ );

    };

    die $@ if $@;

    do { print "$VERSION\n"; exit } if $opt{version};

    help(1) if $opt{help};
    help(2) if $opt{usage};


    for my $deprecate ( grep { exists $opt{$_ } } qw[ csh ksh sh ] ) {

	$opt{shell} = $deprecate;
	warn( "$0: the --$deprecate option is deprecated; use --shell=$deprecate\n" );

    }

    die( "the --shell option must be specified\n" )
      if ! defined $opt{shell};

    die( "unsupported shell: $opt{shell}\n" )
      if ! defined $shell_set_var{$opt{shell}};

    die( "--exclude only supported if Text::Glob is installed\n" )
      if @{ $opt{exclude} } && ! $have_TextGlob;

    $opt{append} = 0 if exists $opt{prepend};

    $opt{define}{$_} = delete $opt{$_} for qw/ append fullpath sysarch ldlibrarypath ignore_errors /;

    return %opt;
}


sub help
{
    my ( $verbose ) = @_;

    require Pod::Usage;
    Pod::Usage::pod2usage ( { -exitval => 0, -verbose => $verbose } );
}

__END__

=head1 NAME

mst_envs - configure MST environment

=head1 SYNOPSIS

mst_envs [options]

=head1 OPTIONS

=over 8

=item B<--shell> I<enumerated value>

output commands compatible with the specified shell.  Available shells are

  sh
  bash
  ksh
  csh
  tcsh

=item B<--define>|B<-D> I<option>=I<value>

Define a subsystem specific option; see <L/Subsystem Options> for more information.


=item B<--env> I<environment variable name>

Only output the specified environment variable.  This option may be repeated.

=item B<--envs>

only output the environment variables

=item B<--path>

only output the path

=item B<--prepend>

add MST executables to the front of the user's path (default behavior)

=item B<--append>

add MST executables to the end of the user's path

=item B<--export>, B<--noexport>

whether the MST variables will be exported; defaults to B<--export>

=item B<--fullpath>, B<--nofullpath>

whether the output PATH will include the user's PATH; defaults to
B<--fullpath> (yes)

=item B<--ignore-errors>

Ignore the absence of Perl or Lua; normally this would be a fatail
occurrence.

=item B<--ldlibrarypath>, B<--noldlibrarypath>

whether the output will include the LD_LIBRARY_PATH environment variable;
defaults to B<--noldlibrarypath> (no)

=item B<--ldrunpath>, B<--noldrunpath>

whether the output will include the LD_RUN_PATH at all environment variable;
defaults to B<--ldrunpath> (yes)

=item B<--pfx>|B<--prefix> I<pfx>

prefix the MST variable names with the given string.

=item B<--sysarch>, B<--nosysarch>

whether to output the system architecture variables; defaults to
B<--nosysarch>.

=item B<--exclude> I<file glob pattern>

Don't output variables which match the pattern.  May be used more than once.

=item B<--help>

print a short help message and exit.

=item B<--usage>

print detailed usage instructions and exit.

=back

=head1 DESCRIPTION

B<mst_envs> is normally used inside a shell script (most likely the
user's shell startup script, like F<.cshrc> or F<.profile>) to add the
required entities to the user's environment to access the MST programs
and facilities.  B<mst_envs> is designed to be C<eval>'d by the shell,
e.g.

  eval `mst_envs -csh`

normally this results in the setting of various environment
variables, including the user's path.  To have the MST variables
treated as shell variables, use the B<--noexport> flag.

the B<--sysarch> flag causes variables containing architecture
specific info to be output.  these variables are used in constructing
paths in the MST enviroment.  by outputing these variables, the user
may make use of them at a later point without having to run the
B<sysarch> script separately.

In general, play with the options; it'll be pretty obvious what they do.
Just don't B<eval> the output until you've got what you want.

=head2 Subsystem Options

The C<--define> option is used to provide extra options for various subsystems:

=over

=item *

perl_version

The version of Perl to enable access to.  It may take the following values:

=over

=item C<path>

Use the Perl in the current path.

=item C<default>

Use the Perl pointed to by F<@MST_OTS_ROOT@/pkgs/perl>.

=item I<version>

Use the Perl found at F<@MST_OTS_ROOT@/pkgs/perl->I<version>.

=back

The C<MSTENVS_WRAP_perl> environment variable is set if the requested Perl isn't the default one so that
the F<@MST_ROOT@/bin/perl> wrapper will use that specified.

=item *

lua_version

The version of Lua to enable access to.  It may take the following values:

=over

=item C<path>

Use the Lua in the current path.

=item C<default>

Use the Lua found in F<@MST_OTS_ROOT@/>I<system>F</bin/lua>.

=item I<version>

Use the Lua found at F<@MST_OTS_ROOT@/pkgs/lua->I<version>.

=back


=back

=head1 SPECIAL CASES

The LD_LIBRARY_PATH variable is set up to behave a bit differently
from the other environment variables.  Since we have chosen to avoid
setting LD_LIBRARY_PATH in a user's environment in the past, if it is
not present in the user's environment B<mst_envs> will not output an
LD_LIBRARY_PATH.  If it is present, B<mst_envs> with treat it much
like it does PATH and MANPATH.  Expect I<--append>, I<--prepend>, and
I<--nofullpath> to work as they would for PATH.

=head1 AUTHOR

Diab Jerius (djerius@cfa.harvard.edu)

M Tibbetts ( mtibbetts@cfa.harvard.edu )
