openvz 1.5 → 1.5.3
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/README.md +115 -0
- data/lib/openvz/container.rb +65 -10
- data/lib/openvz/inventory.rb +11 -10
- data/lib/openvz/util.rb +21 -1
- data/lib/openvz.rb +1 -1
- data/openvz.gemspec +11 -35
- metadata +27 -26
- data/lib/openvz/vendor/load_systemu.rb +0 -1
- data/lib/openvz/vendor/systemu/README +0 -160
- data/lib/openvz/vendor/systemu/README.tmpl +0 -30
- data/lib/openvz/vendor/systemu/a.rb +0 -6
- data/lib/openvz/vendor/systemu/gemspec.rb +0 -23
- data/lib/openvz/vendor/systemu/gen_readme.rb +0 -32
- data/lib/openvz/vendor/systemu/install.rb +0 -206
- data/lib/openvz/vendor/systemu/lib/systemu.rb +0 -299
- data/lib/openvz/vendor/systemu/samples/a.rb +0 -11
- data/lib/openvz/vendor/systemu/samples/b.rb +0 -12
- data/lib/openvz/vendor/systemu/samples/c.rb +0 -10
- data/lib/openvz/vendor/systemu/samples/d.rb +0 -11
- data/lib/openvz/vendor/systemu/samples/e.rb +0 -9
- data/lib/openvz/vendor/systemu/samples/f.rb +0 -18
data/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
OpenVZ API
|
2
|
+
==========
|
3
|
+
|
4
|
+
OpenVZ is a container based virtualization for Linux. This API will allow you
|
5
|
+
to easily write tools to manipulate containers on a host.
|
6
|
+
|
7
|
+
USAGE
|
8
|
+
=====
|
9
|
+
|
10
|
+
Here are some examples on how you can use the API.
|
11
|
+
|
12
|
+
<pre>
|
13
|
+
container = OpenVZ::Container.new('110')
|
14
|
+
container.start
|
15
|
+
</pre>
|
16
|
+
|
17
|
+
UBC Access
|
18
|
+
----------
|
19
|
+
|
20
|
+
To get the current value of privvmpages you can use the config accessor.
|
21
|
+
|
22
|
+
<pre>
|
23
|
+
container = OpenVZ::Container.new('110')
|
24
|
+
puts container.config.privvmpages
|
25
|
+
</pre>
|
26
|
+
|
27
|
+
Also in case you would like to update a UBC, use the same config accessor.
|
28
|
+
|
29
|
+
<pre>
|
30
|
+
container = OpenVZ::Container.new('110')
|
31
|
+
container.config.kmemsize = '5505024:5872024'
|
32
|
+
</pre>
|
33
|
+
|
34
|
+
Inventory
|
35
|
+
---------
|
36
|
+
|
37
|
+
<pre>
|
38
|
+
# Create an inventoy of all containers
|
39
|
+
inventory = OpenVZ::Inventory.new()
|
40
|
+
inventory.load
|
41
|
+
# Print a certain containers configuration option
|
42
|
+
inventory['110'].config.privvmpages
|
43
|
+
# Restart
|
44
|
+
inventory['110'].restart
|
45
|
+
</pre>
|
46
|
+
|
47
|
+
|
48
|
+
Provisioning
|
49
|
+
============
|
50
|
+
|
51
|
+
You can as well use the build in functions to provision a new container.
|
52
|
+
|
53
|
+
<pre>
|
54
|
+
container = OpenVZ::Container.new('110')
|
55
|
+
|
56
|
+
container.create( :ostemplate => 'centos-5-x86_64-minimal',
|
57
|
+
:config => 'vps.basic' )
|
58
|
+
|
59
|
+
container.start
|
60
|
+
</pre>
|
61
|
+
|
62
|
+
|
63
|
+
Debootstrapping Containers
|
64
|
+
-------------------------
|
65
|
+
|
66
|
+
If your host is running Debian and you want to bootstrap a new Debian container,
|
67
|
+
you do not have to use a template, just use debootstrap.
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
container = OpenVZ::Container.new('110')
|
71
|
+
|
72
|
+
container.create( :ostemplate => 'debain-6.0-bootstrap',
|
73
|
+
:config => 'vps.basic' )
|
74
|
+
|
75
|
+
container.debootstrap( :dist => 'squeeze',
|
76
|
+
:mirror => 'http://cdn.debian.net/debian' )
|
77
|
+
|
78
|
+
container.set( :nameserver => '8.8.8.8',
|
79
|
+
:ipadd => '10.0.0.2',
|
80
|
+
:hostname => 'mia.ono.at' )
|
81
|
+
|
82
|
+
container.start
|
83
|
+
|
84
|
+
# Update the system
|
85
|
+
container.command('aptitude update ; aptitude -y upgrade ; apt-key update')
|
86
|
+
|
87
|
+
# Install puppet
|
88
|
+
container.command('aptitude -o Aptitude::Cmdline::ignore-trust-violations=true -y install puppet')
|
89
|
+
</pre>
|
90
|
+
|
91
|
+
NOTE: You need to create an empty template for this to work. Here is how
|
92
|
+
you do that:
|
93
|
+
|
94
|
+
<pre>
|
95
|
+
mkdir /tmp/empty-template
|
96
|
+
# We need a file in the tarball since vzcreate barfs on empty tarballs
|
97
|
+
touch /tmp/empty-template/BOOSTRAPPED
|
98
|
+
tar -zc -C /tmp/empty-template . -f debian-6.0-bootstrap.tar
|
99
|
+
gzip debian-6.0-bootstrap.tar
|
100
|
+
mv debian-6.0-bootstrap.tar.gz /var/lib/vz/template/cache
|
101
|
+
</pre>
|
102
|
+
|
103
|
+
|
104
|
+
BUGS
|
105
|
+
====
|
106
|
+
|
107
|
+
For bugs or feature requests, please use the GitHub issue tracker.
|
108
|
+
|
109
|
+
https://github.com/sts/ruby-openvz/issues
|
110
|
+
|
111
|
+
|
112
|
+
WHO
|
113
|
+
===
|
114
|
+
|
115
|
+
Stefan Schlesinger / sts@ono.at / @stsonoat / http://sts.ono.at
|
data/lib/openvz/container.rb
CHANGED
@@ -37,6 +37,7 @@ module OpenVZ
|
|
37
37
|
def initialize(ctid=false)
|
38
38
|
@ctid = ctid
|
39
39
|
@vzctl = "/usr/sbin/vzctl"
|
40
|
+
@vzmigrate = "/usr/sbin/vzmigrate"
|
40
41
|
@configfile = "/etc/vz/conf/#{ctid}.conf"
|
41
42
|
|
42
43
|
@config = Config.new(load_config_file)
|
@@ -106,6 +107,13 @@ module OpenVZ
|
|
106
107
|
cmd = "#{@vzctl} restore #{@ctid} --dumpfile #{snapshot_path}"
|
107
108
|
execute(cmd)
|
108
109
|
end
|
110
|
+
|
111
|
+
# Migrate container to another node
|
112
|
+
#
|
113
|
+
def migrate(destination_address, options=%w(--remove-area yes --online --rsync=-az))
|
114
|
+
cmd = "#{@vzmigrate} #{options.join ' '} #{destination_address} #{@ctid}"
|
115
|
+
execute(cmd)
|
116
|
+
end
|
109
117
|
|
110
118
|
|
111
119
|
# Update one or multiple Container properties and keep the configration
|
@@ -197,8 +205,53 @@ module OpenVZ
|
|
197
205
|
# '#\1')
|
198
206
|
end
|
199
207
|
|
208
|
+
# Write into or copy a file into a container
|
209
|
+
#
|
210
|
+
# The destination file will be prepended with the containers private directory. If
|
211
|
+
# you specify a source, this is relative to the virtualization hosts root directory.
|
212
|
+
#
|
213
|
+
#
|
214
|
+
# @example Create /etc/hostname
|
215
|
+
#
|
216
|
+
# container.file('/etc/hostname', :content => 'vm01')
|
217
|
+
#
|
218
|
+
# @example Copy a file from /etc/vz/template.conf/hosts (host) to /etc/hosts (container)
|
219
|
+
#
|
220
|
+
# container.file('/etc/hosts', :source => '/etc/hosts'
|
221
|
+
#
|
222
|
+
#
|
223
|
+
# @param filename Destination filename, relative to the containers root
|
224
|
+
# @param :source The source filename, relative to the virtualization hosts root directory
|
225
|
+
# @param :content Pass a string which will be written to the file.
|
226
|
+
# @param :mode Specify the file mode.
|
227
|
+
def file(filename, options={})
|
228
|
+
unless filename
|
229
|
+
raise ArgumentError, "file requires destination filename as first argument."
|
230
|
+
end
|
231
|
+
|
232
|
+
if options[:source] and options[:content]
|
233
|
+
raise ArgumentError, "file can either take :source or :content as an argument."
|
234
|
+
end
|
235
|
+
|
236
|
+
destination ="#{@config.ve_private}/#{filename}"
|
237
|
+
|
238
|
+
if options[:source]
|
239
|
+
FileUtils.cp(options[:source], destination)
|
240
|
+
end
|
241
|
+
|
242
|
+
if options[:content]
|
243
|
+
File.open(destination, 'w') { |file|
|
244
|
+
file.write(options[:content])
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
if options[:mode]
|
249
|
+
FileUtils.chmod options[:mode], destination
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
200
253
|
|
201
|
-
# Copy a file from the hardware node into the container.
|
254
|
+
# Copy a file from the hardware node into the container. (OBSOLETE)
|
202
255
|
#
|
203
256
|
# @example Copy resolv.conf
|
204
257
|
# container.cp_into(
|
@@ -252,6 +305,16 @@ module OpenVZ
|
|
252
305
|
raw.split(/\W/).first.to_i
|
253
306
|
end
|
254
307
|
|
308
|
+
# Add veth to a CT
|
309
|
+
# vzctl set <CTID> --netif_add <ifname>[,<mac>,<host_ifname>,<host_mac>,<bridge>]
|
310
|
+
#
|
311
|
+
# @param [Hash] interface settings (keys as listed above)
|
312
|
+
def add_veth veth
|
313
|
+
cmd = "#{@vzctl} set #{@ctid} --netif_add #{veth[:ifname]},#{veth[:mac]},#{veth[:host_ifname]}," \
|
314
|
+
"#{veth[:host_mac]}, #{veth[:bridge]}"
|
315
|
+
execute(cmd)
|
316
|
+
end
|
317
|
+
|
255
318
|
|
256
319
|
####
|
257
320
|
#### Helper methods
|
@@ -357,15 +420,7 @@ module OpenVZ
|
|
357
420
|
|
358
421
|
# Execute a System Command
|
359
422
|
def execute(cmd)
|
360
|
-
|
361
|
-
Log.debug("#{cmd}")
|
362
|
-
|
363
|
-
s = Shell.new("#{cmd}", :cwd => "/tmp")
|
364
|
-
s.runcommand
|
365
|
-
if s.status.exitstatus != 0
|
366
|
-
raise "Cannot execute: '#{cmd}'. Return code: #{s.status.exitstatus}. Stderr: #{s.stderr}"
|
367
|
-
end
|
368
|
-
s.stdout
|
423
|
+
Util.execute(cmd)
|
369
424
|
end
|
370
425
|
end
|
371
426
|
end
|
data/lib/openvz/inventory.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
module OpenVZ
|
2
2
|
class Inventory < ConfigHash
|
3
|
+
def initialize()
|
4
|
+
@vzlist = "/usr/sbin/vzlist"
|
5
|
+
end
|
6
|
+
|
3
7
|
def load
|
4
|
-
|
5
|
-
s.runcommand
|
6
|
-
|
7
|
-
ret_code = s.status
|
8
|
-
if ret_code != 0
|
9
|
-
raise StandardError, "Execution of shell command failed. Command: #{s.command} RC: #{ret_code} Error: #{s.stderr}\n\n"
|
10
|
-
end
|
11
|
-
|
12
|
-
s.stdout.each { |l|
|
8
|
+
Util.execute("#{@vzlist} -a").each { |l|
|
13
9
|
# inventarize a container object for each avaiable container.
|
14
10
|
if l =~ /^\s+(\d+)\s+(.*)\s+(running|stopped)\s+(.*)\s\s(.*)$/
|
15
11
|
self[$1] = Container.new($1)
|
16
12
|
end
|
17
13
|
}
|
18
14
|
end
|
15
|
+
|
16
|
+
# Returns cotainers' id as a array of strings
|
17
|
+
def ids
|
18
|
+
Util.execute("#{@vzlist} -a1").split
|
19
|
+
end
|
19
20
|
|
20
21
|
def to_hash
|
21
22
|
@data
|
22
23
|
end
|
23
24
|
end
|
24
|
-
end
|
25
|
+
end
|
data/lib/openvz/util.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module OpenVZ
|
2
|
-
class Util
|
2
|
+
class Util
|
3
3
|
# Generate a mac address based upon three different variables
|
4
4
|
def generate_mac(ctid, vlanid, for_host)
|
5
5
|
ctid_str = '%06i' % ctid
|
@@ -35,5 +35,25 @@ module OpenVZ
|
|
35
35
|
raise "File not writeable: #{file}."
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
# Class variable which denotes whether execute commands using sudo
|
41
|
+
# should be true or false
|
42
|
+
attr_accessor :enforce_sudo
|
43
|
+
end
|
44
|
+
|
45
|
+
# Execute a System Command
|
46
|
+
def self.execute(cmd, params = {:cwd => "/tmp"})
|
47
|
+
cmd = "sudo " + cmd if self.enforce_sudo
|
48
|
+
|
49
|
+
Log.debug("#{cmd}")
|
50
|
+
|
51
|
+
s = Shell.new("#{cmd}", params)
|
52
|
+
s.runcommand
|
53
|
+
if s.status.exitstatus != 0
|
54
|
+
raise "Cannot execute: '#{cmd}'. Return code: #{s.status.exitstatus}. Stderr: #{s.stderr}"
|
55
|
+
end
|
56
|
+
s.stdout
|
57
|
+
end
|
38
58
|
end
|
39
59
|
end
|
data/lib/openvz.rb
CHANGED
data/openvz.gemspec
CHANGED
@@ -1,48 +1,24 @@
|
|
1
|
+
$: << File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'openvz'
|
4
|
+
|
1
5
|
Gem::Specification.new do |s|
|
2
6
|
s.name = 'openvz'
|
3
|
-
s.version =
|
4
|
-
s.date = '2012-
|
7
|
+
s.version = OpenVZ::VERSION
|
8
|
+
s.date = '2012-10-09'
|
5
9
|
s.authors = 'Stefan Schlesinger'
|
6
10
|
s.email = 'sts@ono.at'
|
7
11
|
s.homepage = 'http://github.com/sts/ruby-openvz'
|
8
12
|
|
9
13
|
s.summary = 'OpenVZ API'
|
10
14
|
s.description = 'OpenVZ is a container based virtualization for Linux. This API will
|
11
|
-
allow you to easily write tools to manipulate containers on a host.'
|
15
|
+
allow you to easily write tools to manipulate containers on a host.'
|
16
|
+
|
17
|
+
s.has_rdoc = false
|
12
18
|
|
13
19
|
s.extra_rdoc_files = %w[COPYING]
|
14
20
|
|
15
|
-
|
16
|
-
s.files = %w[
|
17
|
-
openvz.gemspec
|
18
|
-
lib/openvz.rb
|
19
|
-
lib/openvz/vendor
|
20
|
-
lib/openvz/vendor/systemu
|
21
|
-
lib/openvz/vendor/systemu/README.tmpl
|
22
|
-
lib/openvz/vendor/systemu/gemspec.rb
|
23
|
-
lib/openvz/vendor/systemu/install.rb
|
24
|
-
lib/openvz/vendor/systemu/samples
|
25
|
-
lib/openvz/vendor/systemu/samples/e.rb
|
26
|
-
lib/openvz/vendor/systemu/samples/b.rb
|
27
|
-
lib/openvz/vendor/systemu/samples/d.rb
|
28
|
-
lib/openvz/vendor/systemu/samples/c.rb
|
29
|
-
lib/openvz/vendor/systemu/samples/a.rb
|
30
|
-
lib/openvz/vendor/systemu/samples/f.rb
|
31
|
-
lib/openvz/vendor/systemu/gen_readme.rb
|
32
|
-
lib/openvz/vendor/systemu/lib
|
33
|
-
lib/openvz/vendor/systemu/lib/systemu.rb
|
34
|
-
lib/openvz/vendor/systemu/a.rb
|
35
|
-
lib/openvz/vendor/systemu/README
|
36
|
-
lib/openvz/vendor/require_vendored.rb
|
37
|
-
lib/openvz/vendor/load_systemu.rb
|
38
|
-
lib/openvz/log.rb
|
39
|
-
lib/openvz/inventory.rb
|
40
|
-
lib/openvz/util.rb
|
41
|
-
lib/openvz/vendor.rb
|
42
|
-
lib/openvz/confighash.rb
|
43
|
-
lib/openvz/container.rb
|
44
|
-
lib/openvz/shell.rb
|
45
|
-
lib/openvz.rb
|
46
|
-
]
|
21
|
+
s.add_dependency 'systemu'
|
47
22
|
|
23
|
+
s.files = Dir.glob("{**/**/**/**/*}")
|
48
24
|
end
|
metadata
CHANGED
@@ -6,7 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
|
-
|
9
|
+
- 3
|
10
|
+
version: 1.5.3
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Stefan Schlesinger
|
@@ -14,9 +15,22 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2012-
|
18
|
-
dependencies:
|
19
|
-
|
18
|
+
date: 2012-10-09 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: systemu
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
20
34
|
description: |-
|
21
35
|
OpenVZ is a container based virtualization for Linux. This API will
|
22
36
|
allow you to easily write tools to manipulate containers on a host.
|
@@ -28,31 +42,18 @@ extensions: []
|
|
28
42
|
extra_rdoc_files:
|
29
43
|
- COPYING
|
30
44
|
files:
|
31
|
-
-
|
32
|
-
- lib/openvz.rb
|
33
|
-
- lib/openvz/vendor/systemu/README.tmpl
|
34
|
-
- lib/openvz/vendor/systemu/gemspec.rb
|
35
|
-
- lib/openvz/vendor/systemu/install.rb
|
36
|
-
- lib/openvz/vendor/systemu/samples/e.rb
|
37
|
-
- lib/openvz/vendor/systemu/samples/b.rb
|
38
|
-
- lib/openvz/vendor/systemu/samples/d.rb
|
39
|
-
- lib/openvz/vendor/systemu/samples/c.rb
|
40
|
-
- lib/openvz/vendor/systemu/samples/a.rb
|
41
|
-
- lib/openvz/vendor/systemu/samples/f.rb
|
42
|
-
- lib/openvz/vendor/systemu/gen_readme.rb
|
43
|
-
- lib/openvz/vendor/systemu/lib/systemu.rb
|
44
|
-
- lib/openvz/vendor/systemu/a.rb
|
45
|
-
- lib/openvz/vendor/systemu/README
|
46
|
-
- lib/openvz/vendor/require_vendored.rb
|
47
|
-
- lib/openvz/vendor/load_systemu.rb
|
48
|
-
- lib/openvz/log.rb
|
49
|
-
- lib/openvz/inventory.rb
|
50
|
-
- lib/openvz/util.rb
|
51
|
-
- lib/openvz/vendor.rb
|
45
|
+
- COPYING
|
52
46
|
- lib/openvz/confighash.rb
|
53
47
|
- lib/openvz/container.rb
|
48
|
+
- lib/openvz/inventory.rb
|
49
|
+
- lib/openvz/log.rb
|
54
50
|
- lib/openvz/shell.rb
|
55
|
-
-
|
51
|
+
- lib/openvz/util.rb
|
52
|
+
- lib/openvz/vendor/require_vendored.rb
|
53
|
+
- lib/openvz/vendor.rb
|
54
|
+
- lib/openvz.rb
|
55
|
+
- openvz.gemspec
|
56
|
+
- README.md
|
56
57
|
homepage: http://github.com/sts/ruby-openvz
|
57
58
|
licenses: []
|
58
59
|
|
@@ -1 +0,0 @@
|
|
1
|
-
$: << File.join([File.dirname(__FILE__), "systemu/lib"])
|
@@ -1,160 +0,0 @@
|
|
1
|
-
NAME
|
2
|
-
|
3
|
-
systemu
|
4
|
-
|
5
|
-
SYNOPSIS
|
6
|
-
|
7
|
-
univeral capture of stdout and stderr and handling of child process pid for windows, *nix, etc.
|
8
|
-
|
9
|
-
URIS
|
10
|
-
|
11
|
-
http://rubyforge.org/projects/codeforpeople/
|
12
|
-
http://codeforpeople.com/lib/ruby/
|
13
|
-
http://codeforpeople.rubyforge.org/svn/
|
14
|
-
|
15
|
-
INSTALL
|
16
|
-
|
17
|
-
gem install systemu
|
18
|
-
|
19
|
-
HISTORY
|
20
|
-
|
21
|
-
1.2.0
|
22
|
-
|
23
|
-
- fixed handling of background thread management - needed
|
24
|
-
Thread.current.abort_on_exception = true
|
25
|
-
|
26
|
-
- fixed reporting of child pid, it was reported as the parent's pid before
|
27
|
-
|
28
|
-
SAMPLES
|
29
|
-
|
30
|
-
<========< samples/a.rb >========>
|
31
|
-
|
32
|
-
~ > cat samples/a.rb
|
33
|
-
|
34
|
-
#
|
35
|
-
# systemu can be used on any platform to return status, stdout, and stderr of
|
36
|
-
# any command. unlike other methods like open3/popen4 there is zero danger of
|
37
|
-
# full pipes or threading issues hanging your process or subprocess.
|
38
|
-
#
|
39
|
-
require 'systemu'
|
40
|
-
|
41
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
42
|
-
|
43
|
-
status, stdout, stderr = systemu date
|
44
|
-
p [ status, stdout, stderr ]
|
45
|
-
|
46
|
-
~ > ruby samples/a.rb
|
47
|
-
|
48
|
-
[#<Process::Status: pid=987,exited(0)>, "Thu Dec 06 16:01:59 -0700 2007\n", "Thu Dec 06 16:01:59 -0700 2007\n"]
|
49
|
-
|
50
|
-
|
51
|
-
<========< samples/b.rb >========>
|
52
|
-
|
53
|
-
~ > cat samples/b.rb
|
54
|
-
|
55
|
-
#
|
56
|
-
# quite a few keys can be passed to the command to alter it's behaviour. if
|
57
|
-
# either stdout or stderr is supplied those objects should respond_to? '<<'
|
58
|
-
# and only status will be returned
|
59
|
-
#
|
60
|
-
require 'systemu'
|
61
|
-
|
62
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
63
|
-
|
64
|
-
stdout, stderr = '', ''
|
65
|
-
status = systemu date, 'stdout' => stdout, 'stderr' => stderr
|
66
|
-
p [ status, stdout, stderr ]
|
67
|
-
|
68
|
-
~ > ruby samples/b.rb
|
69
|
-
|
70
|
-
[#<Process::Status: pid=992,exited(0)>, "Thu Dec 06 16:01:59 -0700 2007\n", "Thu Dec 06 16:01:59 -0700 2007\n"]
|
71
|
-
|
72
|
-
|
73
|
-
<========< samples/c.rb >========>
|
74
|
-
|
75
|
-
~ > cat samples/c.rb
|
76
|
-
|
77
|
-
#
|
78
|
-
# of course stdin can be supplied too. synonyms for 'stdin' include '0' and
|
79
|
-
# 0. the other stdio streams have similar shortcuts
|
80
|
-
#
|
81
|
-
require 'systemu'
|
82
|
-
|
83
|
-
cat = %q( ruby -e" ARGF.each{|line| puts line} " )
|
84
|
-
|
85
|
-
status = systemu cat, 0=>'the stdin for cat', 1=>stdout=''
|
86
|
-
puts stdout
|
87
|
-
|
88
|
-
~ > ruby samples/c.rb
|
89
|
-
|
90
|
-
the stdin for cat
|
91
|
-
|
92
|
-
|
93
|
-
<========< samples/d.rb >========>
|
94
|
-
|
95
|
-
~ > cat samples/d.rb
|
96
|
-
|
97
|
-
#
|
98
|
-
# the cwd can be supplied
|
99
|
-
#
|
100
|
-
require 'systemu'
|
101
|
-
require 'tmpdir'
|
102
|
-
|
103
|
-
pwd = %q( ruby -e" STDERR.puts Dir.pwd " )
|
104
|
-
|
105
|
-
status = systemu pwd, 2=>(stderr=''), :cwd=>Dir.tmpdir
|
106
|
-
puts stderr
|
107
|
-
|
108
|
-
|
109
|
-
~ > ruby samples/d.rb
|
110
|
-
|
111
|
-
/private/tmp
|
112
|
-
|
113
|
-
|
114
|
-
<========< samples/e.rb >========>
|
115
|
-
|
116
|
-
~ > cat samples/e.rb
|
117
|
-
|
118
|
-
#
|
119
|
-
# any environment vars specified are merged into the child's environment
|
120
|
-
#
|
121
|
-
require 'systemu'
|
122
|
-
|
123
|
-
env = %q( ruby -r yaml -e" puts ENV[ 'answer' ] " )
|
124
|
-
|
125
|
-
status = systemu env, 1=>stdout='', 'env'=>{ 'answer' => 0b101010 }
|
126
|
-
puts stdout
|
127
|
-
|
128
|
-
~ > ruby samples/e.rb
|
129
|
-
|
130
|
-
42
|
131
|
-
|
132
|
-
|
133
|
-
<========< samples/f.rb >========>
|
134
|
-
|
135
|
-
~ > cat samples/f.rb
|
136
|
-
|
137
|
-
#
|
138
|
-
# if a block is specified then it is passed the child pid and run in a
|
139
|
-
# background thread. note that this thread will __not__ be blocked during the
|
140
|
-
# execution of the command so it may do useful work such as killing the child
|
141
|
-
# if execution time passes a certain threshold
|
142
|
-
#
|
143
|
-
require 'systemu'
|
144
|
-
|
145
|
-
looper = %q( ruby -e" loop{ STDERR.puts Time.now.to_i; sleep 1 } " )
|
146
|
-
|
147
|
-
status, stdout, stderr =
|
148
|
-
systemu looper do |cid|
|
149
|
-
sleep 3
|
150
|
-
Process.kill 9, cid
|
151
|
-
end
|
152
|
-
|
153
|
-
p status
|
154
|
-
p stderr
|
155
|
-
|
156
|
-
~ > ruby samples/f.rb
|
157
|
-
|
158
|
-
#<Process::Status: pid=1012,signaled(SIGKILL=9)>
|
159
|
-
"1196982119\n1196982120\n1196982121\n"
|
160
|
-
|
@@ -1,30 +0,0 @@
|
|
1
|
-
NAME
|
2
|
-
|
3
|
-
systemu
|
4
|
-
|
5
|
-
SYNOPSIS
|
6
|
-
|
7
|
-
univeral capture of stdout and stderr and handling of child process pid for windows, *nix, etc.
|
8
|
-
|
9
|
-
URIS
|
10
|
-
|
11
|
-
http://rubyforge.org/projects/codeforpeople/
|
12
|
-
http://codeforpeople.com/lib/ruby/
|
13
|
-
http://codeforpeople.rubyforge.org/svn/
|
14
|
-
|
15
|
-
INSTALL
|
16
|
-
|
17
|
-
gem install systemu
|
18
|
-
|
19
|
-
HISTORY
|
20
|
-
|
21
|
-
1.2.0
|
22
|
-
|
23
|
-
- fixed handling of background thread management - needed
|
24
|
-
Thread.current.abort_on_exception = true
|
25
|
-
|
26
|
-
- fixed reporting of child pid, it was reported as the parent's pid before
|
27
|
-
|
28
|
-
SAMPLES
|
29
|
-
|
30
|
-
@samples
|
@@ -1,23 +0,0 @@
|
|
1
|
-
lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
|
5
|
-
Gem::Specification::new do |spec|
|
6
|
-
spec.name = lib
|
7
|
-
spec.version = version
|
8
|
-
spec.platform = Gem::Platform::RUBY
|
9
|
-
spec.summary = lib
|
10
|
-
|
11
|
-
spec.files = Dir::glob "**/**"
|
12
|
-
spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
|
13
|
-
|
14
|
-
spec.require_path = "lib"
|
15
|
-
spec.autorequire = lib
|
16
|
-
|
17
|
-
spec.has_rdoc = File::exist? "doc"
|
18
|
-
spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
|
19
|
-
|
20
|
-
spec.author = "Ara T. Howard"
|
21
|
-
spec.email = "ara.t.howard@noaa.gov"
|
22
|
-
spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
|
23
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
$VERBOSE=nil
|
4
|
-
|
5
|
-
def indent s, n = 2
|
6
|
-
ws = ' ' * n
|
7
|
-
s.gsub %r/^/, ws
|
8
|
-
end
|
9
|
-
|
10
|
-
template = IO::read 'README.tmpl'
|
11
|
-
|
12
|
-
samples = ''
|
13
|
-
prompt = '~ > '
|
14
|
-
|
15
|
-
Dir['sample*/*'].sort.each do |sample|
|
16
|
-
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
17
|
-
|
18
|
-
cmd = "cat #{ sample }"
|
19
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
20
|
-
samples << indent(`#{ cmd }`, 4) << "\n"
|
21
|
-
|
22
|
-
cmd = "ruby #{ sample }"
|
23
|
-
samples << indent(prompt + cmd, 2) << "\n\n"
|
24
|
-
|
25
|
-
cmd = "ruby -W0 -Ilib #{ sample }"
|
26
|
-
samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
|
27
|
-
end
|
28
|
-
|
29
|
-
#samples.gsub! %r/^/, ' '
|
30
|
-
|
31
|
-
readme = template.gsub %r/^\s*@samples\s*$/, samples
|
32
|
-
print readme
|
@@ -1,206 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'rbconfig'
|
3
|
-
require 'find'
|
4
|
-
require 'ftools'
|
5
|
-
require 'tempfile'
|
6
|
-
include Config
|
7
|
-
|
8
|
-
LIBDIR = "lib"
|
9
|
-
LIBDIR_MODE = 0644
|
10
|
-
|
11
|
-
BINDIR = "bin"
|
12
|
-
BINDIR_MODE = 0755
|
13
|
-
|
14
|
-
|
15
|
-
$srcdir = CONFIG["srcdir"]
|
16
|
-
$version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
17
|
-
$libdir = File.join(CONFIG["libdir"], "ruby", $version)
|
18
|
-
$archdir = File.join($libdir, CONFIG["arch"])
|
19
|
-
$site_libdir = $:.find {|x| x =~ /site_ruby$/}
|
20
|
-
$bindir = CONFIG["bindir"] || CONFIG['BINDIR']
|
21
|
-
$ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
|
22
|
-
$ruby_ext = CONFIG['EXEEXT'] || ''
|
23
|
-
$ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
|
24
|
-
|
25
|
-
if !$site_libdir
|
26
|
-
$site_libdir = File.join($libdir, "site_ruby")
|
27
|
-
elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
|
28
|
-
$site_libdir = File.join($site_libdir, $version)
|
29
|
-
end
|
30
|
-
|
31
|
-
def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
|
32
|
-
#{{{
|
33
|
-
path = []
|
34
|
-
dir = []
|
35
|
-
Find.find(srcdir) do |f|
|
36
|
-
next unless FileTest.file?(f)
|
37
|
-
next if (f = f[srcdir.length+1..-1]) == nil
|
38
|
-
next if (/CVS$/ =~ File.dirname(f))
|
39
|
-
next if f =~ %r/\.lnk/
|
40
|
-
path.push f
|
41
|
-
dir |= [File.dirname(f)]
|
42
|
-
end
|
43
|
-
for f in dir
|
44
|
-
next if f == "."
|
45
|
-
next if f == "CVS"
|
46
|
-
File::makedirs(File.join(destdir, f))
|
47
|
-
end
|
48
|
-
for f in path
|
49
|
-
next if (/\~$/ =~ f)
|
50
|
-
next if (/^\./ =~ File.basename(f))
|
51
|
-
unless bin
|
52
|
-
File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
|
53
|
-
else
|
54
|
-
from = File.join(srcdir, f)
|
55
|
-
to = File.join(destdir, f)
|
56
|
-
shebangify(from) do |sf|
|
57
|
-
$deferr.print from, " -> ", File::catname(from, to), "\n"
|
58
|
-
$deferr.printf "chmod %04o %s\n", mode, to
|
59
|
-
File::install(sf, to, mode, false)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
#}}}
|
64
|
-
end
|
65
|
-
def shebangify f
|
66
|
-
#{{{
|
67
|
-
open(f) do |fd|
|
68
|
-
buf = fd.read 42
|
69
|
-
if buf =~ %r/^\s*#\s*!.*ruby/o
|
70
|
-
ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
|
71
|
-
begin
|
72
|
-
fd.rewind
|
73
|
-
ftmp.puts "#!#{ $ruby }"
|
74
|
-
while((buf = fd.read(8192)))
|
75
|
-
ftmp.write buf
|
76
|
-
end
|
77
|
-
ftmp.close
|
78
|
-
yield ftmp.path
|
79
|
-
ensure
|
80
|
-
ftmp.close!
|
81
|
-
end
|
82
|
-
else
|
83
|
-
yield f
|
84
|
-
end
|
85
|
-
end
|
86
|
-
#}}}
|
87
|
-
end
|
88
|
-
def ARGV.switch
|
89
|
-
#{{{
|
90
|
-
return nil if self.empty?
|
91
|
-
arg = self.shift
|
92
|
-
return nil if arg == '--'
|
93
|
-
if arg =~ /^-(.)(.*)/
|
94
|
-
return arg if $1 == '-'
|
95
|
-
raise 'unknown switch "-"' if $2.index('-')
|
96
|
-
self.unshift "-#{$2}" if $2.size > 0
|
97
|
-
"-#{$1}"
|
98
|
-
else
|
99
|
-
self.unshift arg
|
100
|
-
nil
|
101
|
-
end
|
102
|
-
#}}}
|
103
|
-
end
|
104
|
-
def ARGV.req_arg
|
105
|
-
#{{{
|
106
|
-
self.shift || raise('missing argument')
|
107
|
-
#}}}
|
108
|
-
end
|
109
|
-
def linkify d, linked = []
|
110
|
-
#--{{{
|
111
|
-
if test ?d, d
|
112
|
-
versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
|
113
|
-
versioned.each do |v|
|
114
|
-
src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
|
115
|
-
lnk = nil
|
116
|
-
begin
|
117
|
-
if test ?l, dst
|
118
|
-
lnk = "#{ dst }.lnk"
|
119
|
-
puts "#{ dst } -> #{ lnk }"
|
120
|
-
File::rename dst, lnk
|
121
|
-
end
|
122
|
-
unless test ?e, dst
|
123
|
-
puts "#{ src } -> #{ dst }"
|
124
|
-
File::copy src, dst
|
125
|
-
linked << dst
|
126
|
-
end
|
127
|
-
ensure
|
128
|
-
if lnk
|
129
|
-
at_exit do
|
130
|
-
puts "#{ lnk } -> #{ dst }"
|
131
|
-
File::rename lnk, dst
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
linked
|
138
|
-
#--}}}
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
#
|
143
|
-
# main program
|
144
|
-
#
|
145
|
-
|
146
|
-
libdir = $site_libdir
|
147
|
-
bindir = $bindir
|
148
|
-
no_linkify = false
|
149
|
-
linked = nil
|
150
|
-
help = false
|
151
|
-
|
152
|
-
usage = <<-usage
|
153
|
-
#{ File::basename $0 }
|
154
|
-
-d, --destdir <destdir>
|
155
|
-
-l, --libdir <libdir>
|
156
|
-
-b, --bindir <bindir>
|
157
|
-
-r, --ruby <ruby>
|
158
|
-
-n, --no_linkify
|
159
|
-
-s, --sudo
|
160
|
-
-h, --help
|
161
|
-
usage
|
162
|
-
|
163
|
-
begin
|
164
|
-
while switch = ARGV.switch
|
165
|
-
case switch
|
166
|
-
when '-d', '--destdir'
|
167
|
-
libdir = ARGV.req_arg
|
168
|
-
when '-l', '--libdir'
|
169
|
-
libdir = ARGV.req_arg
|
170
|
-
when '-b', '--bindir'
|
171
|
-
bindir = ARGV.req_arg
|
172
|
-
when '-r', '--ruby'
|
173
|
-
$ruby = ARGV.req_arg
|
174
|
-
when '-n', '--no_linkify'
|
175
|
-
no_linkify = true
|
176
|
-
when '-s', '--sudo'
|
177
|
-
sudo = 'sudo'
|
178
|
-
when '-h', '--help'
|
179
|
-
help = true
|
180
|
-
else
|
181
|
-
raise "unknown switch #{switch.dump}"
|
182
|
-
end
|
183
|
-
end
|
184
|
-
rescue
|
185
|
-
STDERR.puts $!.to_s
|
186
|
-
STDERR.puts usage
|
187
|
-
exit 1
|
188
|
-
end
|
189
|
-
|
190
|
-
if help
|
191
|
-
STDOUT.puts usage
|
192
|
-
exit
|
193
|
-
end
|
194
|
-
|
195
|
-
unless no_linkify
|
196
|
-
linked = linkify('lib') + linkify('bin')
|
197
|
-
end
|
198
|
-
|
199
|
-
system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
|
200
|
-
|
201
|
-
install_rb(LIBDIR, libdir, LIBDIR_MODE)
|
202
|
-
install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
|
203
|
-
|
204
|
-
if linked
|
205
|
-
linked.each{|path| File::rm_f path}
|
206
|
-
end
|
@@ -1,299 +0,0 @@
|
|
1
|
-
# vim: ts=2:sw=2:sts=2:et:fdm=marker
|
2
|
-
require 'tmpdir'
|
3
|
-
require 'socket'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'rbconfig'
|
6
|
-
require 'thread'
|
7
|
-
require 'yaml'
|
8
|
-
|
9
|
-
class Object
|
10
|
-
def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end
|
11
|
-
end
|
12
|
-
|
13
|
-
class SystemUniversal
|
14
|
-
#
|
15
|
-
# constants
|
16
|
-
#
|
17
|
-
SystemUniversal::VERSION = '1.2.0' unless defined? SystemUniversal::VERSION
|
18
|
-
def version() SystemUniversal::VERSION end
|
19
|
-
#
|
20
|
-
# class methods
|
21
|
-
#
|
22
|
-
|
23
|
-
@host = Socket.gethostname
|
24
|
-
@ppid = Process.ppid
|
25
|
-
@pid = Process.pid
|
26
|
-
@turd = ENV['SYSTEMU_TURD']
|
27
|
-
|
28
|
-
c = ::Config::CONFIG
|
29
|
-
ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
30
|
-
@ruby = if system('%s -e 42' % ruby)
|
31
|
-
ruby
|
32
|
-
else
|
33
|
-
system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
|
34
|
-
end
|
35
|
-
|
36
|
-
class << self
|
37
|
-
%w( host ppid pid ruby turd ).each{|a| attr_accessor a}
|
38
|
-
end
|
39
|
-
|
40
|
-
#
|
41
|
-
# instance methods
|
42
|
-
#
|
43
|
-
|
44
|
-
def initialize argv, opts = {}, &block
|
45
|
-
getopt = getopts opts
|
46
|
-
|
47
|
-
@argv = argv
|
48
|
-
@block = block
|
49
|
-
|
50
|
-
@stdin = getopt[ ['stdin', 'in', '0', 0] ]
|
51
|
-
@stdout = getopt[ ['stdout', 'out', '1', 1] ]
|
52
|
-
@stderr = getopt[ ['stderr', 'err', '2', 2] ]
|
53
|
-
@env = getopt[ 'env' ]
|
54
|
-
@cwd = getopt[ 'cwd' ]
|
55
|
-
|
56
|
-
@host = getopt[ 'host', self.class.host ]
|
57
|
-
@ppid = getopt[ 'ppid', self.class.ppid ]
|
58
|
-
@pid = getopt[ 'pid', self.class.pid ]
|
59
|
-
@ruby = getopt[ 'ruby', self.class.ruby ]
|
60
|
-
end
|
61
|
-
|
62
|
-
def systemu
|
63
|
-
tmpdir do |tmp|
|
64
|
-
c = child_setup tmp
|
65
|
-
status = nil
|
66
|
-
|
67
|
-
begin
|
68
|
-
thread = nil
|
69
|
-
|
70
|
-
quietly{
|
71
|
-
IO.popen "#{ @ruby } #{ c['program'] }", 'r+' do |pipe|
|
72
|
-
line = pipe.gets
|
73
|
-
case line
|
74
|
-
when %r/^pid: \d+$/
|
75
|
-
cid = Integer line[%r/\d+/]
|
76
|
-
else
|
77
|
-
begin
|
78
|
-
buf = pipe.read
|
79
|
-
buf = "#{ line }#{ buf }"
|
80
|
-
e = Marshal.load buf
|
81
|
-
raise unless Exception === e
|
82
|
-
raise e
|
83
|
-
rescue
|
84
|
-
raise "wtf?\n#{ buf }\n"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
thread = new_thread cid, @block if @block
|
88
|
-
pipe.read rescue nil
|
89
|
-
end
|
90
|
-
}
|
91
|
-
status = $?
|
92
|
-
ensure
|
93
|
-
if thread
|
94
|
-
begin
|
95
|
-
class << status
|
96
|
-
attr 'thread'
|
97
|
-
end
|
98
|
-
status.instance_eval{ @thread = thread }
|
99
|
-
rescue
|
100
|
-
42
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
if @stdout or @stderr
|
106
|
-
open(c['stdout']){|f| relay f => @stdout} if @stdout
|
107
|
-
open(c['stderr']){|f| relay f => @stderr} if @stderr
|
108
|
-
status
|
109
|
-
else
|
110
|
-
[status, IO.read(c['stdout']), IO.read(c['stderr'])]
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def new_thread cid, block
|
116
|
-
q = Queue.new
|
117
|
-
Thread.new(cid) do |cid|
|
118
|
-
current = Thread.current
|
119
|
-
current.abort_on_exception = true
|
120
|
-
q.push current
|
121
|
-
block.call cid
|
122
|
-
end
|
123
|
-
q.pop
|
124
|
-
end
|
125
|
-
|
126
|
-
def child_setup tmp
|
127
|
-
stdin = File.expand_path(File.join(tmp, 'stdin'))
|
128
|
-
stdout = File.expand_path(File.join(tmp, 'stdout'))
|
129
|
-
stderr = File.expand_path(File.join(tmp, 'stderr'))
|
130
|
-
program = File.expand_path(File.join(tmp, 'program'))
|
131
|
-
config = File.expand_path(File.join(tmp, 'config'))
|
132
|
-
|
133
|
-
if @stdin
|
134
|
-
open(stdin, 'w'){|f| relay @stdin => f}
|
135
|
-
else
|
136
|
-
FileUtils.touch stdin
|
137
|
-
end
|
138
|
-
FileUtils.touch stdout
|
139
|
-
FileUtils.touch stderr
|
140
|
-
|
141
|
-
c = {}
|
142
|
-
c['argv'] = @argv
|
143
|
-
c['env'] = @env
|
144
|
-
c['cwd'] = @cwd
|
145
|
-
c['stdin'] = stdin
|
146
|
-
c['stdout'] = stdout
|
147
|
-
c['stderr'] = stderr
|
148
|
-
c['program'] = program
|
149
|
-
open(config, 'w'){|f| YAML.dump c, f}
|
150
|
-
|
151
|
-
open(program, 'w'){|f| f.write child_program(config)}
|
152
|
-
|
153
|
-
c
|
154
|
-
end
|
155
|
-
|
156
|
-
def quietly
|
157
|
-
v = $VERBOSE
|
158
|
-
$VERBOSE = nil
|
159
|
-
yield
|
160
|
-
ensure
|
161
|
-
$VERBOSE = v
|
162
|
-
end
|
163
|
-
|
164
|
-
def child_program config
|
165
|
-
<<-program
|
166
|
-
PIPE = STDOUT.dup
|
167
|
-
begin
|
168
|
-
require 'yaml'
|
169
|
-
|
170
|
-
config = YAML.load(IO.read('#{ config }'))
|
171
|
-
|
172
|
-
argv = config['argv']
|
173
|
-
env = config['env']
|
174
|
-
cwd = config['cwd']
|
175
|
-
stdin = config['stdin']
|
176
|
-
stdout = config['stdout']
|
177
|
-
stderr = config['stderr']
|
178
|
-
|
179
|
-
Dir.chdir cwd if cwd
|
180
|
-
env.each{|k,v| ENV[k.to_s] = v.to_s} if env
|
181
|
-
|
182
|
-
STDIN.reopen stdin
|
183
|
-
STDOUT.reopen stdout
|
184
|
-
STDERR.reopen stderr
|
185
|
-
|
186
|
-
PIPE.puts "pid: \#{ Process.pid }"
|
187
|
-
PIPE.flush ### the process is ready yo!
|
188
|
-
PIPE.close
|
189
|
-
|
190
|
-
exec *argv
|
191
|
-
rescue Exception => e
|
192
|
-
PIPE.write Marshal.dump(e) rescue nil
|
193
|
-
exit 42
|
194
|
-
end
|
195
|
-
program
|
196
|
-
end
|
197
|
-
|
198
|
-
def relay srcdst
|
199
|
-
src, dst, ignored = srcdst.to_a.first
|
200
|
-
if src.respond_to? 'read'
|
201
|
-
while((buf = src.read(8192))); dst << buf; end
|
202
|
-
else
|
203
|
-
src.each{|buf| dst << buf}
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def tmpdir d = Dir.tmpdir, max = 42, &b
|
208
|
-
i = -1 and loop{
|
209
|
-
i += 1
|
210
|
-
|
211
|
-
tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
|
212
|
-
|
213
|
-
begin
|
214
|
-
Dir.mkdir tmp
|
215
|
-
rescue Errno::EEXIST
|
216
|
-
raise if i >= max
|
217
|
-
next
|
218
|
-
end
|
219
|
-
|
220
|
-
break(
|
221
|
-
if b
|
222
|
-
begin
|
223
|
-
b.call tmp
|
224
|
-
ensure
|
225
|
-
FileUtils.rm_rf tmp unless SystemU.turd
|
226
|
-
end
|
227
|
-
else
|
228
|
-
tmp
|
229
|
-
end
|
230
|
-
)
|
231
|
-
}
|
232
|
-
end
|
233
|
-
|
234
|
-
def getopts opts = {}
|
235
|
-
lambda do |*args|
|
236
|
-
keys, default, ignored = args
|
237
|
-
catch('opt') do
|
238
|
-
[keys].flatten.each do |key|
|
239
|
-
[key, key.to_s, key.to_s.intern].each do |key|
|
240
|
-
throw 'opt', opts[key] if opts.has_key?(key)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
default
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
SystemU = SystemUniversal unless defined? SystemU
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
if $0 == __FILE__
|
264
|
-
#
|
265
|
-
# date
|
266
|
-
#
|
267
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
268
|
-
|
269
|
-
status, stdout, stderr = systemu date
|
270
|
-
p [status, stdout, stderr]
|
271
|
-
|
272
|
-
status = systemu date, 1=>(stdout = '')
|
273
|
-
p [status, stdout]
|
274
|
-
|
275
|
-
status = systemu date, 2=>(stderr = '')
|
276
|
-
p [status, stderr]
|
277
|
-
#
|
278
|
-
# sleep
|
279
|
-
#
|
280
|
-
sleep = %q( ruby -e" p(sleep(1)) " )
|
281
|
-
status, stdout, stderr = systemu sleep
|
282
|
-
p [status, stdout, stderr]
|
283
|
-
|
284
|
-
sleep = %q( ruby -e" p(sleep(42)) " )
|
285
|
-
status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid}
|
286
|
-
p [status, stdout, stderr]
|
287
|
-
#
|
288
|
-
# env
|
289
|
-
#
|
290
|
-
env = %q( ruby -e" p ENV['A'] " )
|
291
|
-
status, stdout, stderr = systemu env, :env => {'A' => 42}
|
292
|
-
p [status, stdout, stderr]
|
293
|
-
#
|
294
|
-
# cwd
|
295
|
-
#
|
296
|
-
env = %q( ruby -e" p Dir.pwd " )
|
297
|
-
status, stdout, stderr = systemu env, :cwd => Dir.tmpdir
|
298
|
-
p [status, stdout, stderr]
|
299
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# systemu can be used on any platform to return status, stdout, and stderr of
|
3
|
-
# any command. unlike other methods like open3/popen4 there is zero danger of
|
4
|
-
# full pipes or threading issues hanging your process or subprocess.
|
5
|
-
#
|
6
|
-
require 'systemu'
|
7
|
-
|
8
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
9
|
-
|
10
|
-
status, stdout, stderr = systemu date
|
11
|
-
p [ status, stdout, stderr ]
|
@@ -1,12 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# quite a few keys can be passed to the command to alter it's behaviour. if
|
3
|
-
# either stdout or stderr is supplied those objects should respond_to? '<<'
|
4
|
-
# and only status will be returned
|
5
|
-
#
|
6
|
-
require 'systemu'
|
7
|
-
|
8
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
9
|
-
|
10
|
-
stdout, stderr = '', ''
|
11
|
-
status = systemu date, 'stdout' => stdout, 'stderr' => stderr
|
12
|
-
p [ status, stdout, stderr ]
|
@@ -1,10 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# of course stdin can be supplied too. synonyms for 'stdin' include '0' and
|
3
|
-
# 0. the other stdio streams have similar shortcuts
|
4
|
-
#
|
5
|
-
require 'systemu'
|
6
|
-
|
7
|
-
cat = %q( ruby -e" ARGF.each{|line| puts line} " )
|
8
|
-
|
9
|
-
status = systemu cat, 0=>'the stdin for cat', 1=>stdout=''
|
10
|
-
puts stdout
|
@@ -1,18 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# if a block is specified then it is passed the child pid and run in a
|
3
|
-
# background thread. note that this thread will __not__ be blocked during the
|
4
|
-
# execution of the command so it may do useful work such as killing the child
|
5
|
-
# if execution time passes a certain threshold
|
6
|
-
#
|
7
|
-
require 'systemu'
|
8
|
-
|
9
|
-
looper = %q( ruby -e" loop{ STDERR.puts Time.now.to_i; sleep 1 } " )
|
10
|
-
|
11
|
-
status, stdout, stderr =
|
12
|
-
systemu looper do |cid|
|
13
|
-
sleep 3
|
14
|
-
Process.kill 9, cid
|
15
|
-
end
|
16
|
-
|
17
|
-
p status
|
18
|
-
p stderr
|