Skip to content

Commit

Permalink
Imported Upstream version 0.14.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jelmer committed Jul 3, 2016
2 parents dd41028 + 4f34f1d commit 8bb0011
Show file tree
Hide file tree
Showing 34 changed files with 451 additions and 148 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Expand Up @@ -5,13 +5,13 @@ env:
matrix:
include:
- python: "2.7"
env: TEST_REQUIRE="gevent geventhttpclient fastimport"
env: TEST_REQUIRE="gevent greenlet geventhttpclient fastimport"
- python: "pypy"
env: TEST_REQUIRE="fastimport"
- python: "3.4"
env: TEST_REQUIRE="fastimport"
env: TEST_REQUIRE="gevent greenlet geventhttpclient fastimport"
- python: "3.5"
env: TEST_REQUIRE="fastimport"
env: TEST_REQUIRE="gevent greenlet geventhttpclient fastimport"
cache:
directories:
- $HOME/.cache/pip
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
@@ -1,6 +1,7 @@
include NEWS
include AUTHORS
include README.md
include README.swift
include Makefile
include COPYING
include HACKING
Expand All @@ -16,3 +17,4 @@ include dulwich.cfg
include appveyor.yml
include .testr.conf
include .travis.yml
include relicensing-apachev2.txt
19 changes: 19 additions & 0 deletions NEWS
@@ -1,3 +1,22 @@
0.14.0 2016-07-03

BUG FIXES

* Fix ShaFile.id after modification of a copied ShaFile.
(Félix Mattrat, Jelmer Vernooij)

* Support removing refs from porcelain.push.
(Jelmer Vernooij, #437)

* Stop magic protocol ref `capabilities^{}` from leaking out
to clients. (Jelmer Vernooij, #254)

IMPROVEMENTS

* Add `dulwich.config.parse_submodules` function.

* Add `RefsContainer.follow` method. (#438)

0.13.0 2016-04-24

IMPROVEMENTS
Expand Down
2 changes: 1 addition & 1 deletion PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: dulwich
Version: 0.13.0
Version: 0.14.0
Summary: Python Git Library
Home-page: https://www.dulwich.io/
Author: Jelmer Vernooij
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -22,7 +22,7 @@ If you don't want to install the C bindings, specify the --pure argument to setu

$ python setup.py --pure install

or if you are installing from pip:
or if you are installing from pip::

$ pip install dulwich --global-option="--pure"

Expand Down
133 changes: 133 additions & 0 deletions README.swift
@@ -0,0 +1,133 @@
Openstack Swift as backend for Dulwich
======================================
Fabien Boucher <fabien.boucher@enovance.com>

The module dulwich/contrib/swift.py implements dulwich.repo.BaseRepo
in order to being compatible with Openstack Swift.
We can then use Dulwich as server (Git server) and instead of using
a regular POSIX file system to store repository objects we use the
object storage Swift via its own API.

c Git client <---> Dulwich server <---> Openstack Swift API

This implementation is still a work in progress and we can say that
is a Beta version so you need to be prepared to find bugs.

Configuration file
------------------

We need to provide some configuration values in order to let Dulwich
talk and authenticate against Swift. The following config file must
be used as template:

[swift]
# Authentication URL (Keystone or Swift)
auth_url = http://127.0.0.1:5000/v2.0
# Authentication version to use
auth_ver = 2
# The tenant and username separated by a semicolon
username = admin;admin
# The user password
password = pass
# The Object storage region to use (auth v2) (Default RegionOne)
region_name = RegionOne
# The Object storage endpoint URL to use (auth v2) (Default internalURL)
endpoint_type = internalURL
# Concurrency to use for parallel tasks (Default 10)
concurrency = 10
# Size of the HTTP pool (Default 10)
http_pool_length = 10
# Timeout delay for HTTP connections (Default 20)
http_timeout = 20
# Chunk size to read from pack (Bytes) (Default 12228)
chunk_length = 12228
# Cache size (MBytes) (Default 20)
cache_length = 20


Note that for now we use the same tenant to perform the requests
against Swift. Therefor there is only one Swift account used
for storing repositories. Each repository will be contained in
a Swift container.

How to start unittest
---------------------

There is no need to have a Swift cluster running to run the unitests.
Just run the following command in the Dulwich source directory:

$ PYTHONPATH=. python -m dulwich.contrib.test_swift

How to start functional tests
-----------------------------

We provide some basic tests to perform smoke tests against a real Swift
cluster. To run those functional tests you need a properly configured
configuration file. The tests can be run as follow:

$ DULWICH_SWIFT_CFG=/etc/swift-dul.conf PYTHONPATH=. python -m dulwich.contrib.test_swift_smoke

How to install
--------------

Install the Dulwich library via the setup.py. The dependencies will be
automatically retrieved from pypi:

$ python ./setup.py install

How to run the server
---------------------

Start the server using the following command:

$ python -m dulwich.contrib.swift daemon -c /etc/swift-dul.conf -l 127.0.0.1

Note that a lot of request will be performed against the Swift
cluster so it is better to start the Dulwich server as close
as possible of the Swift proxy. The best solution is to run
the server on the Swift proxy node to reduce the latency.

How to use
----------

Once you have validated that the functional tests is working as expected and
the server is running we can init a bare repository. Run this
command with the name of the repository to create:

$ python -m dulwich.contrib.swift init -c /etc/swift-dul.conf edeploy

The repository name will be the container that will contain all the Git
objects for the repository. Then standard c Git client can be used to
perform operations againt this repository.

As an example we can clone the previously empty bare repository:

$ git clone git://localhost/edeploy

Then push an existing project in it:

$ git clone https://github.com/enovance/edeploy.git edeployclone
$ cd edeployclone
$ git remote add alt git://localhost/edeploy
$ git push alt master
$ git ls-remote alt
9dc50a9a9bff1e232a74e365707f22a62492183e HEAD
9dc50a9a9bff1e232a74e365707f22a62492183e refs/heads/master

The other Git commands can be used the way you do usually against
a regular repository.

Note the daemon subcommands starts a Git server listening for the
Git protocol. Therefor there is no authentication or encryption
at all between the cGIT client and the GIT server (Dulwich).

Note on the .info file for pack object
--------------------------------------

The Swift interface of Dulwich relies only on the pack format
to store Git objects. Instead of using only an index (pack-sha.idx)
along with the pack, we add a second file (pack-sha.info). This file
is automatically created when a client pushes some references on the
repository. The purpose of this file is to speed up pack creation
server side when a client fetches some references. Currently this
.info format is not optimized and may change in future.
2 changes: 1 addition & 1 deletion docs/protocol.txt
Expand Up @@ -24,7 +24,7 @@ remote program.
A common way of sending a unit of information is a pkt_line. This is a 4 byte
size as human encoded hex (i.e. totally underusing the 4 bytes...) that tells
you the size of the payload, followed by the payload. The size includes the 4
byes used by the size itself.
bytes used by the size itself.

0009ABCD\n

Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/porcelain.txt
Expand Up @@ -30,5 +30,5 @@ Commit changes

>>> r = porcelain.init("testrepo")
>>> open("testrepo/testfile", "w").write("data")
>>> porcelain.add(r, "testrepo/testfile")
>>> porcelain.commit(r, "A sample commit")
>>> porcelain.add(r, "testfile")
>>> porcelain.commit(r, b"A sample commit")
2 changes: 1 addition & 1 deletion dulwich.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: dulwich
Version: 0.13.0
Version: 0.14.0
Summary: Python Git Library
Home-page: https://www.dulwich.io/
Author: Jelmer Vernooij
Expand Down
2 changes: 2 additions & 0 deletions dulwich.egg-info/SOURCES.txt
Expand Up @@ -7,9 +7,11 @@ MANIFEST.in
Makefile
NEWS
README.md
README.swift
TODO
appveyor.yml
dulwich.cfg
relicensing-apachev2.txt
setup.cfg
setup.py
tox.ini
Expand Down
2 changes: 1 addition & 1 deletion dulwich/__init__.py
Expand Up @@ -21,4 +21,4 @@

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

__version__ = (0, 13, 0)
__version__ = (0, 14, 0)
41 changes: 33 additions & 8 deletions dulwich/client.py
Expand Up @@ -70,6 +70,7 @@
CAPABILITY_REPORT_STATUS,
CAPABILITY_SIDE_BAND_64K,
CAPABILITY_THIN_PACK,
CAPABILITIES_REF,
COMMAND_DONE,
COMMAND_HAVE,
COMMAND_WANT,
Expand Down Expand Up @@ -175,6 +176,8 @@ def read_pkt_refs(proto):

if len(refs) == 0:
return None, set([])
if refs == {CAPABILITIES_REF: ZERO_SHA}:
refs = {}
return refs, set(server_capabilities)


Expand Down Expand Up @@ -218,6 +221,8 @@ def send_pack(self, path, determine_wants, generate_pack_contents,
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.
"""
raise NotImplementedError(self.send_pack)

Expand Down Expand Up @@ -349,8 +354,16 @@ def _handle_receive_pack_head(self, proto, capabilities, old_refs,

all_refs = set(new_refs.keys()).union(set(old_refs.keys()))
for refname in all_refs:
if not isinstance(refname, bytes):
raise TypeError('refname is not a bytestring: %r' % refname)
old_sha1 = old_refs.get(refname, ZERO_SHA)
if not isinstance(old_sha1, bytes):
raise TypeError('old sha1 for %s is not a bytestring: %r' %
(refname, old_sha1))
new_sha1 = new_refs.get(refname, ZERO_SHA)
if not isinstance(new_sha1, bytes):
raise TypeError('old sha1 for %s is not a bytestring %r' %
(refname, new_sha1))

if old_sha1 != new_sha1:
if sent_capabilities:
Expand Down Expand Up @@ -489,6 +502,8 @@ def send_pack(self, path, determine_wants, generate_pack_contents,
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.
"""
proto, unused_can_read = self._connect(b'receive-pack', path)
with proto:
Expand Down Expand Up @@ -761,7 +776,11 @@ def send_pack(self, path, determine_wants, generate_pack_contents,
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.
"""
if not progress:
progress = lambda x: None
from dulwich.repo import Repo

with closing(Repo(path)) as target:
Expand All @@ -770,20 +789,23 @@ def send_pack(self, path, determine_wants, generate_pack_contents,

have = [sha1 for sha1 in old_refs.values() if sha1 != ZERO_SHA]
want = []
all_refs = set(new_refs.keys()).union(set(old_refs.keys()))
for refname in all_refs:
old_sha1 = old_refs.get(refname, ZERO_SHA)
new_sha1 = new_refs.get(refname, ZERO_SHA)
if new_sha1 not in have and new_sha1 != ZERO_SHA:
for refname, new_sha1 in new_refs.items():
if new_sha1 not in have and not new_sha1 in want and new_sha1 != ZERO_SHA:
want.append(new_sha1)

if not want and old_refs == new_refs:
if not want and set(new_refs.items()).issubset(set(old_refs.items())):
return new_refs

target.object_store.add_objects(generate_pack_contents(have, want))

for name, sha in new_refs.items():
target.refs[name] = sha
for refname, new_sha1 in new_refs.items():
old_sha1 = old_refs.get(refname, ZERO_SHA)
if new_sha1 != ZERO_SHA:
if not target.refs.set_if_equals(refname, old_sha1, new_sha1):
progress('unable to set %s to %s' % (refname, new_sha1))
else:
if not target.refs.remove_if_equals(refname, old_sha1):
progress('unable to remove %s' % refname)

return new_refs

Expand Down Expand Up @@ -1034,6 +1056,8 @@ def send_pack(self, path, determine_wants, generate_pack_contents,
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.
"""
url = self._get_url(path)
old_refs, server_capabilities = self._discover_references(
Expand All @@ -1045,6 +1069,7 @@ def send_pack(self, path, determine_wants, generate_pack_contents,

new_refs = determine_wants(dict(old_refs))
if new_refs is None:
# Determine wants function is aborting the push.
return old_refs
if self.dumb:
raise NotImplementedError(self.fetch_pack)
Expand Down

0 comments on commit 8bb0011

Please sign in to comment.