5 # This software may be used and distributed according to the terms of the |
5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2, incorporated herein by reference. |
6 # GNU General Public License version 2, incorporated herein by reference. |
7 |
7 |
8 from node import hex, nullid, nullrev, short |
8 from node import hex, nullid, nullrev, short |
9 from i18n import _ |
9 from i18n import _ |
10 import os, sys, errno, re, glob |
10 import os, sys, errno, re, glob, tempfile, time |
11 import mdiff, bdiff, util, templater, patch, error, encoding, templatekw |
11 import mdiff, bdiff, util, templater, patch, error, encoding, templatekw |
12 import match as _match |
12 import match as _match |
13 |
13 |
14 revrangesep = ':' |
14 revrangesep = ':' |
15 |
15 |
565 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None, |
565 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None, |
566 runargs=None, appendpid=False): |
566 runargs=None, appendpid=False): |
567 '''Run a command as a service.''' |
567 '''Run a command as a service.''' |
568 |
568 |
569 if opts['daemon'] and not opts['daemon_pipefds']: |
569 if opts['daemon'] and not opts['daemon_pipefds']: |
570 rfd, wfd = os.pipe() |
570 # Signal child process startup with file removal |
571 if not runargs: |
571 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-') |
572 runargs = sys.argv[:] |
572 os.close(lockfd) |
573 runargs.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) |
573 try: |
574 # Don't pass --cwd to the child process, because we've already |
574 if not runargs: |
575 # changed directory. |
575 runargs = sys.argv[:] |
576 for i in xrange(1,len(runargs)): |
576 runargs.append('--daemon-pipefds=%s' % lockpath) |
577 if runargs[i].startswith('--cwd='): |
577 # Don't pass --cwd to the child process, because we've already |
578 del runargs[i] |
578 # changed directory. |
579 break |
579 for i in xrange(1,len(runargs)): |
580 elif runargs[i].startswith('--cwd'): |
580 if runargs[i].startswith('--cwd='): |
581 del runargs[i:i+2] |
581 del runargs[i] |
582 break |
582 break |
583 pid = util.spawndetached(runargs) |
583 elif runargs[i].startswith('--cwd'): |
584 os.close(wfd) |
584 del runargs[i:i+2] |
585 os.read(rfd, 1) |
585 break |
|
586 pid = util.spawndetached(runargs) |
|
587 while os.path.exists(lockpath): |
|
588 time.sleep(0.1) |
|
589 finally: |
|
590 try: |
|
591 os.unlink(lockpath) |
|
592 except OSError, e: |
|
593 if e.errno != errno.ENOENT: |
|
594 raise |
586 if parentfn: |
595 if parentfn: |
587 return parentfn(pid) |
596 return parentfn(pid) |
588 else: |
597 else: |
589 return |
598 return |
590 |
599 |
596 fp = open(opts['pid_file'], mode) |
605 fp = open(opts['pid_file'], mode) |
597 fp.write(str(os.getpid()) + '\n') |
606 fp.write(str(os.getpid()) + '\n') |
598 fp.close() |
607 fp.close() |
599 |
608 |
600 if opts['daemon_pipefds']: |
609 if opts['daemon_pipefds']: |
601 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')] |
610 lockpath = opts['daemon_pipefds'] |
602 os.close(rfd) |
|
603 try: |
611 try: |
604 os.setsid() |
612 os.setsid() |
605 except AttributeError: |
613 except AttributeError: |
606 pass |
614 pass |
607 os.write(wfd, 'y') |
615 os.unlink(lockpath) |
608 os.close(wfd) |
|
609 sys.stdout.flush() |
616 sys.stdout.flush() |
610 sys.stderr.flush() |
617 sys.stderr.flush() |
611 |
618 |
612 nullfd = os.open(util.nulldev, os.O_RDWR) |
619 nullfd = os.open(util.nulldev, os.O_RDWR) |
613 logfilefd = nullfd |
620 logfilefd = nullfd |