react 0.0.2 → 0.1.0

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/.gitignore CHANGED
@@ -1,22 +1,12 @@
1
- ## MAC OS
2
1
  .DS_Store
3
-
4
- ## TEXTMATE
5
2
  *.tmproj
6
3
  tmtags
7
-
8
- ## EMACS
9
4
  *~
10
5
  \#*
11
6
  .\#*
12
-
13
- ## VIM
14
7
  *.swp
15
-
16
- ## PROJECT::GENERAL
17
8
  coverage
18
9
  rdoc
19
10
  pkg
20
-
21
- ## PROJECT::SPECIFIC
22
11
  *.gem
12
+ *.rdb
data/README.md CHANGED
@@ -24,12 +24,9 @@ You can simply install React using rubygems:
24
24
  Firs you have to prepare file with available commands. It can look like this:
25
25
 
26
26
  # my_commands.yml
27
- restart_httpd: |
28
- apache2ctl graceful
29
- restart_mysql: |
30
- /etc/init.d/mysql restart
31
- reboot: |
32
- reboot
27
+ restart_httpd: apache2ctl graceful
28
+ restart_mysql: /etc/init.d/mysql restart
29
+ reboot: reboot
33
30
 
34
31
  And now you can start a consumer.
35
32
 
@@ -74,4 +71,11 @@ There are few more runtime options, which can be useful for you.
74
71
 
75
72
  ## Copyright
76
73
 
77
- Copyright (c) 2010 Kriss Kowalik. See LICENSE for details.
74
+ == Copyright
75
+
76
+ Copyleft 2010 Chris Kowalik. WTFPL Baby!
77
+
78
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
79
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
80
+
81
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
data/Rakefile CHANGED
@@ -1,54 +1,44 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "react"
8
- gem.version = "0.0.2"
9
- gem.default_executable = 'react'
10
- gem.executables = ['react']
11
- gem.summary = %Q{Redis based remote command executor.}
12
- gem.description = %Q{A simple application that allows for remote execution of commands.}
13
- gem.email = "kriss.kowalik@gmail.com"
14
- gem.homepage = "http://github.com/nu7hatch/react"
15
- gem.authors = ["Kriss 'nu7hatch' Kowalik"]
16
- gem.add_development_dependency "riot", ">= 0.11.3"
17
- gem.add_dependency "daemons", ">= 0"
18
- end
19
- Jeweler::GemcutterTasks.new
20
- rescue LoadError
21
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
- end
23
-
1
+ # -*- ruby -*-
2
+ $:.unshift(File.expand_path('../lib', __FILE__))
3
+ require 'react/version'
24
4
  require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
25
7
  Rake::TestTask.new(:test) do |test|
26
8
  test.libs << 'lib' << 'test'
27
- test.pattern = 'test/**/*_test.rb'
9
+ test.pattern = 'test/**/test_*.rb'
28
10
  test.verbose = true
29
11
  end
30
12
 
31
13
  begin
32
- require 'rcov/rcovtask'
33
14
  Rcov::RcovTask.new do |test|
34
15
  test.libs << 'test'
35
- test.pattern = 'test/**/*_test.rb'
16
+ test.pattern = 'test/**/test_*.rb'
36
17
  test.verbose = true
37
18
  end
38
- rescue LoadError
39
- task :rcov do
40
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
- end
19
+ rescue
20
+ puts "Rcov is not available!"
42
21
  end
43
22
 
44
- task :test => :check_dependencies
45
-
46
- task :default => :test
47
-
48
- require 'rake/rdoctask'
49
23
  Rake::RDocTask.new do |rdoc|
50
24
  rdoc.rdoc_dir = 'rdoc'
51
- rdoc.title = "React"
25
+ rdoc.title = "React #{React.version}"
52
26
  rdoc.rdoc_files.include('README*')
53
27
  rdoc.rdoc_files.include('lib/**/*.rb')
54
28
  end
29
+
30
+ task :default => :spec
31
+
32
+ desc "Build current version as a rubygem"
33
+ task :build do
34
+ `gem build react.gemspec`
35
+ `mv react-*.gem pkg/`
36
+ end
37
+
38
+ desc "Relase current version to rubygems.org"
39
+ task :release => :build do
40
+ `git tag -am "Version bump to #{React.version}" v#{React.version}`
41
+ `git push origin master`
42
+ `git push origin master --tags`
43
+ `gem push pkg/react-#{React.version}.gem`
44
+ end
data/bin/react CHANGED
@@ -1,35 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
- require 'react'
5
- require 'optparse'
6
- require 'daemons'
7
-
8
- if ARGV.empty?
9
- ARGV << '--help'
10
- else
11
- if File.exists?(ARGV[0])
12
- options[:commands] = YAML.load_file(ARGV[0])
13
- else
14
- puts "ERROR: File not found: `#{ARGV[0]}`"
15
- exit
16
- end
3
+ begin
4
+ require 'react'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'react'
17
8
  end
18
9
 
19
- options = {
20
- :redis => {:host => '127.0.0.1', :port => 6379, :db => 0},
21
- :commands => {},
22
- :queue => 'queue'
23
- }
24
-
25
- opts = OptionParser.new do |opts|
26
- opts.banner = "Usage: react commands.yml [options]"
27
- opts.on('-q', '--queue [QUEUE]', 'Specify queue which will be consumed') {|val| val and options[:queue] = val }
28
- opts.on('-h', '--host [HOST]', 'Select redis host') {|val| val and options[:redis][:host] = val }
29
- opts.on('-p', '--port [PORT]', Integer, 'Select redis port') {|val| val and options[:redis][:port] = val }
30
- opts.on('-D', '--db [DATABASE]', 'Select redis database number') {|val| val and options[:redis][:db] = val }
31
- opts.on('-P', '--password [PASSWORD]', 'Select redis database password') {|val| val and options[:redis][:password] = val }
32
- opts.on('-d', '--daemon', 'Run in background') { options[:daemon] = true }
33
- end.parse(ARGV)
10
+ require 'react/cli'
34
11
 
35
- React.start(options).join
12
+ React::CLI.dispatch(ARGV)
@@ -1,106 +1,16 @@
1
1
  require 'redis'
2
- require 'thread'
2
+ require 'daemons'
3
+
4
+ begin
5
+ require 'fastthread'
6
+ rescue LoadError
7
+ $stderr.puts("The fastthread gem not found. Using standard ruby threads.")
8
+ require 'thread'
9
+ end
3
10
 
4
- # React is a simple application that allows for remote execution of commands,
5
- # and it uses Redis as a queue.
6
- #
7
- # == Inspiration
8
- #
9
- # It's inspired by Simon Willison's example of "Queue-activated shell scripts"
10
- # in his redis tutorial:
11
- #
12
- # while [ 1 ] do
13
- # redis-cli blpop restart-httpd 0
14
- # apache2ctl graceful
15
- # done
16
- #
17
- # == Usage
18
- #
19
- # Firs you have to prepare file with available commands. It can look like this:
20
- #
21
- # # my_commands.yml
22
- # restart_httpd: |
23
- # apache2ctl graceful
24
- # restart_mysql: |
25
- # /etc/init.d/mysql restart
26
- # reboot: |
27
- # reboot
28
- #
29
- # Now you can start consumer.
30
- #
31
- # react my_commands.yml
32
- #
33
- # == Pushing commands
34
- #
35
- # While your consumer is working, you can push any of specified command to
36
- # queue (default queue name is `queue`), eg:
37
- #
38
- # redis-cli lpush queue restart_httpd
39
- # redis-cli lpush queue reboot
40
- #
41
- # After that consumer will pick up enqueued command names from and execute
42
- # related commands.
43
- #
44
- # == Configuration
45
- #
46
- # There are few more runtime options, which can be useful for you.
47
- #
48
- # * you can specify queue which will be consumed:
49
- #
50
- # react my_commands.yml --queue "my:queue:name"
51
- #
52
- # * you can specify the database to which consumer should connect:
53
- #
54
- # react my_commands.yml --host "yourhost.com" --port 6379 --db 2 --password pass
55
- #
56
- # * and finally, you can demonize the consumer:
57
- #
58
- # react my_commands.yml --daemon
59
11
  module React
60
12
 
61
- # It starts the consumer loop.
62
- def self.start(conf)
63
- @config = conf
64
-
65
- puts "== Connected to #{redis.client.id}"
66
- puts "== Waiting for commands from `#{@config[:queue]}`"
67
-
68
- if @config[:daemon]
69
- puts "== Daemonizing..."
70
- Daemons.daemonize
71
- end
72
-
73
- loop do
74
- begin
75
- cid = redis.blpop(@config[:queue], 0)[1]
76
- if cmd = @config[:commands][cid.to_s]
77
- puts "\e[33m[#{Time.now}]\e[0m Reacting for `#{cid}` command"
78
- threads.add(Thread.new { system(cmd) })
79
- end
80
- rescue Interrupt
81
- puts "\nCleaning up..."
82
- break
83
- rescue Exception => ex
84
- puts "ERROR: #{ex}"
85
- end
86
- end
87
-
88
- self
89
- end
90
-
91
- # Returns group of executor threads.
92
- def self.threads
93
- @threads ||= ThreadGroup.new
94
- end
95
-
96
- # It joins all alive threads, and it's waiting till they will finish.
97
- def self.join
98
- threads.list.each {|t| t.join if t.alive? }
99
- end
100
-
101
- # Redis client instance.
102
- def self.redis
103
- @redis ||= Redis.new(@config[:redis])
104
- end
105
-
13
+ require 'react/runner'
14
+ require 'react/version'
15
+
106
16
  end # React
@@ -0,0 +1,32 @@
1
+ require 'optitron'
2
+
3
+ module React
4
+ class CLI < Optitron::CLI
5
+
6
+ desc "Show used React version"
7
+ def version
8
+ puts "React v#{React.version}"
9
+ end
10
+
11
+ desc "Run react executor"
12
+ opt 'queue', 'Specify quehe which will be consumed', :short_name => 'q'
13
+ opt 'host', 'Specify redis host', :short_name => 'h', :default => 'localhost'
14
+ opt 'port', 'Specify redis port', :short_name => 'p', :default => 6379
15
+ opt 'db', 'Specify redis database number', :short_name => 'D', :default => 0
16
+ opt 'password', 'Specify password to redis database', :short_name => 'P', :default => nil
17
+ opt 'daemon', 'Run in background', :short_name => 'd', :default => false
18
+ def start(file)
19
+ params[:redis] ||= {
20
+ :host => params.delete(:host),
21
+ :port => params.delete(:port),
22
+ :db => params.delete(:db),
23
+ :password => params.delete(:password),
24
+ }
25
+ Runner.new(file, params).start
26
+ rescue => ex
27
+ puts "ERROR: #{ex.to_s}"
28
+ exit 1
29
+ end
30
+
31
+ end # CLI
32
+ end # React
@@ -0,0 +1,58 @@
1
+ module React
2
+ class Runner
3
+
4
+ class NoQueueError < RuntimeError; end
5
+
6
+ attr_reader :options
7
+ attr_reader :commands
8
+
9
+ def initialize(commands_file, options)
10
+ @options = options
11
+ @commands = YAML.load_file(commands_file)
12
+
13
+ raise NoQueueError, "Queue have to be specified!" unless options[:queue]
14
+ end
15
+
16
+ # It starts the consumer loop.
17
+ def start
18
+ puts "== Connected to #{redis.client.id}"
19
+ puts "== Waiting for commands from `#{options[:queue]}`"
20
+
21
+ if options[:daemon]
22
+ puts "== Daemonizing..."
23
+ Daemons.daemonize
24
+ end
25
+
26
+ loop do
27
+ begin
28
+ cid = redis.blpop(options[:queue], 10)[1]
29
+ if cmd = commands[cid.to_s]
30
+ puts "\e[33m[#{Time.now}]\e[0m Reacting for `#{cid}` command"
31
+ threads.add(Thread.new { system(cmd) })
32
+ end
33
+ rescue Interrupt, SystemExit
34
+ puts "\nCleaning up..."
35
+ return 0
36
+ rescue => ex
37
+ puts "ERROR: #{ex}"
38
+ end
39
+ end
40
+ end
41
+
42
+ # Returns group of executor's threads.
43
+ def threads
44
+ @threads ||= ThreadGroup.new
45
+ end
46
+
47
+ # It joins all alive threads, and it's waiting till they will finish.
48
+ def join
49
+ threads.list.each {|t| t.join if t.alive? }
50
+ end
51
+
52
+ # Redis client instance.
53
+ def redis
54
+ @redis ||= Redis.new(options[:redis].merge(:thread_safe => true))
55
+ end
56
+
57
+ end # Runner
58
+ end # React
@@ -0,0 +1,12 @@
1
+ module React
2
+ module Version # :nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ STRING = [MAJOR, MINOR, PATCH].join('.')
7
+ end
8
+
9
+ def self.version # :nodoc:
10
+ Version::STRING
11
+ end
12
+ end # React
@@ -1,60 +1,23 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ # -*- ruby -*-
2
+ $:.unshift(File.expand_path('../lib', __FILE__))
3
+ require 'react/version'
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{react}
8
- s.version = "0.0.2"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Kriss 'nu7hatch' Kowalik"]
12
- s.date = %q{2010-08-17}
13
- s.default_executable = %q{react}
14
- s.description = %q{A simple application that allows for remote execution of commands.}
15
- s.email = %q{kriss.kowalik@gmail.com}
16
- s.executables = ["react"]
17
- s.extra_rdoc_files = [
18
- "LICENSE",
19
- "README.md"
20
- ]
21
- s.files = [
22
- ".document",
23
- ".gitignore",
24
- "LICENSE",
25
- "README.md",
26
- "Rakefile",
27
- "bin/react",
28
- "examples/commands.yml",
29
- "lib/react.rb",
30
- "react.gemspec",
31
- "test/react_test.rb",
32
- "test/teststrap.rb"
33
- ]
34
- s.homepage = %q{http://github.com/nu7hatch/react}
35
- s.rdoc_options = ["--charset=UTF-8"]
36
- s.require_paths = ["lib"]
37
- s.rubygems_version = %q{1.3.6}
38
- s.summary = %q{Redis based remote command executor.}
39
- s.test_files = [
40
- "test/teststrap.rb",
41
- "test/react_test.rb"
42
- ]
43
-
44
- if s.respond_to? :specification_version then
45
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
- s.specification_version = 3
47
-
48
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
- s.add_development_dependency(%q<riot>, [">= 0.11.3"])
50
- s.add_runtime_dependency(%q<daemons>, [">= 0"])
51
- else
52
- s.add_dependency(%q<riot>, [">= 0.11.3"])
53
- s.add_dependency(%q<daemons>, [">= 0"])
54
- end
55
- else
56
- s.add_dependency(%q<riot>, [">= 0.11.3"])
57
- s.add_dependency(%q<daemons>, [">= 0"])
58
- end
6
+ s.name = 'react'
7
+ s.version = React.version
8
+ s.homepage = 'http://github.com/nu7hatch/react'
9
+ s.email = ['chris@nu7hat.ch']
10
+ s.authors = ['Chris Kowalik']
11
+ s.summary = %q{Redis based remote commands executor.}
12
+ s.description = %q{A simple application that allows for remote execution of commands.}
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
15
+ s.require_paths = %w[lib]
16
+ s.extra_rdoc_files = %w[README.md]
17
+ s.executables = %w[react]
18
+ s.default_executable = 'react'
19
+
20
+ s.add_runtime_dependency 'daemons', ["~> 1.0"]
21
+ s.add_runtime_dependency 'redis', [">= 2.0"]
22
+ s.add_runtime_dependency 'optitron', [">= 2.1"]
59
23
  end
60
-
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require 'react'
@@ -0,0 +1,3 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ # Maybe someday it will be tested ;p
metadata CHANGED
@@ -1,59 +1,78 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 27
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
8
+ - 1
7
9
  - 0
8
- - 2
9
- version: 0.0.2
10
+ version: 0.1.0
10
11
  platform: ruby
11
12
  authors:
12
- - Kriss 'nu7hatch' Kowalik
13
+ - Chris Kowalik
13
14
  autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-08-17 00:00:00 +02:00
18
+ date: 2010-11-05 00:00:00 +01:00
18
19
  default_executable: react
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
- name: riot
22
+ name: daemons
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
- - - ">="
27
+ - - ~>
26
28
  - !ruby/object:Gem::Version
29
+ hash: 15
27
30
  segments:
31
+ - 1
28
32
  - 0
29
- - 11
30
- - 3
31
- version: 0.11.3
32
- type: :development
33
+ version: "1.0"
34
+ type: :runtime
33
35
  version_requirements: *id001
34
36
  - !ruby/object:Gem::Dependency
35
- name: daemons
37
+ name: redis
36
38
  prerelease: false
37
39
  requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
38
41
  requirements:
39
42
  - - ">="
40
43
  - !ruby/object:Gem::Version
44
+ hash: 3
41
45
  segments:
46
+ - 2
42
47
  - 0
43
- version: "0"
48
+ version: "2.0"
44
49
  type: :runtime
45
50
  version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: optitron
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 1
60
+ segments:
61
+ - 2
62
+ - 1
63
+ version: "2.1"
64
+ type: :runtime
65
+ version_requirements: *id003
46
66
  description: A simple application that allows for remote execution of commands.
47
- email: kriss.kowalik@gmail.com
67
+ email:
68
+ - chris@nu7hat.ch
48
69
  executables:
49
70
  - react
50
71
  extensions: []
51
72
 
52
73
  extra_rdoc_files:
53
- - LICENSE
54
74
  - README.md
55
75
  files:
56
- - .document
57
76
  - .gitignore
58
77
  - LICENSE
59
78
  - README.md
@@ -61,39 +80,45 @@ files:
61
80
  - bin/react
62
81
  - examples/commands.yml
63
82
  - lib/react.rb
83
+ - lib/react/cli.rb
84
+ - lib/react/runner.rb
85
+ - lib/react/version.rb
64
86
  - react.gemspec
65
- - test/react_test.rb
66
- - test/teststrap.rb
87
+ - test/hepler.rb
88
+ - test/test_react.rb
67
89
  has_rdoc: true
68
90
  homepage: http://github.com/nu7hatch/react
69
91
  licenses: []
70
92
 
71
93
  post_install_message:
72
- rdoc_options:
73
- - --charset=UTF-8
94
+ rdoc_options: []
95
+
74
96
  require_paths:
75
97
  - lib
76
98
  required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
77
100
  requirements:
78
101
  - - ">="
79
102
  - !ruby/object:Gem::Version
103
+ hash: 3
80
104
  segments:
81
105
  - 0
82
106
  version: "0"
83
107
  required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
84
109
  requirements:
85
110
  - - ">="
86
111
  - !ruby/object:Gem::Version
112
+ hash: 3
87
113
  segments:
88
114
  - 0
89
115
  version: "0"
90
116
  requirements: []
91
117
 
92
118
  rubyforge_project:
93
- rubygems_version: 1.3.6
119
+ rubygems_version: 1.3.7
94
120
  signing_key:
95
121
  specification_version: 3
96
- summary: Redis based remote command executor.
97
- test_files:
98
- - test/teststrap.rb
99
- - test/react_test.rb
122
+ summary: Redis based remote commands executor.
123
+ test_files: []
124
+
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.md
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
@@ -1 +0,0 @@
1
- require 'teststrap'
@@ -1,6 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
-
4
- require 'rubygems'
5
- require 'riot'
6
- require 'react'