def _get_id(cmd): p = subprocess.run(cmd, stdout=subprocess.PIPE) try: p.check_returncode() except subprocess.CalledProcessError as err: logging.critical(f"{err} Please check path and revision.") else: return tools.get_string(p.stdout).strip()
def _get_id(cmd): cmd = tuple(cmd) if cmd not in _ID_CACHE: p = subprocess.run(cmd, stdout=subprocess.PIPE) try: p.check_returncode() except subprocess.CalledProcessError as err: logging.critical(f"{err} Please check path and revision.") else: _ID_CACHE[cmd] = tools.get_string(p.stdout).strip() return _ID_CACHE[cmd]
def _get_id(cmd): cmd = tuple(cmd) if cmd not in _ID_CACHE: try: result = tools.get_string(subprocess.check_output(cmd).strip()) except subprocess.CalledProcessError: logging.critical( 'Call failed: "{}". Please check path and revision.'.format( " ".join(cmd))) else: assert result _ID_CACHE[cmd] = result return _ID_CACHE[cmd]
def hg_id(repo, args=None, rev=None): args = args or [] if rev: args.extend(['-r', str(rev)]) cmd = ('hg', 'id', '--repository', repo) + tuple(args) if cmd not in _HG_ID_CACHE: try: result = tools.get_string(subprocess.check_output(cmd).strip()) except subprocess.CalledProcessError: logging.critical( 'Call failed: "{}". Please check path and revision.'.format( ' '.join(cmd))) else: assert result _HG_ID_CACHE[cmd] = result return _HG_ID_CACHE[cmd]
def _redirect_streams(self): """ Redirect output from original stdout and stderr streams to new streams if redirection is requested in the constructor and limit the output written to the new streams. Redirection could also be achieved py passing suitable parameters to Popen, but neither Popen.wait() nor Popen.communicate() allow limiting the redirected output. Code adapted from the Python 2 version of subprocess.py. """ fd_to_infile = {} fd_to_outfile = {} fd_to_limits = {} fd_to_bytes = {} poller = select.poll() def register_and_append(file_obj, eventmask): poller.register(file_obj.fileno(), eventmask) fd_to_infile[file_obj.fileno()] = file_obj fd_to_bytes[file_obj.fileno()] = 0 def close_unregister_and_remove(fd): poller.unregister(fd) fd_to_infile[fd].close() fd_to_infile.pop(fd) select_POLLIN_POLLPRI = select.POLLIN | select.POLLPRI for ( stream_name, (new_stream, limits), ) in self.redirected_streams_and_limits.items(): old_stream = getattr(self.process, stream_name) register_and_append(old_stream, select_POLLIN_POLLPRI) fd = old_stream.fileno() fd_to_outfile[fd] = new_stream fd_to_limits[fd] = limits while fd_to_infile: try: ready = poller.poll() except OSError as e: if e.args[0] == errno.EINTR: continue raise for fd, mode in ready: if mode & select_POLLIN_POLLPRI: data = os.read(fd, 4096) if not data: close_unregister_and_remove(fd) if fd_to_outfile[fd]: outfile = fd_to_outfile[fd] _, hard_limit = fd_to_limits[fd] if (hard_limit is not None and fd_to_bytes[fd] + len(data) > hard_limit): # Don't write to this outfile in subsequent rounds. fd_to_outfile[fd] = None logging.error( f"{self.name} wrote {hard_limit / 1024} KiB (hard limit) " f"to {outfile.name} -> abort command") self.process.terminate() # Strip extra bytes. data = data[:hard_limit - fd_to_bytes[fd]] outfile.write(tools.get_string(data)) fd_to_bytes[fd] += len(data) else: # Ignore hang up or errors. close_unregister_and_remove(fd) # Check soft limit. for fd, outfile in fd_to_outfile.items(): # Ignore streams that exceeded the hard limit. if outfile is not None: soft_limit, _ = fd_to_limits[fd] bytes_written = fd_to_bytes[fd] if soft_limit is not None and bytes_written > soft_limit: logging.error( f"{self.name} finished and wrote {bytes_written / 1024} KiB " f"to {outfile.name} (soft limit: {soft_limit / 1024} KiB)" )