# HG changeset patch # User Bryan O'Sullivan # Date 1177734655 25200 # Node ID e89f9afc462b40b0bc673aa82e661c54a2b48af8 # Parent e33ad7cea15fd01ad055be44ab801237fb843399 Refactor commands.serve to allow other commands to run as services. This introduces a new function, cmdutil.service. diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -200,6 +200,50 @@ def addremove(repo, pats=[], opts={}, wl if not dry_run: repo.copy(old, new, wlock=wlock) +def service(opts, parentfn=None, initfn=None, runfn=None): + '''Run a command as a service.''' + + if opts['daemon'] and not opts['daemon_pipefds']: + rfd, wfd = os.pipe() + args = sys.argv[:] + args.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) + pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), + args[0], args) + os.close(wfd) + os.read(rfd, 1) + if parentfn: + return parentfn(pid) + else: + os._exit(0) + + if initfn: + initfn() + + if opts['pid_file']: + fp = open(opts['pid_file'], 'w') + fp.write(str(os.getpid()) + '\n') + fp.close() + + if opts['daemon_pipefds']: + rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')] + os.close(rfd) + try: + os.setsid() + except AttributeError: + pass + os.write(wfd, 'y') + os.close(wfd) + sys.stdout.flush() + sys.stderr.flush() + fd = os.open(util.nulldev, os.O_RDWR) + if fd != 0: os.dup2(fd, 0) + if fd != 1: os.dup2(fd, 1) + if fd != 2: os.dup2(fd, 2) + if fd not in (0, 1, 2): os.close(fd) + + if runfn: + return runfn() + class changeset_printer(object): '''show changeset information when templating not requested.''' diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -2375,44 +2375,27 @@ def serve(ui, repo, **opts): raise hg.RepoError(_("There is no Mercurial repository here" " (.hg not found)")) - if opts['daemon'] and not opts['daemon_pipefds']: - rfd, wfd = os.pipe() - args = sys.argv[:] - args.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) - pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), - args[0], args) - os.close(wfd) - os.read(rfd, 1) - os._exit(0) - - httpd = hgweb.server.create_server(parentui, repo) - - if ui.verbose: - if httpd.port != 80: - ui.status(_('listening at http://%s:%d/\n') % - (httpd.addr, httpd.port)) - else: - ui.status(_('listening at http://%s/\n') % httpd.addr) - - if opts['pid_file']: - fp = open(opts['pid_file'], 'w') - fp.write(str(os.getpid()) + '\n') - fp.close() - - if opts['daemon_pipefds']: - rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')] - os.close(rfd) - os.write(wfd, 'y') - os.close(wfd) - sys.stdout.flush() - sys.stderr.flush() - fd = os.open(util.nulldev, os.O_RDWR) - if fd != 0: os.dup2(fd, 0) - if fd != 1: os.dup2(fd, 1) - if fd != 2: os.dup2(fd, 2) - if fd not in (0, 1, 2): os.close(fd) - - httpd.serve_forever() + class service: + def init(self): + try: + self.httpd = hgweb.server.create_server(parentui, repo) + except socket.error, inst: + raise util.Abort(_('cannot start server: ') + inst.args[1]) + + if not ui.verbose: return + + if httpd.port != 80: + ui.status(_('listening at http://%s:%d/\n') % + (httpd.addr, httpd.port)) + else: + ui.status(_('listening at http://%s/\n') % httpd.addr) + + def run(self): + self.httpd.serve_forever() + + service = service() + + cmdutil.service(opts, initfn=service.init, runfn=service.run) def status(ui, repo, *pats, **opts): """show changed files in the working directory