averell23-bj 1.0.2

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.
@@ -0,0 +1,87 @@
1
+ unless defined? Bj
2
+ class Bj
3
+ #
4
+ # constants and associated attrs
5
+ #
6
+ Bj::VERSION = "1.0.2" #unless defined?(Bj::VERSION)
7
+ def self.version() Bj::VERSION end
8
+
9
+ Bj::LIBDIR = File.expand_path(File::join(File.dirname(__FILE__), "bj")) + File::SEPARATOR unless
10
+ defined? Bj::LIBDIR
11
+ def self.libdir(*value)
12
+ unless value.empty?
13
+ File.join libdir, *value
14
+ else
15
+ Bj::LIBDIR
16
+ end
17
+ end
18
+
19
+ module EXIT
20
+ SUCCESS = 0
21
+ FAILURE = 1
22
+ WARNING = 42
23
+ end
24
+ #
25
+ # built-in
26
+ #
27
+ require "socket"
28
+ require "yaml"
29
+ require "thread"
30
+ require "rbconfig"
31
+ require "set"
32
+ require "erb"
33
+ require "tempfile"
34
+ #
35
+ # bootstrap rubygems
36
+ #
37
+ begin
38
+ require "rubygems"
39
+ rescue LoadError
40
+ 42
41
+ end
42
+ #
43
+ # rubyforge/remote
44
+ #
45
+ require "active_record"
46
+ #
47
+ # rubyforge/remote or local/lib
48
+ #
49
+ #%w[ attributes systemu orderedhash ].each do |lib|
50
+ %w[ systemu orderedhash ].each do |lib|
51
+ begin
52
+ require lib
53
+ rescue
54
+ require libdir(lib)
55
+ end
56
+ end
57
+ #
58
+ # local
59
+ #
60
+ load libdir("attributes.rb")
61
+ load libdir("stdext.rb")
62
+ load libdir("util.rb")
63
+ load libdir("errors.rb")
64
+ load libdir("logger.rb")
65
+ load libdir("bj.rb")
66
+ load libdir("joblist.rb")
67
+ load libdir("table.rb")
68
+ load libdir("runner.rb")
69
+ load libdir("api.rb")
70
+ #
71
+ # an imperfect reloading hook - because neither rails' plugins nor gems provide one, sigh...
72
+ #
73
+ def self.reload!
74
+ background = nil
75
+ ::Object.module_eval do
76
+ background = Bj.runner.background
77
+ remove_const :Bj rescue nil
78
+ remove_const :BackgroundJob rescue nil
79
+ end
80
+ returned = load __FILE__ rescue nil
81
+ Bj.runner.background = background if background
82
+ returned
83
+ end
84
+ end
85
+
86
+ BackgroundJob = Bj
87
+ end
@@ -0,0 +1,164 @@
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', :priority => 42
34
+ #
35
+ # jobs = Bj.submit './script/runner ./scripts/a.rb', :rails_env => 'production'
36
+ #
37
+ # jobs = Bj.submit './script/runner /dev/stdin', :stdin => 'p RAILS_ENV', :tag => 'dynamic ruby code'
38
+ #
39
+ # jobs = Bj.submit array_of_commands, :priority => 451
40
+ #
41
+ # when jobs are run, they are run in RAILS_ROOT. various attributes are
42
+ # available *only* once the job has finished. you can check whether or not
43
+ # a job is finished by using the #finished method, which simple does a
44
+ # reload and checks to see if the exit_status is non-nil.
45
+ #
46
+ # eg:
47
+ #
48
+ # jobs = Bj.submit list_of_jobs, :tag => 'important'
49
+ # ...
50
+ #
51
+ # jobs.each do |job|
52
+ # if job.finished?
53
+ # p job.exit_status
54
+ # p job.stdout
55
+ # p job.stderr
56
+ # end
57
+ # end
58
+ #
59
+ #
60
+ def submit jobs, options = {}, &block
61
+ options.to_options!
62
+ Bj.transaction(options) do
63
+ table.job.submit jobs, options, &block
64
+ end
65
+ ensure
66
+ Bj.runner.tickle unless options[:no_tickle]
67
+ end
68
+ #
69
+ # this method changes the context under which bj is operating. a context is
70
+ # a RAILS_ENV. the method accepts a block and it used to alter the
71
+ # behaviour of the bj lib on a global scale such that all operations,
72
+ # spawning of background runnner processes, etc, occur in that context.
73
+ #
74
+ # eg:
75
+ #
76
+ # Bj.in :production do
77
+ # Bj.submit './script/runner ./scripts/facebook_notification.rb'
78
+ # end
79
+ #
80
+ # Bj.in :development do
81
+ # Bj.submit 'does_this_eat_memory.exe'
82
+ # end
83
+ #
84
+ def in rails_env = Bj.rails_env, &block
85
+ transaction(:rails_env => rails_env.to_s, &block)
86
+ end
87
+ #
88
+ # list simply returns a list of all jobs in the job table
89
+ #
90
+ def list options = {}, &block
91
+ options.to_options!
92
+ Bj.transaction(options) do
93
+ options.delete :rails_env
94
+ table.job.find(:all, options)
95
+ end
96
+ end
97
+ #
98
+ #
99
+ #
100
+ def run options = {}
101
+ runner.run options
102
+ end
103
+ #
104
+ # generate a migration and migrate a database (production/development/etc)
105
+ #
106
+ def setup options = {}
107
+ options.to_options!
108
+ chroot do
109
+ generate_migration options
110
+ migrate options
111
+ end
112
+ end
113
+ #
114
+ # generate_migration, suprisingly, generates the single migration needed for
115
+ # bj. you'll notice the the migration is very short as the migration
116
+ # classes themselves are inner classes of the respective bj table class.
117
+ # see lib/bj/table.rb for details.
118
+ #
119
+ def generate_migration options = {}
120
+ options.to_options!
121
+ options[:verbose] = true
122
+ chroot do
123
+ before = Dir.glob "./db/migrate/*"
124
+ n = Dir.glob("./db/migrate/*_bj_*").size
125
+ classname = "BjMigration#{ n }"
126
+ util.spawn "#{ Bj.ruby } ./script/generate migration #{ classname }", options rescue nil
127
+ after = Dir.glob "./db/migrate/*"
128
+ candidates = after - before
129
+ case candidates.size
130
+ when 0
131
+ false
132
+ when 1
133
+ generated = candidates.first
134
+ open(generated, "w"){|fd| fd.puts Bj.table.migration_code(classname)}
135
+ Bj.logger.info{ "generated <#{ generated }>" }
136
+ generated
137
+ else
138
+ raise "ambiguous migration <#{ candidates.inspect }>"
139
+ end
140
+ end
141
+ end
142
+ #
143
+ # migrate a database (production|development|etc)
144
+ #
145
+ def migrate options = {}
146
+ options.to_options!
147
+ options[:verbose] = true
148
+ chroot do
149
+ util.spawn "#{ Bj.rake } RAILS_ENV=#{ Bj.rails_env } db:migrate", options
150
+ end
151
+ end
152
+ #
153
+ # install plugin into this rails app
154
+ #
155
+ def plugin options = {}
156
+ options.to_options!
157
+ options[:verbose] = true
158
+ chroot do
159
+ util.spawn "#{ Bj.ruby } ./script/plugin install http://codeforpeople.rubyforge.org/svn/rails/plugins/bj --force", options
160
+ end
161
+ end
162
+ end
163
+ send :extend, API
164
+ end
@@ -0,0 +1,120 @@
1
+ module Attributes
2
+ Attributes::VERSION = '5.0.0' unless defined? Attributes::VERSION
3
+ def self.version() Attributes::VERSION end
4
+
5
+ class List < ::Array
6
+ def << element
7
+ super
8
+ self
9
+ ensure
10
+ uniq!
11
+ index!
12
+ end
13
+ def index!
14
+ @index ||= Hash.new
15
+ each{|element| @index[element] = true}
16
+ end
17
+ def include? element
18
+ @index ||= Hash.new
19
+ @index[element] ? true : false
20
+ end
21
+ def initializers
22
+ @initializers ||= Hash.new
23
+ end
24
+ end
25
+
26
+ def attributes *a, &b
27
+ unless a.empty?
28
+ returned = Hash.new
29
+
30
+ hashes, names = a.partition{|x| Hash === x}
31
+ names_and_defaults = {}
32
+ hashes.each{|h| names_and_defaults.update h}
33
+ names.flatten.compact.each{|name| names_and_defaults.update name => nil}
34
+
35
+ initializers = __attributes__.initializers
36
+
37
+ names_and_defaults.each do |name, default|
38
+ raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o
39
+ name = name.to_s
40
+
41
+ initialize = b || lambda { default }
42
+ initializer = lambda do |this|
43
+ Object.instance_method('instance_eval').bind(this).call &initialize
44
+ end
45
+ initializer_id = initializer.object_id
46
+ __attributes__.initializers[name] = initializer
47
+
48
+ module_eval <<-code
49
+ def #{ name }=(*value, &block)
50
+ value.unshift block if block
51
+ @#{ name } = value.first
52
+ end
53
+ code
54
+
55
+ module_eval <<-code
56
+ def #{ name }(*value, &block)
57
+ value.unshift block if block
58
+ return self.send('#{ name }=', value.first) unless value.empty?
59
+ #{ name }! unless defined? @#{ name }
60
+ @#{ name }
61
+ end
62
+ code
63
+
64
+ module_eval <<-code
65
+ def #{ name }!
66
+ initializer = ObjectSpace._id2ref #{ initializer_id }
67
+ self.#{ name } = initializer.call(self)
68
+ @#{ name }
69
+ end
70
+ code
71
+
72
+ module_eval <<-code
73
+ def #{ name }?
74
+ #{ name }
75
+ end
76
+ code
77
+
78
+ attributes << name
79
+ returned[name] = initializer
80
+ end
81
+
82
+ returned
83
+ else
84
+ begin
85
+ __attribute_list__
86
+ rescue NameError
87
+ singleton_class =
88
+ class << self
89
+ self
90
+ end
91
+ klass = self
92
+ singleton_class.module_eval do
93
+ attribute_list = List.new
94
+ define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
95
+ alias_method '__attribute_list__', 'attribute_list'
96
+ end
97
+ __attribute_list__
98
+ end
99
+ end
100
+ end
101
+
102
+ %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
103
+ end
104
+
105
+ =begin
106
+ class Object
107
+ def attributes *a, &b
108
+ sc =
109
+ class << self
110
+ self
111
+ end
112
+ sc.attributes *a, &b
113
+ end
114
+ %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
115
+ end
116
+ =end
117
+
118
+ class Module
119
+ include Attributes
120
+ end
@@ -0,0 +1,72 @@
1
+ class Bj
2
+ module ClassMethods
3
+ attribute("rails_root"){ Util.const_or_env("RAILS_ROOT"){ "." } }
4
+ attribute("rails_env"){ Util.const_or_env("RAILS_ENV"){ "development" } }
5
+ attribute("database_yml"){ File.join rails_root, "config", "database.yml" }
6
+ attribute("configurations"){ YAML::load(ERB.new(IO.read(database_yml)).result) }
7
+ attribute("tables"){ Table.list }
8
+ attribute("hostname"){ Socket.gethostname }
9
+ attribute("logger"){ Bj::Logger.off STDERR }
10
+ attribute("ruby"){ Util.which_ruby }
11
+ attribute("rake"){ Util.which_rake }
12
+ attribute("script"){ Util.find_script "bj" }
13
+ attribute("ttl"){ Integer(Bj::Table::Config["ttl"] || (twenty_four_hours = 24 * 60 * 60)) }
14
+ attribute("table"){ Table }
15
+ attribute("config"){ table.config }
16
+ attribute("util"){ Util }
17
+ attribute("runner"){ Runner }
18
+ attribute("joblist"){ Joblist }
19
+ attribute("default_path"){ %w'/bin /usr/bin /usr/local/bin /opt/local/bin'.join(File::PATH_SEPARATOR) }
20
+
21
+ def transaction options = {}, &block
22
+ options.to_options!
23
+
24
+ cur_rails_env = Bj.rails_env.to_s
25
+ new_rails_env = options[:rails_env].to_s
26
+
27
+ cur_spec = configurations[cur_rails_env]
28
+ table.establish_connection(cur_spec) unless table.connected?
29
+
30
+ if(new_rails_env.empty? or cur_rails_env == new_rails_env)
31
+ table.transaction{ block.call(table.connection) }
32
+ else
33
+ new_spec = configurations[new_rails_env]
34
+ table.establish_connection(new_spec)
35
+ Bj.rails_env = new_rails_env
36
+ begin
37
+ table.transaction{ block.call(table.connection) }
38
+ ensure
39
+ table.establish_connection(cur_spec)
40
+ Bj.rails_env = cur_rails_env
41
+ end
42
+ end
43
+ end
44
+
45
+ def chroot options = {}, &block
46
+ if defined? @chrooted and @chrooted
47
+ return(block ? block.call(@chrooted) : @chrooted)
48
+ end
49
+ if block
50
+ begin
51
+ chrooted = @chrooted
52
+ Dir.chdir(@chrooted = rails_root) do
53
+ raise RailsRoot, "<#{ Dir.pwd }> is not a rails root" unless Util.valid_rails_root?(Dir.pwd)
54
+ block.call(@chrooted)
55
+ end
56
+ ensure
57
+ @chrooted = chrooted
58
+ end
59
+ else
60
+ Dir.chdir(@chrooted = rails_root)
61
+ raise RailsRoot, "<#{ Dir.pwd }> is not a rails root" unless Util.valid_rails_root?(Dir.pwd)
62
+ @chrooted
63
+ end
64
+ end
65
+
66
+ def boot
67
+ load File.join(rails_root, "config", "boot.rb")
68
+ load File.join(rails_root, "config", "environment.rb")
69
+ end
70
+ end
71
+ send :extend, ClassMethods
72
+ end
@@ -0,0 +1,4 @@
1
+ class Bj
2
+ class Error < ::StandardError; end
3
+ class RailsRoot < Error; end
4
+ end