react 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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'