launch 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +1 -0
- data/.autotest +8 -0
- data/.gemtest +0 -0
- data/History.txt +5 -0
- data/Manifest.txt +11 -0
- data/README.txt +72 -0
- data/Rakefile +37 -0
- data/ext/launch/extconf.rb +6 -0
- data/ext/launch/launch.c +355 -0
- data/lib/launch.rb +86 -0
- data/lib/launch/webrick.rb +78 -0
- data/sample/echo.rb +107 -0
- data/test/test_launch.rb +55 -0
- metadata +153 -0
- metadata.gz.sig +2 -0
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
d�(4�äQIm�v��H�������Pp6f��#��P�Ob�JњL��.t�K2>���;��j��[�<v�I?7v���̸$D{C<���&7۲���L��M[WO�� �����ԋkU�)X^)?SƋ��6s'K,ǝ�o~D�ub��PN}�l���(�]/��7��t�|vy�Yr��3N��:����)�H}�������;dS��a���ǵ���?�r`'��s`@�un�+��A}b����J|%[�U
|
data/.autotest
ADDED
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
= launch
|
2
|
+
|
3
|
+
* https://github.com/drbrain/launch
|
4
|
+
* http://docs.seattlerb.org/launch
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
Launch allows agents and daemons launched by launchd to retrieve their list of
|
9
|
+
sockets. Launchd is an open source framework for launching and managing
|
10
|
+
daemons, programs and scripts provided by Apple.
|
11
|
+
|
12
|
+
== FEATURES/PROBLEMS:
|
13
|
+
|
14
|
+
* Provides the Launch module for easy integration with existing programs
|
15
|
+
* Allows on-demand execution of ruby programs through launchd
|
16
|
+
|
17
|
+
== SYNOPSIS:
|
18
|
+
|
19
|
+
require 'launch'
|
20
|
+
|
21
|
+
class MyDaemon
|
22
|
+
def initialize
|
23
|
+
launch_checkin
|
24
|
+
launch_sockets('MyDaemonSocket', TCPServer).each do |server|
|
25
|
+
# handle requests, see sample/echo.rb
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
MyDaemon.new
|
31
|
+
|
32
|
+
== REQUIREMENTS:
|
33
|
+
|
34
|
+
* An installed launchd
|
35
|
+
|
36
|
+
== INSTALL:
|
37
|
+
|
38
|
+
gem install launch
|
39
|
+
|
40
|
+
== DEVELOPERS:
|
41
|
+
|
42
|
+
After checking out the source, run:
|
43
|
+
|
44
|
+
$ rake newb
|
45
|
+
|
46
|
+
This task will install any missing dependencies, run the tests/specs,
|
47
|
+
and generate the RDoc.
|
48
|
+
|
49
|
+
== LICENSE:
|
50
|
+
|
51
|
+
(The MIT License)
|
52
|
+
|
53
|
+
Copyright (c) 2011 Eric Hodel
|
54
|
+
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
56
|
+
a copy of this software and associated documentation files (the
|
57
|
+
'Software'), to deal in the Software without restriction, including
|
58
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
59
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
60
|
+
permit persons to whom the Software is furnished to do so, subject to
|
61
|
+
the following conditions:
|
62
|
+
|
63
|
+
The above copyright notice and this permission notice shall be
|
64
|
+
included in all copies or substantial portions of the Software.
|
65
|
+
|
66
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
69
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
70
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
71
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
72
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
task :default => :compile
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'hoe'
|
7
|
+
|
8
|
+
Hoe.plugin :minitest
|
9
|
+
Hoe.plugin :git
|
10
|
+
|
11
|
+
hoe = Hoe.spec 'launch' do
|
12
|
+
developer 'Eric Hodel', 'drbrain@segment7.net'
|
13
|
+
|
14
|
+
rdoc_locations << 'docs.seattlerb.org:/data/www/docs.seattlerb.org/launch/'
|
15
|
+
|
16
|
+
extra_dev_deps << ['rake-compiler', '~> 0.7']
|
17
|
+
self.spec_extras[:extensions] = %w[ext/launch/extconf.rb]
|
18
|
+
|
19
|
+
self.spec_extras[:required_ruby_version] = '>= 1.9.2'
|
20
|
+
|
21
|
+
self.clean_globs = %[
|
22
|
+
lib/launch/launch.bundle
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
gem 'rake-compiler', '~> 0.7'
|
28
|
+
require 'rake/extensiontask'
|
29
|
+
|
30
|
+
Rake::ExtensionTask.new hoe.name, hoe.spec do |ext|
|
31
|
+
ext.lib_dir = File.join 'lib', 'launch'
|
32
|
+
end
|
33
|
+
rescue Gem::LoadError
|
34
|
+
warn 'You need to rake newb'
|
35
|
+
end
|
36
|
+
|
37
|
+
# vim: syntax=ruby
|
data/ext/launch/launch.c
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <launch.h>
|
3
|
+
#include <errno.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
VALUE mLaunch;
|
7
|
+
VALUE mLaunchKey;
|
8
|
+
VALUE mLaunchJobKey;
|
9
|
+
VALUE mLaunchSocket;
|
10
|
+
VALUE mLaunchJobPolicy;
|
11
|
+
VALUE mLaunchData;
|
12
|
+
VALUE cLaunchError;
|
13
|
+
|
14
|
+
static VALUE launch_data_to_ruby(launch_data_t);
|
15
|
+
|
16
|
+
static void
|
17
|
+
launch_dict_iterator(launch_data_t item, const char * key, void * hash) {
|
18
|
+
rb_hash_aset((VALUE)hash, rb_str_new2(key), launch_data_to_ruby(item));
|
19
|
+
}
|
20
|
+
|
21
|
+
static VALUE
|
22
|
+
launch_data_to_ruby(launch_data_t item) {
|
23
|
+
VALUE out = Qnil;
|
24
|
+
launch_data_t temp = NULL;
|
25
|
+
launch_data_type_t item_type = launch_data_get_type(item);
|
26
|
+
int i = 0;
|
27
|
+
size_t length = 0;
|
28
|
+
|
29
|
+
switch(item_type) {
|
30
|
+
case LAUNCH_DATA_DICTIONARY:
|
31
|
+
out = rb_hash_new();
|
32
|
+
|
33
|
+
launch_data_dict_iterate(item, launch_dict_iterator, (void *)out);
|
34
|
+
|
35
|
+
break;
|
36
|
+
case LAUNCH_DATA_ARRAY:
|
37
|
+
length = launch_data_array_get_count(item);
|
38
|
+
out = rb_ary_new2(length);
|
39
|
+
|
40
|
+
for (i = 0; i < length; i++) {
|
41
|
+
temp = launch_data_array_get_index(item, i);
|
42
|
+
rb_ary_store(out, i, launch_data_to_ruby(temp));
|
43
|
+
}
|
44
|
+
|
45
|
+
break;
|
46
|
+
case LAUNCH_DATA_FD:
|
47
|
+
out = INT2NUM(launch_data_get_fd(item));
|
48
|
+
break;
|
49
|
+
case LAUNCH_DATA_INTEGER:
|
50
|
+
out = LONG2NUM(launch_data_get_integer(item));
|
51
|
+
break;
|
52
|
+
case LAUNCH_DATA_REAL:
|
53
|
+
out = DBL2NUM(launch_data_get_real(item));
|
54
|
+
break;
|
55
|
+
case LAUNCH_DATA_BOOL:
|
56
|
+
out = launch_data_get_bool(item) == TRUE ? Qtrue : Qfalse;
|
57
|
+
break;
|
58
|
+
case LAUNCH_DATA_STRING:
|
59
|
+
out = rb_str_new2(launch_data_get_string(item));
|
60
|
+
break;
|
61
|
+
case LAUNCH_DATA_OPAQUE:
|
62
|
+
out = rb_str_new(launch_data_get_opaque(item),
|
63
|
+
launch_data_get_opaque_size(item));
|
64
|
+
break;
|
65
|
+
case LAUNCH_DATA_ERRNO:
|
66
|
+
out = INT2NUM(launch_data_get_errno(item));
|
67
|
+
break;
|
68
|
+
case LAUNCH_DATA_MACHPORT:
|
69
|
+
break;
|
70
|
+
default:
|
71
|
+
rb_raise(cLaunchError, "unknown item type %d", item_type);
|
72
|
+
}
|
73
|
+
|
74
|
+
return out;
|
75
|
+
}
|
76
|
+
|
77
|
+
/*
|
78
|
+
* call-seq:
|
79
|
+
* launch_message(Launch::Key::CHECKIN) # => response
|
80
|
+
*
|
81
|
+
* launch_message wraps launch(3)'s launch_msg function. The argument is a
|
82
|
+
* message to send launchd from Launch::Key. Please use launch_checkin
|
83
|
+
* and launch_sockets instead of this method.
|
84
|
+
*
|
85
|
+
* The response from launchd is converted to a ruby structure and freed
|
86
|
+
* (usually a Hash). Currently the following data types in the response are
|
87
|
+
* indistinguishable in the ruby structure:
|
88
|
+
*
|
89
|
+
* * STRING and OPAQUE
|
90
|
+
* * INTEGER, FD and ERRNO
|
91
|
+
*
|
92
|
+
* Additionally, MACHPORT is ignored.
|
93
|
+
*
|
94
|
+
* If there was a failure to retrieve checkin data an error will be raised.
|
95
|
+
*/
|
96
|
+
static VALUE
|
97
|
+
message(VALUE self, VALUE message) {
|
98
|
+
VALUE out, tmp;
|
99
|
+
launch_data_t send, response;
|
100
|
+
launch_data_type_t response_type;
|
101
|
+
|
102
|
+
message = rb_str_to_str(message);
|
103
|
+
|
104
|
+
send = launch_data_new_string(StringValueCStr(message));
|
105
|
+
|
106
|
+
if (send == NULL) {
|
107
|
+
tmp = rb_inspect(message);
|
108
|
+
rb_raise(cLaunchError, "unable to create message %s",
|
109
|
+
StringValueCStr(tmp));
|
110
|
+
}
|
111
|
+
|
112
|
+
response = launch_msg(send);
|
113
|
+
|
114
|
+
if (response == NULL)
|
115
|
+
rb_sys_fail("launch_msg");
|
116
|
+
|
117
|
+
response_type = launch_data_get_type(response);
|
118
|
+
|
119
|
+
if (response_type == LAUNCH_DATA_ERRNO) {
|
120
|
+
errno = launch_data_get_errno(response);
|
121
|
+
rb_sys_fail("launch_msg");
|
122
|
+
}
|
123
|
+
|
124
|
+
out = launch_data_to_ruby(response);
|
125
|
+
|
126
|
+
launch_data_free(response);
|
127
|
+
|
128
|
+
return out;
|
129
|
+
}
|
130
|
+
|
131
|
+
void
|
132
|
+
Init_launch() {
|
133
|
+
mLaunch = rb_define_module("Launch");
|
134
|
+
cLaunchError = rb_define_class_under(mLaunch, "Error", rb_eRuntimeError);
|
135
|
+
|
136
|
+
rb_define_method(mLaunch, "launch_message", message, 1);
|
137
|
+
|
138
|
+
rb_const_set(mLaunch, rb_intern("JOBINETDCOMPATIBILITY_WAIT"),
|
139
|
+
rb_str_new2(LAUNCH_JOBINETDCOMPATIBILITY_WAIT));
|
140
|
+
|
141
|
+
/*
|
142
|
+
* Launch::Key holds launch message types
|
143
|
+
*/
|
144
|
+
mLaunchKey = rb_define_module_under(mLaunch, "Key");
|
145
|
+
rb_const_set(mLaunchKey, rb_intern("SUBMITJOB"),
|
146
|
+
rb_str_new2(LAUNCH_KEY_SUBMITJOB));
|
147
|
+
rb_const_set(mLaunchKey, rb_intern("REMOVEJOB"),
|
148
|
+
rb_str_new2(LAUNCH_KEY_REMOVEJOB));
|
149
|
+
rb_const_set(mLaunchKey, rb_intern("STARTJOB"),
|
150
|
+
rb_str_new2(LAUNCH_KEY_STARTJOB));
|
151
|
+
rb_const_set(mLaunchKey, rb_intern("STOPJOB"),
|
152
|
+
rb_str_new2(LAUNCH_KEY_STOPJOB));
|
153
|
+
rb_const_set(mLaunchKey, rb_intern("GETJOB"),
|
154
|
+
rb_str_new2(LAUNCH_KEY_GETJOB));
|
155
|
+
rb_const_set(mLaunchKey, rb_intern("GETJOBS"),
|
156
|
+
rb_str_new2(LAUNCH_KEY_GETJOBS));
|
157
|
+
rb_const_set(mLaunchKey, rb_intern("CHECKIN"),
|
158
|
+
rb_str_new2(LAUNCH_KEY_CHECKIN));
|
159
|
+
|
160
|
+
/*
|
161
|
+
* Launch::JobKey holds various keys returned in a message response
|
162
|
+
*/
|
163
|
+
mLaunchJobKey = rb_define_module_under(mLaunch, "JobKey");
|
164
|
+
rb_const_set(mLaunchJobKey, rb_intern("LABEL"),
|
165
|
+
rb_str_new2(LAUNCH_JOBKEY_LABEL));
|
166
|
+
rb_const_set(mLaunchJobKey, rb_intern("DISABLED"),
|
167
|
+
rb_str_new2(LAUNCH_JOBKEY_DISABLED));
|
168
|
+
rb_const_set(mLaunchJobKey, rb_intern("USERNAME"),
|
169
|
+
rb_str_new2(LAUNCH_JOBKEY_USERNAME));
|
170
|
+
rb_const_set(mLaunchJobKey, rb_intern("GROUPNAME"),
|
171
|
+
rb_str_new2(LAUNCH_JOBKEY_GROUPNAME));
|
172
|
+
rb_const_set(mLaunchJobKey, rb_intern("TIMEOUT"),
|
173
|
+
rb_str_new2(LAUNCH_JOBKEY_TIMEOUT));
|
174
|
+
rb_const_set(mLaunchJobKey, rb_intern("EXITTIMEOUT"),
|
175
|
+
rb_str_new2(LAUNCH_JOBKEY_EXITTIMEOUT));
|
176
|
+
rb_const_set(mLaunchJobKey, rb_intern("INITGROUPS"),
|
177
|
+
rb_str_new2(LAUNCH_JOBKEY_INITGROUPS));
|
178
|
+
rb_const_set(mLaunchJobKey, rb_intern("SOCKETS"),
|
179
|
+
rb_str_new2(LAUNCH_JOBKEY_SOCKETS));
|
180
|
+
rb_const_set(mLaunchJobKey, rb_intern("MACHSERVICES"),
|
181
|
+
rb_str_new2(LAUNCH_JOBKEY_MACHSERVICES));
|
182
|
+
rb_const_set(mLaunchJobKey, rb_intern("MACHSERVICELOOKUPPOLICIES"),
|
183
|
+
rb_str_new2(LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES));
|
184
|
+
rb_const_set(mLaunchJobKey, rb_intern("INETDCOMPATIBILITY"),
|
185
|
+
rb_str_new2(LAUNCH_JOBKEY_INETDCOMPATIBILITY));
|
186
|
+
rb_const_set(mLaunchJobKey, rb_intern("ENABLEGLOBBING"),
|
187
|
+
rb_str_new2(LAUNCH_JOBKEY_ENABLEGLOBBING));
|
188
|
+
rb_const_set(mLaunchJobKey, rb_intern("PROGRAMARGUMENTS"),
|
189
|
+
rb_str_new2(LAUNCH_JOBKEY_PROGRAMARGUMENTS));
|
190
|
+
rb_const_set(mLaunchJobKey, rb_intern("PROGRAM"),
|
191
|
+
rb_str_new2(LAUNCH_JOBKEY_PROGRAM));
|
192
|
+
rb_const_set(mLaunchJobKey, rb_intern("ONDEMAND"),
|
193
|
+
rb_str_new2(LAUNCH_JOBKEY_ONDEMAND));
|
194
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE"),
|
195
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE));
|
196
|
+
rb_const_set(mLaunchJobKey, rb_intern("LIMITLOADTOHOSTS"),
|
197
|
+
rb_str_new2(LAUNCH_JOBKEY_LIMITLOADTOHOSTS));
|
198
|
+
rb_const_set(mLaunchJobKey, rb_intern("LIMITLOADFROMHOSTS"),
|
199
|
+
rb_str_new2(LAUNCH_JOBKEY_LIMITLOADFROMHOSTS));
|
200
|
+
rb_const_set(mLaunchJobKey, rb_intern("LIMITLOADTOSESSIONTYPE"),
|
201
|
+
rb_str_new2(LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE));
|
202
|
+
rb_const_set(mLaunchJobKey, rb_intern("RUNATLOAD"),
|
203
|
+
rb_str_new2(LAUNCH_JOBKEY_RUNATLOAD));
|
204
|
+
rb_const_set(mLaunchJobKey, rb_intern("ROOTDIRECTORY"),
|
205
|
+
rb_str_new2(LAUNCH_JOBKEY_ROOTDIRECTORY));
|
206
|
+
rb_const_set(mLaunchJobKey, rb_intern("WORKINGDIRECTORY"),
|
207
|
+
rb_str_new2(LAUNCH_JOBKEY_WORKINGDIRECTORY));
|
208
|
+
rb_const_set(mLaunchJobKey, rb_intern("ENVIRONMENTVARIABLES"),
|
209
|
+
rb_str_new2(LAUNCH_JOBKEY_ENVIRONMENTVARIABLES));
|
210
|
+
rb_const_set(mLaunchJobKey, rb_intern("USERENVIRONMENTVARIABLES"),
|
211
|
+
rb_str_new2(LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES));
|
212
|
+
rb_const_set(mLaunchJobKey, rb_intern("UMASK"),
|
213
|
+
rb_str_new2(LAUNCH_JOBKEY_UMASK));
|
214
|
+
rb_const_set(mLaunchJobKey, rb_intern("NICE"),
|
215
|
+
rb_str_new2(LAUNCH_JOBKEY_NICE));
|
216
|
+
rb_const_set(mLaunchJobKey, rb_intern("HOPEFULLYEXITSFIRST"),
|
217
|
+
rb_str_new2(LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST));
|
218
|
+
rb_const_set(mLaunchJobKey, rb_intern("HOPEFULLYEXITSLAST"),
|
219
|
+
rb_str_new2(LAUNCH_JOBKEY_HOPEFULLYEXITSLAST));
|
220
|
+
rb_const_set(mLaunchJobKey, rb_intern("LOWPRIORITYIO"),
|
221
|
+
rb_str_new2(LAUNCH_JOBKEY_LOWPRIORITYIO));
|
222
|
+
rb_const_set(mLaunchJobKey, rb_intern("SESSIONCREATE"),
|
223
|
+
rb_str_new2(LAUNCH_JOBKEY_SESSIONCREATE));
|
224
|
+
rb_const_set(mLaunchJobKey, rb_intern("STARTONMOUNT"),
|
225
|
+
rb_str_new2(LAUNCH_JOBKEY_STARTONMOUNT));
|
226
|
+
rb_const_set(mLaunchJobKey, rb_intern("SOFTRESOURCELIMITS"),
|
227
|
+
rb_str_new2(LAUNCH_JOBKEY_SOFTRESOURCELIMITS));
|
228
|
+
rb_const_set(mLaunchJobKey, rb_intern("HARDRESOURCELIMITS"),
|
229
|
+
rb_str_new2(LAUNCH_JOBKEY_HARDRESOURCELIMITS));
|
230
|
+
rb_const_set(mLaunchJobKey, rb_intern("STANDARDINPATH"),
|
231
|
+
rb_str_new2(LAUNCH_JOBKEY_STANDARDINPATH));
|
232
|
+
rb_const_set(mLaunchJobKey, rb_intern("STANDARDOUTPATH"),
|
233
|
+
rb_str_new2(LAUNCH_JOBKEY_STANDARDOUTPATH));
|
234
|
+
rb_const_set(mLaunchJobKey, rb_intern("STANDARDERRORPATH"),
|
235
|
+
rb_str_new2(LAUNCH_JOBKEY_STANDARDERRORPATH));
|
236
|
+
rb_const_set(mLaunchJobKey, rb_intern("DEBUG"),
|
237
|
+
rb_str_new2(LAUNCH_JOBKEY_DEBUG));
|
238
|
+
rb_const_set(mLaunchJobKey, rb_intern("WAITFORDEBUGGER"),
|
239
|
+
rb_str_new2(LAUNCH_JOBKEY_WAITFORDEBUGGER));
|
240
|
+
rb_const_set(mLaunchJobKey, rb_intern("QUEUEDIRECTORIES"),
|
241
|
+
rb_str_new2(LAUNCH_JOBKEY_QUEUEDIRECTORIES));
|
242
|
+
rb_const_set(mLaunchJobKey, rb_intern("WATCHPATHS"),
|
243
|
+
rb_str_new2(LAUNCH_JOBKEY_WATCHPATHS));
|
244
|
+
rb_const_set(mLaunchJobKey, rb_intern("STARTINTERVAL"),
|
245
|
+
rb_str_new2(LAUNCH_JOBKEY_STARTINTERVAL));
|
246
|
+
rb_const_set(mLaunchJobKey, rb_intern("STARTCALENDARINTERVAL"),
|
247
|
+
rb_str_new2(LAUNCH_JOBKEY_STARTCALENDARINTERVAL));
|
248
|
+
rb_const_set(mLaunchJobKey, rb_intern("BONJOURFDS"),
|
249
|
+
rb_str_new2(LAUNCH_JOBKEY_BONJOURFDS));
|
250
|
+
rb_const_set(mLaunchJobKey, rb_intern("LASTEXITSTATUS"),
|
251
|
+
rb_str_new2(LAUNCH_JOBKEY_LASTEXITSTATUS));
|
252
|
+
rb_const_set(mLaunchJobKey, rb_intern("PID"),
|
253
|
+
rb_str_new2(LAUNCH_JOBKEY_PID));
|
254
|
+
rb_const_set(mLaunchJobKey, rb_intern("THROTTLEINTERVAL"),
|
255
|
+
rb_str_new2(LAUNCH_JOBKEY_THROTTLEINTERVAL));
|
256
|
+
rb_const_set(mLaunchJobKey, rb_intern("LAUNCHONLYONCE"),
|
257
|
+
rb_str_new2(LAUNCH_JOBKEY_LAUNCHONLYONCE));
|
258
|
+
rb_const_set(mLaunchJobKey, rb_intern("ABANDONPROCESSGROUP"),
|
259
|
+
rb_str_new2(LAUNCH_JOBKEY_ABANDONPROCESSGROUP));
|
260
|
+
rb_const_set(mLaunchJobKey, rb_intern("IGNOREPROCESSGROUPATSHUTDOWN"),
|
261
|
+
rb_str_new2(LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN));
|
262
|
+
rb_const_set(mLaunchJobKey, rb_intern("POLICIES"),
|
263
|
+
rb_str_new2(LAUNCH_JOBKEY_POLICIES));
|
264
|
+
rb_const_set(mLaunchJobKey, rb_intern("ENABLETRANSACTIONS"),
|
265
|
+
rb_str_new2(LAUNCH_JOBKEY_ENABLETRANSACTIONS));
|
266
|
+
|
267
|
+
rb_const_set(mLaunchJobKey, rb_intern("MACH_RESETATCLOSE"),
|
268
|
+
rb_str_new2(LAUNCH_JOBKEY_MACH_RESETATCLOSE));
|
269
|
+
rb_const_set(mLaunchJobKey, rb_intern("MACH_HIDEUNTILCHECKIN"),
|
270
|
+
rb_str_new2(LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN));
|
271
|
+
rb_const_set(mLaunchJobKey, rb_intern("MACH_DRAINMESSAGESONCRASH"),
|
272
|
+
rb_str_new2(LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH));
|
273
|
+
|
274
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_SUCCESSFULEXIT"),
|
275
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT));
|
276
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_NETWORKSTATE"),
|
277
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE));
|
278
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_PATHSTATE"),
|
279
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE));
|
280
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_OTHERJOBACTIVE"),
|
281
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE));
|
282
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_OTHERJOBENABLED"),
|
283
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED));
|
284
|
+
rb_const_set(mLaunchJobKey, rb_intern("KEEPALIVE_AFTERINITIALDEMAND"),
|
285
|
+
rb_str_new2(LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND));
|
286
|
+
|
287
|
+
rb_const_set(mLaunchJobKey, rb_intern("CAL_MINUTE"),
|
288
|
+
rb_str_new2(LAUNCH_JOBKEY_CAL_MINUTE));
|
289
|
+
rb_const_set(mLaunchJobKey, rb_intern("CAL_HOUR"),
|
290
|
+
rb_str_new2(LAUNCH_JOBKEY_CAL_HOUR));
|
291
|
+
rb_const_set(mLaunchJobKey, rb_intern("CAL_DAY"),
|
292
|
+
rb_str_new2(LAUNCH_JOBKEY_CAL_DAY));
|
293
|
+
rb_const_set(mLaunchJobKey, rb_intern("CAL_WEEKDAY"),
|
294
|
+
rb_str_new2(LAUNCH_JOBKEY_CAL_WEEKDAY));
|
295
|
+
rb_const_set(mLaunchJobKey, rb_intern("CAL_MONTH"),
|
296
|
+
rb_str_new2(LAUNCH_JOBKEY_CAL_MONTH));
|
297
|
+
|
298
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_CORE"),
|
299
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_CORE));
|
300
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_CPU"),
|
301
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_CPU));
|
302
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_DATA"),
|
303
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_DATA));
|
304
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_FSIZE"),
|
305
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE));
|
306
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_MEMLOCK"),
|
307
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK));
|
308
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_NOFILE"),
|
309
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE));
|
310
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_NPROC"),
|
311
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_NPROC));
|
312
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_RSS"),
|
313
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_RSS));
|
314
|
+
rb_const_set(mLaunchJobKey, rb_intern("RESOURCELIMIT_STACK"),
|
315
|
+
rb_str_new2(LAUNCH_JOBKEY_RESOURCELIMIT_STACK));
|
316
|
+
|
317
|
+
rb_const_set(mLaunchJobKey, rb_intern("DISABLED_MACHINETYPE"),
|
318
|
+
rb_str_new2(LAUNCH_JOBKEY_DISABLED_MACHINETYPE));
|
319
|
+
rb_const_set(mLaunchJobKey, rb_intern("DISABLED_MODELNAME"),
|
320
|
+
rb_str_new2(LAUNCH_JOBKEY_DISABLED_MODELNAME));
|
321
|
+
|
322
|
+
/*
|
323
|
+
* Launch::Socket holds various socket keys
|
324
|
+
*/
|
325
|
+
mLaunchSocket = rb_define_module_under(mLaunch, "Socket");
|
326
|
+
rb_const_set(mLaunchSocket, rb_intern("TYPE"),
|
327
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_TYPE));
|
328
|
+
rb_const_set(mLaunchSocket, rb_intern("PASSIVE"),
|
329
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_PASSIVE));
|
330
|
+
rb_const_set(mLaunchSocket, rb_intern("BONJOUR"),
|
331
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_BONJOUR));
|
332
|
+
rb_const_set(mLaunchSocket, rb_intern("SECUREWITHKEY"),
|
333
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_SECUREWITHKEY));
|
334
|
+
rb_const_set(mLaunchSocket, rb_intern("PATHNAME"),
|
335
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_PATHNAME));
|
336
|
+
rb_const_set(mLaunchSocket, rb_intern("PATHMODE"),
|
337
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_PATHMODE));
|
338
|
+
rb_const_set(mLaunchSocket, rb_intern("NODENAME"),
|
339
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_NODENAME));
|
340
|
+
rb_const_set(mLaunchSocket, rb_intern("SERVICENAME"),
|
341
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_SERVICENAME));
|
342
|
+
rb_const_set(mLaunchSocket, rb_intern("FAMILY"),
|
343
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_FAMILY));
|
344
|
+
rb_const_set(mLaunchSocket, rb_intern("PROTOCOL"),
|
345
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_PROTOCOL));
|
346
|
+
rb_const_set(mLaunchSocket, rb_intern("MULTICASTGROUP"),
|
347
|
+
rb_str_new2(LAUNCH_JOBSOCKETKEY_MULTICASTGROUP));
|
348
|
+
|
349
|
+
/*
|
350
|
+
* Launch::JobPolicy holds the job policy keys
|
351
|
+
*/
|
352
|
+
mLaunchJobPolicy = rb_define_module_under(mLaunch, "JobPolicy");
|
353
|
+
rb_const_set(mLaunchJobPolicy, rb_intern("DENYCREATINGOTHERJOBS"),
|
354
|
+
rb_str_new2(LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS));
|
355
|
+
}
|
data/lib/launch.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
##
|
2
|
+
# Launch is a wrapper for the launch(3) API for daemons and agents spawned by
|
3
|
+
# launchd(8).
|
4
|
+
#
|
5
|
+
# Launch agents and daemons MUST NOT:
|
6
|
+
#
|
7
|
+
# * Call daemon(3)
|
8
|
+
# * Do the equivalent of daemon(3) by calling fork and having the parent exit
|
9
|
+
#
|
10
|
+
# Launch agents and daemons SHOULD NOT do the following as part of their
|
11
|
+
# starup initialization:
|
12
|
+
#
|
13
|
+
# * Set the user ID or group ID (Process::Sys.setuid, Process::Sys.setgid and
|
14
|
+
# friends)
|
15
|
+
# * Setup the working directory (Dir.chdir)
|
16
|
+
# * chroot(2)
|
17
|
+
# * setsid(2) (Process.setsid)
|
18
|
+
# * Close "stray" file descriptors
|
19
|
+
# * Change stdio(3) to /dev/null (STDOUT.reopen and friends)
|
20
|
+
# * Setup resource limits with setrusage (Process.setrlimit)
|
21
|
+
# * Ignore the SIGTERM signal (trap 'TERM', 'IGNORE')
|
22
|
+
#
|
23
|
+
# The above is from launchd.plist(5). Please read it for further details.
|
24
|
+
#
|
25
|
+
# To shut down cleanly <tt>trap 'TERM'</tt> and perform any shutdown steps
|
26
|
+
# before exiting.
|
27
|
+
|
28
|
+
module Launch
|
29
|
+
|
30
|
+
##
|
31
|
+
# The version of launch you are using
|
32
|
+
|
33
|
+
VERSION = '1.0'
|
34
|
+
|
35
|
+
##
|
36
|
+
# Checks in with launch and retrieves the agent's configuration. The
|
37
|
+
# configuration can be retrieved later through <tt>@launch_checkin<tt>.
|
38
|
+
|
39
|
+
def launch_checkin
|
40
|
+
response = launch_message Launch::Key::CHECKIN
|
41
|
+
|
42
|
+
return if response.nil?
|
43
|
+
|
44
|
+
@launch_checkin = response
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Creates ruby sockets from the sockets list in +name+.
|
49
|
+
# <tt>socket_class.for_fd</tt> is called for each socket in the named list.
|
50
|
+
#
|
51
|
+
# +name+ comes from the socket's name key in the launchd plist.
|
52
|
+
#
|
53
|
+
# Example plist Sockets dictionary:
|
54
|
+
#
|
55
|
+
# <key>Sockets</key>
|
56
|
+
# <dict>
|
57
|
+
# <key>EchoSocket</key>
|
58
|
+
# <dict>
|
59
|
+
# <key>SockServiceName</key>
|
60
|
+
# <string>12345</string>
|
61
|
+
# </dict>
|
62
|
+
# </dict>
|
63
|
+
#
|
64
|
+
# Example call:
|
65
|
+
#
|
66
|
+
# servers = launch_sockets 'Echo', TCPServer
|
67
|
+
#
|
68
|
+
# p servers.map { |server| server.addr }
|
69
|
+
|
70
|
+
def launch_sockets name, socket_class
|
71
|
+
require 'socket'
|
72
|
+
|
73
|
+
sockets = @launch_checkin[Launch::JobKey::SOCKETS][name]
|
74
|
+
|
75
|
+
raise Error, "no sockets found for #{name.inspect}" unless sockets
|
76
|
+
|
77
|
+
sockets.map do |fd|
|
78
|
+
socket_class.for_fd fd
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
require 'launch/launch'
|
85
|
+
require 'socket'
|
86
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'launch'
|
2
|
+
require 'webrick'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Launch::WEBrickHTTPServer adds launchd support to WEBrick.
|
6
|
+
#
|
7
|
+
# To use, replace WEBrick::HTTPServer with Launch::WEBrickHTTPServer.
|
8
|
+
#
|
9
|
+
# By default Launch::WEBrickHTTPServer expects to find the socket list under
|
10
|
+
# <tt>'WEBrickSockets'</tt> but this may be overridden through the
|
11
|
+
# +:LaunchdSockets+ option.
|
12
|
+
#
|
13
|
+
# The server will automatically shut down when a TERM signal is sent. If you
|
14
|
+
# wish to perform other shutdown actions override TERM but be sure to shut
|
15
|
+
# down webrick.
|
16
|
+
#
|
17
|
+
# An example WEBrick server using Launch::WEBrickHTTPServer would be:
|
18
|
+
#
|
19
|
+
# require 'launch/webrick'
|
20
|
+
#
|
21
|
+
# Launch::WEBrickHTTPServer.new(:DocumentRoot => ARGV.shift).start
|
22
|
+
#
|
23
|
+
# Here is an example plist for this server which listens on port 8000:
|
24
|
+
#
|
25
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
26
|
+
# <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
27
|
+
# <plist version="1.0">
|
28
|
+
# <dict>
|
29
|
+
# <key>Label</key>
|
30
|
+
# <string>net.segment7.launch.webrick</string>
|
31
|
+
# <key>ProgramArguments</key>
|
32
|
+
# <array>
|
33
|
+
# <string>/path/to/ruby</string>
|
34
|
+
# <string>/path/to/webrick</string>
|
35
|
+
# <string>/Users/your_user/Sites</string>
|
36
|
+
# </array>
|
37
|
+
# <key>ServiceIPC</key>
|
38
|
+
# <true/>
|
39
|
+
# <key>Sockets</key>
|
40
|
+
# <dict>
|
41
|
+
# <key>WEBrickSockets</key>
|
42
|
+
# <dict>
|
43
|
+
# <key>SockServiceName</key>
|
44
|
+
# <string>8000</string>
|
45
|
+
# </dict>
|
46
|
+
# </dict>
|
47
|
+
# </dict>
|
48
|
+
# </plist>
|
49
|
+
|
50
|
+
class Launch::WEBrickHTTPServer < WEBrick::HTTPServer
|
51
|
+
|
52
|
+
include Launch
|
53
|
+
|
54
|
+
##
|
55
|
+
# Initializes an HTTP server with +options+ and set the server's listeners
|
56
|
+
# using Launch. A TERM handler to shut down the server is automatically
|
57
|
+
# set.
|
58
|
+
#
|
59
|
+
# +:LaunchdSockets+ may be set to change the socket key from the default of
|
60
|
+
# <tt>'WEBrickSockets'</tt>
|
61
|
+
|
62
|
+
def initialize options = {}
|
63
|
+
options[:DoNotListen] = true
|
64
|
+
sockets_key = options.delete(:LaunchdSockets) || 'WEBrickSockets'
|
65
|
+
|
66
|
+
super
|
67
|
+
|
68
|
+
launch_checkin
|
69
|
+
|
70
|
+
servers = launch_sockets sockets_key, TCPServer
|
71
|
+
|
72
|
+
listeners.replace servers
|
73
|
+
|
74
|
+
trap 'TERM' do shutdown end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
data/sample/echo.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'launch'
|
3
|
+
|
4
|
+
##
|
5
|
+
# This is an echo server that runs using launchd on port 12345.
|
6
|
+
#
|
7
|
+
# To start, run:
|
8
|
+
#
|
9
|
+
# ruby echo.rb net.segment7.launch.echo.plist
|
10
|
+
# launchctl load net.segment7.launch.echo.plist
|
11
|
+
#
|
12
|
+
# To use the echo server run:
|
13
|
+
#
|
14
|
+
# telnet localhost 12345
|
15
|
+
#
|
16
|
+
# To quit the echo server type ^] followed by ^D
|
17
|
+
#
|
18
|
+
# To stop run:
|
19
|
+
#
|
20
|
+
# launchctl unload net.segment7.launch.echo.plist
|
21
|
+
|
22
|
+
class Echo
|
23
|
+
|
24
|
+
include Launch
|
25
|
+
|
26
|
+
def self.plist name
|
27
|
+
file = File.expand_path __FILE__
|
28
|
+
root = File.expand_path '../..', __FILE__
|
29
|
+
|
30
|
+
plist = <<-PLIST
|
31
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
32
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
33
|
+
<plist version="1.0">
|
34
|
+
<dict>
|
35
|
+
<key>Label</key>
|
36
|
+
<string>#{name}</string>
|
37
|
+
<key>ProgramArguments</key>
|
38
|
+
<array>
|
39
|
+
<string>#{Gem.ruby}</string>
|
40
|
+
<string>-I#{root}/lib</string>
|
41
|
+
<string>-I#{root}/ext</string>
|
42
|
+
<string>#{file}</string>
|
43
|
+
</array>
|
44
|
+
<key>ServiceIPC</key>
|
45
|
+
<true/>
|
46
|
+
<key>Sockets</key>
|
47
|
+
<dict>
|
48
|
+
<key>EchoSocket</key>
|
49
|
+
<dict>
|
50
|
+
<key>SockServiceName</key>
|
51
|
+
<string>12345</string>
|
52
|
+
</dict>
|
53
|
+
</dict>
|
54
|
+
</dict>
|
55
|
+
</plist>
|
56
|
+
PLIST
|
57
|
+
|
58
|
+
open name, 'w' do |io|
|
59
|
+
io.write plist
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize
|
64
|
+
launch_checkin
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# echo lines sent from +socket+
|
69
|
+
|
70
|
+
def echo socket
|
71
|
+
Thread.start do
|
72
|
+
loop do
|
73
|
+
socket.puts socket.gets
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Listens on +server+ for connections to echo on.
|
80
|
+
|
81
|
+
def listen server
|
82
|
+
Thread.start do
|
83
|
+
loop do
|
84
|
+
echo server.accept
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Starts listening on the sockets given by launchd and waits forever
|
91
|
+
|
92
|
+
def run
|
93
|
+
launch_sockets('EchoSocket', TCPServer).each do |server|
|
94
|
+
listen server
|
95
|
+
end
|
96
|
+
|
97
|
+
sleep
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
if ARGV.empty? then
|
103
|
+
Echo.new.run
|
104
|
+
else
|
105
|
+
Echo.plist ARGV.first
|
106
|
+
end
|
107
|
+
|
data/test/test_launch.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'launch'
|
3
|
+
|
4
|
+
class TestLaunch < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
include Launch
|
7
|
+
|
8
|
+
def launch_message message
|
9
|
+
@message = message
|
10
|
+
|
11
|
+
return { 'response' => 'hash' }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_launch_checkin
|
15
|
+
response = launch_checkin
|
16
|
+
|
17
|
+
assert_equal Launch::Key::CHECKIN, @message
|
18
|
+
|
19
|
+
expected = { 'response' => 'hash' }
|
20
|
+
|
21
|
+
assert_equal expected, response
|
22
|
+
assert_equal expected, @launch_checkin
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_launch_sockets
|
26
|
+
@launch_checkin = {
|
27
|
+
Launch::JobKey::SOCKETS => {
|
28
|
+
'MySockets' => [STDIN.to_i, STDOUT.to_i]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
sockets = launch_sockets 'MySockets', IO
|
33
|
+
|
34
|
+
assert_equal 2, sockets.length
|
35
|
+
|
36
|
+
assert_instance_of IO, sockets.first
|
37
|
+
assert_instance_of IO, sockets.last
|
38
|
+
|
39
|
+
assert_equal [0, 1], sockets.map { |io| io.to_i }
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_launch_sockets_none
|
43
|
+
@launch_checkin = {
|
44
|
+
Launch::JobKey::SOCKETS => {
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
e = assert_raises Launch::Error do
|
49
|
+
launch_sockets 'NoSockets', IO
|
50
|
+
end
|
51
|
+
|
52
|
+
assert_equal 'no sockets found for "NoSockets"', e.message
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: launch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: "1.0"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Eric Hodel
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain:
|
16
|
+
- |
|
17
|
+
-----BEGIN CERTIFICATE-----
|
18
|
+
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
|
19
|
+
YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
|
20
|
+
ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
|
21
|
+
cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
|
22
|
+
FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
|
23
|
+
LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
|
24
|
+
U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
|
25
|
+
Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
|
26
|
+
mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
|
27
|
+
g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
|
28
|
+
sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
29
|
+
BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
|
30
|
+
kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
|
31
|
+
bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
|
32
|
+
DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
|
33
|
+
UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
|
34
|
+
14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
|
35
|
+
x52qPcexcYZR7w==
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
|
38
|
+
date: 2011-02-27 00:00:00 -08:00
|
39
|
+
default_executable:
|
40
|
+
dependencies:
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
prerelease: false
|
44
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 11
|
50
|
+
segments:
|
51
|
+
- 2
|
52
|
+
- 0
|
53
|
+
- 2
|
54
|
+
version: 2.0.2
|
55
|
+
type: :development
|
56
|
+
version_requirements: *id001
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rake-compiler
|
59
|
+
prerelease: false
|
60
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 5
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
- 7
|
69
|
+
version: "0.7"
|
70
|
+
type: :development
|
71
|
+
version_requirements: *id002
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: hoe
|
74
|
+
prerelease: false
|
75
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 43
|
81
|
+
segments:
|
82
|
+
- 2
|
83
|
+
- 9
|
84
|
+
- 0
|
85
|
+
version: 2.9.0
|
86
|
+
type: :development
|
87
|
+
version_requirements: *id003
|
88
|
+
description: |-
|
89
|
+
Launch allows agents and daemons launched by launchd to retrieve their list of
|
90
|
+
sockets. Launchd is an open source framework for launching and managing
|
91
|
+
daemons, programs and scripts provided by Apple.
|
92
|
+
email:
|
93
|
+
- drbrain@segment7.net
|
94
|
+
executables: []
|
95
|
+
|
96
|
+
extensions:
|
97
|
+
- ext/launch/extconf.rb
|
98
|
+
extra_rdoc_files:
|
99
|
+
- History.txt
|
100
|
+
- Manifest.txt
|
101
|
+
- README.txt
|
102
|
+
files:
|
103
|
+
- .autotest
|
104
|
+
- History.txt
|
105
|
+
- Manifest.txt
|
106
|
+
- README.txt
|
107
|
+
- Rakefile
|
108
|
+
- ext/launch/extconf.rb
|
109
|
+
- ext/launch/launch.c
|
110
|
+
- lib/launch.rb
|
111
|
+
- lib/launch/webrick.rb
|
112
|
+
- sample/echo.rb
|
113
|
+
- test/test_launch.rb
|
114
|
+
- .gemtest
|
115
|
+
has_rdoc: true
|
116
|
+
homepage: https://github.com/drbrain/launch
|
117
|
+
licenses: []
|
118
|
+
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options:
|
121
|
+
- --main
|
122
|
+
- README.txt
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
hash: 55
|
131
|
+
segments:
|
132
|
+
- 1
|
133
|
+
- 9
|
134
|
+
- 2
|
135
|
+
version: 1.9.2
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project: launch
|
148
|
+
rubygems_version: 1.5.3
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: Launch allows agents and daemons launched by launchd to retrieve their list of sockets
|
152
|
+
test_files:
|
153
|
+
- test/test_launch.rb
|
metadata.gz.sig
ADDED