def _get_fetch_info_from_stderr(self, proc, progress): # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() for line in self._digest_process_messages(proc.stderr, progress): if line.startswith('From') or line.startswith('remote: Total'): continue fetch_info_lines.append(line) # END for each line # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'r') fetch_head_info = fp.readlines() fp.close() assert len(fetch_info_lines) == len(fetch_head_info) output.extend( FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) self._finalize_proc(proc) return output
def list_traverse(self, *args, **kwargs): """ :return: IterableList with the results of the traversal as produced by traverse()""" out = IterableList(self._id_attribute_) out.extend(self.traverse(*args, **kwargs)) return out
def _list_traverse( self, as_edge: bool = False, *args: Any, **kwargs: Any ) -> IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']]: """ :return: IterableList with the results of the traversal as produced by traverse() Commit -> IterableList['Commit'] Submodule -> IterableList['Submodule'] Tree -> IterableList[Union['Submodule', 'Tree', 'Blob']] """ # Commit and Submodule have id.__attribute__ as IterableObj # Tree has id.__attribute__ inherited from IndexObject if isinstance(self, Has_id_attribute): id = self._id_attribute_ else: id = "" # shouldn't reach here, unless Traversable subclass created with no _id_attribute_ # could add _id_attribute_ to Traversable, or make all Traversable also Iterable? if not as_edge: out: IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']] = IterableList(id) out.extend(self.traverse(as_edge=as_edge, *args, **kwargs)) return out # overloads in subclasses (mypy does't allow typing self: subclass) # Union[IterableList['Commit'], IterableList['Submodule'], IterableList[Union['Submodule', 'Tree', 'Blob']]] else: # Raise deprecationwarning, doesn't make sense to use this out_list: IterableList = IterableList( self.traverse(*args, **kwargs)) return out_list
def stale_refs(self): """ :return: IterableList RemoteReference objects that do not have a corresponding head in the remote reference anymore as they have been deleted on the remote side, but are still available locally. The IterableList is prefixed, hence the 'origin' must be omitted. See 'refs' property for an example. To make things more complicated, it can be possble for the list to include other kinds of references, for example, tag references, if these are stale as well. This is a fix for the issue described here: https://github.com/gitpython-developers/GitPython/issues/260 """ out_refs = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) for line in self.repo.git.remote("prune", "--dry-run", self).splitlines()[2:]: # expecting # * [would prune] origin/new_branch token = " * [would prune] " if not line.startswith(token): raise ValueError("Could not parse git-remote prune result: %r" % line) ref_name = line.replace(token, "") # sometimes, paths start with a full ref name, like refs/tags/foo, see #260 if ref_name.startswith(Reference._common_path_default + '/'): out_refs.append(SymbolicReference.from_path(self.repo, ref_name)) else: fqhn = "%s/%s" % (RemoteReference._common_path_default, ref_name) out_refs.append(RemoteReference(self.repo, fqhn)) # end special case handlin # END for each line return out_refs
def get_fetch_info_from_stderr(repo, proc, progress): # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() for line in digest_process_messages(proc.stderr, progress): if line.startswith('From') or line.startswith('remote: Total'): continue elif line.startswith('warning:'): print >> sys.stderr, line continue elif line.startswith('fatal:'): raise GitCommandError(("Error when fetching: %s" % line, ), 2) # END handle special messages fetch_info_lines.append(line) # END for each line # read head information fp = open(join(repo.git_dir, 'FETCH_HEAD'), 'r') fetch_head_info = fp.readlines() fp.close() assert len(fetch_info_lines) == len(fetch_head_info) output.extend( CmdFetchInfo._from_line(repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) finalize_process(proc) return output
def _get_fetch_info_from_stderr(self, proc, progress): # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() for line in self._digest_process_messages(proc.stderr, progress): if line.startswith('From') or line.startswith('remote: Total'): continue fetch_info_lines.append(line) # END for each line # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'),'r') fetch_head_info = fp.readlines() fp.close() assert len(fetch_info_lines) == len(fetch_head_info) output.extend(FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line,fetch_line in zip(fetch_info_lines, fetch_head_info)) self._finalize_proc(proc) return output
def get_fetch_info_from_stderr(repo, proc, progress): # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() for line in digest_process_messages(proc.stderr, progress): if line.startswith('From') or line.startswith('remote: Total'): continue elif line.startswith('warning:'): print >> sys.stderr, line continue elif line.startswith('fatal:'): raise GitCommandError(("Error when fetching: %s" % line,), 2) # END handle special messages fetch_info_lines.append(line) # END for each line # read head information fp = open(join(repo.git_dir, 'FETCH_HEAD'), 'r') fetch_head_info = fp.readlines() fp.close() assert len(fetch_info_lines) == len(fetch_head_info) output.extend(CmdFetchInfo._from_line(repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) finalize_process(proc) return output
def _get_fetch_info_from_stderr(self, proc, progress): progress = to_progress_instance(progress) # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = [] # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() handle_process_output(proc, None, progress_handler, finalizer=None, decode_streams=False) stderr_text = progress.error_lines and '\n'.join( progress.error_lines) or '' proc.wait(stderr=stderr_text) if stderr_text: log.warning("Error lines received while fetching: %s", stderr_text) for line in progress.other_lines: line = force_text(line) for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # read head information with open(osp.join(self.repo.common_dir, 'FETCH_HEAD'), 'rb') as fp: fetch_head_info = [l.decode(defenc) for l in fp.readlines()] l_fil = len(fetch_info_lines) l_fhi = len(fetch_head_info) if l_fil != l_fhi: msg = "Fetch head lines do not match lines provided via progress information\n" msg += "length of progress lines %i should be equal to lines in FETCH_HEAD file %i\n" msg += "Will ignore extra progress lines or fetch head lines." msg %= (l_fil, l_fhi) log.debug(msg) log.debug("info lines: " + str(fetch_info_lines)) log.debug("head info : " + str(fetch_head_info)) if l_fil < l_fhi: fetch_head_info = fetch_head_info[:l_fil] else: fetch_info_lines = fetch_info_lines[:l_fhi] # end truncate correct list # end sanity check + sanitization output.extend( FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def _get_fetch_info_from_stderr(self, proc, progress): progress = to_progress_instance(progress) # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(PushInfo._flag_map.keys()) & set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() stderr_text = None for line in proc.stderr: line = force_text(line) for pline in progress_handler(line): # END handle special messages for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # end find command code # end for each comand code we know # end for each line progress didn't handle # end if progress.error_lines(): stderr_text = '\n'.join(progress.error_lines()) finalize_process(proc, stderr=stderr_text) # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') fetch_head_info = [l.decode(defenc) for l in fp.readlines()] fp.close() l_fil = len(fetch_info_lines) l_fhi = len(fetch_head_info) if l_fil != l_fhi: msg = "Fetch head lines do not match lines provided via progress information\n" msg += "length of progress lines %i should be equal to lines in FETCH_HEAD file %i\n" msg += "Will ignore extra progress lines or fetch head lines." msg %= (l_fil, l_fhi) log.debug(msg) if l_fil < l_fhi: fetch_head_info = fetch_head_info[:l_fil] else: fetch_info_lines = fetch_info_lines[:l_fhi] # end truncate correct list # end sanity check + sanitization output.extend( FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def _get_fetch_info_from_stderr(self, proc, progress): progress = to_progress_instance(progress) # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(PushInfo._flag_map.keys()) & set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() stderr_text = None for line in proc.stderr: line = force_text(line) for pline in progress_handler(line): # END handle special messages for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # end find command code # end for each comand code we know # end for each line progress didn't handle # end if progress.error_lines(): stderr_text = '\n'.join(progress.error_lines()) finalize_process(proc, stderr=stderr_text) # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') fetch_head_info = [l.decode(defenc) for l in fp.readlines()] fp.close() l_fil = len(fetch_info_lines) l_fhi = len(fetch_head_info) if l_fil != l_fhi: msg = "Fetch head lines do not match lines provided via progress information\n" msg += "length of progress lines %i should be equal to lines in FETCH_HEAD file %i\n" msg += "Will ignore extra progress lines or fetch head lines." msg %= (l_fil, l_fhi) log.debug(msg) if l_fil < l_fhi: fetch_head_info = fetch_head_info[:l_fil] else: fetch_info_lines = fetch_info_lines[:l_fhi] # end truncate correct list # end sanity check + sanitization output.extend(FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def refs(self): """ :return: IterableList of RemoteReference objects. It is prefixed, allowing you to omit the remote path portion, i.e.:: remote.refs.master # yields RemoteReference('/refs/remotes/origin/master')""" out_refs = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) out_refs.extend(RemoteReference.list_items(self.repo, remote=self.name)) return out_refs
def _get_fetch_info_from_stderr(self, proc, progress): # skip first line as it is some remote info we are not interested in # TODO: Use poll() to process stdout and stderr at same time output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(PushInfo._flag_map.keys()) & set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() for line in proc.stderr: line = line.decode(defenc) line = line.rstrip() for pline in progress_handler(line): if line.startswith('fatal:'): raise GitCommandError(("Error when fetching: %s" % line, ), 2) # END handle special messages for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # end find command code # end for each comand code we know # end for each line progress didn't handle # end # We are only interested in stderr here ... try: finalize_process(proc) except Exception: if len(fetch_info_lines) == 0: raise # end exception handler # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') fetch_head_info = [l.decode(defenc) for l in fp.readlines()] fp.close() # NOTE: We assume to fetch at least enough progress lines to allow matching each fetch head line with it. assert len(fetch_info_lines) >= len( fetch_head_info), "len(%s) <= len(%s)" % (fetch_head_info, fetch_info_lines) output.extend( FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def _get_fetch_info_from_stderr(self, proc, progress): progress = to_progress_instance(progress) # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = [] # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() handle_process_output(proc, None, progress_handler, finalizer=None, decode_streams=False) stderr_text = progress.error_lines and '\n'.join(progress.error_lines) or '' proc.wait(stderr=stderr_text) if stderr_text: log.warning("Error lines received while fetching: %s", stderr_text) for line in progress.other_lines: line = force_text(line) for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # read head information with open(osp.join(self.repo.common_dir, 'FETCH_HEAD'), 'rb') as fp: fetch_head_info = [l.decode(defenc) for l in fp.readlines()] l_fil = len(fetch_info_lines) l_fhi = len(fetch_head_info) if l_fil != l_fhi: msg = "Fetch head lines do not match lines provided via progress information\n" msg += "length of progress lines %i should be equal to lines in FETCH_HEAD file %i\n" msg += "Will ignore extra progress lines or fetch head lines." msg %= (l_fil, l_fhi) log.debug(msg) log.debug("info lines: " + str(fetch_info_lines)) log.debug("head info : " + str(fetch_head_info)) if l_fil < l_fhi: fetch_head_info = fetch_head_info[:l_fil] else: fetch_info_lines = fetch_info_lines[:l_fhi] # end truncate correct list # end sanity check + sanitization output.extend(FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def _get_fetch_info_from_stderr(self, proc, progress): # skip first line as it is some remote info we are not interested in # TODO: Use poll() to process stdout and stderr at same time output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(PushInfo._flag_map.keys()) & set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() for line in proc.stderr: line = line.decode(defenc) line = line.rstrip() for pline in progress_handler(line): if line.startswith('fatal:') or line.startswith('error:'): raise GitCommandError(("Error when fetching: %s" % line,), 2) # END handle special messages for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # end find command code # end for each comand code we know # end for each line progress didn't handle # end # We are only interested in stderr here ... try: finalize_process(proc) except Exception: if len(fetch_info_lines) == 0: raise # end exception handler # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') fetch_head_info = [l.decode(defenc) for l in fp.readlines()] fp.close() # NOTE: We assume to fetch at least enough progress lines to allow matching each fetch head line with it. assert len(fetch_info_lines) >= len(fetch_head_info), "len(%s) <= len(%s)" % (fetch_head_info, fetch_info_lines) output.extend(FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) return output
def refs(self): """ :return: IterableList of RemoteReference objects. It is prefixed, allowing you to omit the remote path portion, i.e.:: remote.refs.master # yields RemoteReference('/refs/remotes/origin/master')""" out_refs = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) for ref in RemoteReference.list_items(self.repo): if ref.remote_name == self.name: out_refs.append(ref) # END if names match # END for each ref assert out_refs, "Remote %s did not have any references" % self.name return out_refs
def mock_repo(): """repo mock fixture""" repo_mock = Mock() repo_git_mock = Mock() repo_mock.attach_mock(repo_git_mock, 'git') remote = Mock(spec=git.Remote) remote.configure_mock(name="origin", url="http://example.com") remote_list = IterableList("name") remote_list.extend([remote]) repo_mock.remotes = remote_list repo_mock.branches = [] return repo_mock
def test_iterable_list(self, case): name, prefix = case l = IterableList(name, prefix) name1 = "one" name2 = "two" m1 = TestIterableMember(prefix + name1) m2 = TestIterableMember(prefix + name2) l.extend((m1, m2)) self.assertEqual(len(l), 2) # contains works with name and identity self.assertIn(name1, l) self.assertIn(name2, l) self.assertIn(m2, l) self.assertIn(m2, l) self.assertNotIn('invalid', l) # with string index self.assertIs(l[name1], m1) self.assertIs(l[name2], m2) # with int index self.assertIs(l[0], m1) self.assertIs(l[1], m2) # with getattr self.assertIs(l.one, m1) self.assertIs(l.two, m2) # test exceptions self.failUnlessRaises(AttributeError, getattr, l, 'something') self.failUnlessRaises(IndexError, l.__getitem__, 'something') # delete by name and index self.failUnlessRaises(IndexError, l.__delitem__, 'something') del(l[name2]) self.assertEqual(len(l), 1) self.assertNotIn(name2, l) self.assertIn(name1, l) del(l[0]) self.assertNotIn(name1, l) self.assertEqual(len(l), 0) self.failUnlessRaises(IndexError, l.__delitem__, 0) self.failUnlessRaises(IndexError, l.__delitem__, 'something')
def test_iterable_list(self, case): name, prefix = case ilist = IterableList(name, prefix) name1 = "one" name2 = "two" m1 = TestIterableMember(prefix + name1) m2 = TestIterableMember(prefix + name2) ilist.extend((m1, m2)) self.assertEqual(len(ilist), 2) # contains works with name and identity self.assertIn(name1, ilist) self.assertIn(name2, ilist) self.assertIn(m2, ilist) self.assertIn(m2, ilist) self.assertNotIn('invalid', ilist) # with string index self.assertIs(ilist[name1], m1) self.assertIs(ilist[name2], m2) # with int index self.assertIs(ilist[0], m1) self.assertIs(ilist[1], m2) # with getattr self.assertIs(ilist.one, m1) self.assertIs(ilist.two, m2) # test exceptions self.failUnlessRaises(AttributeError, getattr, ilist, 'something') self.failUnlessRaises(IndexError, ilist.__getitem__, 'something') # delete by name and index self.failUnlessRaises(IndexError, ilist.__delitem__, 'something') del (ilist[name2]) self.assertEqual(len(ilist), 1) self.assertNotIn(name2, ilist) self.assertIn(name1, ilist) del (ilist[0]) self.assertNotIn(name1, ilist) self.assertEqual(len(ilist), 0) self.failUnlessRaises(IndexError, ilist.__delitem__, 0) self.failUnlessRaises(IndexError, ilist.__delitem__, 'something')
def _get_push_info(self, proc, progress): progress = to_progress_instance(progress) # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually progress_handler = progress.new_message_handler() output = IterableList('name') def stdout_handler(line): try: output.append(PushInfo._from_line(self, line)) except ValueError: # If an error happens, additional info is given which we parse below. pass handle_process_output(proc, stdout_handler, progress_handler, finalizer=None, decode_streams=False) stderr_text = progress.error_lines and '\n'.join( progress.error_lines) or '' try: proc.wait(stderr=stderr_text) except Exception: if not output: raise elif stderr_text: log.warning("Error lines received while fetching: %s", stderr_text) return output
def stale_refs(self) -> IterableList[Reference]: """ :return: IterableList RemoteReference objects that do not have a corresponding head in the remote reference anymore as they have been deleted on the remote side, but are still available locally. The IterableList is prefixed, hence the 'origin' must be omitted. See 'refs' property for an example. To make things more complicated, it can be possible for the list to include other kinds of references, for example, tag references, if these are stale as well. This is a fix for the issue described here: https://github.com/gitpython-developers/GitPython/issues/260 """ out_refs: IterableList[Reference] = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) for line in self.repo.git.remote("prune", "--dry-run", self).splitlines()[2:]: # expecting # * [would prune] origin/new_branch token = " * [would prune] " if not line.startswith(token): continue ref_name = line.replace(token, "") # sometimes, paths start with a full ref name, like refs/tags/foo, see #260 if ref_name.startswith(Reference._common_path_default + '/'): out_refs.append(Reference.from_path(self.repo, ref_name)) else: fqhn = "%s/%s" % (RemoteReference._common_path_default, ref_name) out_refs.append(RemoteReference(self.repo, fqhn)) # end special case handling # END for each line return out_refs
def _get_push_info(self, proc, progress): # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually # TODO: poll() on file descriptors to know what to read next, process streams concurrently progress_handler = progress.new_message_handler() output = IterableList('name') def stdout_handler(line): try: output.append(PushInfo._from_line(self, line)) except ValueError: # if an error happens, additional info is given which we cannot parse pass # END exception handling # END for each line try: handle_process_output(proc, stdout_handler, progress_handler, finalize_process) except Exception: if len(output) == 0: raise return output
def test_iterable_list(self): for args in (('name',), ('name', 'prefix_')): l = IterableList('name') m1 = TestIterableMember('one') m2 = TestIterableMember('two') l.extend((m1, m2)) assert len(l) == 2 # contains works with name and identity assert m1.name in l assert m2.name in l assert m2 in l assert m2 in l assert 'invalid' not in l # with string index assert l[m1.name] is m1 assert l[m2.name] is m2 # with int index assert l[0] is m1 assert l[1] is m2 # with getattr assert l.one is m1 assert l.two is m2 # test exceptions self.failUnlessRaises(AttributeError, getattr, l, 'something') self.failUnlessRaises(IndexError, l.__getitem__, 'something') # delete by name and index self.failUnlessRaises(IndexError, l.__delitem__, 'something') del(l[m2.name]) assert len(l) == 1 assert m2.name not in l and m1.name in l del(l[0]) assert m1.name not in l assert len(l) == 0 self.failUnlessRaises(IndexError, l.__delitem__, 0) self.failUnlessRaises(IndexError, l.__delitem__, 'something')
def test_iterable_list(self): for args in (('name', ), ('name', 'prefix_')): l = IterableList('name') m1 = TestIterableMember('one') m2 = TestIterableMember('two') l.extend((m1, m2)) assert len(l) == 2 # contains works with name and identity assert m1.name in l assert m2.name in l assert m2 in l assert m2 in l assert 'invalid' not in l # with string index assert l[m1.name] is m1 assert l[m2.name] is m2 # with int index assert l[0] is m1 assert l[1] is m2 # with getattr assert l.one is m1 assert l.two is m2 # test exceptions self.failUnlessRaises(AttributeError, getattr, l, 'something') self.failUnlessRaises(IndexError, l.__getitem__, 'something') # delete by name and index self.failUnlessRaises(IndexError, l.__delitem__, 'something') del (l[m2.name]) assert len(l) == 1 assert m2.name not in l and m1.name in l del (l[0]) assert m1.name not in l assert len(l) == 0 self.failUnlessRaises(IndexError, l.__delitem__, 0) self.failUnlessRaises(IndexError, l.__delitem__, 'something')
def _get_push_info(self, proc, progress): # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually digest_process_messages(proc.stderr, progress) output = IterableList('name') for line in proc.stdout.readlines(): try: output.append(PushInfo._from_line(self, line)) except ValueError: # if an error happens, additional info is given which we cannot parse pass # END exception handling # END for each line finalize_process(proc) return output
def get_push_info(repo, remotename_or_url, proc, progress): # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually stdout, stderr = proc.communicate() digest_process_messages(StringIO(stderr), progress) output = IterableList('name') for line in stdout.splitlines(): try: output.append(CmdPushInfo._from_line(repo, remotename_or_url, line)) except ValueError: # if an error happens, additional info is given which we cannot parse pass # END exception handling # END for each line return output
def _get_push_info(self, proc, progress): # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually self._digest_process_messages(proc.stderr, progress) output = IterableList('name') for line in proc.stdout.readlines(): try: output.append(PushInfo._from_line(self, line)) except ValueError: # if an error happens, additional info is given which we cannot parse pass # END exception handling # END for each line self._finalize_proc(proc) return output
def stale_refs(self): """ :return: IterableList RemoteReference objects that do not have a corresponding head in the remote reference anymore as they have been deleted on the remote side, but are still available locally. The IterableList is prefixed, hence the 'origin' must be omitted. See 'refs' property for an example.""" out_refs = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) for line in self.repo.git.remote("prune", "--dry-run", self).splitlines()[2:]: # expecting # * [would prune] origin/new_branch token = " * [would prune] " if not line.startswith(token): raise ValueError("Could not parse git-remote prune result: %r" % line) fqhn = "%s/%s" % (RemoteReference._common_path_default, line.replace(token, "")) out_refs.append(RemoteReference(self.repo, fqhn)) # END for each line return out_refs
def stale_refs(self): """ :return: IterableList RemoteReference objects that do not have a corresponding head in the remote reference anymore as they have been deleted on the remote side, but are still available locally. The IterableList is prefixed, hence the 'origin' must be omitted. See 'refs' property for an example.""" out_refs = IterableList(RemoteReference._id_attribute_, "%s/" % self.name) for line in self.repo.git.remote("prune", "--dry-run", self).splitlines()[2:]: # expecting # * [would prune] origin/new_branch token = " * [would prune] " if not line.startswith(token): raise ValueError("Could not parse git-remote prune result: %r" % line) fqhn = "%s/%s" % (RemoteReference._common_path_default,line.replace(token, "")) out_refs.append(RemoteReference(self.repo, fqhn)) # END for each line return out_refs
def _get_fetch_info_from_stderr(self, proc, progress): # skip first line as it is some remote info we are not interested in output = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = list() for line in digest_process_messages(proc.stderr, progress): if line.startswith('From') or line.startswith('remote: Total') or line.startswith('POST') \ or line.startswith(' ='): continue elif line.startswith('warning:'): print >> sys.stderr, line continue elif line.startswith('fatal:'): raise GitCommandError(("Error when fetching: %s" % line, ), 2) # END handle special messages fetch_info_lines.append(line) # END for each line # read head information fp = open(join(self.repo.git_dir, 'FETCH_HEAD'), 'r') fetch_head_info = fp.readlines() fp.close() # NOTE: HACK Just disabling this line will make github repositories work much better. # I simply couldn't stand it anymore, so here is the quick and dirty fix ... . # This project needs a lot of work ! # assert len(fetch_info_lines) == len(fetch_head_info), "len(%s) != len(%s)" % (fetch_head_info, fetch_info_lines) output.extend( FetchInfo._from_line(self.repo, err_line, fetch_line) for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info)) finalize_process(proc) return output
def _get_push_info( self, proc: 'Git.AutoInterrupt', progress: Union[Callable[..., Any], RemoteProgress, None], kill_after_timeout: Union[None, float] = None) -> IterableList[PushInfo]: progress = to_progress_instance(progress) # read progress information from stderr # we hope stdout can hold all the data, it should ... # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually progress_handler = progress.new_message_handler() output: IterableList[PushInfo] = IterableList('push_infos') def stdout_handler(line: str) -> None: try: output.append(PushInfo._from_line(self, line)) except ValueError: # If an error happens, additional info is given which we parse below. pass handle_process_output(proc, stdout_handler, progress_handler, finalizer=None, decode_streams=False, kill_after_timeout=kill_after_timeout) stderr_text = progress.error_lines and '\n'.join( progress.error_lines) or '' try: proc.wait(stderr=stderr_text) except Exception: # This is different than fetch (which fails if there is any std_err # even if there is an output) if not output: raise elif stderr_text: log.warning("Error lines received while fetching: %s", stderr_text) return output
def __new__(cls) -> 'PushInfoList': return cast(PushInfoList, IterableList.__new__(cls, 'push_infos'))
def _get_fetch_info_from_stderr(self, proc: 'Git.AutoInterrupt', progress: Union[Callable[..., Any], RemoteProgress, None], kill_after_timeout: Union[None, float] = None, ) -> IterableList['FetchInfo']: progress = to_progress_instance(progress) # skip first line as it is some remote info we are not interested in output: IterableList['FetchInfo'] = IterableList('name') # lines which are no progress are fetch info lines # this also waits for the command to finish # Skip some progress lines that don't provide relevant information fetch_info_lines = [] # Basically we want all fetch info lines which appear to be in regular form, and thus have a # command character. Everything else we ignore, cmds = set(FetchInfo._flag_map.keys()) progress_handler = progress.new_message_handler() handle_process_output(proc, None, progress_handler, finalizer=None, decode_streams=False, kill_after_timeout=kill_after_timeout) stderr_text = progress.error_lines and '\n'.join(progress.error_lines) or '' proc.wait(stderr=stderr_text) if stderr_text: log.warning("Error lines received while fetching: %s", stderr_text) for line in progress.other_lines: line = force_text(line) for cmd in cmds: if len(line) > 1 and line[0] == ' ' and line[1] == cmd: fetch_info_lines.append(line) continue # read head information fetch_head = SymbolicReference(self.repo, "FETCH_HEAD") with open(fetch_head.abspath, 'rb') as fp: fetch_head_info = [line.decode(defenc) for line in fp.readlines()] l_fil = len(fetch_info_lines) l_fhi = len(fetch_head_info) if l_fil != l_fhi: msg = "Fetch head lines do not match lines provided via progress information\n" msg += "length of progress lines %i should be equal to lines in FETCH_HEAD file %i\n" msg += "Will ignore extra progress lines or fetch head lines." msg %= (l_fil, l_fhi) log.debug(msg) log.debug(b"info lines: " + str(fetch_info_lines).encode("UTF-8")) log.debug(b"head info: " + str(fetch_head_info).encode("UTF-8")) if l_fil < l_fhi: fetch_head_info = fetch_head_info[:l_fil] else: fetch_info_lines = fetch_info_lines[:l_fhi] # end truncate correct list # end sanity check + sanitization for err_line, fetch_line in zip(fetch_info_lines, fetch_head_info): try: output.append(FetchInfo._from_line(self.repo, err_line, fetch_line)) except ValueError as exc: log.debug("Caught error while parsing line: %s", exc) log.warning("Git informed while fetching: %s", err_line.strip()) return output