##// END OF EJS Templates
remotefilelog: transplant runbgcommand to procutil...
Augie Fackler -
r40532:3fbfbc8c default
parent child Browse files
Show More
@@ -10,88 +10,15 b' from __future__ import absolute_import'
10 import contextlib
10 import contextlib
11 import errno
11 import errno
12 import os
12 import os
13 import subprocess
14 import time
13 import time
15
14
16 from mercurial import (
15 from mercurial import (
17 error,
16 error,
18 lock as lockmod,
17 lock as lockmod,
19 pycompat,
20 util,
18 util,
21 vfs as vfsmod,
19 vfs as vfsmod,
22 )
20 )
23
21
24 if pycompat.iswindows:
25 # no fork on Windows, but we can create a detached process
26 # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx
27 # No stdlib constant exists for this value
28 DETACHED_PROCESS = 0x00000008
29 _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
30
31 def runbgcommand(script, env, shell=False, stdout=None, stderr=None):
32 '''Spawn a command without waiting for it to finish.'''
33 # we can't use close_fds *and* redirect stdin. I'm not sure that we
34 # need to because the detached process has no console connection.
35 subprocess.Popen(
36 script, shell=shell, env=env, close_fds=True,
37 creationflags=_creationflags, stdout=stdout, stderr=stderr)
38 else:
39 def runbgcommand(cmd, env, shell=False, stdout=None, stderr=None):
40 '''Spawn a command without waiting for it to finish.'''
41 # double-fork to completely detach from the parent process
42 # based on http://code.activestate.com/recipes/278731
43 pid = os.fork()
44 if pid:
45 # Parent process
46 (_pid, status) = os.waitpid(pid, 0)
47 if os.WIFEXITED(status):
48 returncode = os.WEXITSTATUS(status)
49 else:
50 returncode = -os.WTERMSIG(status)
51 if returncode != 0:
52 # The child process's return code is 0 on success, an errno
53 # value on failure, or 255 if we don't have a valid errno
54 # value.
55 #
56 # (It would be slightly nicer to return the full exception info
57 # over a pipe as the subprocess module does. For now it
58 # doesn't seem worth adding that complexity here, though.)
59 if returncode == 255:
60 returncode = errno.EINVAL
61 raise OSError(returncode, 'error running %r: %s' %
62 (cmd, os.strerror(returncode)))
63 return
64
65 returncode = 255
66 try:
67 # Start a new session
68 os.setsid()
69
70 stdin = open(os.devnull, 'r')
71 if stdout is None:
72 stdout = open(os.devnull, 'w')
73 if stderr is None:
74 stderr = open(os.devnull, 'w')
75
76 # connect stdin to devnull to make sure the subprocess can't
77 # muck up that stream for mercurial.
78 subprocess.Popen(
79 cmd, shell=shell, env=env, close_fds=True,
80 stdin=stdin, stdout=stdout, stderr=stderr)
81 returncode = 0
82 except EnvironmentError as ex:
83 returncode = (ex.errno & 0xff)
84 if returncode == 0:
85 # This shouldn't happen, but just in case make sure the
86 # return code is never 0 here.
87 returncode = 255
88 except Exception:
89 returncode = 255
90 finally:
91 # mission accomplished, this child needs to exit and not
92 # continue the hg process here.
93 os._exit(returncode)
94
95 @contextlib.contextmanager
22 @contextlib.contextmanager
96 def flock(lockpath, description, timeout=-1):
23 def flock(lockpath, description, timeout=-1):
97 """A flock based lock object. Currently it is always non-blocking.
24 """A flock based lock object. Currently it is always non-blocking.
@@ -50,7 +50,7 b' def backgroundrepack(repo, incremental=T'
50 if packsonly:
50 if packsonly:
51 cmd.append('--packsonly')
51 cmd.append('--packsonly')
52 repo.ui.warn(msg)
52 repo.ui.warn(msg)
53 extutil.runbgcommand(cmd, encoding.environ)
53 procutil.runbgcommand(cmd, encoding.environ)
54
54
55 def fullrepack(repo, options=None):
55 def fullrepack(repo, options=None):
56 """If ``packsonly`` is True, stores creating only loose objects are skipped.
56 """If ``packsonly`` is True, stores creating only loose objects are skipped.
@@ -25,7 +25,6 b' from . import ('
25 constants,
25 constants,
26 contentstore,
26 contentstore,
27 datapack,
27 datapack,
28 extutil,
29 fileserverclient,
28 fileserverclient,
30 historypack,
29 historypack,
31 metadatastore,
30 metadatastore,
@@ -199,7 +198,7 b' def wraprepo(repo):'
199 cmd.append('--repack')
198 cmd.append('--repack')
200 if revs:
199 if revs:
201 cmd += ['-r', revs]
200 cmd += ['-r', revs]
202 extutil.runbgcommand(cmd, encoding.environ)
201 procutil.runbgcommand(cmd, encoding.environ)
203
202
204 def prefetch(self, revs, base=None, pats=None, opts=None):
203 def prefetch(self, revs, base=None, pats=None, opts=None):
205 """Prefetches all the necessary file revisions for the given revs
204 """Prefetches all the necessary file revisions for the given revs
@@ -10,6 +10,7 b''
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 import contextlib
12 import contextlib
13 import errno
13 import imp
14 import imp
14 import io
15 import io
15 import os
16 import os
@@ -467,3 +468,74 b' def uninterruptable(warn):'
467 signal.signal(signal.SIGINT, oldsiginthandler[0])
468 signal.signal(signal.SIGINT, oldsiginthandler[0])
468 if shouldbail:
469 if shouldbail:
469 raise KeyboardInterrupt
470 raise KeyboardInterrupt
471
472 if pycompat.iswindows:
473 # no fork on Windows, but we can create a detached process
474 # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx
475 # No stdlib constant exists for this value
476 DETACHED_PROCESS = 0x00000008
477 _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
478
479 def runbgcommand(script, env, shell=False, stdout=None, stderr=None):
480 '''Spawn a command without waiting for it to finish.'''
481 # we can't use close_fds *and* redirect stdin. I'm not sure that we
482 # need to because the detached process has no console connection.
483 subprocess.Popen(
484 script, shell=shell, env=env, close_fds=True,
485 creationflags=_creationflags, stdout=stdout, stderr=stderr)
486 else:
487 def runbgcommand(cmd, env, shell=False, stdout=None, stderr=None):
488 '''Spawn a command without waiting for it to finish.'''
489 # double-fork to completely detach from the parent process
490 # based on http://code.activestate.com/recipes/278731
491 pid = os.fork()
492 if pid:
493 # Parent process
494 (_pid, status) = os.waitpid(pid, 0)
495 if os.WIFEXITED(status):
496 returncode = os.WEXITSTATUS(status)
497 else:
498 returncode = -os.WTERMSIG(status)
499 if returncode != 0:
500 # The child process's return code is 0 on success, an errno
501 # value on failure, or 255 if we don't have a valid errno
502 # value.
503 #
504 # (It would be slightly nicer to return the full exception info
505 # over a pipe as the subprocess module does. For now it
506 # doesn't seem worth adding that complexity here, though.)
507 if returncode == 255:
508 returncode = errno.EINVAL
509 raise OSError(returncode, 'error running %r: %s' %
510 (cmd, os.strerror(returncode)))
511 return
512
513 returncode = 255
514 try:
515 # Start a new session
516 os.setsid()
517
518 stdin = open(os.devnull, 'r')
519 if stdout is None:
520 stdout = open(os.devnull, 'w')
521 if stderr is None:
522 stderr = open(os.devnull, 'w')
523
524 # connect stdin to devnull to make sure the subprocess can't
525 # muck up that stream for mercurial.
526 subprocess.Popen(
527 cmd, shell=shell, env=env, close_fds=True,
528 stdin=stdin, stdout=stdout, stderr=stderr)
529 returncode = 0
530 except EnvironmentError as ex:
531 returncode = (ex.errno & 0xff)
532 if returncode == 0:
533 # This shouldn't happen, but just in case make sure the
534 # return code is never 0 here.
535 returncode = 255
536 except Exception:
537 returncode = 255
538 finally:
539 # mission accomplished, this child needs to exit and not
540 # continue the hg process here.
541 os._exit(returncode)
General Comments 0
You need to be logged in to leave comments. Login now