treequel 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|