def _NeedUpdate(self): Trace(': scan refs %s', self._gitdir) for name, mtime in self._mtime.items(): try: if mtime != os.path.getmtime(os.path.join(self._gitdir, name)): return True except OSError: return True return False
def _ReadJson(self): try: if os.path.getmtime(self._json) <= os.path.getmtime(self.file): platform_utils.remove(self._json) return None except OSError: return None try: Trace(': parsing %s', self.file) with open(self._json) as fd: return json.load(fd) except (IOError, ValueError): platform_utils.remove(self._json) return None
def _LoadAll(self): Trace(': load refs %s', self._gitdir) self._phyref = {} self._symref = {} self._mtime = {} self._ReadPackedRefs() self._ReadLoose('refs/') self._ReadLoose1(os.path.join(self._gitdir, HEAD), HEAD) scan = self._symref attempts = 0 while scan and attempts < 5: scan_next = {} for name, dest in scan.items(): if dest in self._phyref: self._phyref[name] = self._phyref[dest] else: scan_next[name] = dest scan = scan_next attempts += 1
def __init__(self, project, cmdv, bare=False, input=None, capture_stdout=False, capture_stderr=False, merge_output=False, disable_editor=False, ssh_proxy=None, cwd=None, gitdir=None): env = self._GetBasicEnv() if disable_editor: env['GIT_EDITOR'] = ':' if ssh_proxy: env['REPO_SSH_SOCK'] = ssh_proxy.sock() env['GIT_SSH'] = ssh_proxy.proxy env['GIT_SSH_VARIANT'] = 'ssh' if 'http_proxy' in env and 'darwin' == sys.platform: s = "'http.proxy=%s'" % (env['http_proxy'],) p = env.get('GIT_CONFIG_PARAMETERS') if p is not None: s = p + ' ' + s env['GIT_CONFIG_PARAMETERS'] = s if 'GIT_ALLOW_PROTOCOL' not in env: env['GIT_ALLOW_PROTOCOL'] = ( 'file:git:http:https:ssh:persistent-http:persistent-https:sso:rpc') env['GIT_HTTP_USER_AGENT'] = user_agent.git if project: if not cwd: cwd = project.worktree if not gitdir: gitdir = project.gitdir command = [GIT] if bare: if gitdir: # Git on Windows wants its paths only using / for reliability. if platform_utils.isWindows(): gitdir = gitdir.replace('\\', '/') env[GIT_DIR] = gitdir cwd = None command.append(cmdv[0]) # Need to use the --progress flag for fetch/clone so output will be # displayed as by default git only does progress output if stderr is a TTY. if sys.stderr.isatty() and cmdv[0] in ('fetch', 'clone'): if '--progress' not in cmdv and '--quiet' not in cmdv: command.append('--progress') command.extend(cmdv[1:]) stdin = subprocess.PIPE if input else None stdout = subprocess.PIPE if capture_stdout else None stderr = (subprocess.STDOUT if merge_output else (subprocess.PIPE if capture_stderr else None)) if IsTrace(): global LAST_CWD global LAST_GITDIR dbg = '' if cwd and LAST_CWD != cwd: if LAST_GITDIR or LAST_CWD: dbg += '\n' dbg += ': cd %s\n' % cwd LAST_CWD = cwd if GIT_DIR in env and LAST_GITDIR != env[GIT_DIR]: if LAST_GITDIR or LAST_CWD: dbg += '\n' dbg += ': export GIT_DIR=%s\n' % env[GIT_DIR] LAST_GITDIR = env[GIT_DIR] dbg += ': ' dbg += ' '.join(command) if stdin == subprocess.PIPE: dbg += ' 0<|' if stdout == subprocess.PIPE: dbg += ' 1>|' if stderr == subprocess.PIPE: dbg += ' 2>|' elif stderr == subprocess.STDOUT: dbg += ' 2>&1' Trace('%s', dbg) try: p = subprocess.Popen(command, cwd=cwd, env=env, encoding='utf-8', errors='backslashreplace', stdin=stdin, stdout=stdout, stderr=stderr) except Exception as e: raise GitError('%s: %s' % (command[1], e)) if ssh_proxy: ssh_proxy.add_client(p) self.process = p if input: if isinstance(input, str): input = input.encode('utf-8') p.stdin.write(input) p.stdin.close() try: self.stdout, self.stderr = p.communicate() finally: if ssh_proxy: ssh_proxy.remove_client(p) self.rc = p.wait()
def _open_unlocked(self, host, port=None): """Make sure a ssh master session exists for |host| & |port|. If one doesn't exist already, we'll create it. We won't grab any locks, so the caller has to do that. This helps keep the business logic of actually creating the master separate from grabbing locks. """ # Check to see whether we already think that the master is running; if we # think it's already running, return right away. if port is not None: key = '%s:%s' % (host, port) else: key = host if key in self._master_keys: return True if self._master_broken.value or 'GIT_SSH' in os.environ: # Failed earlier, so don't retry. return False # We will make two calls to ssh; this is the common part of both calls. command_base = ['ssh', '-o', 'ControlPath %s' % self.sock(), host] if port is not None: command_base[1:1] = ['-p', str(port)] # Since the key wasn't in _master_keys, we think that master isn't running. # ...but before actually starting a master, we'll double-check. This can # be important because we can't tell that that '*****@*****.**' is the same # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file. check_command = command_base + ['-O', 'check'] try: Trace(': %s', ' '.join(check_command)) check_process = subprocess.Popen(check_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) check_process.communicate() # read output, but ignore it... isnt_running = check_process.wait() if not isnt_running: # Our double-check found that the master _was_ infact running. Add to # the list of keys. self._master_keys[key] = True return True except Exception: # Ignore excpetions. We we will fall back to the normal command and print # to the log there. pass command = command_base[:1] + ['-M', '-N'] + command_base[1:] try: Trace(': %s', ' '.join(command)) p = subprocess.Popen(command) except Exception as e: self._master_broken.value = True print('\nwarn: cannot enable ssh control master for %s:%s\n%s' % (host, port, str(e)), file=sys.stderr) return False time.sleep(1) ssh_died = (p.poll() is not None) if ssh_died: return False self.add_master(p) self._master_keys[key] = True return True
def _open_ssh(host, port=None): global _ssh_master # Acquire the lock. This is needed to prevent opening multiple masters for # the same host when we're running "repo sync -jN" (for N > 1) _and_ the # manifest <remote fetch="ssh://xyz"> specifies a different host from the # one that was passed to repo init. _master_keys_lock.acquire() try: # Check to see whether we already think that the master is running; if we # think it's already running, return right away. if port is not None: key = '%s:%s' % (host, port) else: key = host if key in _master_keys: return True if (not _ssh_master or 'GIT_SSH' in os.environ or sys.platform in ('win32', 'cygwin')): # failed earlier, or cygwin ssh can't do this # return False # We will make two calls to ssh; this is the common part of both calls. command_base = ['ssh', '-o', 'ControlPath %s' % ssh_sock(), host] if port is not None: command_base[1:1] = ['-p', str(port)] # Since the key wasn't in _master_keys, we think that master isn't running. # ...but before actually starting a master, we'll double-check. This can # be important because we can't tell that that '*****@*****.**' is the same # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file. check_command = command_base + ['-O', 'check'] try: Trace(': %s', ' '.join(check_command)) check_process = subprocess.Popen(check_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) check_process.communicate() # read output, but ignore it... isnt_running = check_process.wait() if not isnt_running: # Our double-check found that the master _was_ infact running. Add to # the list of keys. _master_keys.add(key) return True except Exception: # Ignore excpetions. We we will fall back to the normal command and print # to the log there. pass command = command_base[:1] + ['-M', '-N'] + command_base[1:] try: Trace(': %s', ' '.join(command)) p = subprocess.Popen(command) except Exception as e: _ssh_master = False print('\nwarn: cannot enable ssh control master for %s:%s\n%s' % (host, port, str(e)), file=sys.stderr) return False time.sleep(1) ssh_died = (p.poll() is not None) if ssh_died: return False _master_processes.append(p) _master_keys.add(key) return True finally: _master_keys_lock.release()
def __init__(self, project, cmdv, bare=False, provide_stdin=False, capture_stdout=False, capture_stderr=False, merge_output=False, disable_editor=False, ssh_proxy=False, cwd=None, gitdir=None): env = self._GetBasicEnv() # If we are not capturing std* then need to print it. self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr} if disable_editor: env['GIT_EDITOR'] = ':' if ssh_proxy: env['REPO_SSH_SOCK'] = ssh_sock() env['GIT_SSH'] = _ssh_proxy() env['GIT_SSH_VARIANT'] = 'ssh' if 'http_proxy' in env and 'darwin' == sys.platform: s = "'http.proxy=%s'" % (env['http_proxy'], ) p = env.get('GIT_CONFIG_PARAMETERS') if p is not None: s = p + ' ' + s env['GIT_CONFIG_PARAMETERS'] = s if 'GIT_ALLOW_PROTOCOL' not in env: env['GIT_ALLOW_PROTOCOL'] = ( 'file:git:http:https:ssh:persistent-http:persistent-https:sso:rpc' ) env['GIT_HTTP_USER_AGENT'] = user_agent.git if project: if not cwd: cwd = project.worktree if not gitdir: gitdir = project.gitdir command = [GIT] if bare: if gitdir: env[GIT_DIR] = gitdir cwd = None command.append(cmdv[0]) # Need to use the --progress flag for fetch/clone so output will be # displayed as by default git only does progress output if stderr is a TTY. if sys.stderr.isatty() and cmdv[0] in ('fetch', 'clone'): if '--progress' not in cmdv and '--quiet' not in cmdv: command.append('--progress') command.extend(cmdv[1:]) if provide_stdin: stdin = subprocess.PIPE else: stdin = None stdout = subprocess.PIPE stderr = subprocess.STDOUT if merge_output else subprocess.PIPE if IsTrace(): global LAST_CWD global LAST_GITDIR dbg = '' if cwd and LAST_CWD != cwd: if LAST_GITDIR or LAST_CWD: dbg += '\n' dbg += ': cd %s\n' % cwd LAST_CWD = cwd if GIT_DIR in env and LAST_GITDIR != env[GIT_DIR]: if LAST_GITDIR or LAST_CWD: dbg += '\n' dbg += ': export GIT_DIR=%s\n' % env[GIT_DIR] LAST_GITDIR = env[GIT_DIR] dbg += ': ' dbg += ' '.join(command) if stdin == subprocess.PIPE: dbg += ' 0<|' if stdout == subprocess.PIPE: dbg += ' 1>|' if stderr == subprocess.PIPE: dbg += ' 2>|' elif stderr == subprocess.STDOUT: dbg += ' 2>&1' Trace('%s', dbg) try: p = subprocess.Popen(command, cwd=cwd, env=env, stdin=stdin, stdout=stdout, stderr=stderr) except Exception as e: raise GitError('%s: %s' % (command[1], e)) if ssh_proxy: _add_ssh_client(p) self.process = p self.stdin = p.stdin