Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-dulwich for openSUSE:Factory checked in at 2022-01-11 21:17:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-dulwich (Old) and /work/SRC/openSUSE:Factory/.python-dulwich.new.1892 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-dulwich" Tue Jan 11 21:17:08 2022 rev:44 rq:945421 version:0.20.30 Changes: -------- --- /work/SRC/openSUSE:Factory/python-dulwich/python-dulwich.changes 2021-11-15 15:27:59.173850145 +0100 +++ /work/SRC/openSUSE:Factory/.python-dulwich.new.1892/python-dulwich.changes 2022-01-11 21:20:29.241010218 +0100 @@ -1,0 +2,15 @@ +Mon Jan 10 22:22:13 UTC 2022 - Dirk M??ller <[email protected]> + +- update to 0.20.30: + * Support staging submodules. + * Drop deprecated Index.iterblobs and iter_fresh_blobs. + * Unify clone behaviour of ``Repo.clone`` and + ``porcelain.clone``, and add branch parameter for + clone. + * Fix hook test on Mac OSX / Linux when dulwich is + not installed system-wide. + * Cope with gecos being unset. + * Allow adding files to repository in pre-commit hook. + * Raise SubmoduleEncountered in ``tree_lookup_path``. + +------------------------------------------------------------------- Old: ---- dulwich-0.20.26.tar.gz New: ---- dulwich-0.20.30.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-dulwich.spec ++++++ --- /var/tmp/diff_new_pack.hDTTpk/_old 2022-01-11 21:20:31.797012016 +0100 +++ /var/tmp/diff_new_pack.hDTTpk/_new 2022-01-11 21:20:31.801012019 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-dulwich # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,7 +20,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-dulwich -Version: 0.20.26 +Version: 0.20.30 Release: 0 Summary: Pure-Python Git Library License: Apache-2.0 OR GPL-2.0-or-later ++++++ dulwich-0.20.26.tar.gz -> dulwich-0.20.30.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/.github/FUNDING.yml new/dulwich-0.20.30/.github/FUNDING.yml --- old/dulwich-0.20.26/.github/FUNDING.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/dulwich-0.20.30/.github/FUNDING.yml 2022-01-08 02:49:33.000000000 +0100 @@ -0,0 +1 @@ +github: jelmer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/.gitignore new/dulwich-0.20.30/.gitignore --- old/dulwich-0.20.26/.gitignore 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/.gitignore 2022-01-08 02:49:33.000000000 +0100 @@ -25,3 +25,4 @@ .mypy_cache/ .eggs dulwich.dist-info +.stestr diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/.stestr.conf new/dulwich-0.20.30/.stestr.conf --- old/dulwich-0.20.26/.stestr.conf 1970-01-01 01:00:00.000000000 +0100 +++ new/dulwich-0.20.30/.stestr.conf 2022-01-08 02:49:33.000000000 +0100 @@ -0,0 +1,2 @@ +[DEFAULT] +test_path=dulwich/tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/NEWS new/dulwich-0.20.30/NEWS --- old/dulwich-0.20.26/NEWS 2021-10-29 02:39:02.000000000 +0200 +++ new/dulwich-0.20.30/NEWS 2022-01-08 02:51:22.000000000 +0100 @@ -1,3 +1,33 @@ +0.20.30 2022-01-08 + +0.20.29 2022-01-08 + + * Support staging submodules. + (Jelmer Vernoo??) + + * Drop deprecated Index.iterblobs and iter_fresh_blobs. + (Jelmer Vernoo??) + + * Unify clone behaviour of ``Repo.clone`` and + ``porcelain.clone``, and add branch parameter for + clone. (Peter Rowlands, #851) + +0.20.28 2022-01-05 + + * Fix hook test on Mac OSX / Linux when dulwich is + not installed system-wide. (Jelmer Vernoo??, #919) + + * Cope with gecos being unset. + (Jelmer Vernoo??, #917) + +0.20.27 2022-01-04 + + * Allow adding files to repository in pre-commit hook. + (Jelmer Vernoo??, #916) + + * Raise SubmoduleEncountered in ``tree_lookup_path``. + (Jelmer Vernoo??) + 0.20.26 2021-10-29 * Support os.PathLike arguments to Repo.stage(). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/PKG-INFO new/dulwich-0.20.30/PKG-INFO --- old/dulwich-0.20.26/PKG-INFO 2021-10-29 02:39:09.031071400 +0200 +++ new/dulwich-0.20.30/PKG-INFO 2022-01-08 02:51:25.720679500 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: dulwich -Version: 0.20.26 +Version: 0.20.30 Summary: Python Git Library Home-page: https://www.dulwich.io/ Author: Jelmer Vernooij diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/__init__.py new/dulwich-0.20.30/dulwich/__init__.py --- old/dulwich-0.20.26/dulwich/__init__.py 2021-10-29 02:39:02.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/__init__.py 2022-01-08 02:51:22.000000000 +0100 @@ -22,4 +22,4 @@ """Python implementation of the Git file formats and protocols.""" -__version__ = (0, 20, 26) +__version__ = (0, 20, 30) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/hooks.py new/dulwich-0.20.30/dulwich/hooks.py --- old/dulwich-0.20.26/dulwich/hooks.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/hooks.py 2022-01-08 02:49:33.000000000 +0100 @@ -117,10 +117,10 @@ class PreCommitShellHook(ShellHook): """pre-commit shell hook""" - def __init__(self, controldir): + def __init__(self, cwd, controldir): filepath = os.path.join(controldir, "hooks", "pre-commit") - ShellHook.__init__(self, "pre-commit", filepath, 0, cwd=controldir) + ShellHook.__init__(self, "pre-commit", filepath, 0, cwd=cwd) class PostCommitShellHook(ShellHook): @@ -173,7 +173,7 @@ def __init__(self, controldir): self.controldir = controldir filepath = os.path.join(controldir, "hooks", "post-receive") - ShellHook.__init__(self, "post-receive", filepath, 0) + ShellHook.__init__(self, "post-receive", path=filepath, numparam=0) def execute(self, client_refs): # do nothing if the script doesn't exist diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/index.py new/dulwich-0.20.30/dulwich/index.py --- old/dulwich-0.20.26/dulwich/index.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/index.py 2022-01-08 02:49:33.000000000 +0100 @@ -379,12 +379,6 @@ entry = self[path] yield path, entry.sha, cleanup_mode(entry.mode) - def iterblobs(self): - import warnings - - warnings.warn("Use iterobjects() instead.", PendingDeprecationWarning) - return self.iterobjects() - def clear(self): """Remove all contents from this index.""" self._byname = {} @@ -878,6 +872,15 @@ return tree_path +def index_entry_from_directory(st, path): + if os.path.exists(os.path.join(path, b".git")): + head = read_submodule_head(path) + if head is None: + return None + return index_entry_from_stat(st, head, 0, mode=S_IFGITLINK) + return None + + def index_entry_from_path(path, object_store=None): """Create an index from a filesystem path. @@ -894,12 +897,7 @@ assert isinstance(path, bytes) st = os.lstat(path) if stat.S_ISDIR(st.st_mode): - if os.path.exists(os.path.join(path, b".git")): - head = read_submodule_head(path) - if head is None: - return None - return index_entry_from_stat(st, head, 0, mode=S_IFGITLINK) - return None + return index_entry_from_directory(st, path) if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode): blob = blob_from_path_and_stat(path, st) @@ -930,28 +928,6 @@ yield path, entry -def iter_fresh_blobs(index, root_path): - """Iterate over versions of blobs on disk referenced by index. - - Don't use this function; it removes missing entries from index. - - Args: - index: Index file - root_path: Root path to access from - include_deleted: Include deleted entries with sha and - mode set to None - Returns: Iterator over path, sha, mode - """ - import warnings - - warnings.warn(PendingDeprecationWarning, "Use iter_fresh_objects instead.") - for entry in iter_fresh_objects(index, root_path, include_deleted=True): - if entry[1] is None: - del index[entry[0]] - else: - yield entry - - def iter_fresh_objects(paths, root_path, include_deleted=False, object_store=None): """Iterate over versions of objecs on disk referenced by index. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/object_store.py new/dulwich-0.20.30/dulwich/object_store.py --- old/dulwich-0.20.26/dulwich/object_store.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/object_store.py 2022-01-08 02:49:33.000000000 +0100 @@ -331,8 +331,8 @@ def _collect_ancestors( self, heads, - common=set(), - shallow=set(), + common=frozenset(), + shallow=frozenset(), get_parents=lambda commit: commit.parents, ): """Collect all ancestors of heads up to (excluding) those in common. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/objects.py new/dulwich-0.20.30/dulwich/objects.py --- old/dulwich-0.20.26/dulwich/objects.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/objects.py 2022-01-08 02:49:33.000000000 +0100 @@ -100,7 +100,7 @@ def sha_to_hex(sha): """Takes a string and returns the hex of the sha within""" hexsha = binascii.hexlify(sha) - assert len(hexsha) == 40, "Incorrect length of sha1 string: %d" % hexsha + assert len(hexsha) == 40, "Incorrect length of sha1 string: %s" % hexsha return hexsha @@ -1032,6 +1032,14 @@ ) +class SubmoduleEncountered(Exception): + """A submodule was encountered while resolving a path.""" + + def __init__(self, path, sha): + self.path = path + self.sha = sha + + class Tree(ShaFile): """A Git tree object""" @@ -1182,9 +1190,11 @@ parts = path.split(b"/") sha = self.id mode = None - for p in parts: + for i, p in enumerate(parts): if not p: continue + if mode is not None and S_ISGITLINK(mode): + raise SubmoduleEncountered(b'/'.join(parts[:i]), sha) obj = lookup_obj(sha) if not isinstance(obj, Tree): raise NotTreeError(sha) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/porcelain.py new/dulwich-0.20.30/dulwich/porcelain.py --- old/dulwich-0.20.26/dulwich/porcelain.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/porcelain.py 2022-01-08 02:49:33.000000000 +0100 @@ -70,7 +70,6 @@ import os from pathlib import Path import posixpath -import shutil import stat import sys import time @@ -140,6 +139,7 @@ from dulwich.refs import ( ANNOTATED_TAG_SUFFIX, LOCAL_BRANCH_PREFIX, + LOCAL_TAG_PREFIX, strip_peeled_refs, RefsContainer, ) @@ -403,6 +403,7 @@ outstream=None, origin=b"origin", depth=None, + branch=None, **kwargs ): """Clone a local or remote git repository. @@ -416,9 +417,10 @@ outstream: Optional stream to write progress to (deprecated) origin: Name of remote from the repository used to clone depth: Depth to fetch at + branch: Optional branch or tag to be used as HEAD in the new repository + instead of the cloned repository's HEAD. Returns: The new repository """ - # TODO(jelmer): This code overlaps quite a bit with Repo.clone if outstream is not None: import warnings @@ -427,7 +429,7 @@ DeprecationWarning, stacklevel=3, ) - errstream = outstream + # TODO(jelmer): Capture logging output and stream to errstream if checkout is None: checkout = not bare @@ -437,51 +439,17 @@ if target is None: target = source.split("/")[-1] - if not os.path.exists(target): - os.mkdir(target) + mkdir = not os.path.exists(target) - if bare: - r = Repo.init_bare(target) - else: - r = Repo.init(target) - - reflog_message = b"clone: from " + source.encode("utf-8") - try: - target_config = r.get_config() - if not isinstance(source, bytes): - source = source.encode(DEFAULT_ENCODING) - target_config.set((b"remote", origin), b"url", source) - target_config.set( - (b"remote", origin), - b"fetch", - b"+refs/heads/*:refs/remotes/" + origin + b"/*", - ) - target_config.write_to_path() - fetch_result = fetch( - r, - origin, - errstream=errstream, - message=reflog_message, - depth=depth, - **kwargs + with open_repo_closing(source) as r: + return r.clone( + target, + mkdir=mkdir, + bare=bare, + origin=origin, + checkout=checkout, + branch=branch, ) - for key, target in fetch_result.symrefs.items(): - r.refs.set_symbolic_ref(key, target) - try: - head = r[fetch_result.refs[b"HEAD"]] - except KeyError: - head = None - else: - r[b"HEAD"] = head.id - if checkout and not bare and head is not None: - errstream.write(b"Checking out " + head.id + b"\n") - r.reset_index(head.tree) - except BaseException: - shutil.rmtree(target) - r.close() - raise - - return r def add(repo=".", paths=None): @@ -1430,7 +1398,7 @@ def _make_tag_ref(name): if getattr(name, "encode", None): name = name.encode(DEFAULT_ENCODING) - return b"refs/tags/" + name + return LOCAL_TAG_PREFIX + name def branch_delete(repo, name): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/refs.py new/dulwich-0.20.30/dulwich/refs.py --- old/dulwich-0.20.26/dulwich/refs.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/refs.py 2022-01-08 02:49:33.000000000 +0100 @@ -32,6 +32,7 @@ git_line, valid_hexsha, ZERO_SHA, + Tag, ) from dulwich.file import ( GitFile, @@ -1203,3 +1204,68 @@ for (ref, sha) in refs.items() if not ref.endswith(ANNOTATED_TAG_SUFFIX) } + + +def _set_origin_head(refs, origin, origin_head): + # set refs/remotes/origin/HEAD + origin_base = b"refs/remotes/" + origin + b"/" + if origin_head and origin_head.startswith(LOCAL_BRANCH_PREFIX): + origin_ref = origin_base + b"HEAD" + target_ref = origin_base + origin_head[len(LOCAL_BRANCH_PREFIX) :] + if target_ref in refs: + refs.set_symbolic_ref(origin_ref, target_ref) + + +def _set_default_branch(refs, origin, origin_head, branch, ref_message): + origin_base = b"refs/remotes/" + origin + b"/" + if branch: + origin_ref = origin_base + branch + if origin_ref in refs: + local_ref = LOCAL_BRANCH_PREFIX + branch + refs.add_if_new( + local_ref, refs[origin_ref], ref_message + ) + head_ref = local_ref + elif LOCAL_TAG_PREFIX + branch in refs: + head_ref = LOCAL_TAG_PREFIX + branch + else: + raise ValueError( + "%s is not a valid branch or tag" % os.fsencode(branch) + ) + elif origin_head: + head_ref = origin_head + if origin_head.startswith(LOCAL_BRANCH_PREFIX): + origin_ref = origin_base + origin_head[len(LOCAL_BRANCH_PREFIX) :] + else: + origin_ref = origin_head + try: + refs.add_if_new( + head_ref, refs[origin_ref], ref_message + ) + except KeyError: + pass + return head_ref + + +def _set_head(refs, head_ref, ref_message): + if head_ref.startswith(LOCAL_TAG_PREFIX): + # detach HEAD at specified tag + head = refs[head_ref] + if isinstance(head, Tag): + _cls, obj = head.object + head = obj.get_object(obj).id + del refs[b"HEAD"] + refs.set_if_equals( + b"HEAD", None, head, message=ref_message + ) + else: + # set HEAD to specific branch + try: + head = refs[head_ref] + refs.set_symbolic_ref(b"HEAD", head_ref) + refs.set_if_equals( + b"HEAD", None, head, message=ref_message + ) + except KeyError: + head = None + return head diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/repo.py new/dulwich-0.20.30/dulwich/repo.py --- old/dulwich-0.20.26/dulwich/repo.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/repo.py 2022-01-08 02:49:33.000000000 +0100 @@ -87,6 +87,8 @@ from dulwich.refs import ( # noqa: F401 ANNOTATED_TAG_SUFFIX, + LOCAL_BRANCH_PREFIX, + LOCAL_TAG_PREFIX, check_ref_format, RefsContainer, DictRefsContainer, @@ -96,6 +98,9 @@ read_packed_refs_with_peeled, write_packed_refs, SYMREF, + _set_default_branch, + _set_head, + _set_origin_head, ) @@ -146,7 +151,10 @@ except KeyError: fullname = None else: - fullname = gecos.split(",")[0] + if gecos: + fullname = gecos.split(",")[0] + else: + fullname = None if not fullname: fullname = username email = os.environ.get("EMAIL") @@ -895,6 +903,14 @@ New commit SHA1 """ + try: + if not no_verify: + self.hooks["pre-commit"].execute() + except HookError as e: + raise CommitError(e) + except KeyError: # no hook defined, silent fallthrough + pass + c = Commit() if tree is None: index = self.open_index() @@ -904,14 +920,6 @@ raise ValueError("tree must be a 40-byte hex sha string") c.tree = tree - try: - if not no_verify: - self.hooks["pre-commit"].execute() - except HookError as e: - raise CommitError(e) - except KeyError: # no hook defined, silent fallthrough - pass - config = self.get_config_stack() if merge_heads is None: merge_heads = self._read_heads("MERGE_HEAD") @@ -1057,7 +1065,6 @@ if os.path.isfile(hidden_path): with open(hidden_path, "r") as f: path = read_gitfile(f) - self.bare = False self._controldir = os.path.join(root, path) else: self._controldir = hidden_path @@ -1101,7 +1108,7 @@ with graft_file: self._graftpoints.update(parse_graftpoints(graft_file)) - self.hooks["pre-commit"] = PreCommitShellHook(self.controldir()) + self.hooks["pre-commit"] = PreCommitShellHook(self.path, self.controldir()) self.hooks["commit-msg"] = CommitMsgShellHook(self.controldir()) self.hooks["post-commit"] = PostCommitShellHook(self.controldir()) self.hooks["post-receive"] = PostReceiveShellHook(self.controldir()) @@ -1269,6 +1276,7 @@ from dulwich.index import ( blob_from_path_and_stat, index_entry_from_stat, + index_entry_from_directory, _fs_to_tree_path, ) @@ -1293,7 +1301,16 @@ except KeyError: pass # already removed else: - if not stat.S_ISREG(st.st_mode) and not stat.S_ISLNK(st.st_mode): + if stat.S_ISDIR(st.st_mode): + entry = index_entry_from_directory(st, full_path) + if entry: + index[tree_path] = entry + else: + try: + del index[tree_path] + except KeyError: + pass + elif not stat.S_ISREG(st.st_mode) and not stat.S_ISLNK(st.st_mode): try: del index[tree_path] except KeyError: @@ -1371,6 +1388,7 @@ bare=False, origin=b"origin", checkout=None, + branch=None, ): """Clone this repository. @@ -1378,56 +1396,78 @@ target_path: Target path mkdir: Create the target directory bare: Whether to create a bare repository + checkout: Whether or not to check-out HEAD after cloning origin: Base name for refs in target repository cloned from this repository + branch: Optional branch or tag to be used as HEAD in the new repository + instead of this repository's HEAD. Returns: Created repository as `Repo` """ - if not bare: - target = self.init(target_path, mkdir=mkdir) - else: - if checkout: - raise ValueError("checkout and bare are incompatible") - target = self.init_bare(target_path, mkdir=mkdir) - self.fetch(target) + encoded_path = self.path if not isinstance(encoded_path, bytes): encoded_path = os.fsencode(encoded_path) - ref_message = b"clone: from " + encoded_path - target.refs.import_refs( - b"refs/remotes/" + origin, - self.refs.as_dict(b"refs/heads"), - message=ref_message, - ) - target.refs.import_refs( - b"refs/tags", self.refs.as_dict(b"refs/tags"), message=ref_message - ) + + if mkdir: + os.mkdir(target_path) + try: - target.refs.add_if_new( - DEFAULT_REF, self.refs[DEFAULT_REF], message=ref_message + target = None + if not bare: + target = Repo.init(target_path) + if checkout is None: + checkout = True + else: + if checkout: + raise ValueError("checkout and bare are incompatible") + target = Repo.init_bare(target_path) + + target_config = target.get_config() + target_config.set((b"remote", origin), b"url", encoded_path) + target_config.set( + (b"remote", origin), + b"fetch", + b"+refs/heads/*:refs/remotes/" + origin + b"/*", ) - except KeyError: - pass - target_config = target.get_config() - target_config.set(("remote", "origin"), "url", encoded_path) - target_config.set( - ("remote", "origin"), - "fetch", - "+refs/heads/*:refs/remotes/origin/*", - ) - target_config.write_to_path() + target_config.write_to_path() - # Update target head - head_chain, head_sha = self.refs.follow(b"HEAD") - if head_chain and head_sha is not None: - target.refs.set_symbolic_ref(b"HEAD", head_chain[-1], message=ref_message) - target[b"HEAD"] = head_sha - - if checkout is None: - checkout = not bare - if checkout: - # Checkout HEAD to target dir - target.reset_index() + ref_message = b"clone: from " + encoded_path + self.fetch(target) + target.refs.import_refs( + b"refs/remotes/" + origin, + self.refs.as_dict(b"refs/heads"), + message=ref_message, + ) + target.refs.import_refs( + b"refs/tags", self.refs.as_dict(b"refs/tags"), message=ref_message + ) + + head_chain, origin_sha = self.refs.follow(b"HEAD") + origin_head = head_chain[-1] if head_chain else None + if origin_sha and not origin_head: + # set detached HEAD + target.refs[b"HEAD"] = origin_sha + + _set_origin_head(target.refs, origin, origin_head) + head_ref = _set_default_branch( + target.refs, origin, origin_head, branch, ref_message + ) + + # Update target head + if head_ref: + head = _set_head(target.refs, head_ref, ref_message) + else: + head = None + if checkout and head is not None: + target.reset_index() + except BaseException: + if target is not None: + target.close() + if mkdir: + import shutil + shutil.rmtree(target_path) + raise return target def reset_index(self, tree=None): @@ -1443,7 +1483,11 @@ ) if tree is None: - tree = self[b"HEAD"].tree + head = self[b"HEAD"] + if isinstance(head, Tag): + _cls, obj = head.object + head = self.get_object(obj) + tree = head.tree config = self.get_config() honor_filemode = config.get_boolean(b"core", b"filemode", os.name != "nt") if config.get_boolean(b"core", b"core.protectNTFS", os.name == "nt"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/tests/test_hooks.py new/dulwich-0.20.30/dulwich/tests/test_hooks.py --- old/dulwich-0.20.26/dulwich/tests/test_hooks.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/tests/test_hooks.py 2022-01-08 02:49:33.000000000 +0100 @@ -71,7 +71,7 @@ ) pre_commit = os.path.join(repo_dir, "hooks", "pre-commit") - hook = PreCommitShellHook(repo_dir) + hook = PreCommitShellHook(repo_dir, repo_dir) with open(pre_commit, "w") as f: f.write(pre_commit_fail) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/tests/test_index.py new/dulwich-0.20.30/dulwich/tests/test_index.py --- old/dulwich-0.20.26/dulwich/tests/test_index.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/tests/test_index.py 2022-01-08 02:49:33.000000000 +0100 @@ -30,7 +30,6 @@ import struct import sys import tempfile -import warnings from dulwich.index import ( Index, @@ -64,9 +63,6 @@ TestCase, skipIf, ) -from dulwich.tests.utils import ( - setup_warning_catcher, -) def can_symlink(): @@ -109,26 +105,6 @@ list(self.get_simple_index("index").iterobjects()), ) - def test_iterblobs(self): - warnings.simplefilter("always", UserWarning) - self.addCleanup(warnings.resetwarnings) - warnings_list, restore_warnings = setup_warning_catcher() - self.addCleanup(restore_warnings) - - self.assertEqual( - [(b"bla", b"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", 33188)], - list(self.get_simple_index("index").iterblobs()), - ) - - expected_warning = PendingDeprecationWarning("Use iterobjects() instead.") - for w in warnings_list: - if type(w) == type(expected_warning) and w.args == expected_warning.args: - break - else: - raise AssertionError( - "Expected warning %r not in %r" % (expected_warning, warnings_list) - ) - def test_getitem(self): self.assertEqual( ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/tests/test_object_store.py new/dulwich-0.20.30/dulwich/tests/test_object_store.py --- old/dulwich-0.20.26/dulwich/tests/test_object_store.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/tests/test_object_store.py 2022-01-08 02:49:33.000000000 +0100 @@ -42,6 +42,8 @@ Tree, TreeEntry, EmptyFileException, + SubmoduleEncountered, + S_IFGITLINK, ) from dulwich.object_store import ( DiskObjectStore, @@ -582,6 +584,7 @@ (b"ad/bd/c", blob_c.id, 0o100755), (b"ad/c", blob_c.id, 0o100644), (b"c", blob_c.id, 0o100644), + (b"d", blob_c.id, S_IFGITLINK), ] self.tree_id = commit_tree(self.store, blobs) @@ -600,6 +603,12 @@ o_id = tree_lookup_path(self.get_object, self.tree_id, b"ad/bd/")[1] self.assertTrue(isinstance(self.store[o_id], Tree)) + def test_lookup_submodule(self): + tree_lookup_path(self.get_object, self.tree_id, b"d")[1] + self.assertRaises( + SubmoduleEncountered, tree_lookup_path, self.get_object, + self.tree_id, b"d/a") + def test_lookup_nonexistent(self): self.assertRaises( KeyError, tree_lookup_path, self.get_object, self.tree_id, b"j" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/tests/test_porcelain.py new/dulwich-0.20.30/dulwich/tests/test_porcelain.py --- old/dulwich-0.20.26/dulwich/tests/test_porcelain.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/tests/test_porcelain.py 2022-01-08 02:49:33.000000000 +0100 @@ -630,9 +630,12 @@ r.close() def test_source_broken(self): - target_path = tempfile.mkdtemp() - self.assertRaises(Exception, porcelain.clone, "/nonexistant/repo", target_path) - self.assertFalse(os.path.exists(target_path)) + with tempfile.TemporaryDirectory() as parent: + target_path = os.path.join(parent, "target") + self.assertRaises( + Exception, porcelain.clone, "/nonexistant/repo", target_path + ) + self.assertFalse(os.path.exists(target_path)) def test_fetch_symref(self): f1_1 = make_object(Blob, data=b"f1") @@ -652,7 +655,10 @@ self.assertEqual(0, len(target_repo.open_index())) self.assertEqual(c1.id, target_repo.refs[b"refs/heads/else"]) self.assertEqual(c1.id, target_repo.refs[b"HEAD"]) - self.assertEqual({b"HEAD": b"refs/heads/else"}, target_repo.refs.get_symrefs()) + self.assertEqual( + {b"HEAD": b"refs/heads/else", b"refs/remotes/origin/HEAD": b"refs/remotes/origin/else"}, + target_repo.refs.get_symrefs(), + ) class InitTests(TestCase): @@ -2385,6 +2391,8 @@ for k, v in remote_refs.items() if k.startswith(local_ref_prefix) } + if b"HEAD" in locally_known_remote_refs and b"HEAD" in remote_refs: + normalized_remote_refs[b"HEAD"] = remote_refs[b"HEAD"] self.assertEqual(locally_known_remote_refs, normalized_remote_refs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich/tests/test_repository.py new/dulwich-0.20.30/dulwich/tests/test_repository.py --- old/dulwich-0.20.26/dulwich/tests/test_repository.py 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/dulwich/tests/test_repository.py 2022-01-08 02:49:33.000000000 +0100 @@ -385,6 +385,7 @@ { b"HEAD": b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", b"refs/remotes/origin/master": b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", + b"refs/remotes/origin/HEAD": b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", b"refs/heads/master": b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", b"refs/tags/mytag": b"28237f4dc30d0d462658d6b937b08a0f0b6ef55a", b"refs/tags/mytag-packed": b"b0931cadc54336e78a1d980420e3268903b57a50", @@ -451,6 +452,48 @@ ValueError, r.clone, tmp_dir, mkdir=False, checkout=True, bare=True ) + def test_clone_branch(self): + r = self.open_repo("a.git") + r.refs[b"refs/heads/mybranch"] = b"28237f4dc30d0d462658d6b937b08a0f0b6ef55a" + tmp_dir = self.mkdtemp() + self.addCleanup(shutil.rmtree, tmp_dir) + with r.clone(tmp_dir, mkdir=False, branch=b"mybranch") as t: + # HEAD should point to specified branch and not origin HEAD + chain, sha = t.refs.follow(b"HEAD") + self.assertEqual(chain[-1], b"refs/heads/mybranch") + self.assertEqual(sha, b"28237f4dc30d0d462658d6b937b08a0f0b6ef55a") + self.assertEqual( + t.refs[b"refs/remotes/origin/HEAD"], + b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", + ) + + def test_clone_tag(self): + r = self.open_repo("a.git") + tmp_dir = self.mkdtemp() + self.addCleanup(shutil.rmtree, tmp_dir) + with r.clone(tmp_dir, mkdir=False, branch=b"mytag") as t: + # HEAD should be detached (and not a symbolic ref) at tag + self.assertEqual( + t.refs.read_ref(b"HEAD"), + b"28237f4dc30d0d462658d6b937b08a0f0b6ef55a", + ) + self.assertEqual( + t.refs[b"refs/remotes/origin/HEAD"], + b"a90fa2d900a17e99b433217e988c4eb4a2e9a097", + ) + + def test_clone_invalid_branch(self): + r = self.open_repo("a.git") + tmp_dir = self.mkdtemp() + self.addCleanup(shutil.rmtree, tmp_dir) + self.assertRaises( + ValueError, + r.clone, + tmp_dir, + mkdir=False, + branch=b"mybranch", + ) + def test_merge_history(self): r = self.open_repo("simple_merge.git") shas = [e.commit.id for e in r.get_walker()] @@ -568,9 +611,9 @@ self.assertRaises( errors.CommitError, r.do_commit, - "failed commit", - committer="Test Committer <[email protected]>", - author="Test Author <[email protected]>", + b"failed commit", + committer=b"Test Committer <[email protected]>", + author=b"Test Author <[email protected]>", commit_timestamp=12345, commit_timezone=0, author_timestamp=12345, @@ -642,6 +685,54 @@ ) self.assertEqual([], r[commit_sha].parents) + def test_shell_hook_pre_commit_add_files(self): + if os.name != "posix": + self.skipTest("shell hook tests requires POSIX shell") + + pre_commit_contents = """#!%(executable)s +import sys +sys.path.extend(%(path)r) +from dulwich.repo import Repo + +with open('foo', 'w') as f: + f.write('newfile') + +r = Repo('.') +r.stage(['foo']) +""" % { + 'executable': sys.executable, + 'path': [os.path.join(os.path.dirname(__file__), '..', '..')] + sys.path} + + repo_dir = os.path.join(self.mkdtemp()) + self.addCleanup(shutil.rmtree, repo_dir) + r = Repo.init(repo_dir) + self.addCleanup(r.close) + + with open(os.path.join(repo_dir, 'blah'), 'w') as f: + f.write('blah') + + r.stage(['blah']) + + pre_commit = os.path.join(r.controldir(), "hooks", "pre-commit") + + with open(pre_commit, "w") as f: + f.write(pre_commit_contents) + os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + + commit_sha = r.do_commit( + b"new commit", + committer=b"Test Committer <[email protected]>", + author=b"Test Author <[email protected]>", + commit_timestamp=12395, + commit_timezone=0, + author_timestamp=12395, + author_timezone=0, + ) + self.assertEqual([], r[commit_sha].parents) + + tree = r[r[commit_sha].tree] + self.assertEqual(set([b'blah', b'foo']), set(tree)) + def test_shell_hook_post_commit(self): if os.name != "posix": self.skipTest("shell hook tests requires POSIX shell") @@ -1220,6 +1311,7 @@ os.remove(os.path.join(r.path, "a")) r.stage(["a"]) r.stage(["a"]) # double-stage a deleted path + self.assertEqual([], list(r.open_index())) def test_stage_directory(self): r = self._repo @@ -1227,6 +1319,13 @@ r.stage(["c"]) self.assertEqual([b"a"], list(r.open_index())) + def test_stage_submodule(self): + r = self._repo + s = Repo.init(os.path.join(r.path, "sub"), mkdir=True) + s.do_commit(b'message') + r.stage(["sub"]) + self.assertEqual([b"a", b"sub"], list(r.open_index())) + def test_unstage_midify_file_with_dir(self): os.mkdir(os.path.join(self._repo.path, 'new_dir')) full_path = os.path.join(self._repo.path, 'new_dir', 'foo') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich.egg-info/PKG-INFO new/dulwich-0.20.30/dulwich.egg-info/PKG-INFO --- old/dulwich-0.20.26/dulwich.egg-info/PKG-INFO 2021-10-29 02:39:08.000000000 +0200 +++ new/dulwich-0.20.30/dulwich.egg-info/PKG-INFO 2022-01-08 02:51:25.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: dulwich -Version: 0.20.26 +Version: 0.20.30 Summary: Python Git Library Home-page: https://www.dulwich.io/ Author: Jelmer Vernooij diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/dulwich.egg-info/SOURCES.txt new/dulwich-0.20.30/dulwich.egg-info/SOURCES.txt --- old/dulwich-0.20.26/dulwich.egg-info/SOURCES.txt 2021-10-29 02:39:08.000000000 +0200 +++ new/dulwich-0.20.30/dulwich.egg-info/SOURCES.txt 2022-01-08 02:51:25.000000000 +0100 @@ -3,6 +3,7 @@ .flake8 .gitignore .mailmap +.stestr.conf .testr.conf AUTHORS CODE_OF_CONDUCT.md @@ -22,6 +23,7 @@ setup.py status.yaml tox.ini +.github/FUNDING.yml .github/workflows/pythonpackage.yml .github/workflows/pythonpublish.yml bin/dul-receive-pack @@ -96,6 +98,16 @@ dulwich.egg-info/not-zip-safe dulwich.egg-info/requires.txt dulwich.egg-info/top_level.txt +dulwich/../docs/tutorial/conclusion.txt +dulwich/../docs/tutorial/encoding.txt +dulwich/../docs/tutorial/file-format.txt +dulwich/../docs/tutorial/index.txt +dulwich/../docs/tutorial/introduction.txt +dulwich/../docs/tutorial/object-store.txt +dulwich/../docs/tutorial/porcelain.txt +dulwich/../docs/tutorial/remote.txt +dulwich/../docs/tutorial/repo.txt +dulwich/../docs/tutorial/tag.txt dulwich/cloud/__init__.py dulwich/cloud/gcs.py dulwich/contrib/README.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/releaser.conf new/dulwich-0.20.30/releaser.conf --- old/dulwich-0.20.26/releaser.conf 2021-10-29 02:37:19.000000000 +0200 +++ new/dulwich-0.20.30/releaser.conf 2022-01-08 02:49:33.000000000 +0100 @@ -2,7 +2,7 @@ news_file: "NEWS" timeout_days: 5 tag_name: "dulwich-$VERSION" -verify_command: "make check" +verify_command: "flake8 && make check" update_version { path: "setup.py" match: "^dulwich_version_string = '(.*)'$" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dulwich-0.20.26/setup.py new/dulwich-0.20.30/setup.py --- old/dulwich-0.20.26/setup.py 2021-10-29 02:39:02.000000000 +0200 +++ new/dulwich-0.20.30/setup.py 2022-01-08 02:51:22.000000000 +0100 @@ -23,7 +23,7 @@ 'For 2.7 support, please install a version prior to 0.20') -dulwich_version_string = '0.20.26' +dulwich_version_string = '0.20.30' class DulwichDistribution(Distribution):
