Skip to content

Commit

Permalink
New upstream version 0.16.2
Browse files Browse the repository at this point in the history
  • Loading branch information
jelmer committed Jan 14, 2017
2 parents b34ce65 + 6b936e5 commit 5d7d8c1
Show file tree
Hide file tree
Showing 24 changed files with 607 additions and 99 deletions.
58 changes: 55 additions & 3 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
0.16.2 2016-01-14

IMPROVEMENTS

* Fixed failing test-cases on windows.
(Koen Martens)

API CHANGES

* Repo is now a context manager, so that it can be easily
closed using a ``with`` statement. (Søren Løvborg)

TEST FIXES

* Only run worktree list compat tests against git 2.7.0,
when 'git worktree list' was introduced. (Jelmer Vernooij)

BUG FIXES

* Ignore filemode when building index when core.filemode
is false.
(Koen Martens)

* Initialize core.filemode configuration setting by
probing the filesystem for trustable permissions.
(Koen Martens)

* Fix ``porcelain.reset`` to respect the comittish argument.
(Koen Martens)

* Fix dulwich.porcelain.ls_remote() on Python 3.
(#471, Jelmer Vernooij)

* Allow both unicode and byte strings for host paths
in dulwich.client. (#435, Jelmer Vernooij)

* Add remote from porcelain.clone. (#466, Jelmer Vernooij)

* Fix unquoting of credentials before passing to urllib2.
(#475, Volodymyr Holovko)

* Cope with submodules in `build_index_from_tree`.
(#477, Jelmer Vernooij)

* Handle deleted files in `get_unstaged_changes`.
(#483, Doug Hellmann)

* Don't overwrite files when they haven't changed in
`build_file_from_blob`.
(#479, Benoît HERVIER)

* Check for existence of index file before opening pack.
Fixes a race when new packs are being added.
(#482, wme)

0.16.1 2016-12-25

BUG FIXES
Expand Down Expand Up @@ -27,9 +82,6 @@

BUG FIXES

* Fix ``porcelain.reset`` to respect the comittish argument.
(Koen Martens)

* Fix handling of ``Commit.tree`` being set to an actual
tree object rather than a tree id. (Jelmer Vernooij)

Expand Down
2 changes: 1 addition & 1 deletion PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: dulwich
Version: 0.16.1
Version: 0.16.2
Summary: Python Git Library
Home-page: https://www.dulwich.io/
Author: Jelmer Vernooij
Expand Down
2 changes: 1 addition & 1 deletion dulwich.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: dulwich
Version: 0.16.1
Version: 0.16.2
Summary: Python Git Library
Home-page: https://www.dulwich.io/
Author: Jelmer Vernooij
Expand Down
2 changes: 1 addition & 1 deletion dulwich/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@

"""Python implementation of the Git file formats and protocols."""

__version__ = (0, 16, 1)
__version__ = (0, 16, 2)
43 changes: 29 additions & 14 deletions dulwich/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@

try:
from urllib import quote as urlquote
from urllib import unquote as urlunquote
except ImportError:
from urllib.parse import quote as urlquote
from urllib.parse import unquote as urlunquote

try:
import urllib2
Expand Down Expand Up @@ -497,6 +499,12 @@ def _handle_upload_pack_tail(self, proto, capabilities, graph_walker,
class TraditionalGitClient(GitClient):
"""Traditional Git client."""

DEFAULT_ENCODING = 'utf-8'

def __init__(self, path_encoding=DEFAULT_ENCODING, **kwargs):
self._remote_path_encoding = path_encoding
super(TraditionalGitClient, self).__init__(**kwargs)

def _connect(self, cmd, path):
"""Create a connection to the server.
Expand Down Expand Up @@ -672,9 +680,9 @@ def get_url(self, path):

def _connect(self, cmd, path):
if type(cmd) is not bytes:
raise TypeError(path)
raise TypeError(cmd)
if type(path) is not bytes:
raise TypeError(path)
path = path.encode(self._remote_path_encoding)
sockaddrs = socket.getaddrinfo(
self._host, self._port, socket.AF_UNSPEC, socket.SOCK_STREAM)
s = None
Expand Down Expand Up @@ -772,9 +780,9 @@ def from_parsedurl(cls, parsedurl, **kwargs):

def _connect(self, service, path):
if type(service) is not bytes:
raise TypeError(path)
raise TypeError(service)
if type(path) is not bytes:
raise TypeError(path)
path = path.encode(self._remote_path_encoding)
if self.git_command is None:
git_command = find_git_command()
argv = git_command + [service.decode('ascii'), path]
Expand Down Expand Up @@ -806,6 +814,13 @@ def get_url(self, path):
def from_parsedurl(cls, parsedurl, **kwargs):
return cls(**kwargs)

@classmethod
def _open_repo(cls, path):
from dulwich.repo import Repo
if not isinstance(path, str):
path = path.decode(sys.getfilesystemencoding())
return closing(Repo(path))

def send_pack(self, path, determine_wants, generate_pack_contents,
progress=None, write_pack=write_pack_objects):
"""Upload a pack to a remote repository.
Expand All @@ -825,9 +840,8 @@ def send_pack(self, path, determine_wants, generate_pack_contents,
"""
if not progress:
progress = lambda x: None
from dulwich.repo import Repo

with closing(Repo(path)) as target:
with self._open_repo(path) as target:
old_refs = target.get_refs()
new_refs = determine_wants(dict(old_refs))

Expand Down Expand Up @@ -863,8 +877,7 @@ def fetch(self, path, target, determine_wants=None, progress=None):
:param progress: Optional progress function
:return: Dictionary with all remote refs (not just those fetched)
"""
from dulwich.repo import Repo
with closing(Repo(path)) as r:
with self._open_repo(path) as r:
return r.fetch(target, determine_wants=determine_wants,
progress=progress)

Expand All @@ -878,8 +891,7 @@ def fetch_pack(self, path, determine_wants, graph_walker, pack_data,
:param progress: Callback for progress reports (strings)
:return: Dictionary with all remote refs (not just those fetched)
"""
from dulwich.repo import Repo
with closing(Repo(path)) as r:
with self._open_repo(path) as r:
objects_iter = r.fetch_objects(determine_wants, graph_walker, progress)

# Did the process short-circuit (e.g. in a stateless RPC call)? Note
Expand All @@ -891,9 +903,8 @@ def fetch_pack(self, path, determine_wants, graph_walker, pack_data,

def get_refs(self, path):
"""Retrieve the current refs from a git smart server."""
from dulwich.repo import Repo

with closing(Repo(path)) as target:
with self._open_repo(path) as target:
return target.get_refs()


Expand Down Expand Up @@ -994,9 +1005,9 @@ def _get_cmd_path(self, cmd):

def _connect(self, cmd, path):
if type(cmd) is not bytes:
raise TypeError(path)
raise TypeError(cmd)
if type(path) is not bytes:
raise TypeError(path)
path = path.encode(self._remote_path_encoding)
if path.startswith(b"/~"):
path = path[1:]
argv = self._get_cmd_path(cmd) + b" '" + path + b"'"
Expand Down Expand Up @@ -1055,7 +1066,11 @@ def get_url(self, path):
def from_parsedurl(cls, parsedurl, **kwargs):
auth, host = urllib2.splituser(parsedurl.netloc)
password = parsedurl.password
if password is not None:
password = urlunquote(password)
username = parsedurl.username
if username is not None:
username = urlunquote(username)
# TODO(jelmer): This also strips the username
parsedurl = parsedurl._replace(netloc=host)
return cls(urlparse.urlunparse(parsedurl),
Expand Down
4 changes: 4 additions & 0 deletions dulwich/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ def get(self, section, name):
def set(self, section, name, value):
if not isinstance(section, tuple):
section = (section, )
if not isinstance(name, bytes):
raise TypeError(name)
if type(value) not in (bool, bytes):
raise TypeError(value)
self._values.setdefault(section, OrderedDict())[name] = value

def iteritems(self, section):
Expand Down
7 changes: 7 additions & 0 deletions dulwich/contrib/swift.py
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,13 @@ def __init__(self, root, conf):
refs = SwiftInfoRefsContainer(self.scon, object_store)
BaseRepo.__init__(self, object_store, refs)

def _determine_file_mode(self):
"""Probe the file-system to determine whether permissions can be trusted.
:return: True if permissions can be trusted, False otherwise.
"""
return False

def _put_named_file(self, filename, contents):
"""Put an object in a Swift container
Expand Down
56 changes: 41 additions & 15 deletions dulwich/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,21 +422,28 @@ def build_file_from_blob(blob, mode, target_path, honor_filemode=True):
:param honor_filemode: An optional flag to honor core.filemode setting in
config file, default is core.filemode=True, change executable bit
"""
try:
oldstat = os.stat(target_path)
except OSError as e:
if e.errno == errno.ENOENT:
oldstat = None
else:
raise
contents = blob.as_raw_string()
if stat.S_ISLNK(mode):
# FIXME: This will fail on Windows. What should we do instead?
src_path = blob.as_raw_string()
try:
os.symlink(src_path, target_path)
except OSError as e:
if e.errno == errno.EEXIST:
os.unlink(target_path)
os.symlink(src_path, target_path)
else:
raise
if oldstat:
os.unlink(target_path)
os.symlink(contents, target_path)
else:
if oldstat is not None and oldstat.st_size == len(contents):
with open(target_path, 'rb') as f:
if f.read() == contents:
return

with open(target_path, 'wb') as f:
# Write out file
f.write(blob.as_raw_string())
f.write(contents)

if honor_filemode:
os.chmod(target_path, mode)
Expand Down Expand Up @@ -499,11 +506,22 @@ def build_index_from_tree(root_path, index_path, object_store, tree_id,
os.makedirs(os.path.dirname(full_path))

# FIXME: Merge new index into working tree
obj = object_store[entry.sha]
build_file_from_blob(obj, entry.mode, full_path,
honor_filemode=honor_filemode)
if S_ISGITLINK(entry.mode):
os.mkdir(full_path)
else:
obj = object_store[entry.sha]
build_file_from_blob(obj, entry.mode, full_path,
honor_filemode=honor_filemode)
# Add file to index
st = os.lstat(full_path)
if not honor_filemode or S_ISGITLINK(entry.mode):
# we can not use tuple slicing to build a new tuple,
# because on windows that will convert the times to
# longs, which causes errors further along
st_tuple = (entry.mode, st.st_ino, st.st_dev, st.st_nlink,
st.st_uid, st.st_gid, st.st_size, st.st_atime,
st.st_mtime, st.st_ctime)
st = st.__class__(st_tuple)
index[entry.path] = index_entry_from_stat(st, entry.sha, 0)

index.write()
Expand Down Expand Up @@ -539,9 +557,17 @@ def get_unstaged_changes(index, root_path):

for tree_path, entry in index.iteritems():
full_path = _tree_to_fs_path(root_path, tree_path)
blob = blob_from_path_and_stat(full_path, os.lstat(full_path))
if blob.id != entry.sha:
try:
blob = blob_from_path_and_stat(full_path, os.lstat(full_path))
except OSError as e:
if e.errno != errno.ENOENT:
raise
# The file was removed, so we assume that counts as
# different from whatever file used to exist.
yield tree_path
else:
if blob.id != entry.sha:
yield tree_path


os_sep_bytes = os.sep.encode('ascii')
Expand Down
7 changes: 5 additions & 2 deletions dulwich/object_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,12 @@ def _update_pack_cache(self):
pack_files = set()
for name in pack_dir_contents:
assert isinstance(name, basestring if sys.version_info[0] == 2 else str)
# TODO: verify that idx exists first
if name.startswith("pack-") and name.endswith(".pack"):
pack_files.add(name[:-len(".pack")])
# verify that idx exists first (otherwise the pack was not yet fully written)
idx_name = os.path.splitext(name)[0] + ".idx"
if idx_name in pack_dir_contents:
pack_name = name[:-len(".pack")]
pack_files.add(pack_name)

# Open newly appeared pack files
for f in pack_files:
Expand Down
Loading

0 comments on commit 5d7d8c1

Please sign in to comment.