spawncli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: