Multiple help-related changes

- Make every command's POD doc have a single-line introductory description.
This help is then used as a one-liner summary in Term::Shell.

- Tie %cmd_map to IxHash to preserve hash elements' order.

- Fix bug in Term::Shell's code related to command aliases.
(Also emailed Term::Shell author to include the fix in next release.)

- Remove run_() which already exists in Term::Shell.

- Use Term::Shell's help facilities instead of manually redefining
run_help() and other related commands. The complete POD documentation is
still available for viewing if user invokes ./shelldap --help.

- Completer functions are disabled right now (fix coming in the next
commit)

FossilOrigin-Name: a3bfbcceb8e471a3397b5e90cfe9bd0fa7ebe84934de738e34bc620a24f7fe5c
This commit is contained in:
docelic@crystallabs.io 2019-04-29 22:43:51 +00:00
parent c89d193e53
commit c08875fa11

206
shelldap
View file

@ -242,7 +242,9 @@ Display the version number.
=head2 cat =head2 cat
Display LDIF dump of an entry. Globbing is supported. Specify either full DN, or a RDN. Print contents of LDAP entry to STDOUT in LDIF format.
Globbing is supported. Specify either full DN, or a RDN.
RDNs are local to the current search base ('cwd' in shell terms). If RDN is '.' or missing, RDNs are local to the current search base ('cwd' in shell terms). If RDN is '.' or missing,
it defaults to the current search base. it defaults to the current search base.
You may additionally add a list of attributes to display (e.g. use '+' for operational You may additionally add a list of attributes to display (e.g. use '+' for operational
@ -257,11 +259,13 @@ option.
=head2 less =head2 less
Like cat, but uses the configured pager to display output. Like 'cat', but use configured pager to paginate output.
=head2 cd =head2 cd
Change directory. Translated to LDAP, this changes the current basedn. Change the working directory (LDAP search base).
Translated to LDAP, this changes the current basedn.
All commands after a 'cd' operate within the new basedn. All commands after a 'cd' operate within the new basedn.
cd change to 'home' (binddn if any, or basedn) cd change to 'home' (binddn if any, or basedn)
@ -282,11 +286,17 @@ any entry. Many commands then work on '.' or default to '.', meaning
=head2 clear =head2 clear
Clear the screen. Clear the terminal screen.
Clears screen similar to 'clear' or Ctrl+l on the shell command line.
Ctrl+l alias is also supported.
=head2 copy =head2 copy
Copy an entry to a different DN path. All copies are relative to the Copy an entry.
All copies are relative to the
current basedn unless a full DN is specified. All attributes are current basedn unless a full DN is specified. All attributes are
copied and then an LDAP moddn() is performed. copied and then an LDAP moddn() is performed.
@ -298,7 +308,9 @@ aliased to: cp
=head2 create =head2 create
Create an entry from scratch. Arguments are space separated objectClass Create an entry.
Arguments are space separated objectClass
names. Possible objectClasses are derived automatically from the names. Possible objectClasses are derived automatically from the
server, and will tab-complete. server, and will tab-complete.
@ -313,7 +325,9 @@ aliased to: touch
=head2 delete =head2 delete
Remove an entry from the directory. Globbing is supported. Remove an entry.
Globbing is supported.
All deletes are sanity-prompted. The -v flag prints the entries out All deletes are sanity-prompted. The -v flag prints the entries out
for review before delete. for review before delete.
@ -325,7 +339,9 @@ aliased to: rm
=head2 edit =head2 edit
Edit an entry in an external editor. After the editor exits, the Edit an entry in an external editor.
After the editor exits, the
resulting LDIF is sanity checked, and changes are written to the LDAP resulting LDIF is sanity checked, and changes are written to the LDAP
directory. directory.
@ -335,11 +351,15 @@ aliased to: vi
=head2 env =head2 env
Show values for various runtime variables. Print values of configurable shelldap variables.
This is a subset of all variables configurable via shelldap config
file and/or its command line options.
=head2 grep =head2 grep
Search for arbitrary LDAP filters, and return matching DN results. Search using LDAP filters and return matching DN results.
The search string must be a valid LDAP filter. The search string must be a valid LDAP filter.
grep uid=mahlon grep uid=mahlon
@ -350,8 +370,9 @@ The search string must be a valid LDAP filter.
=head2 inspect =head2 inspect
View schema information about a given entry, or a list of arbitrary View schema and flags for an entry or objectClass.
objectClasses, along with the most common flags for the objectClass
It also includes the most common flags for the objectClass
attributes. attributes.
inspect uid=mahlon inspect uid=mahlon
@ -369,7 +390,9 @@ is dumped to screen.
=head2 list =head2 list
List entries for the current basedn. Globbing is supported. List directory contents.
Globbing is supported.
aliased to: ls aliased to: ls
@ -391,19 +414,23 @@ types. You can additionally specify your own mappings in your
=head2 mkdir =head2 mkdir
Creates a new 'organizationalUnit' entry. Create a new 'organizationalUnit' LDAP entry.
mkdir containername mkdir containername
mkdir ou=whatever mkdir ou=whatever
=head2 move =head2 move
Move an entry to a different dn path. Usage is identical to B<copy>. Move (rename) entry.
Usage is identical to B<copy>.
aliased to: mv aliased to: mv
=head2 passwd =head2 passwd
Change user password.
If supported server side, change the password for a specified entry. If supported server side, change the password for a specified entry.
The entry must have a 'userPassword' attribute. The entry must have a 'userPassword' attribute.
@ -411,22 +438,22 @@ The entry must have a 'userPassword' attribute.
=head2 pwd =head2 pwd
Print the 'working directory' - aka, the current ldap basedn. Print name of current/working LDAP search base.
=head2 setenv =head2 setenv
Modify various runtime variables normally set from the command line. Change or define shelldap variable.
setenv debug 1 setenv debug 1
export debug=1 export debug=1
=head2 whoami =head2 whoami
Print current bind DN.
Show current auth credentials. Unless you specified a binddn, this Show current auth credentials. Unless you specified a binddn, this
will just show an anonymous bind. will just show an anonymous bind.
aliased to: id
=back =back
=head1 TODO =head1 TODO
@ -486,6 +513,7 @@ use File::Temp qw//;
use Algorithm::Diff qw//; use Algorithm::Diff qw//;
use Carp 'confess'; use Carp 'confess';
use POSIX qw//; use POSIX qw//;
use Tie::IxHash qw//;
use base 'Term::Shell'; use base 'Term::Shell';
my $conf = $main::conf; my $conf = $main::conf;
@ -494,6 +522,55 @@ my $conf = $main::conf;
$SIG{'__DIE__'} = \&Carp::confess if $conf->{'debug'}; $SIG{'__DIE__'} = \&Carp::confess if $conf->{'debug'};
########################################################################
### Term::Shell Fixes
########################################################################
# Term::Shell function add_handlers() is implemented in an incorrect way.
# We reimplement the method here to fix its problems.
# In add_handlers, we split searching for aliases in a separate loop,
# because otherwise not all aliases are registered before we look them
# up.
sub add_handlers
{
my $o = shift;
for my $hnd (@_)
{
next unless $hnd =~ /^(run|help|smry|comp|catch|alias)_/o;
my $t = $1;
my $a = substr( $hnd, length($t) + 1 );
# Add on the prefix and suffix if the command is defined
if ( length $a )
{
substr( $a, 0, 0 ) = $o->cmd_prefix;
$a .= $o->cmd_suffix;
}
$o->{handlers}{$a}{$t} = $hnd;
}
for my $hnd (@_)
{
next unless $hnd =~ /^(run|help|smry|comp|catch|alias)_/o;
my $t = $1;
my $a = substr( $hnd, length($t) + 1 );
if ( $o->has_aliases($a) )
{
my @a = $o->get_aliases($a);
for my $alias (@a)
{
substr( $alias, 0, 0 ) = $o->cmd_prefix;
$alias .= $o->cmd_suffix;
$o->{handlers}{$alias}{$t} = $hnd;
}
}
}
}
######################################################################## ########################################################################
### U T I L I T Y F U N C T I O N S ### U T I L I T Y F U N C T I O N S
######################################################################## ########################################################################
@ -1379,9 +1456,10 @@ sub diff {
# #
# It is not necessary to list all real commands here, but you can/should # It is not necessary to list all real commands here, but you can/should
# do so to assign autocompleter function to them, and/or to define aliases. # do so to assign autocompleter function to them, and/or to define aliases.
my %cmd_map = ( tie my %cmd_map, 'Tie::IxHash';
#'whoami' => [ undef ], %cmd_map = (
#'pwd' => [ undef ], 'whoami' => [ undef ],
'pwd' => [ undef ],
'list' => [ undef, 'comp_cwd' ], 'list' => [ undef, 'comp_cwd' ],
'grep' => [ undef, 'comp_cwd' ], 'grep' => [ undef, 'comp_cwd' ],
'edit' => [ undef, 'comp_cwd' ], 'edit' => [ undef, 'comp_cwd' ],
@ -1393,11 +1471,11 @@ my %cmd_map = (
'cd' => [ undef, 'comp_cwd' ], 'cd' => [ undef, 'comp_cwd' ],
'create' => [ undef, 'comp_create' ], 'create' => [ undef, 'comp_create' ],
'setenv' => [ undef, 'comp_setenv' ], 'setenv' => [ undef, 'comp_setenv' ],
#'passwd' => [ undef ], 'passwd' => [ undef ],
##'clear' => [ undef ], 'clear' => [ undef ],
#'env' => [ undef ], 'env' => [ undef ],
#'help' => [ undef ], #'help' => [ undef ],
#'mkdir' => [ undef ], 'mkdir' => [ undef ],
'inspect' => [ undef, 'comp_inspect' ], 'inspect' => [ undef, 'comp_inspect' ],
'id' => [ 'whoami' ], 'id' => [ 'whoami' ],
@ -1415,11 +1493,6 @@ my %cmd_map = (
); );
### Don't die on a newline, just no-op.
###
sub run_ { return; }
### Term::Shell hook. ### Term::Shell hook.
### Write history for each command, print shell debug actions. ### Write history for each command, print shell debug actions.
### ###
@ -1928,28 +2001,6 @@ sub run_grep
} }
### Override internal help function with pod2usage output.
###
sub run_help
{
my $self = shift;
my $section = 'SHELL COMMANDS';
my $command = shift;
if( $command ) {
# If it is an alias, resolve to real name:
$command = $cmd_map{$command}[0] if $cmd_map{$command}[0];
$section .= "/$command"
}
return Pod::Usage::pod2usage(
-exitval => 'NOEXIT',
-verbose => 99,
-sections => $section
);
}
### Generate and display a list of LDAP entries, relative to the current ### Generate and display a list of LDAP entries, relative to the current
### location the command was run from. ### location the command was run from.
### ###
@ -2352,25 +2403,46 @@ sub run_inspect
### Inject various autocomplete and alias routines into the symbol table. ### Inject various autocomplete and alias routines into the symbol table.
### ###
# setup alias subs
#
# Term::Shell has an alias_* feature, but
# it seems to work about 90% of the time.
# that last 10% is something of a mystery.
#
{ no strict 'refs'; { no strict 'refs';
local $| = 1;
my %aliases;
while(my($cmd, $data) = each %cmd_map ) { while(my($cmd, $data) = each %cmd_map ) {
# If command is an alias, insert alias symbol.
if( $$data[0]) { if( $$data[0]) {
my $alias_sub = 'run_' . $cmd; $aliases{$$data[0]} ||= [];
my $real_sub = 'run_' . $$data[0]; push @{$aliases{$$data[0]}}, $cmd;
*$alias_sub = \&$real_sub;
} else {
## If completer is defined, set it.
#if( $$data[1]) {
# my $comp_sub = "comp_$cmd";
# *$comp_sub = \&{$$data[1]}
#}
# Define help and summary functions for the command:
my $pod = ''; open my $io, '>', \$pod;
Pod::Usage::pod2usage( -exitval => 'NOEXIT', -verbose => 99, -sections => "SHELL COMMANDS/${\( quotemeta $cmd )}", -output => \*$io );
my @pod = split /\n/, $pod;
my $summary = $pod[1];
if($summary) {
$summary =~ s/^\s+//s;
$summary =~ s/\s+$//s;
$summary =~ s/\s+/ /s;
}
my $help = join "\n", @pod;
my $helpfunc = sub { "$help\n" };
*{"help_$cmd"} = \&$helpfunc;
my $summfunc = sub { $summary };
*{"smry_$cmd"} = \&$summfunc;
}
} }
if( $$data[1]) { while(my($cmd,$aliases) = each %aliases) {
my $comp_sub = "comp_$cmd"; my $aliasfunc = sub { @$aliases };
*$comp_sub = \&{$$data[1]} *{"alias_$cmd"} = \&$aliasfunc;
}
} }
} }