plist4r 0.1.0 → 0.1.1

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.
@@ -10,6 +10,8 @@ Current project status: in alpha
10
10
 
11
11
  == Quick Start
12
12
 
13
+ require 'plist4r'
14
+
13
15
  Plist4r::Config.default_dir "/Library/LaunchDaemons"
14
16
  filename = "com.github.myservice.plist"
15
17
  p = Plist4r.open(filename)
@@ -65,20 +67,20 @@ We believe thats allright for most uses, and decided to include `next_step` for
65
67
  module ::Plist4r::Backend::MyPlistReaderWriter
66
68
  # implement some plist4r api calls here
67
69
  end
68
-
70
+
69
71
  # append my backend to the end of the list
70
72
  Plist4r::Config[:backends] << :my_plist_reader_writer
71
73
 
72
74
  # or to the front of the list (executes first)
73
75
  Plist4r::Config[:backends].insert 0 :my_plist_reader_writer
74
-
76
+
75
77
  # The default directory to load / save files from
76
78
  Plist4r::Config.default_path "/Library/Cars"
77
79
 
78
80
  car = Plist4r.new("car.plist")
79
81
 
80
82
  car.load
81
-
83
+
82
84
  car.file_format :binary
83
85
  # car.plist_type :car # not implemented *yet*
84
86
 
@@ -121,8 +123,32 @@ Plist4r is currently alpha - quality software. Yet to be completed...
121
123
  * Fork the project, and create a topic branch as per {these instructions}[http://wiki.opscode.com/display/opscode/Working+with+Git].
122
124
  * Make your feature addition or bug fix.
123
125
  * Include documentation for it.
124
- * Include a regression test for it. So I don't break it in a future version unintentionally.
126
+ * Include a regression test for it. So I dont break it in a future version unintentionally.
127
+
128
+ == Contributors
129
+
130
+ Popen4
131
+ * Ara T Howard
132
+
133
+ ActiveSupport::OrderedHash
134
+ * Copyright (c) 2005 David Hansson,
135
+ * Copyright (c) 2007 Mauricio Fernandez, Sam Stephenson
136
+ * Copyright (c) 2008 Steve Purcell, Josh Peek
137
+ * Copyright (c) 2009 Christoffer Sawicki
138
+
139
+ Mixlib::Config
140
+ * Author:: Adam Jacob
141
+ * Author:: Nuo Yan
142
+ * Author:: Christopher Brown
143
+ * Copyright:: Copyright (c) 2008 Opscode, Inc.
144
+
145
+ Backends...
146
+
147
+ Haml, Libxml4r, RubyCocoa
148
+ * Dreamcat4
125
149
 
126
150
  == Copyright
127
151
 
128
152
  Copyright (c) 2010 Dreamcat4. See LICENSE for details.
153
+
154
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,23 +1,24 @@
1
1
 
2
- $:.unshift(File.dirname(__FILE__)) unless
3
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ dir = File.dirname(__FILE__)
3
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
4
4
 
5
5
  require 'plist4r/plist'
6
6
 
7
7
  module Plist4r
8
8
  class << self
9
9
  def new *args, &blk
10
- puts args.inspect
10
+ # puts args.inspect
11
11
  return Plist.new *args, &blk
12
12
  end
13
13
 
14
14
  def open filename, *args, &blk
15
- puts args.inspect
16
- return Plist.new filename, *args, &blk
15
+ # puts args.inspect
16
+ p = Plist.new filename, *args, &blk
17
+ p.open
17
18
  end
18
19
 
19
20
  def string_detect_format string
20
- s.strip!
21
+ s = string.strip!
21
22
  case s[0,1]
22
23
  when "{","("
23
24
  :next_step
@@ -1,52 +1,63 @@
1
1
 
2
2
  require 'plist4r/config'
3
+ require 'plist4r/backend_base'
3
4
  require 'plist4r/mixin/ordered_hash'
4
5
 
5
- class Plist4r::Backend
6
- ApiMethods = %w[from_string to_xml to_binary to_next_step open save]
6
+ module Plist4r
7
+ class Backend
8
+ ApiMethods = %w[from_string to_xml to_binary to_next_step open save]
7
9
 
8
- def initialize plist, *args, &blk
9
- @plist = plist
10
- @backends = Config[:backends].collect do |b|
11
- case b
12
- when Module
13
- b
14
- when Symbol, String
15
- eval "::Plist4r::Backend::#{b.to_s.camelcase}"
16
- else
17
- raise "Backend #{b.inspect} is of unsupported type: #{b.class}"
10
+ def initialize plist, *args, &blk
11
+ @plist = plist
12
+ @backends = plist.backends.collect do |b|
13
+ case b
14
+ when Module
15
+ b
16
+ when Symbol, String
17
+ eval "::Plist4r::Backend::#{b.to_s.camelcase}"
18
+ else
19
+ raise "Backend #{b.inspect} is of unsupported type: #{b.class}"
20
+ end
18
21
  end
19
22
  end
20
- end
21
23
 
22
- def call method_sym, *args, &blk
23
- raise "Unsupported api call #{method_sym.inspect}" unless ApiMethods.include? method_sym.to_s
24
- exceptions = []
25
- @backends.each do |backend|
26
- if backend.respond_to? method_sym
27
- begin
28
- return backend.send(method_sym, @plist, *args, &blk)
29
- rescue LoadError
30
- exceptions << $!
31
- rescue
32
- exceptions << $!
24
+ # vv We also need a version of :call for matrix test harness vv
25
+
26
+ def call method_sym, *args, &blk
27
+ puts "in call"
28
+ puts "#{method_sym.inspect} #{args.inspect}"
29
+ raise "Unsupported api call #{method_sym.inspect}" unless ApiMethods.include? method_sym.to_s
30
+ exceptions = []
31
+ @backends.each do |backend|
32
+ if backend.respond_to? method_sym
33
+ begin
34
+ result = backend.send(method_sym, @plist, *args, &blk)
35
+ # puts "result = #{result.inspect}"
36
+ return result
37
+ # return backend.send(method_sym, @plist, *args, &blk)
38
+ rescue LoadError
39
+ exceptions << $!
40
+ rescue
41
+ exceptions << $!
42
+ end
43
+ end
44
+ if Config[:raise_any_failure] && exceptions.first
45
+ raise exceptions.first
33
46
  end
34
47
  end
35
- if Config[:raise_any_failure] && exceptions.first
36
- raise exceptions.first
37
- end
38
- end
39
- if exceptions.empty?
40
- raise "Plist4r: No backend found to handle method #{method_sym.inspect}. Could not execute method #{method_sym.inspect} on plist #{@plist.inspect}"
41
- else
42
- $stderr.puts "Couldn't execute method #{method_sym.inspect} on plist #{@plist.inspect}."
43
- exceptions.each do |e|
44
- $stderr.puts e.inspect
48
+ if exceptions.empty?
49
+ raise "Plist4r: No backend found to handle method #{method_sym.inspect}. Could not execute method #{method_sym.inspect} on plist #{@plist.inspect}"
50
+ else
51
+ # $stderr.puts "Failure(s) while executing method #{method_sym.inspect} on plist #{@plist}."
52
+ exceptions.each do |e|
53
+ $stderr.puts e.inspect
54
+ $stderr.puts e.backtrace.collect { |l| "\tfrom #{l}"}.join "\n"
55
+ end
56
+ # raise exceptions.first
57
+ raise "Failure(s) while executing method #{method_sym.inspect} on plist #{@plist}."
45
58
  end
46
- raise exceptions.first
47
59
  end
48
60
  end
49
61
  end
50
62
 
51
63
 
52
-
@@ -1,5 +1,5 @@
1
1
 
2
- require 'plist4r/backend'
2
+ require 'plist4r/backend_base'
3
3
 
4
4
  module Plist4r::Backend::Example
5
5
  class << self
@@ -1,7 +1,7 @@
1
1
 
2
- require 'plist4r/backend'
2
+ require 'plist4r/backend_base'
3
3
 
4
- module Plist4r::Backend::HamlXmlWriter
4
+ module Plist4r::Backend::Haml
5
5
  class << self
6
6
  def to_xml_haml
7
7
  @to_xml_haml ||= <<-'EOC'
@@ -66,7 +66,7 @@ EOC
66
66
  hash = plist.to_hash
67
67
  filename = plist.filename_path
68
68
  File.open(filename,'w') do |out|
69
- out << to_xml plist
69
+ out << to_xml(plist)
70
70
  end
71
71
  end
72
72
  end
@@ -1,7 +1,7 @@
1
1
 
2
- require 'plist4r/backend'
2
+ require 'plist4r/backend_base'
3
3
 
4
- module Plist4r::Backend::Libxml4rXmlReader
4
+ module Plist4r::Backend::Libxml4r
5
5
  class << self
6
6
  def tree_hash n
7
7
  hash = ::ActiveSupport::OrderedHash.new
@@ -49,6 +49,7 @@ module Plist4r::Backend::Libxml4rXmlReader
49
49
  end
50
50
 
51
51
  def parse_plist_xml string
52
+ require 'rubygems'
52
53
  require 'libxml4r'
53
54
  ::LibXML::XML.default_keep_blanks = false
54
55
  doc = string.to_xmldoc
@@ -60,10 +61,9 @@ module Plist4r::Backend::Libxml4rXmlReader
60
61
  def from_string plist, string
61
62
  plist_format = Plist4r.string_detect_format string
62
63
  raise "#{self} - cant convert string of format #{plist_format}" unless plist_format == :xml
63
-
64
64
  hash = parse_plist_xml string
65
65
  plist.import_hash hash
66
- plist.file_format = file_format
66
+ plist.file_format plist_format
67
67
  return plist
68
68
  end
69
69
 
@@ -1,4 +1,6 @@
1
1
 
2
+ require 'plist4r/backend_base'
3
+
2
4
  module Plist4r::Backend::Plutil
3
5
  # maybe this should be a helper, included by other backends
4
6
  class << self
@@ -1,5 +1,5 @@
1
1
 
2
- require 'plist4r/backend'
2
+ require 'plist4r/backend_base'
3
3
 
4
4
  module Plist4r::Backend::RubyCocoa
5
5
  class << self
@@ -103,7 +103,7 @@ EOC
103
103
  require 'tempfile'
104
104
  require 'plist4r/mixin/popen4'
105
105
 
106
- if @rb_script && File.exists?(@rb_script.path)
106
+ unless @rb_script && File.exists?(@rb_script.path)
107
107
  @rb_script ||= Tempfile.new("ruby_cocoa_wrapper.rb") do |o|
108
108
  o << ruby_cocoa_rb
109
109
  end
@@ -113,7 +113,7 @@ EOC
113
113
  cmd = @rb_script.path
114
114
  ordered_hash_rb = File.join(File.dirname(__FILE__), "..", "mixin", "ordered_hash.rb")
115
115
 
116
- pid, stdin, stdout, stderr = Popen4::popen4 [cmd, ordered_hash_rb]
116
+ pid, stdin, stdout, stderr = ::Plist4r::Popen4::popen4 cmd, ordered_hash_rb
117
117
 
118
118
  stdin.puts stdin_str
119
119
 
@@ -0,0 +1,3 @@
1
+
2
+ module Plist4r end
3
+ class Plist4r::Backend; end
@@ -1,18 +1,21 @@
1
1
 
2
2
  require 'plist4r/mixin/mixlib_config'
3
+ require 'plist4r/backend'
4
+ Dir.glob(File.dirname(__FILE__) + "/backend/**/*.rb").each {|b| require File.expand_path b}
3
5
 
4
- class Plist4r::Config
5
- extend Mixlib::Config
6
+ module Plist4r
7
+ class Config
8
+ extend Mixlib::Config
6
9
 
7
- backends [
8
- Plist4r::Backend::RubyCocoa,
9
- Plist4r::Backend::Haml,
10
- Plist4r::Backend::Libxml4r
11
- ]
10
+ backends [
11
+ ::Plist4r::Backend::RubyCocoa,
12
+ ::Plist4r::Backend::Haml,
13
+ ::Plist4r::Backend::Libxml4r
14
+ ]
12
15
 
13
- unsupported_keys true
14
- raise_any_failure false
15
- deafult_format :xml
16
- default_path nil
16
+ unsupported_keys true
17
+ raise_any_failure false
18
+ deafult_format :xml
19
+ default_path nil
20
+ end
17
21
  end
18
-
@@ -1,63 +1,65 @@
1
1
 
2
- require 'plist4r/mixins/ordered_hash'
2
+ require 'plist4r/mixin/ordered_hash'
3
3
 
4
- module Plst4r::DataMethods
4
+ module Plist4r
5
+ module DataMethods
5
6
 
6
- def classes_for_key_type
7
- {
8
- :string => [String],
9
- :bool => [TrueClass,FalseClass],
10
- :integer => [Fixnum],
11
- :array_of_strings => [Array],
12
- :hash_of_bools => [Hash],
13
- :hash => [Hash],
14
- :bool_or_string_or_array_of_strings => [TrueClass,FalseClass,String,Array]
15
- }
16
- end
7
+ def classes_for_key_type
8
+ {
9
+ :string => [String],
10
+ :bool => [TrueClass,FalseClass],
11
+ :integer => [Fixnum],
12
+ :array_of_strings => [Array],
13
+ :hash_of_bools => [Hash],
14
+ :hash => [Hash],
15
+ :bool_or_string_or_array_of_strings => [TrueClass,FalseClass,String,Array]
16
+ }
17
+ end
17
18
 
18
- def valid_keys
19
- {}
20
- end
19
+ def valid_keys
20
+ {}
21
+ end
21
22
 
22
- def method_missing method_symbol, *args, &blk
23
- puts "method_missing: #{method_symbol.inspect}, args: #{args.inspect}"
24
- valid_keys.each do |key_type, valid_keys_of_those_type|
25
- if valid_keys_of_those_type.include?(method_symbol.to_s.camelcase)
26
- puts "key_type = #{key_type}, method_symbol.to_s.camelcase = #{method_symbol.to_s.camelcase}, args = #{args.inspect}"
27
- return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
23
+ def method_missing method_symbol, *args, &blk
24
+ puts "method_missing: #{method_symbol.inspect}, args: #{args.inspect}"
25
+ valid_keys.each do |key_type, valid_keys_of_those_type|
26
+ if valid_keys_of_those_type.include?(method_symbol.to_s.camelcase)
27
+ puts "key_type = #{key_type}, method_symbol.to_s.camelcase = #{method_symbol.to_s.camelcase}, args = #{args.inspect}"
28
+ return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
29
+ end
28
30
  end
29
31
  end
30
- end
31
32
 
32
- def validate_value key_type, key, value
33
- unless classes_for_key_type[key_type].include? value.class
34
- raise "Key: #{key}, value: #{value.inspect} is of type #{value.class}. Should be: #{classes_for_key_type[key_type].join ", "}"
35
- end
36
- case key_type
37
- when :array_of_strings, :bool_or_string_or_array_of_strings
38
- if value.class == Array
39
- value.each_index do |i|
40
- unless value[i].class == String
41
- raise "Element: #{key}[#{i}], value: #{value[i].inspect} is of type #{value[i].class}. Should be: #{classes_for_key_type[:string].join ", "}"
33
+ def validate_value key_type, key, value
34
+ unless classes_for_key_type[key_type].include? value.class
35
+ raise "Key: #{key}, value: #{value.inspect} is of type #{value.class}. Should be: #{classes_for_key_type[key_type].join ", "}"
36
+ end
37
+ case key_type
38
+ when :array_of_strings, :bool_or_string_or_array_of_strings
39
+ if value.class == Array
40
+ value.each_index do |i|
41
+ unless value[i].class == String
42
+ raise "Element: #{key}[#{i}], value: #{value[i].inspect} is of type #{value[i].class}. Should be: #{classes_for_key_type[:string].join ", "}"
43
+ end
42
44
  end
43
45
  end
44
- end
45
- when :hash_of_bools
46
- value.each do |k,v|
47
- unless [TrueClass,FalseClass].include? v.class
48
- raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{classes_for_key_type[:bool].join ", "}"
46
+ when :hash_of_bools
47
+ value.each do |k,v|
48
+ unless [TrueClass,FalseClass].include? v.class
49
+ raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{classes_for_key_type[:bool].join ", "}"
50
+ end
49
51
  end
50
52
  end
51
53
  end
52
- end
53
54
 
54
- def set_or_return key_type, key, value=nil
55
- puts "#{method_name}, key_type: #{key_type.inspect}, value: #{value.inspect}"
56
- if value
57
- validate_value key_type, key, value unless key_type == nil
58
- @hash[key] = value
59
- else
60
- @orig[key]
55
+ def set_or_return key_type, key, value=nil
56
+ puts "#{method_name}, key_type: #{key_type.inspect}, value: #{value.inspect}"
57
+ if value
58
+ validate_value key_type, key, value unless key_type == nil
59
+ @hash[key] = value
60
+ else
61
+ @orig[key]
62
+ end
61
63
  end
62
64
  end
63
- end
65
+ end
@@ -1,193 +1,199 @@
1
1
 
2
-
3
- module Plist4r::Popen4
4
-
5
- # This is taken directly from Ara T Howard's Open4 library, and then
6
- # modified to suit the needs of Chef. Any bugs here are most likely
7
- # my own, and not Ara's.
8
- #
9
- # The original appears in external/open4.rb in its unmodified form.
10
- #
11
- # Thanks Ara!
12
- def popen4(cmd, args={}, &b)
2
+ require 'fcntl'
3
+ require 'etc'
4
+ require 'io/wait'
5
+
6
+ module Plist4r
7
+ module Popen4
8
+ class << self
9
+ # This is taken directly from Ara T Howard's Open4 library, and then
10
+ # modified to suit the needs of Chef. Any bugs here are most likely
11
+ # my own, and not Ara's.
12
+ #
13
+ # The original appears in external/open4.rb in its unmodified form.
14
+ #
15
+ # Thanks Ara!
16
+ def popen4(cmd, args={}, &b)
13
17
 
14
- # Waitlast - this is magic.
15
- #
16
- # Do we wait for the child process to die before we yield
17
- # to the block, or after? That is the magic of waitlast.
18
- #
19
- # By default, we are waiting before we yield the block.
20
- args[:waitlast] ||= false
18
+ # Waitlast - this is magic.
19
+ #
20
+ # Do we wait for the child process to die before we yield
21
+ # to the block, or after? That is the magic of waitlast.
22
+ #
23
+ # By default, we are waiting before we yield the block.
24
+ args[:waitlast] ||= false
21
25
 
22
- args[:user] ||= nil
23
- unless args[:user].kind_of?(Integer)
24
- args[:user] = Etc.getpwnam(args[:user]).uid if args[:user]
25
- end
26
- args[:group] ||= nil
27
- unless args[:group].kind_of?(Integer)
28
- args[:group] = Etc.getgrnam(args[:group]).gid if args[:group]
29
- end
30
- args[:environment] ||= {}
26
+ args[:user] ||= nil
27
+ unless args[:user].kind_of?(Integer)
28
+ args[:user] = Etc.getpwnam(args[:user]).uid if args[:user]
29
+ end
30
+ args[:group] ||= nil
31
+ unless args[:group].kind_of?(Integer)
32
+ args[:group] = Etc.getgrnam(args[:group]).gid if args[:group]
33
+ end
34
+ args[:environment] ||= {}
31
35
 
32
- # Default on C locale so parsing commands output can be done
33
- # independently of the node's default locale.
34
- # "LC_ALL" could be set to nil, in which case we also must ignore it.
35
- unless args[:environment].has_key?("LC_ALL")
36
- args[:environment]["LC_ALL"] = "C"
37
- end
36
+ # Default on C locale so parsing commands output can be done
37
+ # independently of the node's default locale.
38
+ # "LC_ALL" could be set to nil, in which case we also must ignore it.
39
+ unless args[:environment].has_key?("LC_ALL")
40
+ args[:environment]["LC_ALL"] = "C"
41
+ end
38
42
 
39
- pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
43
+ pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
40
44
 
41
- verbose = $VERBOSE
42
- begin
43
- $VERBOSE = nil
44
- ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
45
+ verbose = $VERBOSE
46
+ begin
47
+ $VERBOSE = nil
48
+ ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
45
49
 
46
- cid = fork {
47
- pw.last.close
48
- STDIN.reopen pw.first
49
- pw.first.close
50
+ cid = fork {
51
+ pw.last.close
52
+ STDIN.reopen pw.first
53
+ pw.first.close
50
54
 
51
- pr.first.close
52
- STDOUT.reopen pr.last
53
- pr.last.close
55
+ pr.first.close
56
+ STDOUT.reopen pr.last
57
+ pr.last.close
54
58
 
55
- pe.first.close
56
- STDERR.reopen pe.last
57
- pe.last.close
59
+ pe.first.close
60
+ STDERR.reopen pe.last
61
+ pe.last.close
58
62
 
59
- STDOUT.sync = STDERR.sync = true
63
+ STDOUT.sync = STDERR.sync = true
60
64
 
61
- if args[:group]
62
- Process.egid = args[:group]
63
- Process.gid = args[:group]
64
- end
65
+ if args[:group]
66
+ Process.egid = args[:group]
67
+ Process.gid = args[:group]
68
+ end
65
69
 
66
- if args[:user]
67
- Process.euid = args[:user]
68
- Process.uid = args[:user]
69
- end
70
+ if args[:user]
71
+ Process.euid = args[:user]
72
+ Process.uid = args[:user]
73
+ end
70
74
 
71
- args[:environment].each do |key,value|
72
- ENV[key] = value
73
- end
75
+ args[:environment].each do |key,value|
76
+ ENV[key] = value
77
+ end
74
78
 
75
- if args[:umask]
76
- umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777)
77
- File.umask(umask)
78
- end
79
+ if args[:umask]
80
+ umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777)
81
+ File.umask(umask)
82
+ end
79
83
 
80
- begin
81
- if cmd.kind_of?(Array)
82
- exec(*cmd)
83
- else
84
- exec(cmd)
85
- end
86
- raise 'forty-two'
87
- rescue Exception => e
88
- Marshal.dump(e, ps.last)
89
- ps.last.flush
84
+ begin
85
+ if cmd.kind_of?(Array)
86
+ exec(*cmd)
87
+ else
88
+ exec(cmd)
89
+ end
90
+ raise 'forty-two'
91
+ rescue Exception => e
92
+ Marshal.dump(e, ps.last)
93
+ ps.last.flush
94
+ end
95
+ ps.last.close unless (ps.last.closed?)
96
+ exit!
97
+ }
98
+ ensure
99
+ $VERBOSE = verbose
90
100
  end
91
- ps.last.close unless (ps.last.closed?)
92
- exit!
93
- }
94
- ensure
95
- $VERBOSE = verbose
96
- end
97
-
98
- [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
99
101
 
100
- begin
101
- e = Marshal.load ps.first
102
- raise(Exception === e ? e : "unknown failure!")
103
- rescue EOFError # If we get an EOF error, then the exec was successful
104
- 42
105
- ensure
106
- ps.first.close
107
- end
108
-
109
- pw.last.sync = true
102
+ [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
110
103
 
111
- pi = [pw.last, pr.first, pe.first]
104
+ begin
105
+ e = Marshal.load ps.first
106
+ raise(Exception === e ? e : "unknown failure!")
107
+ rescue EOFError # If we get an EOF error, then the exec was successful
108
+ 42
109
+ ensure
110
+ ps.first.close
111
+ end
112
112
 
113
- if b
114
- begin
115
- if args[:waitlast]
116
- b[cid, *pi]
117
- # send EOF so that if the child process is reading from STDIN
118
- # it will actually finish up and exit
119
- pi[0].close_write
120
- Process.waitpid2(cid).last
121
- else
122
- # This took some doing.
123
- # The trick here is to close STDIN
124
- # Then set our end of the childs pipes to be O_NONBLOCK
125
- # Then wait for the child to die, which means any IO it
126
- # wants to do must be done - it's dead. If it isn't,
127
- # it's because something totally skanky is happening,
128
- # and we don't care.
129
- o = StringIO.new
130
- e = StringIO.new
131
-
132
- pi[0].close
113
+ pw.last.sync = true
114
+
115
+ pi = [pw.last, pr.first, pe.first]
116
+
117
+ if b
118
+ begin
119
+ if args[:waitlast]
120
+ b[cid, *pi]
121
+ # send EOF so that if the child process is reading from STDIN
122
+ # it will actually finish up and exit
123
+ pi[0].close_write
124
+ Process.waitpid2(cid).last
125
+ else
126
+ # This took some doing.
127
+ # The trick here is to close STDIN
128
+ # Then set our end of the childs pipes to be O_NONBLOCK
129
+ # Then wait for the child to die, which means any IO it
130
+ # wants to do must be done - it's dead. If it isn't,
131
+ # it's because something totally skanky is happening,
132
+ # and we don't care.
133
+ o = StringIO.new
134
+ e = StringIO.new
135
+
136
+ pi[0].close
133
137
 
134
- stdout = pi[1]
135
- stderr = pi[2]
138
+ stdout = pi[1]
139
+ stderr = pi[2]
136
140
 
137
- stdout.sync = true
138
- stderr.sync = true
141
+ stdout.sync = true
142
+ stderr.sync = true
139
143
 
140
- stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
141
- stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
144
+ stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
145
+ stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
142
146
 
143
- stdout_finished = false
144
- stderr_finished = false
147
+ stdout_finished = false
148
+ stderr_finished = false
145
149
 
146
- results = nil
147
-
148
- while !stdout_finished || !stderr_finished
149
- begin
150
- channels_to_watch = []
151
- channels_to_watch << stdout if !stdout_finished
152
- channels_to_watch << stderr if !stderr_finished
153
- ready = IO.select(channels_to_watch, nil, nil, 1.0)
154
- rescue Errno::EAGAIN
155
- ensure
156
- results = Process.waitpid2(cid, Process::WNOHANG)
157
- if results
158
- stdout_finished = true
159
- stderr_finished = true
160
- end
161
- end
162
-
163
- if ready && ready.first.include?(stdout)
164
- line = results ? stdout.gets(nil) : stdout.gets
165
- if line
166
- o.write(line)
167
- else
168
- stdout_finished = true
169
- end
170
- end
171
- if ready && ready.first.include?(stderr)
172
- line = results ? stderr.gets(nil) : stderr.gets
173
- if line
174
- e.write(line)
175
- else
176
- stderr_finished = true
150
+ results = nil
151
+
152
+ while !stdout_finished || !stderr_finished
153
+ begin
154
+ channels_to_watch = []
155
+ channels_to_watch << stdout if !stdout_finished
156
+ channels_to_watch << stderr if !stderr_finished
157
+ ready = IO.select(channels_to_watch, nil, nil, 1.0)
158
+ rescue Errno::EAGAIN
159
+ ensure
160
+ results = Process.waitpid2(cid, Process::WNOHANG)
161
+ if results
162
+ stdout_finished = true
163
+ stderr_finished = true
164
+ end
165
+ end
166
+
167
+ if ready && ready.first.include?(stdout)
168
+ line = results ? stdout.gets(nil) : stdout.gets
169
+ if line
170
+ o.write(line)
171
+ else
172
+ stdout_finished = true
173
+ end
174
+ end
175
+ if ready && ready.first.include?(stderr)
176
+ line = results ? stderr.gets(nil) : stderr.gets
177
+ if line
178
+ e.write(line)
179
+ else
180
+ stderr_finished = true
181
+ end
182
+ end
177
183
  end
184
+ results = Process.waitpid2(cid) unless results
185
+ o.rewind
186
+ e.rewind
187
+ b[cid, pi[0], o, e]
188
+ results.last
178
189
  end
190
+ ensure
191
+ pi.each{|fd| fd.close unless fd.closed?}
179
192
  end
180
- results = Process.waitpid2(cid) unless results
181
- o.rewind
182
- e.rewind
183
- b[cid, pi[0], o, e]
184
- results.last
193
+ else
194
+ [cid, pw.last, pr.first, pe.first]
185
195
  end
186
- ensure
187
- pi.each{|fd| fd.close unless fd.closed?}
188
196
  end
189
- else
190
- [cid, pw.last, pr.first, pe.first]
191
197
  end
192
198
  end
193
199
  end