Show More
@@ -80,7 +80,7 b' io.BufferedIOBase.register(LineBufferedW' | |||
|
80 | 80 | |
|
81 | 81 | |
|
82 | 82 | def make_line_buffered(stream): |
|
83 |
if |
|
|
83 | if not isinstance(stream, io.BufferedIOBase): | |
|
84 | 84 | # On Python 3, buffered streams can be expected to subclass |
|
85 | 85 | # BufferedIOBase. This is definitively the case for the streams |
|
86 | 86 | # initialized by the interpreter. For unbuffered streams, we don't need |
@@ -121,7 +121,6 b' io.IOBase.register(WriteAllWrapper)' | |||
|
121 | 121 | |
|
122 | 122 | |
|
123 | 123 | def _make_write_all(stream): |
|
124 | assert pycompat.ispy3 | |
|
125 | 124 | if isinstance(stream, WriteAllWrapper): |
|
126 | 125 | return stream |
|
127 | 126 | if isinstance(stream, io.BufferedIOBase): |
@@ -133,52 +132,32 b' def _make_write_all(stream):' | |||
|
133 | 132 | return WriteAllWrapper(stream) |
|
134 | 133 | |
|
135 | 134 | |
|
136 | if pycompat.ispy3: | |
|
137 | # Python 3 implements its own I/O streams. Unlike stdio of C library, | |
|
138 | # sys.stdin/stdout/stderr may be None if underlying fd is closed. | |
|
139 | ||
|
140 | # TODO: .buffer might not exist if std streams were replaced; we'll need | |
|
141 | # a silly wrapper to make a bytes stream backed by a unicode one. | |
|
135 | # Python 3 implements its own I/O streams. Unlike stdio of C library, | |
|
136 | # sys.stdin/stdout/stderr may be None if underlying fd is closed. | |
|
142 | 137 | |
|
143 | if sys.stdin is None: | |
|
144 | stdin = BadFile() | |
|
145 | else: | |
|
146 | stdin = sys.stdin.buffer | |
|
147 | if sys.stdout is None: | |
|
148 | stdout = BadFile() | |
|
149 | else: | |
|
150 | stdout = _make_write_all(sys.stdout.buffer) | |
|
151 | if sys.stderr is None: | |
|
152 | stderr = BadFile() | |
|
153 | else: | |
|
154 | stderr = _make_write_all(sys.stderr.buffer) | |
|
138 | # TODO: .buffer might not exist if std streams were replaced; we'll need | |
|
139 | # a silly wrapper to make a bytes stream backed by a unicode one. | |
|
155 | 140 | |
|
156 | if pycompat.iswindows: | |
|
157 | # Work around Windows bugs. | |
|
158 | stdout = platform.winstdout(stdout) # pytype: disable=module-attr | |
|
159 | stderr = platform.winstdout(stderr) # pytype: disable=module-attr | |
|
160 | if isatty(stdout): | |
|
161 | # The standard library doesn't offer line-buffered binary streams. | |
|
162 | stdout = make_line_buffered(stdout) | |
|
141 | if sys.stdin is None: | |
|
142 | stdin = BadFile() | |
|
143 | else: | |
|
144 | stdin = sys.stdin.buffer | |
|
145 | if sys.stdout is None: | |
|
146 | stdout = BadFile() | |
|
163 | 147 | else: |
|
164 | # Python 2 uses the I/O streams provided by the C library. | |
|
165 | stdin = sys.stdin | |
|
166 | stdout = sys.stdout | |
|
167 | stderr = sys.stderr | |
|
168 | if pycompat.iswindows: | |
|
169 | # Work around Windows bugs. | |
|
170 | stdout = platform.winstdout(stdout) # pytype: disable=module-attr | |
|
171 | stderr = platform.winstdout(stderr) # pytype: disable=module-attr | |
|
172 | if isatty(stdout): | |
|
173 | if pycompat.iswindows: | |
|
174 | # The Windows C runtime library doesn't support line buffering. | |
|
175 | stdout = make_line_buffered(stdout) | |
|
176 | else: | |
|
177 | # glibc determines buffering on first write to stdout - if we | |
|
178 | # replace a TTY destined stdout with a pipe destined stdout (e.g. | |
|
179 | # pager), we want line buffering. | |
|
180 | stdout = os.fdopen(stdout.fileno(), 'wb', 1) | |
|
148 | stdout = _make_write_all(sys.stdout.buffer) | |
|
149 | if sys.stderr is None: | |
|
150 | stderr = BadFile() | |
|
151 | else: | |
|
152 | stderr = _make_write_all(sys.stderr.buffer) | |
|
181 | 153 | |
|
154 | if pycompat.iswindows: | |
|
155 | # Work around Windows bugs. | |
|
156 | stdout = platform.winstdout(stdout) # pytype: disable=module-attr | |
|
157 | stderr = platform.winstdout(stderr) # pytype: disable=module-attr | |
|
158 | if isatty(stdout): | |
|
159 | # The standard library doesn't offer line-buffered binary streams. | |
|
160 | stdout = make_line_buffered(stdout) | |
|
182 | 161 | |
|
183 | 162 | findexe = platform.findexe |
|
184 | 163 | _gethgcmd = platform.gethgcmd |
@@ -704,7 +683,7 b' if pycompat.iswindows:' | |||
|
704 | 683 | |
|
705 | 684 | else: |
|
706 | 685 | |
|
707 |
def runbgcommand |
|
|
686 | def runbgcommand( | |
|
708 | 687 | cmd, |
|
709 | 688 | env, |
|
710 | 689 | shell=False, |
@@ -787,128 +766,3 b' else:' | |||
|
787 | 766 | returncode = p.wait |
|
788 | 767 | if record_wait is not None: |
|
789 | 768 | record_wait(returncode) |
|
790 | ||
|
791 | def runbgcommandpy2( | |
|
792 | cmd, | |
|
793 | env, | |
|
794 | shell=False, | |
|
795 | stdout=None, | |
|
796 | stderr=None, | |
|
797 | ensurestart=True, | |
|
798 | record_wait=None, | |
|
799 | stdin_bytes=None, | |
|
800 | ): | |
|
801 | """Spawn a command without waiting for it to finish. | |
|
802 | ||
|
803 | ||
|
804 | When `record_wait` is not None, the spawned process will not be fully | |
|
805 | detached and the `record_wait` argument will be called with a the | |
|
806 | `Subprocess.wait` function for the spawned process. This is mostly | |
|
807 | useful for developers that need to make sure the spawned process | |
|
808 | finished before a certain point. (eg: writing test)""" | |
|
809 | if pycompat.isdarwin: | |
|
810 | # avoid crash in CoreFoundation in case another thread | |
|
811 | # calls gui() while we're calling fork(). | |
|
812 | gui() | |
|
813 | ||
|
814 | # double-fork to completely detach from the parent process | |
|
815 | # based on http://code.activestate.com/recipes/278731 | |
|
816 | if record_wait is None: | |
|
817 | pid = os.fork() | |
|
818 | if pid: | |
|
819 | if not ensurestart: | |
|
820 | # Even though we're not waiting on the child process, | |
|
821 | # we still must call waitpid() on it at some point so | |
|
822 | # it's not a zombie/defunct. This is especially relevant for | |
|
823 | # chg since the parent process won't die anytime soon. | |
|
824 | # We use a thread to make the overhead tiny. | |
|
825 | def _do_wait(): | |
|
826 | os.waitpid(pid, 0) | |
|
827 | ||
|
828 | t = threading.Thread(target=_do_wait) | |
|
829 | t.daemon = True | |
|
830 | t.start() | |
|
831 | return | |
|
832 | # Parent process | |
|
833 | (_pid, status) = os.waitpid(pid, 0) | |
|
834 | if os.WIFEXITED(status): | |
|
835 | returncode = os.WEXITSTATUS(status) | |
|
836 | else: | |
|
837 | returncode = -(os.WTERMSIG(status)) | |
|
838 | if returncode != 0: | |
|
839 | # The child process's return code is 0 on success, an errno | |
|
840 | # value on failure, or 255 if we don't have a valid errno | |
|
841 | # value. | |
|
842 | # | |
|
843 | # (It would be slightly nicer to return the full exception info | |
|
844 | # over a pipe as the subprocess module does. For now it | |
|
845 | # doesn't seem worth adding that complexity here, though.) | |
|
846 | if returncode == 255: | |
|
847 | returncode = errno.EINVAL | |
|
848 | raise OSError( | |
|
849 | returncode, | |
|
850 | b'error running %r: %s' | |
|
851 | % (cmd, os.strerror(returncode)), | |
|
852 | ) | |
|
853 | return | |
|
854 | ||
|
855 | returncode = 255 | |
|
856 | stdin = None | |
|
857 | ||
|
858 | try: | |
|
859 | if record_wait is None: | |
|
860 | # Start a new session | |
|
861 | os.setsid() | |
|
862 | # connect stdin to devnull to make sure the subprocess can't | |
|
863 | # muck up that stream for mercurial. | |
|
864 | if stdin_bytes is None: | |
|
865 | stdin = open(os.devnull, b'r') | |
|
866 | else: | |
|
867 | stdin = pycompat.unnamedtempfile() | |
|
868 | stdin.write(stdin_bytes) | |
|
869 | stdin.flush() | |
|
870 | stdin.seek(0) | |
|
871 | ||
|
872 | if stdout is None: | |
|
873 | stdout = open(os.devnull, b'w') | |
|
874 | if stderr is None: | |
|
875 | stderr = open(os.devnull, b'w') | |
|
876 | ||
|
877 | p = subprocess.Popen( | |
|
878 | cmd, | |
|
879 | shell=shell, | |
|
880 | env=env, | |
|
881 | close_fds=True, | |
|
882 | stdin=stdin, | |
|
883 | stdout=stdout, | |
|
884 | stderr=stderr, | |
|
885 | ) | |
|
886 | if record_wait is not None: | |
|
887 | record_wait(p.wait) | |
|
888 | returncode = 0 | |
|
889 | except EnvironmentError as ex: | |
|
890 | returncode = ex.errno & 0xFF | |
|
891 | if returncode == 0: | |
|
892 | # This shouldn't happen, but just in case make sure the | |
|
893 | # return code is never 0 here. | |
|
894 | returncode = 255 | |
|
895 | except Exception: | |
|
896 | returncode = 255 | |
|
897 | finally: | |
|
898 | # mission accomplished, this child needs to exit and not | |
|
899 | # continue the hg process here. | |
|
900 | if stdin is not None: | |
|
901 | stdin.close() | |
|
902 | if record_wait is None: | |
|
903 | os._exit(returncode) | |
|
904 | ||
|
905 | if pycompat.ispy3: | |
|
906 | # This branch is more robust, because it avoids running python | |
|
907 | # code (hence gc finalizers, like sshpeer.__del__, which | |
|
908 | # blocks). But we can't easily do the equivalent in py2, | |
|
909 | # because of the lack of start_new_session=True flag. Given | |
|
910 | # that the py2 branch should die soon, the short-lived | |
|
911 | # duplication seems acceptable. | |
|
912 | runbgcommand = runbgcommandpy3 | |
|
913 | else: | |
|
914 | runbgcommand = runbgcommandpy2 |
General Comments 0
You need to be logged in to leave comments.
Login now