brew-launchd 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,189 @@
1
+
2
+ module Launchr
3
+ module ActiveSupport
4
+ # <tt></tt>
5
+ # ActiveSupport::OrderedHash
6
+ #
7
+ # Copyright (c) 2005 David Hansson,
8
+ # Copyright (c) 2007 Mauricio Fernandez, Sam Stephenson
9
+ # Copyright (c) 2008 Steve Purcell, Josh Peek
10
+ # Copyright (c) 2009 Christoffer Sawicki
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining
13
+ # a copy of this software and associated documentation files (the
14
+ # "Software"), to deal in the Software without restriction, including
15
+ # without limitation the rights to use, copy, modify, merge, publish,
16
+ # distribute, sublicense, and/or sell copies of the Software, and to
17
+ # permit persons to whom the Software is furnished to do so, subject to
18
+ # the following conditions:
19
+ #
20
+ # The above copyright notice and this permission notice shall be
21
+ # included in all copies or substantial portions of the Software.
22
+ #
23
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
+ #
31
+ class OrderedHash < Hash
32
+ def initialize(*args, &block)
33
+ super
34
+ @keys = []
35
+ end
36
+
37
+ def self.[](*args)
38
+ ordered_hash = new
39
+
40
+ if (args.length == 1 && args.first.is_a?(Array))
41
+ args.first.each do |key_value_pair|
42
+ next unless (key_value_pair.is_a?(Array))
43
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
44
+ end
45
+
46
+ return ordered_hash
47
+ end
48
+
49
+ unless (args.size % 2 == 0)
50
+ raise ArgumentError.new("odd number of arguments for Hash")
51
+ end
52
+
53
+ args.each_with_index do |val, ind|
54
+ next if (ind % 2 != 0)
55
+ ordered_hash[val] = args[ind + 1]
56
+ end
57
+
58
+ ordered_hash
59
+ end
60
+
61
+ def initialize_copy(other)
62
+ super
63
+ # make a deep copy of keys
64
+ @keys = other.keys
65
+ end
66
+
67
+ def store(key, value)
68
+ @keys << key if !has_key?(key)
69
+ super
70
+ end
71
+
72
+ def []=(key, value)
73
+ @keys << key if !has_key?(key)
74
+ super
75
+ end
76
+
77
+ def delete(key)
78
+ if has_key? key
79
+ index = @keys.index(key)
80
+ @keys.delete_at index
81
+ end
82
+ super
83
+ end
84
+
85
+ def delete_if
86
+ super
87
+ sync_keys!
88
+ self
89
+ end
90
+
91
+ def reject!
92
+ super
93
+ sync_keys!
94
+ self
95
+ end
96
+
97
+ def reject(&block)
98
+ dup.reject!(&block)
99
+ end
100
+
101
+ def keys
102
+ (@keys || []).dup
103
+ end
104
+
105
+ def values
106
+ @keys.collect { |key| self[key] }
107
+ end
108
+
109
+ def to_hash
110
+ self
111
+ end
112
+
113
+ def to_a
114
+ @keys.map { |key| [ key, self[key] ] }
115
+ end
116
+
117
+ def each_key
118
+ @keys.each { |key| yield key }
119
+ end
120
+
121
+ def each_value
122
+ @keys.each { |key| yield self[key]}
123
+ end
124
+
125
+ def each
126
+ @keys.each {|key| yield [key, self[key]]}
127
+ end
128
+
129
+ alias_method :each_pair, :each
130
+
131
+ def clear
132
+ super
133
+ @keys.clear
134
+ self
135
+ end
136
+
137
+ def shift
138
+ k = @keys.first
139
+ v = delete(k)
140
+ [k, v]
141
+ end
142
+
143
+ def merge!(other_hash)
144
+ other_hash.each {|k,v| self[k] = v }
145
+ self
146
+ end
147
+
148
+ def merge(other_hash)
149
+ dup.merge!(other_hash)
150
+ end
151
+
152
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
153
+ def replace(other)
154
+ super
155
+ @keys = other.keys
156
+ self
157
+ end
158
+
159
+ def inspect
160
+ "#<OrderedHash #{super}>"
161
+ end
162
+
163
+ private
164
+
165
+ def sync_keys!
166
+ @keys.delete_if {|k| !has_key?(k)}
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ module Launchr
173
+ if RUBY_VERSION >= '1.9'
174
+ # Inheritance
175
+ # Ruby 1.9 < Hash
176
+ # Ruby 1.8 < ActiveSupport::OrderedHash
177
+ class OrderedHash < ::Hash
178
+ end
179
+ else
180
+ # Inheritance
181
+ # Ruby 1.9 < Hash
182
+ # Ruby 1.8 < ActiveSupport::OrderedHash
183
+ class OrderedHash < Launchr::ActiveSupport::OrderedHash
184
+ end
185
+ end
186
+ end
187
+
188
+
189
+
@@ -0,0 +1,219 @@
1
+
2
+ require 'fcntl'
3
+ require 'etc'
4
+ require 'io/wait'
5
+
6
+ module Launchr
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 the Chef project.
11
+ #
12
+ # http://github.com/ahoward/open4
13
+ #
14
+ # http://www.ruby-forum.com/topic/54593
15
+ #
16
+ # Don't use the "Block form" calling method. It screws up on the pipes IO.
17
+ #
18
+ # Use "Simple form", always. Simple form = more robust IO handling.
19
+ #
20
+ # @example Simple form
21
+ # def popen4_exec stdin_str, cmd, *args
22
+ # require 'plist4r/mixin/popen4'
23
+ #
24
+ # pid, stdin, stdout, stderr = ::Plist4r::Popen4::popen4 [cmd, *args]
25
+ #
26
+ # stdin.puts stdin_str
27
+ #
28
+ # stdin.close
29
+ # ignored, status = Process::waitpid2 pid
30
+ #
31
+ # stdout_result = stdout.read.strip
32
+ # stderr_result = stderr.read.strip
33
+ #
34
+ # return [cmd, status, stdout_result, stderr_result]
35
+ # end
36
+ def popen4(cmd, args={}, &b)
37
+
38
+ # Waitlast - this is magic.
39
+ #
40
+ # Do we wait for the child process to die before we yield
41
+ # to the block, or after? That is the magic of waitlast.
42
+ #
43
+ # By default, we are waiting before we yield the block.
44
+ args[:waitlast] ||= false
45
+
46
+ args[:user] ||= nil
47
+ unless args[:user].kind_of?(Integer)
48
+ args[:user] = Etc.getpwnam(args[:user]).uid if args[:user]
49
+ end
50
+ args[:group] ||= nil
51
+ unless args[:group].kind_of?(Integer)
52
+ args[:group] = Etc.getgrnam(args[:group]).gid if args[:group]
53
+ end
54
+ args[:environment] ||= {}
55
+
56
+ # Default on C locale so parsing commands output can be done
57
+ # independently of the node's default locale.
58
+ # "LC_ALL" could be set to nil, in which case we also must ignore it.
59
+ unless args[:environment].has_key?("LC_ALL")
60
+ args[:environment]["LC_ALL"] = "C"
61
+ end
62
+
63
+ pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
64
+
65
+ verbose = $VERBOSE
66
+ begin
67
+ $VERBOSE = nil
68
+ ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
69
+
70
+ cid = fork {
71
+ pw.last.close
72
+ STDIN.reopen pw.first
73
+ pw.first.close
74
+
75
+ pr.first.close
76
+ STDOUT.reopen pr.last
77
+ pr.last.close
78
+
79
+ pe.first.close
80
+ STDERR.reopen pe.last
81
+ pe.last.close
82
+
83
+ STDOUT.sync = STDERR.sync = true
84
+
85
+ if args[:group]
86
+ Process.egid = args[:group]
87
+ Process.gid = args[:group]
88
+ end
89
+
90
+ if args[:user]
91
+ Process.euid = args[:user]
92
+ Process.uid = args[:user]
93
+ end
94
+
95
+ args[:environment].each do |key,value|
96
+ ENV[key] = value
97
+ end
98
+
99
+ if args[:umask]
100
+ umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777)
101
+ File.umask(umask)
102
+ end
103
+
104
+ begin
105
+ if cmd.kind_of?(Array)
106
+ exec(*cmd)
107
+ else
108
+ exec(cmd)
109
+ end
110
+ raise 'forty-two'
111
+ rescue Exception => e
112
+ Marshal.dump(e, ps.last)
113
+ ps.last.flush
114
+ end
115
+ ps.last.close unless (ps.last.closed?)
116
+ exit!
117
+ }
118
+ ensure
119
+ $VERBOSE = verbose
120
+ end
121
+
122
+ [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
123
+
124
+ begin
125
+ e = Marshal.load ps.first
126
+ raise(Exception === e ? e : "unknown failure!")
127
+ rescue EOFError # If we get an EOF error, then the exec was successful
128
+ 42
129
+ ensure
130
+ ps.first.close
131
+ end
132
+
133
+ pw.last.sync = true
134
+
135
+ pi = [pw.last, pr.first, pe.first]
136
+
137
+ if b
138
+ begin
139
+ if args[:waitlast]
140
+ b[cid, *pi]
141
+ # send EOF so that if the child process is reading from STDIN
142
+ # it will actually finish up and exit
143
+ pi[0].close_write
144
+ Process.waitpid2(cid).last
145
+ else
146
+ # This took some doing.
147
+ # The trick here is to close STDIN
148
+ # Then set our end of the childs pipes to be O_NONBLOCK
149
+ # Then wait for the child to die, which means any IO it
150
+ # wants to do must be done - it's dead. If it isn't,
151
+ # it's because something totally skanky is happening,
152
+ # and we don't care.
153
+ o = StringIO.new
154
+ e = StringIO.new
155
+
156
+ pi[0].close
157
+
158
+ stdout = pi[1]
159
+ stderr = pi[2]
160
+
161
+ stdout.sync = true
162
+ stderr.sync = true
163
+
164
+ stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
165
+ stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
166
+
167
+ stdout_finished = false
168
+ stderr_finished = false
169
+
170
+ results = nil
171
+
172
+ while !stdout_finished || !stderr_finished
173
+ begin
174
+ channels_to_watch = []
175
+ channels_to_watch << stdout if !stdout_finished
176
+ channels_to_watch << stderr if !stderr_finished
177
+ ready = IO.select(channels_to_watch, nil, nil, 1.0)
178
+ rescue Errno::EAGAIN
179
+ ensure
180
+ results = Process.waitpid2(cid, Process::WNOHANG)
181
+ if results
182
+ stdout_finished = true
183
+ stderr_finished = true
184
+ end
185
+ end
186
+
187
+ if ready && ready.first.include?(stdout)
188
+ line = results ? stdout.gets(nil) : stdout.gets
189
+ if line
190
+ o.write(line)
191
+ else
192
+ stdout_finished = true
193
+ end
194
+ end
195
+ if ready && ready.first.include?(stderr)
196
+ line = results ? stderr.gets(nil) : stderr.gets
197
+ if line
198
+ e.write(line)
199
+ else
200
+ stderr_finished = true
201
+ end
202
+ end
203
+ end
204
+ results = Process.waitpid2(cid) unless results
205
+ o.rewind
206
+ e.rewind
207
+ b[cid, pi[0], o, e]
208
+ results.last
209
+ end
210
+ ensure
211
+ pi.each{|fd| fd.close unless fd.closed?}
212
+ end
213
+ else
214
+ [cid, pw.last, pr.first, pe.first]
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,106 @@
1
+
2
+ require 'launchr'
3
+ require 'pathname'
4
+
5
+ module Launchr
6
+ module Path
7
+ class << self
8
+ def user_launchdaemons
9
+ Pathname.new("~/Library/LaunchAgents").expand_path
10
+ end
11
+
12
+ def boot_launchdaemons
13
+ Pathname.new("/Library/LaunchDaemons")
14
+ end
15
+
16
+ def brew_launchdaemons
17
+ if homebrew_prefix
18
+ homebrew_prefix+"Library/LaunchDaemons"
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ def launchr_default_boot
25
+ Pathname.new("~/Library/Preferences/#{Launchr.label}.default-boot").expand_path
26
+ end
27
+
28
+ def launchr_bin
29
+ Pathname.new(LAUNCHR_BIN).expand_path
30
+ end
31
+
32
+ def launchr_root
33
+ launchr_bin.dirname.parent
34
+ end
35
+
36
+ def launchr_version
37
+ launchr_root+"VERSION"
38
+ end
39
+
40
+ def cwd_homebrew_prefix
41
+ case @cwd_homebrew_prefix
42
+ when nil
43
+ Pathname.pwd.ascend do |path|
44
+ if (path+"/Library/Homebrew").exist?
45
+ @cwd_homebrew_prefix = path
46
+ break
47
+ end
48
+ end
49
+ @cwd_homebrew_prefix ||= false
50
+ else
51
+ @cwd_homebrew_prefix
52
+ end
53
+ end
54
+
55
+ # Same as Kernel.const_defined?, except it works for global constants
56
+ def global_const_defined? string
57
+ begin
58
+ eval string
59
+ true
60
+ rescue NameError
61
+ false
62
+ end
63
+ end
64
+
65
+ def bin_homebrew_prefix
66
+ case @bin_homebrew_prefix
67
+ when nil
68
+ if global_const_defined?("HOMEBREW_PREFIX")
69
+ @bin_homebrew_prefix = HOMEBREW_PREFIX
70
+ elsif launchr_root.include?("Cellar/launchr")
71
+ @bin_homebrew_prefix = Pathname.new(launchr_root.to_s.gsub(/\/Cellar\/launchr.*$/,""))
72
+ end
73
+
74
+ @bin_homebrew_prefix ||= false
75
+ else
76
+ @bin_homebrew_prefix
77
+ end
78
+ end
79
+
80
+ def homebrew_prefix
81
+ # cwd_homebrew_prefix || bin_homebrew_prefix
82
+ bin_homebrew_prefix
83
+ end
84
+
85
+ def chown_down path
86
+ if Launchr.superuser?
87
+ FileUtils.chown_R Launchr.user, Launchr.group, path.to_s
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+