# HG changeset patch # User Davor Ocelic # Date 1556577832 -7200 # Node ID d37c6197818f39af4d56abf20825f6fac25a755d # Parent 24340fdef27618783bd77b1bbd8d14f3578078ef 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) diff -r 24340fdef276 -r d37c6197818f shelldap --- a/shelldap Mon Apr 29 21:57:57 2019 +0200 +++ b/shelldap Tue Apr 30 00:43:52 2019 +0200 @@ -242,7 +242,9 @@ =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, it defaults to the current search base. You may additionally add a list of attributes to display (e.g. use '+' for operational @@ -257,11 +259,13 @@ =head2 less -Like cat, but uses the configured pager to display output. +Like 'cat', but use configured pager to paginate output. =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. cd change to 'home' (binddn if any, or basedn) @@ -282,11 +286,17 @@ =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 -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 copied and then an LDAP moddn() is performed. @@ -298,7 +308,9 @@ =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 server, and will tab-complete. @@ -313,7 +325,9 @@ =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 for review before delete. @@ -325,7 +339,9 @@ =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 directory. @@ -335,11 +351,15 @@ =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 -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. grep uid=mahlon @@ -350,8 +370,9 @@ =head2 inspect -View schema information about a given entry, or a list of arbitrary -objectClasses, along with the most common flags for the objectClass +View schema and flags for an entry or objectClass. + +It also includes the most common flags for the objectClass attributes. inspect uid=mahlon @@ -369,7 +390,9 @@ =head2 list -List entries for the current basedn. Globbing is supported. +List directory contents. + +Globbing is supported. aliased to: ls @@ -391,19 +414,23 @@ =head2 mkdir -Creates a new 'organizationalUnit' entry. - - mkdir containername - mkdir ou=whatever +Create a new 'organizationalUnit' LDAP entry. + + mkdir containername + mkdir ou=whatever =head2 move -Move an entry to a different dn path. Usage is identical to B. +Move (rename) entry. + +Usage is identical to B. aliased to: mv =head2 passwd +Change user password. + If supported server side, change the password for a specified entry. The entry must have a 'userPassword' attribute. @@ -411,22 +438,22 @@ =head2 pwd -Print the 'working directory' - aka, the current ldap basedn. +Print name of current/working LDAP search base. =head2 setenv -Modify various runtime variables normally set from the command line. +Change or define shelldap variable. setenv debug 1 export debug=1 =head2 whoami +Print current bind DN. + Show current auth credentials. Unless you specified a binddn, this will just show an anonymous bind. -aliased to: id - =back =head1 TODO @@ -486,6 +513,7 @@ use Algorithm::Diff qw//; use Carp 'confess'; use POSIX qw//; +use Tie::IxHash qw//; use base 'Term::Shell'; my $conf = $main::conf; @@ -494,6 +522,55 @@ $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 ######################################################################## @@ -1379,9 +1456,10 @@ # # 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. -my %cmd_map = ( - #'whoami' => [ undef ], - #'pwd' => [ undef ], +tie my %cmd_map, 'Tie::IxHash'; +%cmd_map = ( + 'whoami' => [ undef ], + 'pwd' => [ undef ], 'list' => [ undef, 'comp_cwd' ], 'grep' => [ undef, 'comp_cwd' ], 'edit' => [ undef, 'comp_cwd' ], @@ -1393,11 +1471,11 @@ 'cd' => [ undef, 'comp_cwd' ], 'create' => [ undef, 'comp_create' ], 'setenv' => [ undef, 'comp_setenv' ], - #'passwd' => [ undef ], - ##'clear' => [ undef ], - #'env' => [ undef ], + 'passwd' => [ undef ], + 'clear' => [ undef ], + 'env' => [ undef ], #'help' => [ undef ], - #'mkdir' => [ undef ], + 'mkdir' => [ undef ], 'inspect' => [ undef, 'comp_inspect' ], 'id' => [ 'whoami' ], @@ -1415,11 +1493,6 @@ ); -### Don't die on a newline, just no-op. -### -sub run_ { return; } - - ### Term::Shell hook. ### Write history for each command, print shell debug actions. ### @@ -1928,28 +2001,6 @@ } -### 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 ### location the command was run from. ### @@ -2352,25 +2403,46 @@ ### 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'; + local $| = 1; + my %aliases; + while(my($cmd, $data) = each %cmd_map ) { + # If command is an alias, insert alias symbol. if( $$data[0]) { - my $alias_sub = 'run_' . $cmd; - my $real_sub = 'run_' . $$data[0]; - *$alias_sub = \&$real_sub; + $aliases{$$data[0]} ||= []; + push @{$aliases{$$data[0]}}, $cmd; + + } 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]) { - my $comp_sub = "comp_$cmd"; - *$comp_sub = \&{$$data[1]} - } + } + + while(my($cmd,$aliases) = each %aliases) { + my $aliasfunc = sub { @$aliases }; + *{"alias_$cmd"} = \&$aliasfunc; } } @@ -2432,10 +2504,10 @@ 'tls_key=s', 'tls', 'debug', 'version', help => sub { - Pod::Usage::pod2usage( - -verbose => 1, - -message => "\n$0 command line flags\n" . '-' x 65 - ); + Pod::Usage::pod2usage( + -verbose => 1, + -message => "\n$0 command line flags\n" . '-' x 65 + ); } );