spawncli 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 299f86db99d8e30a0b14ca6040fff591db71cfbe
4
+ data.tar.gz: ec23fd6b89dce707ce2c55889606f3a4c734ce10
5
+ SHA512:
6
+ metadata.gz: 2c19b171c45fb85b16f68981538381ad9dcf142591101ce121868b052e294d791413b3dc3fe31217b3cd48ba37c286686a03ef07460dd3c64a574091e68de19e
7
+ data.tar.gz: 657daddb7e3e1be0203d87e4be8b6a57a23f8a3c7b021ca8fa4a51f9f28739af5e58e406f26a10f692982ac7d695b237367178a53bcfe03384b1b2589fbada47
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
11
+ /**/.DS_Store
12
+ /bin-ignore
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spawncli.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Spawncli
2
+
3
+ Spawncli lets you run several copies of a command-line in parallel, capturing their stdout and stderr.
4
+
5
+ ## Installation
6
+
7
+ Spawncli doesn't expose any worthwhile functionality as a library. It can be installed as a command-line gem from RubyGems:
8
+
9
+ ``gem install spawncli``
10
+
11
+ ## Usage
12
+
13
+ ``spawncli n command-line arg1 arg2 argN``
14
+
15
+ Spawncli takes two arguments: a number and a command to run. Any further arguments are interpreted as being part of the second.
16
+
17
+ To avoid shell interpretation of pipes and redirections, the command-line to run should be quoted.
18
+
19
+ ### Example
20
+
21
+ ``spawncli 10 "curl http://localhost:8080/foo"``
22
+
23
+ ### Return Code
24
+
25
+ Returns 1 if anything spawned process wrote to its stderr, 0 otherwise.
26
+
27
+ ## Development
28
+
29
+ TODO
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it ( https://github.com/[my-github-username]/spawn/fork )
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/spawncli ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'spawncli'
4
+
5
+ spawner = Spawncli::Spawncli.new
6
+ spawner.run $*
data/lib/spawncli.rb ADDED
@@ -0,0 +1,131 @@
1
+ require 'open4'
2
+ require 'threadinfo'
3
+
4
+ module Spawncli
5
+
6
+ class Spawncli
7
+
8
+ @@help_text = <<-EOF.gsub /^ /, ""
9
+ Spawn: Spawns 'n' copies of a command line.
10
+ John Hawksley <john.hawksley@gmail.com> -*- MIT License
11
+
12
+ See https://github.com/jhawksley/spawn for details.
13
+
14
+ Options:
15
+ spawncli 2 "sleep 1 && curl http://localhost" # Run 2 copies of the command
16
+ EOF
17
+
18
+
19
+ def run(args)
20
+
21
+ # Proces out the arguments - this is a very simple parse since we don't support any options.
22
+ n = process_args(args)
23
+
24
+ # Parse out the remainder of the args values as a command line to run in the shell.
25
+ argline = generate_arg_line(args) # Gets rid of the trailing space.
26
+
27
+ # An array to hold our ThreadInfo objects.
28
+ threads = spawn_threads(argline, n)
29
+
30
+ puts
31
+
32
+ # Poll the thread array, seeing if any have completed (status false)
33
+ # or there was an exception (nil).
34
+ # Any exceptions are not currently handled.
35
+ any_stderr = poll_threads(threads)
36
+
37
+ # If any thread wrote to stderr, exit 1, otherwise 0.
38
+ exit any_stderr ? 1 : 0
39
+
40
+ end
41
+
42
+ private
43
+
44
+ def poll_threads(threads)
45
+ any_stderr = false
46
+
47
+ while threads.length > 0 do
48
+ threads.each do |ti|
49
+ if (ti.thread.status == false || ti.thread.status == nil) then
50
+ # Done or exited with exception
51
+ threads.delete(ti)
52
+
53
+ print "#{ti.id}: complete #{ti.thread.status == nil ? '(failed) ' : ''}"
54
+ $stdout.flush
55
+ puts (Time.now - ti.start_time).to_s << 's'
56
+
57
+ if ti.stdout != nil && !ti.stdout.empty?
58
+ ti.stdout.each_line do |l|
59
+ puts "#{ti.id}: out: #{l}"
60
+ end
61
+ end
62
+ if ti.stderr != nil && !ti.stderr.empty?
63
+ any_stderr = true
64
+ ti.stderr.each_line do |l|
65
+ puts "#{ti.id}: err: #{l}"
66
+ end
67
+ end
68
+
69
+ puts
70
+ end
71
+ end
72
+ end
73
+ any_stderr
74
+ end
75
+
76
+ def spawn_threads(argline, n)
77
+ threads = Array.new #of ThreadInfos
78
+
79
+ puts "Spawning #{n} copies of #{argline}"
80
+
81
+ # Do all the spawns
82
+ (1..n).each do |i|
83
+ ti = ThreadInfo.new i #... initializes the internal ID with 'i'
84
+ threads << ti
85
+ thread = Thread.new do
86
+ status = Open4::popen4(argline) do |pid, stdin, stdout, stderr|
87
+ ti.stdout = stdout.read.strip
88
+ ti.stderr = stderr.read.strip
89
+ end
90
+ end
91
+ ti.thread = thread
92
+ puts "#{i}: spawned."
93
+ end
94
+ threads
95
+ end
96
+
97
+ def generate_arg_line(args)
98
+ argline=''
99
+
100
+ args.each do |a|
101
+ argline = argline + a + ' '
102
+ end
103
+
104
+ argline.strip!
105
+ argline
106
+ end
107
+
108
+ def process_args(args)
109
+ if args.length < 2 then
110
+ do_help
111
+ abort
112
+ else
113
+ # The first argument is interpreted as the number of concurrent thread
114
+ # to run.
115
+ begin
116
+ n = Integer(args.shift)
117
+ rescue Exception => e
118
+ abort "The first argument of a multiple argument invocation must be an integer (#{e})"
119
+ end
120
+ end
121
+ n
122
+ end
123
+
124
+
125
+ def do_help
126
+ puts @@help_text
127
+ end
128
+
129
+ end
130
+
131
+ end
data/lib/threadinfo.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Spawncli
2
+
3
+
4
+ # A class to hold information about a spawned thread.
5
+ class ThreadInfo
6
+
7
+ attr_accessor :thread, :id, :stdout, :stderr, :exit_code
8
+ attr_reader :start_time
9
+
10
+ # Create a new ThreadInfo holder.
11
+ # @param id [String] the thread ID
12
+ def initialize(id)
13
+ @id = id
14
+ @start_time = Time.now
15
+ end
16
+
17
+ end
18
+
19
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Spawncli
2
+ VERSION = '1.0.1'
3
+ end
data/spawncli.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "spawncli"
9
+ spec.version = Spawncli::VERSION
10
+ spec.authors = ["John Hawksley"]
11
+ spec.email = ["john.hawksley@gmail.com"]
12
+
13
+ spec.summary = %q{Run several command-lines in parallel.}
14
+ spec.description = %q{Spawncli forks several processes to run concurrently, and monitors their status.}
15
+ spec.homepage = "https://github.com/jhawksley/spawncli/"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "open4", "~> 1.3"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.9"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spawncli
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John Hawksley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: open4
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Spawncli forks several processes to run concurrently, and monitors their
56
+ status.
57
+ email:
58
+ - john.hawksley@gmail.com
59
+ executables:
60
+ - spawncli
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - bin/spawncli
70
+ - lib/spawncli.rb
71
+ - lib/threadinfo.rb
72
+ - lib/version.rb
73
+ - spawncli.gemspec
74
+ homepage: https://github.com/jhawksley/spawncli/
75
+ licenses: []
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.4.5
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Run several command-lines in parallel.
97
+ test_files: []
98
+ has_rdoc: