@@ -40,6 +40,8 @@ def detect_provider():
4040 print (os .path .realpath (cmd ))
4141 if b'systemd' in os .path .realpath (cmd ):
4242 return Systemd
43+ if b'supervisor' in os .path .realpath (cmd ):
44+ return Supervisor
4345 return Upstart
4446
4547
@@ -228,3 +230,78 @@ def _fill_template(self, template):
228230 self .interpreter .file (f )
229231 return self .interpreter .output .getvalue ()
230232 self .set_job_path ()
233+
234+
235+ class Supervisor (Generic ):
236+ """ The Supervisor implementation places the user-specified files in ``/etc/ros/DISTRO/NAME.d``,
237+ and creates an systemd job configuration in ``/lib/systemd/system/NAME.d``. Two additional
238+ helper scripts are created for starting and stopping the job, places in
239+ ``/usr/sbin``.
240+ To detect which system you're using run: ps -p1 | grep systemd && echo systemd || echo upstart
241+ """
242+
243+ def generate_install (self ):
244+ # Default is /etc/ros/DISTRO/JOBNAME.d
245+ self ._set_job_path ()
246+
247+ # User-specified launch files.
248+ self ._add_job_files ()
249+
250+ # This is optional to support the old --augment flag where a "job" only adds
251+ # launch files to an existing configuration.
252+ if self .job .generate_system_files :
253+ # Share a single instance of the EmPy interpreter.
254+ self .interpreter = em .Interpreter (globals = self .job .__dict__ .copy ())
255+
256+ self .installation_files [os .path .join (self .root , "etc/supervisor/conf.d" , self .job .name + ".conf" )] = {
257+ "content" : self ._fill_template ("templates/supervisor_job.conf.em" ), "mode" : 0o644 }
258+ self .installation_files [os .path .join (self .root , "usr/sbin" , self .job .name + "-start" )] = {
259+ "content" : self ._fill_template ("templates/job-start.em" ), "mode" : 0o755 }
260+ self .installation_files [os .path .join (self .root , "usr/sbin" , self .job .name + "-stop" )] = {
261+ "content" : self ._fill_template ("templates/job-stop.em" ), "mode" : 0o755 }
262+ self .interpreter .shutdown ()
263+
264+ # Add an annotation file listing what has been installed. This is a union of what's being
265+ # installed now with what has been installed previously, so that an uninstall should remove
266+ # all of it. A more sophisticated future implementation could track contents or hashes and
267+ # thereby warn users when a new installation is stomping a change they have made.
268+ self ._load_installed_files_set ()
269+ self .installed_files_set .update (list (self .installation_files .keys ()))
270+
271+ # Remove the job directory. This will fail if it is not empty, and notify the user.
272+ self .installed_files_set .add (self .job .job_path )
273+
274+ # Remove the annotation file itself.
275+ self .installed_files_set .add (self .installed_files_set_location )
276+
277+ self .installation_files [self .installed_files_set_location ] = {
278+ "content" : "\n " .join (self .installed_files_set )}
279+
280+ return self .installation_files
281+
282+ def post_install (self ):
283+ print ("** To complete installation please run the following command:" )
284+ print (" sudo supervisorctl reload" +
285+ " && sudo supervisorctl status" +
286+ " ; browse https://localhost:9001" )
287+
288+ def generate_uninstall (self ):
289+ self ._set_job_path ()
290+ self ._load_installed_files_set ()
291+
292+ for filename in self .installed_files_set :
293+ self .installation_files [filename ] = {"remove" : True }
294+
295+ return self .installation_files
296+
297+ def _set_job_path (self ):
298+ self .job .job_path = os .path .join (
299+ self .root , "etc/ros" , self .job .rosdistro , self .job .name + ".d" )
300+
301+ def _fill_template (self , template ):
302+ self .interpreter .output = io .StringIO ()
303+ self .interpreter .reset ()
304+ with open (find_in_workspaces (project = "robot_upstart" , path = template )[0 ]) as f :
305+ self .interpreter .file (f )
306+ return self .interpreter .output .getvalue ()
307+ self .set_job_path ()
0 commit comments