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.
Files changed (5) hide show
  1. data.tar.gz.sig +0 -0
  2. data/bin/treequel +93 -50
  3. data/lib/treequel.rb +3 -3
  4. metadata +2 -2
  5. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
@@ -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.to_sym
432
- if @@option_parsers.key?( cmd )
433
- oparser, _ = @@option_parsers[ cmd ]
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.inspect}'" )
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 :help do |oparser, 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
- raise "invalid RDN %p" % [ rdn ] unless RELATIVE_DISTINGUISHED_NAME.match( rdn )
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
- branch = @currbranch.get_child( args.first )
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
- ### U T I L I T Y M E T H O D S
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|
@@ -25,7 +25,7 @@ end
25
25
 
26
26
  # A library for interacting with LDAP modelled after Sequel.
27
27
  #
28
- # @version 1.3.0
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.1'
56
+ VERSION = '1.4.2'
57
57
 
58
58
  # VCS revision
59
- REVISION = %q$Revision: 72213abfe94d $
59
+ REVISION = %q$Revision: a48b3d18545c $
60
60
 
61
61
  # Common paths for ldap.conf
62
62
  COMMON_LDAP_CONF_PATHS = %w[
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 4
8
- - 1
9
- version: 1.4.1
8
+ - 2
9
+ version: 1.4.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Michael Granger
metadata.gz.sig CHANGED
Binary file