acts_as_ferret 0.4.1 → 0.4.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.
@@ -1,9 +1,39 @@
1
1
  module Ferret
2
2
 
3
+ module Analysis
4
+
5
+ # = PerFieldAnalyzer
6
+ #
7
+ # This PerFieldAnalyzer is a workaround to a memory leak in
8
+ # ferret 0.11.4. It does basically do the same as the original
9
+ # Ferret::Analysis::PerFieldAnalyzer, but without the leak :)
10
+ #
11
+ # http://ferret.davebalmain.com/api/classes/Ferret/Analysis/PerFieldAnalyzer.html
12
+ #
13
+ # Thanks to Ben from omdb.org for tracking this down and creating this
14
+ # workaround.
15
+ # You can read more about the issue there:
16
+ # http://blog.omdb-beta.org/2007/7/29/tracking-down-a-memory-leak-in-ferret-0-11-4
17
+ class PerFieldAnalyzer < ::Ferret::Analysis::Analyzer
18
+ def initialize( default_analyzer = StandardAnalyzer.new )
19
+ @analyzers = {}
20
+ @default_analyzer = default_analyzer
21
+ end
22
+
23
+ def add_field( field, analyzer )
24
+ @analyzers[field] = analyzer
25
+ end
26
+ alias []= add_field
27
+
28
+ def token_stream(field, string)
29
+ @analyzers.has_key?(field) ? @analyzers[field].token_stream(field, string) :
30
+ @default_analyzer.token_stream(field, string)
31
+ end
32
+ end
33
+ end
3
34
 
4
35
  class Index::Index
5
- attr_accessor :batch_size
6
- attr_accessor :logger
36
+ attr_accessor :batch_size, :logger
7
37
 
8
38
  def index_models(models)
9
39
  models.each { |model| index_model model }
@@ -14,32 +44,36 @@ module Ferret
14
44
  end
15
45
 
16
46
  def index_model(model)
17
- @batch_size ||= 0
18
- work_done = 0
19
- batch_time = 0
47
+ bulk_indexer = ActsAsFerret::BulkIndexer.new(:batch_size => @batch_size, :logger => logger,
48
+ :model => model, :index => self, :reindex => true)
20
49
  logger.info "reindexing model #{model.name}"
21
50
 
22
- model_count = model.count.to_f
23
51
  model.records_for_rebuild(@batch_size) do |records, offset|
24
- #records = [ records ] unless records.is_a?(Array)
25
- batch_time = measure_time {
26
- records.each { |rec| self << rec.to_doc if rec.ferret_enabled?(true) }
27
- }.to_f
28
- work_done = offset.to_f / model_count * 100.0 if model_count > 0
29
- remaining_time = ( batch_time / @batch_size ) * ( model_count - offset + @batch_size )
30
- logger.info "reindex model #{model.name} : #{'%.2f' % work_done}% complete : #{'%.2f' % remaining_time} secs to finish"
52
+ bulk_indexer.index_records(records, offset)
31
53
  end
32
54
  end
33
55
 
34
- def measure_time
35
- t1 = Time.now
36
- yield
37
- Time.now - t1
56
+ def bulk_index(model, ids, options = {})
57
+ options.reverse_merge! :optimize => true
58
+ orig_flush = @auto_flush
59
+ @auto_flush = false
60
+ bulk_indexer = ActsAsFerret::BulkIndexer.new(:batch_size => @batch_size, :logger => logger,
61
+ :model => model, :index => self, :total => ids.size)
62
+ model.records_for_bulk_index(ids, @batch_size) do |records, offset|
63
+ logger.debug "#{model} bulk indexing #{records.size} at #{offset}"
64
+ bulk_indexer.index_records(records, offset)
65
+ end
66
+ logger.info 'finishing bulk index...'
67
+ flush
68
+ if options[:optimize]
69
+ logger.info 'optimizing...'
70
+ optimize
71
+ end
72
+ @auto_flush = orig_flush
38
73
  end
39
74
 
40
75
  end
41
76
 
42
-
43
77
  # add marshalling support to SortFields
44
78
  class Search::SortField
45
79
  def _dump(depth)
data/lib/ferret_server.rb CHANGED
@@ -3,29 +3,41 @@ require 'thread'
3
3
  require 'yaml'
4
4
  require 'erb'
5
5
 
6
-
6
+ ################################################################################
7
7
  module ActsAsFerret
8
-
9
8
  module Remote
10
9
 
11
- module Config
12
- class << self
13
- DEFAULTS = {
14
- 'host' => 'localhost',
15
- 'port' => '9009'
16
- }
17
- # read connection settings from config file
18
- def load(file = "#{RAILS_ROOT}/config/ferret_server.yml")
19
- config = DEFAULTS.merge(YAML.load(ERB.new(IO.read(file)).result))
20
- if config = config[RAILS_ENV]
21
- config[:uri] = "druby://#{config['host']}:#{config['port']}"
22
- return config
23
- end
24
- {}
25
- end
10
+ ################################################################################
11
+ class Config
12
+
13
+ ################################################################################
14
+ DEFAULTS = {
15
+ 'host' => 'localhost',
16
+ 'port' => '9009',
17
+ 'cf' => "#{RAILS_ROOT}/config/ferret_server.yml",
18
+ 'pid_file' => "#{RAILS_ROOT}/log/ferret_server.pid",
19
+ 'log_file' => "#{RAILS_ROOT}/log/ferret_server.log",
20
+ 'log_level' => 'debug',
21
+ }
22
+
23
+ ################################################################################
24
+ # load the configuration file and apply default settings
25
+ def initialize (file=DEFAULTS['cf'])
26
+ @everything = YAML.load(ERB.new(IO.read(file)).result)
27
+ raise "malformed ferret server config" unless @everything.is_a?(Hash)
28
+ @config = DEFAULTS.merge(@everything[RAILS_ENV] || {})
29
+ @config['uri'] = "druby://#{host}:#{port}" if @everything[RAILS_ENV]
30
+ end
31
+
32
+ ################################################################################
33
+ # treat the keys of the config data as methods
34
+ def method_missing (name, *args)
35
+ @config.has_key?(name.to_s) ? @config[name.to_s] : super
26
36
  end
37
+
27
38
  end
28
39
 
40
+ #################################################################################
29
41
  # This class acts as a drb server listening for indexing and
30
42
  # search requests from models declared to 'acts_as_ferret :remote => true'
31
43
  #
@@ -33,25 +45,46 @@ module ActsAsFerret
33
45
  # - modify RAILS_ROOT/config/ferret_server.yml to suit your needs.
34
46
  # - environments for which no section in the config file exists will use
35
47
  # the index locally (good for unit tests/development mode)
36
- # - run script/ferret_start to start the server:
37
- # RAILS_ENV=production script/ferret_start
48
+ # - run script/ferret_server to start the server:
49
+ # script/ferret_server -e production start
50
+ # - to stop the server run
51
+ # script/ferret_server -e production stop
38
52
  #
39
53
  class Server
40
54
 
55
+ #################################################################################
56
+ # FIXME include detection of OS and include the correct file
57
+ require 'unix_daemon'
58
+ include(ActsAsFerret::Remote::UnixDaemon)
59
+
60
+ ################################################################################
41
61
  cattr_accessor :running
42
62
 
43
- def self.start(uri = nil)
63
+ ################################################################################
64
+ def initialize
65
+ @cfg = ActsAsFerret::Remote::Config.new
44
66
  ActiveRecord::Base.allow_concurrency = true
45
- ActiveRecord::Base.logger = Logger.new("#{RAILS_ROOT}/log/ferret_server.log")
46
- uri ||= ActsAsFerret::Remote::Config.load[:uri]
47
- DRb.start_service(uri, ActsAsFerret::Remote::Server.new)
48
- self.running = true
67
+ ActiveRecord::Base.logger = @logger = Logger.new(@cfg.log_file)
68
+ ActiveRecord::Base.logger.level = Logger.const_get(@cfg.log_level.upcase) rescue Logger::DEBUG
49
69
  end
50
70
 
51
- def initialize
52
- @logger = ActiveRecord::Base.logger
71
+ ################################################################################
72
+ # start the server
73
+ def start
74
+ raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil)
75
+ $stdout.puts("starting ferret server...")
76
+
77
+ platform_daemon do
78
+ self.class.running = true
79
+ DRb.start_service(@cfg.uri, self)
80
+ DRb.thread.join
81
+ end
82
+ rescue Exception => e
83
+ @logger.error(e.to_s)
84
+ raise
53
85
  end
54
86
 
87
+ #################################################################################
55
88
  # handles all incoming method calls, and sends them on to the LocalIndex
56
89
  # instance of the correct model class.
57
90
  #
@@ -59,17 +92,25 @@ module ActsAsFerret
59
92
  #
60
93
  def method_missing(name, *args)
61
94
  @logger.debug "\#method_missing(#{name.inspect}, #{args.inspect})"
95
+ retried = false
62
96
  with_class args.shift do |clazz|
63
- begin
64
- clazz.aaf_index.send name, *args
65
- rescue NoMethodError
66
- @logger.debug "no luck, trying to call class method instead"
67
- clazz.send name, *args
97
+ reconnect_when_needed(clazz) do
98
+ # using respond_to? here so we not have to catch NoMethodError
99
+ # which would silently catch those from deep inside the indexing
100
+ # code, too...
101
+ if clazz.aaf_index.respond_to?(name)
102
+ clazz.aaf_index.send name, *args
103
+ elsif clazz.respond_to?(name)
104
+ @logger.debug "no luck, trying to call class method instead"
105
+ clazz.send name, *args
106
+ else
107
+ raise NoMethodError.new("method #{name} not supported by DRb server")
108
+ end
68
109
  end
69
110
  end
70
- rescue
71
- @logger.error "ferret server error #{$!}\n#{$!.backtrace.join '\n'}"
72
- raise
111
+ rescue => e
112
+ @logger.error "ferret server error #{$!}\n#{$!.backtrace.join "\n"}"
113
+ raise e
73
114
  end
74
115
 
75
116
  # make sure we have a versioned index in place, building one if necessary
@@ -83,14 +124,24 @@ module ActsAsFerret
83
124
  end
84
125
  end
85
126
 
127
+ # disconnects the db connection for the class specified by class_name
128
+ # used only in unit tests to check the automatic reconnection feature
129
+ def db_disconnect!(class_name)
130
+ with_class class_name do |clazz|
131
+ clazz.connection.disconnect!
132
+ end
133
+ end
134
+
86
135
  # hides LocalIndex#rebuild_index to implement index versioning
87
136
  def rebuild_index(clazz, *models)
88
137
  with_class clazz do |clazz|
89
138
  models = models.flatten.uniq.map(&:constantize)
90
139
  models << clazz unless models.include?(clazz)
91
140
  index = new_index_for(clazz, models)
92
- @logger.debug "DRb server: rebuild index for class(es) #{models.inspect} in #{index.options[:path]}"
93
- index.index_models models
141
+ reconnect_when_needed(clazz) do
142
+ @logger.debug "DRb server: rebuild index for class(es) #{models.inspect} in #{index.options[:path]}"
143
+ index.index_models models
144
+ end
94
145
  new_version = File.join clazz.aaf_configuration[:index_base_dir], Time.now.utc.strftime('%Y%m%d%H%M%S')
95
146
  # create a unique directory name (needed for unit tests where
96
147
  # multiple rebuilds per second may occur)
@@ -113,6 +164,27 @@ module ActsAsFerret
113
164
  yield clazz, *args
114
165
  end
115
166
 
167
+ def reconnect_when_needed(clazz)
168
+ retried = false
169
+ begin
170
+ yield
171
+ rescue ActiveRecord::StatementInvalid => e
172
+ if e.message =~ /MySQL server has gone away/
173
+ if retried
174
+ raise e
175
+ else
176
+ @logger.info "StatementInvalid caught, trying to reconnect..."
177
+ clazz.connection.reconnect!
178
+ retried = true
179
+ retry
180
+ end
181
+ else
182
+ @logger.error "StatementInvalid caught, but unsure what to do with it: #{e}"
183
+ raise e
184
+ end
185
+ end
186
+ end
187
+
116
188
  def new_index_for(clazz, models)
117
189
  aaf_configuration = clazz.aaf_configuration
118
190
  ferret_cfg = aaf_configuration[:ferret].dup
@@ -120,7 +192,7 @@ module ActsAsFerret
120
192
  :create => true,
121
193
  :field_infos => ActsAsFerret::field_infos(models),
122
194
  :path => File.join(aaf_configuration[:index_base_dir], 'rebuild')
123
- returning Ferret::Index::Index.new ferret_cfg do |i|
195
+ returning Ferret::Index::Index.new(ferret_cfg) do |i|
124
196
  i.batch_size = aaf_configuration[:reindex_batch_size]
125
197
  i.logger = @logger
126
198
  end
@@ -31,20 +31,36 @@ module ActsAsFerret #:nodoc:
31
31
  self.class.aaf_index.highlight(id, self.class.name, query, options)
32
32
  end
33
33
 
34
- # re-eneable ferret indexing after a call to #disable_ferret
35
- def ferret_enable; @ferret_disabled = nil end
34
+ # re-eneable ferret indexing for this instance after a call to #disable_ferret
35
+ def enable_ferret
36
+ @ferret_disabled = nil
37
+ end
38
+ alias ferret_enable enable_ferret # compatibility
36
39
 
37
- # returns true if ferret indexing is enabled
38
- # the optional parameter will be true if the method is called by rebuild_index,
39
- # and false otherwise. I.e. useful to enable a model only for indexing during
40
- # scheduled reindex runs.
41
- def ferret_enabled?(is_rebuild = false); @ferret_disabled.nil? end
40
+ # returns true if ferret indexing is enabled for this record.
41
+ #
42
+ # The optional is_bulk_index parameter will be true if the method is called
43
+ # by rebuild_index or bulk_index, and false otherwise.
44
+ #
45
+ # If is_bulk_index is true, the class level ferret_enabled state will be
46
+ # ignored by this method (per-instance ferret_enabled checks however will
47
+ # take place, so if you override this method to forbid indexing of certain
48
+ # records you're still safe).
49
+ def ferret_enabled?(is_bulk_index = false)
50
+ @ferret_disabled.nil? && (is_bulk_index || self.class.ferret_enabled?)
51
+ end
42
52
 
43
- # Disable Ferret for a specified amount of time. ::once will disable
44
- # Ferret for the next call to #save (this is the default), ::always will
45
- # do so for all subsequent calls.
46
- # To manually trigger reindexing of a record, you can call #ferret_update
47
- # directly.
53
+ # Disable Ferret for this record for a specified amount of time. ::once will
54
+ # disable Ferret for the next call to #save (this is the default), ::always
55
+ # will do so for all subsequent calls.
56
+ #
57
+ # Note that this will turn off only the create and update hooks, but not the
58
+ # destroy hook. I think that's reasonable, if you think the opposite, please
59
+ # tell me.
60
+ #
61
+ # To manually trigger reindexing of a record after you're finished modifying
62
+ # it, you can call #ferret_update directly instead of #save (remember to
63
+ # enable ferret again before).
48
64
  #
49
65
  # When given a block, this will be executed without any ferret indexing of
50
66
  # this object taking place. The optional argument in this case can be used
@@ -52,6 +68,7 @@ module ActsAsFerret #:nodoc:
52
68
  # (::index_when_finished). Automatic Ferret indexing of this object will be
53
69
  # turned on after the block has been executed. If passed ::index_when_true,
54
70
  # the index will only be updated if the block evaluated not to false or nil.
71
+ #
55
72
  def disable_ferret(option = :once)
56
73
  if block_given?
57
74
  @ferret_disabled = :always
@@ -94,7 +111,7 @@ module ActsAsFerret #:nodoc:
94
111
  # fieldname => value pairs)
95
112
  def to_doc
96
113
  logger.debug "creating doc for class: #{self.class.name}, id: #{self.id}"
97
- returning doc = Ferret::Document.new do
114
+ returning Ferret::Document.new do |doc|
98
115
  # store the id of each item
99
116
  doc[:id] = self.id
100
117
 
@@ -105,6 +122,14 @@ module ActsAsFerret #:nodoc:
105
122
  aaf_configuration[:ferret_fields].each_pair do |field, config|
106
123
  doc[field] = self.send("#{field}_to_ferret") unless config[:ignore]
107
124
  end
125
+ if aaf_configuration[:boost]
126
+ if self.respond_to?(aaf_configuration[:boost])
127
+ boost = self.send aaf_configuration[:boost]
128
+ doc.boost = boost.to_i if boost
129
+ else
130
+ logger.error "boost option should point to an instance method: #{aaf_configuration[:boost]}"
131
+ end
132
+ end
108
133
  end
109
134
  end
110
135
 
@@ -116,8 +141,13 @@ module ActsAsFerret #:nodoc:
116
141
  self.class.aaf_index.query_for_record(id, self.class.name)
117
142
  end
118
143
 
119
- def content_for_field_name(field)
120
- self[field] || self.instance_variable_get("@#{field.to_s}".to_sym) || self.send(field.to_sym)
144
+ def content_for_field_name(field, dynamic_boost = nil)
145
+ field_data = self[field] || self.instance_variable_get("@#{field.to_s}".to_sym) || self.send(field.to_sym)
146
+ if (dynamic_boost && boost_value = self.send(dynamic_boost))
147
+ field_data = Ferret::Field.new(field_data)
148
+ field_data.boost = boost_value.to_i
149
+ end
150
+ field_data
121
151
  end
122
152
 
123
153
 
data/lib/local_index.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  module ActsAsFerret
2
-
3
2
  class LocalIndex < AbstractIndex
4
3
  include MoreLikeThis::IndexMethods
5
4
 
6
-
7
5
  def initialize(aaf_configuration)
8
6
  super
9
7
  ensure_index_exists
@@ -62,6 +60,10 @@ module ActsAsFerret
62
60
  index.index_models models
63
61
  end
64
62
 
63
+ def bulk_index(ids, options)
64
+ ferret_index.bulk_index(aaf_configuration[:class_name].constantize, ids, options)
65
+ end
66
+
65
67
  # Parses the given query string into a Ferret Query object.
66
68
  def process_query(query)
67
69
  # work around ferret bug in #process_query (doesn't ensure the
@@ -74,9 +76,9 @@ module ActsAsFerret
74
76
 
75
77
  # Total number of hits for the given query.
76
78
  # To count the results of a multi_search query, specify an array of
77
- # class names with the :models option.
79
+ # class names with the :multi option.
78
80
  def total_hits(query, options = {})
79
- index = (models = options.delete(:models)) ? multi_index(models) : ferret_index
81
+ index = (models = options.delete(:multi)) ? multi_index(models) : ferret_index
80
82
  index.search(query, options).total_hits
81
83
  end
82
84
 
@@ -96,7 +98,7 @@ module ActsAsFerret
96
98
  def find_id_by_contents(query, options = {})
97
99
  result = []
98
100
  index = ferret_index
99
- logger.debug "query: #{ferret_index.process_query query}" # TODO only enable this for debugging purposes
101
+ logger.debug "query: #{ferret_index.process_query query}" if logger.debug?
100
102
  lazy_fields = determine_lazy_fields options
101
103
 
102
104
  total_hits = index.search_each(query, options) do |hit, score|
@@ -0,0 +1,53 @@
1
+ module ActsAsFerret
2
+
3
+ # decorator that adds a total_hits accessor and will_paginate compatible
4
+ # paging support to search result arrays
5
+ class SearchResults
6
+ attr_reader :current_page, :per_page, :total_hits
7
+
8
+ def initialize(results, total_hits, current_page = 1, per_page = nil)
9
+ @results = results
10
+ @total_hits = total_hits
11
+ @current_page = current_page
12
+ @per_page = (per_page || total_hits)
13
+ @total_pages = @per_page > 0 ? (@total_hits / @per_page.to_f).ceil : 0
14
+ end
15
+
16
+ def method_missing(symbol, *args, &block)
17
+ @results.send(symbol, *args, &block)
18
+ end
19
+
20
+ def respond_to?(name)
21
+ self.methods.include?(name) || @results.respond_to?(name)
22
+ end
23
+
24
+
25
+ # code from here on was directly taken from will_paginate's collection.rb
26
+
27
+ #
28
+ # The total number of pages.
29
+ def page_count
30
+ @total_pages
31
+ end
32
+
33
+ # Current offset of the paginated collection. If we're on the first page,
34
+ # it is always 0. If we're on the 2nd page and there are 30 entries per page,
35
+ # the offset is 30. This property is useful if you want to render ordinals
36
+ # besides your records: simply start with offset + 1.
37
+ #
38
+ def offset
39
+ (current_page - 1) * per_page
40
+ end
41
+
42
+ # current_page - 1 or nil if there is no previous page
43
+ def previous_page
44
+ current_page > 1 ? (current_page - 1) : nil
45
+ end
46
+
47
+ # current_page + 1 or nil if there is no next page
48
+ def next_page
49
+ current_page < page_count ? (current_page + 1) : nil
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,44 @@
1
+ ################################################################################
2
+ require 'optparse'
3
+
4
+ ################################################################################
5
+ $ferret_server_options = {
6
+ 'environment' => nil,
7
+ 'debug' => nil,
8
+ }
9
+
10
+ ################################################################################
11
+ OptionParser.new do |optparser|
12
+ optparser.banner = "Usage: #{File.basename($0)} [options] {start|stop}"
13
+
14
+ optparser.on('-h', '--help', "This message") do
15
+ puts optparser
16
+ exit
17
+ end
18
+
19
+ optparser.on('-e', '--environment=NAME', 'Set RAILS_ENV to the given string') do |e|
20
+ $ferret_server_options['environment'] = e
21
+ end
22
+
23
+ optparser.on('--debug', 'Include full stack traces on exceptions') do
24
+ $ferret_server_options['debug'] = true
25
+ end
26
+
27
+ $ferret_server_action = optparser.permute!(ARGV)
28
+ (puts optparser; exit(1)) unless $ferret_server_action.size == 1
29
+
30
+ $ferret_server_action = $ferret_server_action.first
31
+ (puts optparser; exit(1)) unless %w(start stop).include?($ferret_server_action)
32
+ end
33
+
34
+ ################################################################################
35
+ begin
36
+ ENV['FERRET_USE_LOCAL_INDEX'] = 'true'
37
+ ENV['RAILS_ENV'] = $ferret_server_options['environment']
38
+ require(File.join(File.dirname(__FILE__), '../../../../config/environment'))
39
+ ActsAsFerret::Remote::Server.new.send($ferret_server_action)
40
+ rescue Exception => e
41
+ $stderr.puts(e.message)
42
+ $stderr.puts(e.backtrace.join("\n")) if $ferret_server_options['debug']
43
+ exit(1)
44
+ end
@@ -14,7 +14,7 @@ module ActsAsFerret
14
14
 
15
15
  if original_query.is_a? String
16
16
  model_query = options[:models].map(&:name).join '|'
17
- q << %{ +class_name:"#{model_query}"}
17
+ q += %{ +class_name:"#{model_query}"}
18
18
  else
19
19
  q = Ferret::Search::BooleanQuery.new
20
20
  q.add_query(original_query, :must)
@@ -0,0 +1,63 @@
1
+ ################################################################################
2
+ module ActsAsFerret
3
+ module Remote
4
+
5
+ ################################################################################
6
+ # methods for becoming a daemon on Unix-like operating systems
7
+ module UnixDaemon
8
+
9
+ ################################################################################
10
+ def platform_daemon (&block)
11
+ safefork do
12
+ write_pid_file
13
+ trap("TERM") { exit(0) }
14
+ sess_id = Process.setsid
15
+ STDIN.reopen("/dev/null")
16
+ STDOUT.reopen("#{RAILS_ROOT}/log/ferret_server.out", "a")
17
+ STDERR.reopen(STDOUT)
18
+ block.call
19
+ end
20
+ end
21
+
22
+ ################################################################################
23
+ # stop the daemon, nicely at first, and then forcefully if necessary
24
+ def stop
25
+ pid = read_pid_file
26
+ raise "ferret_server doesn't appear to be running" unless pid
27
+ $stdout.puts("stopping ferret server...")
28
+ Process.kill("TERM", pid)
29
+ 30.times { Process.kill(0, pid); sleep(0.5) }
30
+ $stdout.puts("using kill -9 #{pid}")
31
+ Process.kill(9, pid)
32
+ rescue Errno::ESRCH => e
33
+ $stdout.puts("process #{pid} has stopped")
34
+ ensure
35
+ File.unlink(@cfg.pid_file) if File.exist?(@cfg.pid_file)
36
+ end
37
+
38
+ ################################################################################
39
+ def safefork (&block)
40
+ @fork_tries ||= 0
41
+ fork(&block)
42
+ rescue Errno::EWOULDBLOCK
43
+ raise if @fork_tries >= 20
44
+ @fork_tries += 1
45
+ sleep 5
46
+ retry
47
+ end
48
+
49
+ #################################################################################
50
+ # create the PID file and install an at_exit handler
51
+ def write_pid_file
52
+ open(@cfg.pid_file, "w") {|f| f << Process.pid << "\n"}
53
+ at_exit { File.unlink(@cfg.pid_file) if read_pid_file == Process.pid }
54
+ end
55
+
56
+ #################################################################################
57
+ def read_pid_file
58
+ File.read(@cfg.pid_file).to_i if File.exist?(@cfg.pid_file)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
data/rakefile CHANGED
@@ -61,6 +61,9 @@ if PKG_VERSION
61
61
  #s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG)
62
62
  # s.files.delete ...
63
63
  s.require_path = 'lib'
64
+ s.bindir = "bin"
65
+ s.executables = ["aaf_install"]
66
+ s.default_executable = "aaf_install"
64
67
  s.autorequire = 'acts_as_ferret'
65
68
  s.has_rdoc = true
66
69
  # s.test_files = Dir['test/**/*_test.rb']
@@ -92,8 +95,8 @@ if PKG_VERSION
92
95
  fail "SVK status is not clean ... do you have unchecked-in files?"
93
96
  end
94
97
  announce "No outstanding checkins found ... OK"
95
- announce "Pushing to svn..."
96
- `svk push .`
98
+ # announce "Pushing to svn..."
99
+ # `svk push .`
97
100
  end
98
101
  end
99
102