feedupdater 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.
@@ -0,0 +1,150 @@
1
+
2
+ module Daemons
3
+ class ApplicationGroup
4
+
5
+ attr_reader :app_name
6
+ attr_reader :script
7
+
8
+ attr_reader :monitor
9
+
10
+ #attr_reader :controller
11
+
12
+ attr_reader :options
13
+
14
+ attr_reader :applications
15
+
16
+ attr_accessor :controller_argv
17
+ attr_accessor :app_argv
18
+
19
+ attr_accessor :dir_mode
20
+ attr_accessor :dir
21
+
22
+ # true if the application is supposed to run in multiple instances
23
+ attr_reader :multiple
24
+
25
+
26
+ def initialize(app_name, options = {})
27
+ @app_name = app_name
28
+ @options = options
29
+
30
+ if options[:script]
31
+ @script = File.expand_path(options[:script])
32
+ end
33
+
34
+ #@controller = controller
35
+ @monitor = nil
36
+
37
+ #options = controller.options
38
+
39
+ @multiple = options[:multiple] || false
40
+
41
+ @dir_mode = options[:dir_mode] || :script
42
+ @dir = options[:dir] || ''
43
+
44
+ #@applications = find_applications(pidfile_dir())
45
+ @applications = []
46
+ end
47
+
48
+ # Setup the application group.
49
+ # Currently this functions calls <tt>find_applications</tt> which finds
50
+ # all running instances of the application and populates the application array.
51
+ #
52
+ def setup
53
+ @applications = find_applications(pidfile_dir())
54
+ end
55
+
56
+ def pidfile_dir
57
+ PidFile.dir(@dir_mode, @dir, script)
58
+ end
59
+
60
+ def find_applications(dir)
61
+ pid_files = PidFile.find_files(dir, app_name)
62
+
63
+ #pp pid_files
64
+
65
+ @monitor = Monitor.find(dir, app_name + '_monitor')
66
+
67
+ pid_files.reject! {|f| f =~ /_monitor.pid$/}
68
+
69
+ return pid_files.map {|f|
70
+ app = Application.new(self, {}, PidFile.existing(f))
71
+ setup_app(app)
72
+ app
73
+ }
74
+ end
75
+
76
+ def new_application(add_options = {})
77
+ if @applications.size > 0 and not @multiple
78
+ if options[:force]
79
+ @applications.delete_if {|a|
80
+ unless a.running?
81
+ a.zap
82
+ true
83
+ end
84
+ }
85
+ end
86
+
87
+ raise RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
88
+ end
89
+
90
+ app = Application.new(self, add_options)
91
+
92
+ setup_app(app)
93
+
94
+ @applications << app
95
+
96
+ return app
97
+ end
98
+
99
+ def setup_app(app)
100
+ app.controller_argv = @controller_argv
101
+ app.app_argv = @app_argv
102
+ end
103
+ private :setup_app
104
+
105
+ def create_monitor(an_app)
106
+ return if @monitor
107
+
108
+ if options[:monitor]
109
+ @monitor = Monitor.new(an_app)
110
+
111
+ @monitor.start(@applications)
112
+ end
113
+ end
114
+
115
+ def start_all
116
+ @monitor.stop if @monitor
117
+ @monitor = nil
118
+
119
+ @applications.each {|a|
120
+ fork {
121
+ a.start
122
+ }
123
+ }
124
+ end
125
+
126
+ def stop_all(force = false)
127
+ @monitor.stop if @monitor
128
+
129
+ @applications.each {|a|
130
+ if force
131
+ a.stop rescue nil
132
+ else
133
+ a.stop
134
+ end
135
+ }
136
+ end
137
+
138
+ def zap_all
139
+ @monitor.stop if @monitor
140
+
141
+ @applications.each {|a| a.zap}
142
+ end
143
+
144
+ def show_status
145
+ @applications.each {|a| a.show_status}
146
+ end
147
+
148
+ end
149
+
150
+ end
@@ -0,0 +1,106 @@
1
+
2
+ module Daemons
3
+
4
+ class Optparse
5
+
6
+ attr_reader :usage
7
+
8
+ def initialize(controller)
9
+ @controller = controller
10
+ @options = {}
11
+
12
+ @opts = OptionParser.new do |opts|
13
+ #opts.banner = "Usage: example.rb [options]"
14
+ opts.banner = ""
15
+
16
+ # Boolean switch.
17
+ # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
18
+ # @options[:verbose] = v
19
+ # end
20
+
21
+ opts.on("-t", "--ontop", "Stay on top (does not daemonize)") do |t|
22
+ @options[:ontop] = t
23
+ end
24
+
25
+ opts.on("-f", "--force", "Force operation") do |t|
26
+ @options[:force] = t
27
+ end
28
+
29
+ #opts.separator ""
30
+ #opts.separator "Specific options:"
31
+
32
+
33
+ opts.separator ""
34
+ opts.separator "Common options:"
35
+
36
+ # No argument, shows at tail. This will print an options summary.
37
+ # Try it and see!
38
+ opts.on_tail("-h", "--help", "Show this message") do
39
+ #puts opts
40
+ #@usage =
41
+ controller.print_usage()
42
+
43
+ exit
44
+ end
45
+
46
+ # Another typical switch to print the version.
47
+ opts.on_tail("--version", "Show version") do
48
+ puts "daemons version #{Daemons::VERSION}"
49
+ exit
50
+ end
51
+ end
52
+
53
+ @usage = @opts.to_s
54
+ end
55
+
56
+
57
+ #
58
+ # Return a hash describing the options.
59
+ #
60
+ def parse(args)
61
+ # The options specified on the command line will be collected in *options*.
62
+ # We set default values here.
63
+ #options = {}
64
+
65
+
66
+ ##pp args
67
+ @opts.parse(args)
68
+
69
+ return @options
70
+ end
71
+
72
+ end
73
+
74
+
75
+ class Controller
76
+
77
+ def print_usage
78
+ puts "Usage: #{@app_name} <command> <options> -- <application options>"
79
+ puts
80
+ puts "* where <command> is one of:"
81
+ puts " start start an instance of the application"
82
+ puts " stop stop all instances of the application"
83
+ puts " restart stop all instances and restart them afterwards"
84
+ puts " run start the application and stay on top"
85
+ puts " zap set the application to a stopped state"
86
+ puts
87
+ puts "* and where <options> may contain several of the following:"
88
+
89
+ puts @optparse.usage
90
+ end
91
+
92
+ def catch_exceptions(&block)
93
+ begin
94
+ block.call
95
+ rescue CmdException, OptionParser::ParseError => e
96
+ puts "ERROR: #{e.to_s}"
97
+ puts
98
+ print_usage()
99
+ rescue RuntimeException => e
100
+ puts "ERROR: #{e.to_s}"
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,134 @@
1
+
2
+ module Daemons
3
+ class Controller
4
+
5
+ attr_reader :app_name
6
+
7
+ attr_reader :group
8
+
9
+ attr_reader :options
10
+
11
+
12
+ COMMANDS = [
13
+ 'start',
14
+ 'stop',
15
+ 'restart',
16
+ 'run',
17
+ 'zap',
18
+ 'status'
19
+ ]
20
+
21
+ def initialize(options = {}, argv = [])
22
+ @options = options
23
+ @argv = argv
24
+
25
+ # Allow an app_name to be specified. If not specified use the
26
+ # basename of the script.
27
+ @app_name = options[:app_name]
28
+
29
+ if options[:script]
30
+ @script = File.expand_path(options[:script])
31
+
32
+ @app_name ||= File.split(@script)[1]
33
+ end
34
+
35
+ @app_name = options[:app_name] if options[:app_name]
36
+
37
+ @command, @controller_part, @app_part = Controller.split_argv(argv)
38
+
39
+ #@options[:dir_mode] ||= :script
40
+
41
+ @optparse = Optparse.new(self)
42
+ end
43
+
44
+
45
+ # This function is used to do a final update of the options passed to the application
46
+ # before they are really used.
47
+ #
48
+ # Note that this function should only update <tt>@options</tt> and no other variables.
49
+ #
50
+ def setup_options
51
+ #@options[:ontop] ||= true
52
+ end
53
+
54
+ def run
55
+ @options.update @optparse.parse(@controller_part).delete_if {|k,v| !v}
56
+
57
+ setup_options()
58
+
59
+ #pp @options
60
+
61
+ @group = ApplicationGroup.new(@app_name, @options)
62
+ @group.controller_argv = @controller_part
63
+ @group.app_argv = @app_part
64
+
65
+ @group.setup
66
+
67
+ case @command
68
+ when 'start'
69
+ @group.new_application.start
70
+ when 'run'
71
+ @options[:ontop] ||= true
72
+ @group.new_application.start
73
+ when 'stop'
74
+ @group.stop_all
75
+ when 'restart'
76
+ unless @group.applications.empty?
77
+ @group.stop_all
78
+ sleep 1
79
+ @group.start_all
80
+ end
81
+ when 'zap'
82
+ @group.zap_all
83
+ when 'status'
84
+ unless @group.applications.empty?
85
+ @group.show_status
86
+ else
87
+ puts "#{@group.app_name}: no instances running"
88
+ end
89
+ when nil
90
+ raise CmdException.new('no command given')
91
+ #puts "ERROR: No command given"; puts
92
+
93
+ #print_usage()
94
+ #raise('usage function not implemented')
95
+ else
96
+ raise Error.new("command '#{@command}' not implemented")
97
+ end
98
+ end
99
+
100
+
101
+ # Split an _argv_ array.
102
+ # +argv+ is assumed to be in the following format:
103
+ # ['command', 'controller option 1', 'controller option 2', ..., '--', 'app option 1', ...]
104
+ #
105
+ # <tt>command</tt> must be one of the commands listed in <tt>COMMANDS</tt>
106
+ #
107
+ # *Returns*: the command as a string, the controller options as an array, the appliation options
108
+ # as an array
109
+ #
110
+ def Controller.split_argv(argv)
111
+ argv = argv.dup
112
+
113
+ command = nil
114
+ controller_part = []
115
+ app_part = []
116
+
117
+ if COMMANDS.include? argv[0]
118
+ command = argv.shift
119
+ end
120
+
121
+ if i = argv.index('--')
122
+ # Handle the case where no controller options are given, just
123
+ # options after "--" as well (i == 0)
124
+ controller_part = (i == 0 ? [] : argv[0..i-1])
125
+ app_part = argv[i+1..-1]
126
+ else
127
+ controller_part = argv[0..-1]
128
+ end
129
+
130
+ return command, controller_part, app_part
131
+ end
132
+ end
133
+
134
+ end
@@ -0,0 +1,265 @@
1
+ #--
2
+ ###############################################################################
3
+ # daemonize.rb is a slightly modified version of daemonize.rb was #
4
+ # from the Daemonize Library written by Travis Whitton #
5
+ # for details, read the notice below #
6
+ ###############################################################################
7
+ #++
8
+ #
9
+ #
10
+ # =Daemonize Library
11
+ #
12
+ # February. 4, 2005 Travis Whitton <whitton@atlantic.net>
13
+ #
14
+ # Daemonize allows you to easily modify any existing Ruby program to run
15
+ # as a daemon. See README.rdoc for more details.
16
+ #
17
+ # == How to install
18
+ # 1. su to root
19
+ # 2. ruby install.rb
20
+ # build the docs if you want to
21
+ # 3. rdoc --main README.rdoc daemonize.rb README.rdoc
22
+ #
23
+ # == Copying
24
+ # The Daemonize extension module is copywrited free software by Travis Whitton
25
+ # <whitton@atlantic.net>. You can redistribute it under the terms specified in
26
+ # the COPYING file of the Ruby distribution.
27
+ #
28
+ # == WARRANTY
29
+ # THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
30
+ # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31
+ # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
32
+ # PURPOSE.
33
+ #
34
+ #
35
+ # ----
36
+ #
37
+ # == Purpose
38
+ #
39
+ # Daemonize is a module derived from Perl's Proc::Daemon module. This module
40
+ # allows you to easily modify any existing Ruby program to run as a daemon.
41
+ # A daemon is a process that runs in the background with no controlling terminal.
42
+ # Generally servers (like FTP and HTTP servers) run as daemon processes.
43
+ # Note, do not make the mistake that a daemon == server. Converting a program
44
+ # to a daemon by hand is a relatively simple process; however, this module will
45
+ # save you the effort of repeatedly looking up the procedure, and it will also
46
+ # insure that your programs are daemonized in the safest and most corrects
47
+ # fashion possible.
48
+ #
49
+ # == Procedure
50
+ #
51
+ # The Daemonize module does the following:
52
+ #
53
+ # Forks a child and exits the parent process.
54
+ #
55
+ # Becomes a session leader (which detaches the program from
56
+ # the controlling terminal).
57
+ #
58
+ # Forks another child process and exits first child. This prevents
59
+ # the potential of acquiring a controlling terminal.
60
+ #
61
+ # Changes the current working directory to "/".
62
+ #
63
+ # Clears the file creation mask.
64
+ #
65
+ # Closes file descriptors.
66
+ #
67
+ # == Example usage
68
+ #
69
+ # Using the Daemonize module is extremely simple:
70
+ #
71
+ # require 'daemonize'
72
+ #
73
+ # class TestDaemon
74
+ # include Daemonize
75
+ #
76
+ # def initialize
77
+ # daemonize()
78
+ # loop do
79
+ # # do some work here
80
+ # end
81
+ # end
82
+ # end
83
+ #
84
+ # == Credits
85
+ #
86
+ # Daemonize was written by Travis Whitton and is based on Perl's
87
+ # Proc::Daemonize, which was written by Earl Hood. The above documentation
88
+ # is also partially borrowed from the Proc::Daemonize POD documentation.
89
+
90
+
91
+
92
+ module Daemonize
93
+ VERSION = "0.1.1m"
94
+
95
+ # Try to fork if at all possible retrying every 5 sec if the
96
+ # maximum process limit for the system has been reached
97
+ def safefork
98
+ tryagain = true
99
+
100
+ while tryagain
101
+ tryagain = false
102
+ begin
103
+ if pid = fork
104
+ return pid
105
+ end
106
+ rescue Errno::EWOULDBLOCK
107
+ sleep 5
108
+ tryagain = true
109
+ end
110
+ end
111
+ end
112
+ module_function :safefork
113
+
114
+
115
+ def simulate(logfile_name = nil)
116
+ # NOTE: STDOUT and STDERR will not be redirected to the logfile!
117
+
118
+ Dir.chdir "/" # Release old working directory
119
+ File.umask 0000 # Insure sensible umask
120
+
121
+ # Make sure all file descriptors are closed
122
+ ObjectSpace.each_object(IO) do |io|
123
+ unless [STDIN, STDOUT, STDERR].include?(io)
124
+ begin
125
+ unless io.closed?
126
+ io.close
127
+ end
128
+ rescue ::Exception
129
+ end
130
+ end
131
+ end
132
+
133
+ # Free file descriptors and
134
+ # point them somewhere sensible
135
+ # STDOUT/STDERR should go to a logfile
136
+
137
+ STDIN.reopen "/dev/null" rescue nil
138
+ end
139
+ module_function :simulate
140
+
141
+
142
+ def call_as_daemon(block, logfile_name = nil, oldmode = 0)
143
+ rd, wr = IO.pipe
144
+
145
+ if tmppid = safefork
146
+ # parent
147
+ wr.close
148
+ pid = rd.read.to_i
149
+ rd.close
150
+
151
+ Process.waitpid(tmppid)
152
+
153
+ return pid
154
+ else
155
+ rd.close
156
+
157
+ # Detach from the controlling terminal
158
+ unless sess_id = Process.setsid
159
+ raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
160
+ end
161
+
162
+ # Prevent the possibility of acquiring a controlling terminal
163
+ if oldmode.zero?
164
+ trap 'SIGHUP', 'IGNORE'
165
+ exit if pid = safefork
166
+ end
167
+
168
+ wr.write Process.pid
169
+ wr.close
170
+
171
+ Dir.chdir "/" # Release old working directory
172
+ File.umask 0000 # Insure sensible umask
173
+
174
+ # Make sure all file descriptors are closed
175
+ ObjectSpace.each_object(IO) do |io|
176
+ unless [STDIN, STDOUT, STDERR].include?(io)
177
+ begin
178
+ unless io.closed?
179
+ io.close
180
+ end
181
+ rescue ::Exception
182
+ end
183
+ end
184
+ end
185
+
186
+ # Free file descriptors and
187
+ # point them somewhere sensible
188
+ # STDOUT/STDERR should go to a logfile
189
+
190
+ STDIN.reopen "/dev/null" rescue nil
191
+
192
+ if logfile_name
193
+ begin
194
+ STDOUT.reopen logfile_name, "a"
195
+ rescue ::Exception
196
+ STDOUT.reopen "/dev/null" rescue nil
197
+ end
198
+ else
199
+ STDOUT.reopen "/dev/null" rescue nil
200
+ end
201
+
202
+ STDERR.reopen STDOUT rescue nil
203
+
204
+ block.call
205
+
206
+ exit
207
+ end
208
+ end
209
+ module_function :call_as_daemon
210
+
211
+
212
+ # This method causes the current running process to become a daemon
213
+ def daemonize(logfile_name = nil, oldmode=0)
214
+ srand # Split rand streams between spawning and daemonized process
215
+ safefork and exit # Fork and exit from the parent
216
+
217
+ # Detach from the controlling terminal
218
+ unless sess_id = Process.setsid
219
+ raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
220
+ end
221
+
222
+ # Prevent the possibility of acquiring a controlling terminal
223
+ if oldmode.zero?
224
+ trap 'SIGHUP', 'IGNORE'
225
+ exit if pid = safefork
226
+ end
227
+
228
+ Dir.chdir "/" # Release old working directory
229
+ File.umask 0000 # Insure sensible umask
230
+
231
+ # Make sure all file descriptors are closed
232
+ ObjectSpace.each_object(IO) do |io|
233
+ unless [STDIN, STDOUT, STDERR].include?(io)
234
+ begin
235
+ unless io.closed?
236
+ io.close
237
+ end
238
+ rescue ::Exception
239
+ end
240
+ end
241
+ end
242
+
243
+ # Free file descriptors and
244
+ # point them somewhere sensible
245
+ # STDOUT/STDERR should go to a logfile
246
+
247
+ STDIN.reopen "/dev/null" rescue nil
248
+
249
+ if logfile_name
250
+ begin
251
+ STDOUT.reopen logfile_name, "a"
252
+ rescue ::Exception
253
+ STDOUT.reopen "/dev/null" rescue nil
254
+ end
255
+ else
256
+ STDOUT.reopen "/dev/null" rescue nil
257
+ end
258
+
259
+ STDERR.reopen STDOUT rescue nil
260
+
261
+ return oldmode ? sess_id : 0 # Return value is mostly irrelevant
262
+ end
263
+ module_function :daemonize
264
+
265
+ end
@@ -0,0 +1,28 @@
1
+
2
+ module Daemons
3
+
4
+ class Exception < ::RuntimeError
5
+ end
6
+
7
+ class RuntimeException < Exception
8
+ end
9
+
10
+ class CmdException < Exception
11
+ end
12
+
13
+ class Error < Exception
14
+ end
15
+
16
+ class SystemError < Error
17
+
18
+ attr_reader :system_error
19
+
20
+ def initialize(msg, system_error)
21
+ super(msg)
22
+
23
+ @system_error = system_error
24
+ end
25
+
26
+ end
27
+
28
+ end