treequel 1.4.1 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/bin/treequel +93 -50
- data/lib/treequel.rb +3 -3
- metadata +2 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/bin/treequel
CHANGED
@@ -70,6 +70,10 @@ module IRB # :nodoc:
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# The Treequel shell.
|
73
|
+
#
|
74
|
+
# TODO:
|
75
|
+
# * Make more commands use the convert_to_branchsets utility function
|
76
|
+
#
|
73
77
|
class Treequel::Shell
|
74
78
|
include Readline,
|
75
79
|
Treequel::Loggable,
|
@@ -299,6 +303,7 @@ class Treequel::Shell
|
|
299
303
|
else
|
300
304
|
self.handle_missing_cmd( command )
|
301
305
|
end
|
306
|
+
|
302
307
|
rescue LDAP::ResultError => err
|
303
308
|
case err.message
|
304
309
|
when /can't contact ldap server/i
|
@@ -318,6 +323,10 @@ class Treequel::Shell
|
|
318
323
|
error_message( err.class.name, err.message )
|
319
324
|
self.log.debug { " " + err.backtrace.join(" \n") }
|
320
325
|
end
|
326
|
+
|
327
|
+
rescue => err
|
328
|
+
error_message( err.message )
|
329
|
+
self.log.debug { " " + err.backtrace.join(" \n") }
|
321
330
|
end
|
322
331
|
|
323
332
|
|
@@ -418,6 +427,10 @@ class Treequel::Shell
|
|
418
427
|
def show_completions_command
|
419
428
|
message "Completions:", @completions.inspect
|
420
429
|
end
|
430
|
+
set_options :show_completions do |oparser, options|
|
431
|
+
oparser.banner = "show_completions"
|
432
|
+
oparser.separator 'Show the list of command completions (for debugging the shell)'
|
433
|
+
end
|
421
434
|
|
422
435
|
|
423
436
|
### Show help text for the specified command, or a list of all available commands
|
@@ -428,9 +441,11 @@ class Treequel::Shell
|
|
428
441
|
message colorize( "Available commands", :bold, :white ),
|
429
442
|
*columnize(@commands)
|
430
443
|
else
|
431
|
-
cmd = args.shift
|
432
|
-
|
433
|
-
|
444
|
+
cmd = args.shift
|
445
|
+
full_command = @completions[ cmd ]
|
446
|
+
|
447
|
+
if @@option_parsers.key?( full_command.to_sym )
|
448
|
+
oparser, _ = @@option_parsers[ full_command.to_sym ]
|
434
449
|
self.log.debug "Setting summary width to: %p" % [ @columns ]
|
435
450
|
oparser.summary_width = @columns
|
436
451
|
output = oparser.to_s.sub( /^(.*?)\n/ ) do |match|
|
@@ -440,7 +455,7 @@ class Treequel::Shell
|
|
440
455
|
$stderr.puts
|
441
456
|
message( output )
|
442
457
|
else
|
443
|
-
error_message( "No help for '#{cmd
|
458
|
+
error_message( "No help for '#{cmd}'" )
|
444
459
|
end
|
445
460
|
end
|
446
461
|
end
|
@@ -455,7 +470,7 @@ class Treequel::Shell
|
|
455
470
|
message "Okay, exiting."
|
456
471
|
self.quit = true
|
457
472
|
end
|
458
|
-
set_options :
|
473
|
+
set_options :quit do |oparser, options|
|
459
474
|
oparser.banner = "quit"
|
460
475
|
oparser.separator 'Exit the shell.'
|
461
476
|
end
|
@@ -488,6 +503,7 @@ class Treequel::Shell
|
|
488
503
|
|
489
504
|
### Display LDIF for the specified RDNs.
|
490
505
|
def cat_command( options, *args )
|
506
|
+
validate_rdns( *args )
|
491
507
|
args.each do |rdn|
|
492
508
|
extended = rdn.chomp!( '+' )
|
493
509
|
|
@@ -512,6 +528,7 @@ class Treequel::Shell
|
|
512
528
|
|
513
529
|
### Display YAML for the specified RDNs.
|
514
530
|
def yaml_command( options, *args )
|
531
|
+
validate_rdns( *args )
|
515
532
|
args.each do |rdn|
|
516
533
|
branch = @currbranch.get_child( rdn )
|
517
534
|
message( branch_as_yaml(branch) )
|
@@ -534,6 +551,7 @@ class Treequel::Shell
|
|
534
551
|
|
535
552
|
# Otherwise, list each one specified
|
536
553
|
else
|
554
|
+
validate_rdns( *args )
|
537
555
|
args.each do |rdn|
|
538
556
|
if branch = @currbranch.get_child( rdn )
|
539
557
|
targets << branch
|
@@ -545,11 +563,13 @@ class Treequel::Shell
|
|
545
563
|
|
546
564
|
# Fetch each branch's children, sort them, format them in columns, and highlight them
|
547
565
|
targets.each do |branch|
|
566
|
+
header( branch.dn ) if targets.length > 1
|
548
567
|
if options.longform
|
549
568
|
message self.make_longform_ls_output( branch, options )
|
550
569
|
else
|
551
570
|
message self.make_shortform_ls_output( branch, options )
|
552
571
|
end
|
572
|
+
message if targets.length > 1
|
553
573
|
end
|
554
574
|
end
|
555
575
|
set_options :ls do |oparser, options|
|
@@ -575,46 +595,6 @@ class Treequel::Shell
|
|
575
595
|
end
|
576
596
|
|
577
597
|
|
578
|
-
### Generate long-form output lines for the 'ls' command for the given +branch+.
|
579
|
-
def make_longform_ls_output( branch, options )
|
580
|
-
children = branch.children
|
581
|
-
header = colorize( :underscore, :cyan ) { "total %d" % [children.length] }
|
582
|
-
|
583
|
-
# Calcuate column widths
|
584
|
-
oclen = children.map do |subbranch|
|
585
|
-
subbranch.include_operational_attrs = true
|
586
|
-
subbranch[:structuralObjectClass] ? subbranch[:structuralObjectClass].length : 0
|
587
|
-
end.max
|
588
|
-
|
589
|
-
# Set up sorting by collecting all the requested sort criteria as Proc objects which
|
590
|
-
# will be applied
|
591
|
-
sortfuncs = []
|
592
|
-
sortfuncs << lambda {|subbranch| subbranch[:hasSubordinates] ? 0 : 1 } if options.dirsort
|
593
|
-
sortfuncs << lambda {|subbranch| subbranch[:modifyTimestamp] } if options.timesort
|
594
|
-
sortfuncs << lambda {|subbranch| subbranch.rdn.downcase }
|
595
|
-
|
596
|
-
rows = children.
|
597
|
-
sort_by {|subbranch| sortfuncs.collect {|func| func.call(subbranch) } }.
|
598
|
-
collect {|subbranch| self.format_description(subbranch, oclen) }
|
599
|
-
|
600
|
-
return [ header ] + (options.reversesort ? rows.reverse : rows)
|
601
|
-
end
|
602
|
-
|
603
|
-
|
604
|
-
### Generate short-form 'ls' output for the given +branch+ and return it.
|
605
|
-
def make_shortform_ls_output( branch, options )
|
606
|
-
branch.include_operational_attrs = true
|
607
|
-
entries = branch.children.
|
608
|
-
collect {|b| b.rdn + (b[:hasSubordinates] ? '/' : '') }.
|
609
|
-
sort_by {|rdn| rdn.downcase }
|
610
|
-
self.log.debug "Displaying %d entries in short form." % [ entries.length ]
|
611
|
-
|
612
|
-
return columnize( entries ).gsub( /#{ATTRIBUTE_TYPE}=\s*\S+/ ) do |rdn|
|
613
|
-
format_rdn( rdn )
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
|
618
598
|
### Change the current working DN to +rdn+.
|
619
599
|
def cdn_command( options, rdn=nil, *args )
|
620
600
|
if rdn.nil?
|
@@ -624,7 +604,7 @@ class Treequel::Shell
|
|
624
604
|
|
625
605
|
return self.parent_command( options ) if rdn == '..'
|
626
606
|
|
627
|
-
|
607
|
+
validate_rdns( rdn )
|
628
608
|
|
629
609
|
pairs = rdn.split( /\s*,\s*/ )
|
630
610
|
pairs.each do |dnpair|
|
@@ -655,6 +635,7 @@ class Treequel::Shell
|
|
655
635
|
|
656
636
|
# ### Create the entry specified by +rdn+.
|
657
637
|
def create_command( options, rdn )
|
638
|
+
validate_rdns( rdn )
|
658
639
|
branch = @currbranch.get_child( rdn )
|
659
640
|
|
660
641
|
raise "#{branch.dn}: already exists." if branch.exists?
|
@@ -668,6 +649,7 @@ class Treequel::Shell
|
|
668
649
|
|
669
650
|
### Edit the entry specified by +rdn+.
|
670
651
|
def edit_command( options, rdn )
|
652
|
+
validate_rdns( rdn )
|
671
653
|
branch = @currbranch.get_child( rdn )
|
672
654
|
|
673
655
|
raise "#{branch.dn}: no such entry. Did you mean to 'create' it instead? " unless
|
@@ -687,6 +669,7 @@ class Treequel::Shell
|
|
687
669
|
|
688
670
|
### Change the DN of an entry
|
689
671
|
def mv_command( options, rdn, newdn )
|
672
|
+
validate_rdns( rdn, newdn )
|
690
673
|
branch = @currbranch.get_child( rdn )
|
691
674
|
|
692
675
|
raise "#{branch.dn}: no such entry" unless branch.exists?
|
@@ -702,6 +685,8 @@ class Treequel::Shell
|
|
702
685
|
|
703
686
|
### Copy an entry
|
704
687
|
def cp_command( options, rdn, newrdn )
|
688
|
+
# Can't validate as RDNs because they might be full DNs
|
689
|
+
|
705
690
|
base_dn = @currbranch.directory.base_dn
|
706
691
|
|
707
692
|
# If the RDN includes the base, it's a DN
|
@@ -737,6 +722,7 @@ class Treequel::Shell
|
|
737
722
|
|
738
723
|
### Remove the entry specified by +rdn+.
|
739
724
|
def rm_command( options, *rdns )
|
725
|
+
validate_rdns( *rdns )
|
740
726
|
branchsets = self.convert_to_branchsets( *rdns )
|
741
727
|
coll = Treequel::BranchCollection.new( *branchsets )
|
742
728
|
|
@@ -838,7 +824,9 @@ class Treequel::Shell
|
|
838
824
|
if args.empty?
|
839
825
|
branch = @currbranch
|
840
826
|
else
|
841
|
-
|
827
|
+
rdn = args.first
|
828
|
+
validate_rdns( rdn )
|
829
|
+
branch = @currbranch.get_child( rdn )
|
842
830
|
end
|
843
831
|
|
844
832
|
self.log.debug "Setting up IRb shell"
|
@@ -869,6 +857,10 @@ class Treequel::Shell
|
|
869
857
|
end
|
870
858
|
|
871
859
|
|
860
|
+
#################################################################
|
861
|
+
### U T I L I T Y M E T H O D S
|
862
|
+
#################################################################
|
863
|
+
|
872
864
|
### Convert the given +patterns+ to branchsets relative to the current branch and return
|
873
865
|
### them. This is used to map shell arguments like 'cn=*', 'Hosts', 'cn=dav*' into
|
874
866
|
### branchsets that will find matching entries.
|
@@ -882,9 +874,45 @@ class Treequel::Shell
|
|
882
874
|
end
|
883
875
|
|
884
876
|
|
885
|
-
|
886
|
-
|
887
|
-
|
877
|
+
### Generate long-form output lines for the 'ls' command for the given +branch+.
|
878
|
+
def make_longform_ls_output( branch, options )
|
879
|
+
children = branch.children
|
880
|
+
totalmsg = "total %d" % [ children.length ]
|
881
|
+
|
882
|
+
# Calcuate column widths
|
883
|
+
oclen = children.map do |subbranch|
|
884
|
+
subbranch.include_operational_attrs = true
|
885
|
+
subbranch[:structuralObjectClass] ? subbranch[:structuralObjectClass].length : 0
|
886
|
+
end.max
|
887
|
+
|
888
|
+
# Set up sorting by collecting all the requested sort criteria as Proc objects which
|
889
|
+
# will be applied
|
890
|
+
sortfuncs = []
|
891
|
+
sortfuncs << lambda {|subbranch| subbranch[:hasSubordinates] ? 0 : 1 } if options.dirsort
|
892
|
+
sortfuncs << lambda {|subbranch| subbranch[:modifyTimestamp] } if options.timesort
|
893
|
+
sortfuncs << lambda {|subbranch| subbranch.rdn.downcase }
|
894
|
+
|
895
|
+
rows = children.
|
896
|
+
sort_by {|subbranch| sortfuncs.collect {|func| func.call(subbranch) } }.
|
897
|
+
collect {|subbranch| self.format_description(subbranch, oclen) }
|
898
|
+
|
899
|
+
return [ totalmsg ] + (options.reversesort ? rows.reverse : rows)
|
900
|
+
end
|
901
|
+
|
902
|
+
|
903
|
+
### Generate short-form 'ls' output for the given +branch+ and return it.
|
904
|
+
def make_shortform_ls_output( branch, options )
|
905
|
+
branch.include_operational_attrs = true
|
906
|
+
entries = branch.children.
|
907
|
+
collect {|b| b.rdn + (b[:hasSubordinates] ? '/' : '') }.
|
908
|
+
sort_by {|rdn| rdn.downcase }
|
909
|
+
self.log.debug "Displaying %d entries in short form." % [ entries.length ]
|
910
|
+
|
911
|
+
return columnize( entries ).gsub( /#{ATTRIBUTE_TYPE}=\s*\S+/ ) do |rdn|
|
912
|
+
format_rdn( rdn )
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
888
916
|
|
889
917
|
### Return the description of the specified +branch+ suitable for displaying in
|
890
918
|
### the directory listing.
|
@@ -1004,6 +1032,13 @@ class Treequel::Shell
|
|
1004
1032
|
end
|
1005
1033
|
|
1006
1034
|
|
1035
|
+
### Output a header containing the given +text+.
|
1036
|
+
def header( text )
|
1037
|
+
header = colorize( text, :underscore, :cyan )
|
1038
|
+
$stderr.puts( header )
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
|
1007
1042
|
### Output the specified message +parts+.
|
1008
1043
|
def message( *parts )
|
1009
1044
|
$stderr.puts( *parts )
|
@@ -1185,6 +1220,14 @@ class Treequel::Shell
|
|
1185
1220
|
end
|
1186
1221
|
|
1187
1222
|
|
1223
|
+
### Raise a RuntimeError if the specified +rdn+ is invalid.
|
1224
|
+
def validate_rdns( *rdns )
|
1225
|
+
rdns.flatten.each do |rdn|
|
1226
|
+
raise "invalid RDN %p" % [ rdn ] unless RELATIVE_DISTINGUISHED_NAME.match( rdn )
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
|
1188
1231
|
### Return an ANSI-colored version of the given +rdn+ string.
|
1189
1232
|
def format_rdn( rdn )
|
1190
1233
|
rdn.split( /,/ ).collect do |rdn_part|
|
data/lib/treequel.rb
CHANGED
@@ -25,7 +25,7 @@ end
|
|
25
25
|
|
26
26
|
# A library for interacting with LDAP modelled after Sequel.
|
27
27
|
#
|
28
|
-
# @version 1.
|
28
|
+
# @version 1.4.2
|
29
29
|
#
|
30
30
|
# @example
|
31
31
|
# # Connect to the directory at the specified URL
|
@@ -53,10 +53,10 @@ end
|
|
53
53
|
module Treequel
|
54
54
|
|
55
55
|
# Library version
|
56
|
-
VERSION = '1.4.
|
56
|
+
VERSION = '1.4.2'
|
57
57
|
|
58
58
|
# VCS revision
|
59
|
-
REVISION = %q$Revision:
|
59
|
+
REVISION = %q$Revision: a48b3d18545c $
|
60
60
|
|
61
61
|
# Common paths for ldap.conf
|
62
62
|
COMMON_LDAP_CONF_PATHS = %w[
|
metadata
CHANGED
metadata.gz.sig
CHANGED
Binary file
|