818 |
817 |
819 if errors: |
818 if errors: |
820 ui.warn(_('(consider using --after)\n')) |
819 ui.warn(_('(consider using --after)\n')) |
821 |
820 |
822 return errors != 0 |
821 return errors != 0 |
823 |
|
824 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None, |
|
825 runargs=None, appendpid=False): |
|
826 '''Run a command as a service.''' |
|
827 |
|
828 def writepid(pid): |
|
829 if opts['pid_file']: |
|
830 if appendpid: |
|
831 mode = 'a' |
|
832 else: |
|
833 mode = 'w' |
|
834 fp = open(opts['pid_file'], mode) |
|
835 fp.write(str(pid) + '\n') |
|
836 fp.close() |
|
837 |
|
838 if opts['daemon'] and not opts['daemon_postexec']: |
|
839 # Signal child process startup with file removal |
|
840 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-') |
|
841 os.close(lockfd) |
|
842 try: |
|
843 if not runargs: |
|
844 runargs = util.hgcmd() + sys.argv[1:] |
|
845 runargs.append('--daemon-postexec=unlink:%s' % lockpath) |
|
846 # Don't pass --cwd to the child process, because we've already |
|
847 # changed directory. |
|
848 for i in xrange(1, len(runargs)): |
|
849 if runargs[i].startswith('--cwd='): |
|
850 del runargs[i] |
|
851 break |
|
852 elif runargs[i].startswith('--cwd'): |
|
853 del runargs[i:i + 2] |
|
854 break |
|
855 def condfn(): |
|
856 return not os.path.exists(lockpath) |
|
857 pid = util.rundetached(runargs, condfn) |
|
858 if pid < 0: |
|
859 raise error.Abort(_('child process failed to start')) |
|
860 writepid(pid) |
|
861 finally: |
|
862 try: |
|
863 os.unlink(lockpath) |
|
864 except OSError as e: |
|
865 if e.errno != errno.ENOENT: |
|
866 raise |
|
867 if parentfn: |
|
868 return parentfn(pid) |
|
869 else: |
|
870 return |
|
871 |
|
872 if initfn: |
|
873 initfn() |
|
874 |
|
875 if not opts['daemon']: |
|
876 writepid(util.getpid()) |
|
877 |
|
878 if opts['daemon_postexec']: |
|
879 try: |
|
880 os.setsid() |
|
881 except AttributeError: |
|
882 pass |
|
883 for inst in opts['daemon_postexec']: |
|
884 if inst.startswith('unlink:'): |
|
885 lockpath = inst[7:] |
|
886 os.unlink(lockpath) |
|
887 elif inst.startswith('chdir:'): |
|
888 os.chdir(inst[6:]) |
|
889 elif inst != 'none': |
|
890 raise error.Abort(_('invalid value for --daemon-postexec: %s') |
|
891 % inst) |
|
892 util.hidewindow() |
|
893 util.stdout.flush() |
|
894 util.stderr.flush() |
|
895 |
|
896 nullfd = os.open(os.devnull, os.O_RDWR) |
|
897 logfilefd = nullfd |
|
898 if logfile: |
|
899 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND) |
|
900 os.dup2(nullfd, 0) |
|
901 os.dup2(logfilefd, 1) |
|
902 os.dup2(logfilefd, 2) |
|
903 if nullfd not in (0, 1, 2): |
|
904 os.close(nullfd) |
|
905 if logfile and logfilefd not in (0, 1, 2): |
|
906 os.close(logfilefd) |
|
907 |
|
908 if runfn: |
|
909 return runfn() |
|
910 |
822 |
911 ## facility to let extension process additional data into an import patch |
823 ## facility to let extension process additional data into an import patch |
912 # list of identifier to be executed in order |
824 # list of identifier to be executed in order |
913 extrapreimport = [] # run before commit |
825 extrapreimport = [] # run before commit |
914 extrapostimport = [] # run after commit |
826 extrapostimport = [] # run after commit |