Show More
@@ -80,7 +80,7 b' io.BufferedIOBase.register(LineBufferedW' | |||||
80 |
|
80 | |||
81 |
|
81 | |||
82 | def make_line_buffered(stream): |
|
82 | def make_line_buffered(stream): | |
83 |
if |
|
83 | if not isinstance(stream, io.BufferedIOBase): | |
84 | # On Python 3, buffered streams can be expected to subclass |
|
84 | # On Python 3, buffered streams can be expected to subclass | |
85 | # BufferedIOBase. This is definitively the case for the streams |
|
85 | # BufferedIOBase. This is definitively the case for the streams | |
86 | # initialized by the interpreter. For unbuffered streams, we don't need |
|
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 | def _make_write_all(stream): |
|
123 | def _make_write_all(stream): | |
124 | assert pycompat.ispy3 |
|
|||
125 | if isinstance(stream, WriteAllWrapper): |
|
124 | if isinstance(stream, WriteAllWrapper): | |
126 | return stream |
|
125 | return stream | |
127 | if isinstance(stream, io.BufferedIOBase): |
|
126 | if isinstance(stream, io.BufferedIOBase): | |
@@ -133,52 +132,32 b' def _make_write_all(stream):' | |||||
133 | return WriteAllWrapper(stream) |
|
132 | return WriteAllWrapper(stream) | |
134 |
|
133 | |||
135 |
|
134 | |||
136 | if pycompat.ispy3: |
|
135 | # Python 3 implements its own I/O streams. Unlike stdio of C library, | |
137 | # 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. | |
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. |
|
|||
142 |
|
137 | |||
143 | if sys.stdin is None: |
|
138 | # TODO: .buffer might not exist if std streams were replaced; we'll need | |
144 | stdin = BadFile() |
|
139 | # a silly wrapper to make a bytes stream backed by a unicode one. | |
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) |
|
|||
155 |
|
140 | |||
156 | if pycompat.iswindows: |
|
141 | if sys.stdin is None: | |
157 | # Work around Windows bugs. |
|
142 | stdin = BadFile() | |
158 | stdout = platform.winstdout(stdout) # pytype: disable=module-attr |
|
143 | else: | |
159 | stderr = platform.winstdout(stderr) # pytype: disable=module-attr |
|
144 | stdin = sys.stdin.buffer | |
160 | if isatty(stdout): |
|
145 | if sys.stdout is None: | |
161 | # The standard library doesn't offer line-buffered binary streams. |
|
146 | stdout = BadFile() | |
162 | stdout = make_line_buffered(stdout) |
|
|||
163 | else: |
|
147 | else: | |
164 | # Python 2 uses the I/O streams provided by the C library. |
|
148 | stdout = _make_write_all(sys.stdout.buffer) | |
165 | stdin = sys.stdin |
|
149 | if sys.stderr is None: | |
166 | stdout = sys.stdout |
|
150 | stderr = BadFile() | |
167 | stderr = sys.stderr |
|
151 | else: | |
168 | if pycompat.iswindows: |
|
152 | stderr = _make_write_all(sys.stderr.buffer) | |
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) |
|
|||
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 | findexe = platform.findexe |
|
162 | findexe = platform.findexe | |
184 | _gethgcmd = platform.gethgcmd |
|
163 | _gethgcmd = platform.gethgcmd | |
@@ -704,7 +683,7 b' if pycompat.iswindows:' | |||||
704 |
|
683 | |||
705 | else: |
|
684 | else: | |
706 |
|
685 | |||
707 |
def runbgcommand |
|
686 | def runbgcommand( | |
708 | cmd, |
|
687 | cmd, | |
709 | env, |
|
688 | env, | |
710 | shell=False, |
|
689 | shell=False, | |
@@ -787,128 +766,3 b' else:' | |||||
787 | returncode = p.wait |
|
766 | returncode = p.wait | |
788 | if record_wait is not None: |
|
767 | if record_wait is not None: | |
789 | record_wait(returncode) |
|
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