bj 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/gemspec.rb ADDED
@@ -0,0 +1,29 @@
1
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
2
+ require 'rubygems'
3
+
4
+ Gem::Specification::new do |spec|
5
+ $VERBOSE = nil
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
+ spec.add_dependency 'attributes', '>= 5.0.0'
20
+ spec.add_dependency 'main', '>= 2.6.0'
21
+ spec.add_dependency 'systemu', '>= 1.2.0'
22
+ spec.add_dependency 'orderedhash', '>= 0.0.3'
23
+
24
+ spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
25
+
26
+ spec.author = "Ara T. Howard"
27
+ spec.email = "ara.t.howard@gmail.com"
28
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
29
+ end
data/install.rb ADDED
@@ -0,0 +1,210 @@
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
+ system "#{ sudo } #{ $ruby } pre-install.rb" if test(?s, 'pre-install.rb')
196
+
197
+ unless no_linkify
198
+ linked = linkify('lib') + linkify('bin')
199
+ end
200
+
201
+ system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
202
+
203
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
204
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
205
+
206
+ if linked
207
+ linked.each{|path| File::rm_f path}
208
+ end
209
+
210
+ system "#{ sudo } #{ $ruby } post-install.rb" if test(?s, 'post-install.rb')
data/lib/bj.rb ADDED
@@ -0,0 +1,79 @@
1
+ unless defined? Bj
2
+ class Bj
3
+ #
4
+ # constants and associated attrs
5
+ #
6
+ Bj::VERSION = "0.0.1" unless
7
+ defined? Bj::VERSION
8
+ def self.version() Bj::VERSION end
9
+
10
+ Bj::LIBDIR = File.expand_path(File::join(File.dirname(__FILE__), "bj")) + File::SEPARATOR unless
11
+ defined? Bj::LIBDIR
12
+ def self.libdir(*value)
13
+ unless value.empty?
14
+ File.join libdir, *value
15
+ else
16
+ Bj::LIBDIR
17
+ end
18
+ end
19
+
20
+ module EXIT
21
+ SUCCESS = 0
22
+ FAILURE = 1
23
+ WARNING = 42
24
+ end
25
+ #
26
+ # built-in
27
+ #
28
+ require "socket"
29
+ require "yaml"
30
+ require "thread"
31
+ require "rbconfig"
32
+ #
33
+ # bootstrap rubygems
34
+ #
35
+ begin
36
+ require "rubygems"
37
+ rescue LoadError
38
+ 42
39
+ end
40
+ #
41
+ # rubyforge/remote
42
+ #
43
+ require "active_record"
44
+ #
45
+ # rubyforge/remote or local/lib
46
+ #
47
+ %w[ attributes main systemu orderedhash ].each do |lib|
48
+ begin
49
+ require lib
50
+ rescue
51
+ require libdir(lib)
52
+ end
53
+ end
54
+ #
55
+ # local
56
+ #
57
+ load libdir("stdext.rb")
58
+ load libdir("util.rb")
59
+ load libdir("errors.rb")
60
+ load libdir("logger.rb")
61
+ load libdir("bj.rb")
62
+ load libdir("joblist.rb")
63
+ load libdir("table.rb")
64
+ load libdir("runner.rb")
65
+ load libdir("api.rb")
66
+ #
67
+ # an imperfect reloading hook - because neither rails' plugins nor gems provide one, sigh...
68
+ #
69
+ def self.reload!
70
+ ::Object.module_eval do
71
+ remove_const :Bj rescue nil
72
+ remove_const :BackgroundJob rescue nil
73
+ end
74
+ load __FILE__ rescue nil
75
+ end
76
+ end
77
+
78
+ BackgroundJob = Bj
79
+ end
data/lib/bj/api.rb ADDED
@@ -0,0 +1,144 @@
1
+ class Bj
2
+ #
3
+ # the api exposes nearly all the bj code you'll likely need, with the
4
+ # exception of accessing the job table for searching, which is done using
5
+ #
6
+ # eg.
7
+ #
8
+ # Bj.table.job.find :all
9
+ #
10
+ module API
11
+ #
12
+ # submit jobs for background processing. 'jobs' can be a string or array of
13
+ # strings. options are applied to each job in the 'jobs', and the list of
14
+ # submitted jobs is always returned. options (string or symbol) can be
15
+ #
16
+ # :rails_env => production|development|key_in_database_yml
17
+ # when given this keyword causes bj to submit jobs to the
18
+ # specified database. default is RAILS_ENV.
19
+ #
20
+ # :priority => any number, including negative ones. default is zero.
21
+ #
22
+ # :tag => a tag added to the job. simply makes searching easier.
23
+ #
24
+ # :env => a hash specifying any additional environment vars the background
25
+ # process should have.
26
+ #
27
+ # :stdin => any stdin the background process should have.
28
+ #
29
+ # eg:
30
+ #
31
+ # jobs = Bj.submit 'echo foobar', :tag => 'simple job'
32
+ #
33
+ # jobs = Bj.submit '/bin/cat', :stdin => 'in the hat'
34
+ #
35
+ # jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
36
+ #
37
+ # when jobs are run, they are run in RAILS_ROOT. various attributes are
38
+ # available *only* once the job has finished. you can check whether or not
39
+ # a job is finished by using the #finished method, which simple does a
40
+ # reload and checks to see if the exit_status is non-nil.
41
+ #
42
+ # eg:
43
+ #
44
+ # jobs = Bj.submit list_of_jobs, :tag => 'important'
45
+ # ...
46
+ #
47
+ # jobs.each do |job|
48
+ # if job.finished?
49
+ # p job.exit_status
50
+ # p job.stdout
51
+ # p job.stderr
52
+ # end
53
+ # end
54
+ #
55
+ #
56
+ def submit jobs, options = {}, &block
57
+ options.to_options!
58
+ Bj.transaction(options) do
59
+ table.job.submit jobs, options, &block
60
+ end
61
+ ensure
62
+ Bj.runner.tickle unless options[:no_tickle]
63
+ end
64
+ #
65
+ # this method changes the context under which bj is operating. a context is
66
+ # a RAILS_ENV. the method accepts a block and it used to alter the
67
+ # behaviour of the bj lib on a global scale such that all operations,
68
+ # spawning of background runnner processes, etc, occur in that context.
69
+ #
70
+ # eg:
71
+ #
72
+ # Bj.in :production do
73
+ # Bj.submit './script/runner ./scripts/facebook_notification.rb'
74
+ # end
75
+ #
76
+ # Bj.in :development do
77
+ # Bj.submit 'does_this_eat_memory.exe'
78
+ # end
79
+ #
80
+ def in rails_env = Bj.rails_env, &block
81
+ transaction(:rails_env => rails_env.to_s, &block)
82
+ end
83
+ #
84
+ # list simply returns a list of all jobs in the job table
85
+ #
86
+ def list options = {}, &block
87
+ Bj.transaction(options) do
88
+ table.job.find(:all, options)
89
+ end
90
+ end
91
+ #
92
+ #
93
+ #
94
+ def run options = {}
95
+ runner.run options
96
+ end
97
+ #
98
+ # generate a migration and migrate a database (production/development/etc)
99
+ #
100
+ def setup options = {}
101
+ options.to_options!
102
+ chroot do
103
+ generate_migration options
104
+ migrate options
105
+ end
106
+ end
107
+ #
108
+ # generate_migration, suprisingly, generates the single migration needed for
109
+ # bj. you'll notice the the migration is very short as the migration
110
+ # classes themselves are inner classes of the respective bj table class.
111
+ # see lib/bj/table.rb for details.
112
+ #
113
+ def generate_migration options = {}
114
+ options.to_options!
115
+ chroot do
116
+ before = Dir.glob "./db/migrate/*"
117
+ util.spawn "./script/generate migration BjMigration", options rescue nil
118
+ after = Dir.glob "./db/migrate/*"
119
+ candidates = after - before
120
+ case candidates.size
121
+ when 0
122
+ false
123
+ when 1
124
+ generated = candidates.first
125
+ open(generated, "w"){|fd| fd.puts Bj.table.migration_code}
126
+ Bj.logger.info{ "generated <#{ generated }>" }
127
+ generated
128
+ else
129
+ raise "ambiguous migration <#{ candidates.inspect }>"
130
+ end
131
+ end
132
+ end
133
+ #
134
+ # migrate a database (production|development|etc)
135
+ #
136
+ def migrate options = {}
137
+ options.to_options!
138
+ chroot do
139
+ util.spawn "rake RAILS_ENV=#{ Bj.rails_env } db:migrate", options
140
+ end
141
+ end
142
+ end
143
+ send :extend, API
144
+ end