Commit 22244ef7 authored by Jelmer Vernooij's avatar Jelmer Vernooij

New upstream version 0.10.0

parents a6272edb c866ec48
build
_trial_temp
dist
MANIFEST
.coverage
tags
.testrepository
.noseids
apidocs
build
_trial_temp
dist
MANIFEST
.coverage
tags
.testrepository
.noseids
apidocs
*.pyc
*.so
*~
syntax: glob
build
_trial_temp
dist
MANIFEST
.coverage
tags
[DEFAULT]
test_command=PYTHONPATH=. python -m subunit.run $IDOPTION $LISTOPT subvertpy.tests.test_suite
test_id_option=--load-list $IDFILE
test_list_option=--list
language: python
python:
- "2.7"
- "2.6"
script: make check
install:
- pip install unittest2
- sudo apt-get install -qq libsvn-dev
......@@ -5,13 +5,13 @@ Subversion development files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You need the Subversion libraries, including the development files. This should
be readily packaged for most platforms. The package name for Debian
and Debian-based distributions such as Ubuntu is ``libsvn-dev``.
be readily packaged for most platforms. The package name for Debian
and Debian-based distributions such as Ubuntu is ``libsvn-dev``.
Python
~~~~~~
At least version 2.4 is required.
At least version 2.7 is required.
Building
--------
......
PYTHON = python
PYDOCTOR = pydoctor
PYDOCTOR_OPTIONS ?=
SETUP = $(PYTHON) setup.py
ifeq ($(shell $(PYTHON) -c "import sys; print sys.version_info >= (2, 7)"),True)
TESTRUNNER = unittest
else
TESTRUNNER = unittest2.__main__
endif
DEBUGGER ?=
RUNTEST = PYTHONPATH=.:$(PYTHONPATH) $(DEBUGGER) $(PYTHON) -m $(TESTRUNNER)
all: build build-inplace
build::
$(SETUP) build
build-inplace::
$(SETUP) build_ext --inplace
install::
$(SETUP) install
check:: build-inplace
$(RUNTEST) $(TEST_OPTIONS) subvertpy.tests.test_suite
gdb-check::
$(MAKE) check DEBUGGER="gdb --args"
check-one::
$(MAKE) check TEST_OPTIONS=-f
clean::
$(SETUP) clean
rm -f subvertpy/*.so subvertpy/*.o subvertpy/*.pyc
pydoctor:
$(PYDOCTOR) $(PYDOCTOR_OPTIONS) --introspect-c-modules -c subvertpy.cfg --make-html
This diff is collapsed.
Metadata-Version: 1.1
Name: subvertpy
Version: 0.10.0
Summary: Alternative Python bindings for Subversion
Home-page: https://jelmer.uk/subvertpy
Author: Jelmer Vernooij
Author-email: jelmer@jelmer.uk
License: LGPLv2.1 or later
Download-URL: https://jelmer.uk/subvertpy/subvertpy-0.10.0.tar.gz
Description:
Alternative Python bindings for Subversion. The goal is to have
complete, portable and "Pythonic" Python bindings.
Keywords: svn subvertpy subversion bindings
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Operating System :: POSIX
Classifier: Topic :: Software Development :: Version Control
Subvertpy
=========
Homepage: https://jelmer.uk/subvertpy/
Python bindings for the Subversion version control system that are aimed to be
complete, fast and feel native to Python programmers.
Bindings are provided for the working copy, client, delta, remote access and
repository APIs. A hookable server side implementation of the custom Subversion
protocol (svn_ra) is also provided.
Differences with similar packages
---------------------------------
subvertpy covers more of the APIs than python-svn. It provides a more
"Pythonic" API than python-subversion, which wraps the Subversion C API pretty
much directly. Neither provide a hookable server-side.
Dependencies
------------
Subvertpy depends on Python 2.6 or later, and Subversion 1.4 or later. It should
work on Windows as well as most POSIX-based platforms (including Linux, BSDs
and Mac OS X).
A port to Python 3 is planned but has not happened yet. Patches are welcome.
Installation
------------
Standard distutils are used - use "setup.py build" to build and "setup.install"
to install. On most platforms, setup will find the Python and Subversion
development libraries by itself. On Windows you may have to set various
environment variables, see the next section for details.
Build instructions for Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Install the SVN dev kit ZIP for Windows from
http://sourceforge.net/projects/win32svn/files/
E.g. svn-win32-1.4.6_dev.zip
* Find the SVN binary ZIP file with the binaries for your dev kit.
E.g. svn-win32-1.4.6.zip
Unzip this in the *same directory* as the dev kit - README.txt will be
overwritten, but that is all. This is the default location the .ZIP file
will suggest (ie, the directory embedded in both .zip files are the same)
* Set SVN_DEV to point at this directory.
* Install BDB.
For Subversion 1.7.0 and later:
http://www.oracle.com/technetwork/database/berkeleydb/downloads/index-082944.html
download Berkeley DB 4.8.30.msi Windows installer and install it.
For Subversion 1.6.17 and earlier:
http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=688
download "db-4.4.20-win32.zip" or earlier version of BDB and extract it.
* Set SVN_BDB to the installed directory or extracted directory.
* Install SVN libintl.
http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=2627
Download svn-win32-libintl.zip.
extract it to the directory that you want.
* Set SVN_LIBINTL to the extract dir.
Development
-----------
If using GCC it might be useful to disable the deprecation warnings when
compiling to see if there are any more serious warnings:
make CFLAGS="-Wno-deprecated-declarations"
......@@ -15,7 +15,7 @@ branches_path = '/branches/'
tags_path = '/tags/'
address = 'localhost'
from cStringIO import StringIO
from io import BytesIO
import sys, os.path
from optparse import OptionParser
import stat
......@@ -24,12 +24,13 @@ from time import mktime, strptime
from subvertpy.repos import PATH_CHANGE_DELETE, Repository
ct_short = ['M', 'A', 'D', 'R', 'X']
stdout = getattr(sys.stdout, 'buffer', sys.stdout)
def dump_file_blob(root, stream, stream_length):
sys.stdout.write("data %s\n" % stream_length)
sys.stdout.flush()
sys.stdout.write(stream.read())
sys.stdout.write("\n")
stdout.write(("data %s\n" % stream_length).encode("ascii"))
stdout.flush()
stdout.write(stream.read())
stdout.write(b"\n")
class Matcher(object):
......@@ -102,7 +103,7 @@ def export_revision(rev, fs):
marks = {}
file_changes = []
for path, (node_id, change_type, text_changed, prop_changed) in changes.iteritems():
for path, (node_id, change_type, text_changed, prop_changed) in changes.items():
if root.is_dir(path):
continue
if not MATCHER.matches(path):
......@@ -116,22 +117,22 @@ def export_revision(rev, fs):
marks[i] = MATCHER.replace(path)
if props.get("svn:special", ""):
contents = root.file_content(path).read()
if not contents.startswith("link "):
if not contents.startswith(b"link "):
sys.stderr.write("special file '%s' is not a symlink, ignoring...\n" % path)
continue
mode = stat.S_IFLNK
stream = StringIO(contents[len("link "):])
stream = BytesIO(contents[len(b"link "):])
stream_length = len(stream.getvalue())
else:
if props.get("svn:executable", ""):
mode = 0755
mode = 0o755
else:
mode = 0644
mode = 0o644
stream_length = root.file_length(path)
stream = root.file_content(path)
file_changes.append("M %o :%s %s" % (
mode, i, marks[i].lstrip("/")))
sys.stdout.write("blob\nmark :%s\n" % i)
stdout.write(("blob\nmark :%s\n" % i).encode("ascii"))
dump_file_blob(root, stream, stream_length)
stream.close()
i += 1
......@@ -151,13 +152,15 @@ def export_revision(rev, fs):
svndate = props['svn:date'][0:-8]
commit_time = mktime(strptime(svndate, '%Y-%m-%dT%H:%M:%S'))
sys.stdout.write("commit refs/heads/%s\n" % MATCHER.branchname())
sys.stdout.write("committer %s %s -0000\n" % (author, int(commit_time)))
sys.stdout.write("data %s\n" % len(props['svn:log']))
sys.stdout.write(props['svn:log'])
sys.stdout.write("\n")
sys.stdout.write('\n'.join(file_changes))
sys.stdout.write("\n\n")
line = "commit refs/heads/%s\n" % MATCHER.branchname()
stdout.write(line.encode("utf-8"))
line = "committer %s %s -0000\n" % (author, int(commit_time))
stdout.write(line.encode("utf-8"))
stdout.write(("data %s\n" % len(props['svn:log'])).encode("ascii"))
stdout.write(props['svn:log'].encode("utf-8"))
stdout.write(b"\n")
stdout.write(b'\n'.join(c.encode("utf-8") for c in file_changes))
stdout.write(b"\n\n")
sys.stderr.write("done!\n")
......@@ -174,7 +177,7 @@ def crawl_revisions(repos_path, first_rev=None, final_rev=None):
first_rev = 1
if final_rev is None:
final_rev = fs_obj.youngest_revision()
for rev in xrange(first_rev, final_rev + 1):
for rev in range(first_rev, final_rev + 1):
export_revision(rev, fs_obj)
......@@ -218,14 +221,8 @@ if __name__ == '__main__':
# Canonicalize (enough for Subversion, at least) the repository path.
repos_path = os.path.normpath(args[0])
if repos_path == '.':
if repos_path == '.':
repos_path = ''
try:
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
except ImportError:
pass
crawl_revisions(repos_path, first_rev=options.first_rev,
final_rev=options.final_rev)
......@@ -2,14 +2,14 @@
# Demonstrates how to do a new commit using Subvertpy
import os
from cStringIO import StringIO
from io import BytesIO
from subvertpy import delta, repos
from subvertpy.ra import RemoteAccess, Auth, get_username_provider
# Create a repository
repos.create("tmprepo")
# Connect to the "remote" repository using the file transport.
# Connect to the "remote" repository using the file transport.
# Note that a username provider needs to be provided, so that Subversion
# knows who to record as the author of new commits made over this connection.
repo_url = "file://%s" % os.path.abspath("tmprepo")
......@@ -28,7 +28,7 @@ file = root.add_file("somefile")
file.change_prop("svn:executable", "*")
# Obtain a textdelta handler and send the new file contents
txdelta = file.apply_textdelta()
delta.send_stream(StringIO("new file contents"), txdelta)
delta.send_stream(BytesIO(b"new file contents"), txdelta)
file.close()
root.close()
editor.close()
......
......@@ -5,17 +5,17 @@ from subvertpy.ra import RemoteAccess
conn = RemoteAccess("svn://svn.samba.org/subvertpy/trunk")
for (changed_paths, rev, revprops, has_children) in conn.iter_log(paths=None,
start=0, end=conn.get_latest_revnum(), discover_changed_paths=True):
print "=" * 79
print "%d:" % rev
print "Revision properties:"
for entry in revprops.items():
print " %s: %s" % entry
print ""
for (changed_paths, rev, revprops, has_children) in conn.iter_log(
paths=None, start=0, end=conn.get_latest_revnum(),
discover_changed_paths=True):
print("=" * 79)
print("%d:" % rev)
print("Revision properties:")
for entry in revprops.items():
print(" %s: %s" % entry)
print("")
print "Changed paths"
print("Changed paths")
for path, (action, from_path, from_rev, node_kind) in (
changed_paths.iteritems()):
print " %s (%s)" % (path, action)
changed_paths.items()):
print(" %s (%s)" % (path, action))
#!/usr/bin/python
# Demonstrates how to use the replay function to fetch the
# Demonstrates how to use the replay function to fetch the
# changes made in a revision.
from subvertpy.ra import RemoteAccess, Auth, get_username_provider
conn = RemoteAccess("svn://svn.gnome.org/svn/gnome-specimen/trunk",
auth=Auth([get_username_provider()]))
auth=Auth([get_username_provider()]))
class MyFileEditor:
def change_prop(self, key, value):
print "Change prop: %s -> %r" % (key, value)
print("Change prop: %s -> %r" % (key, value))
def apply_textdelta(self, base_checksum):
# This should return a function that can receive delta windows
......@@ -21,29 +22,31 @@ class MyFileEditor:
def close(self):
pass
class MyDirEditor:
def open_directory(self, *args):
print "Open dir: %s (base revnum: %r)" % args
print("Open dir: %s (base revnum: %r)" % args)
return MyDirEditor()
def add_directory(self, path, copyfrom_path=None, copyfrom_rev=-1):
print "Add dir: %s (from %r:%r)" % (path, copyfrom_path, copyfrom_rev)
print("Add dir: %s (from %r:%r)" % (path, copyfrom_path, copyfrom_rev))
return MyDirEditor()
def open_file(self, *args):
print "Open file: %s (base revnum: %r)" % args
print("Open file: %s (base revnum: %r)" % args)
return MyFileEditor()
def add_file(self, path, copyfrom_path=None, copyfrom_rev=-1):
print "Add file: %s (from %r:%r)" % (path, copyfrom_path, copyfrom_rev)
print("Add file: %s (from %r:%r)" %
(path, copyfrom_path, copyfrom_rev))
return MyFileEditor()
def change_prop(self, key, value):
print "Change prop %s -> %r" % (key, value)
print("Change prop %s -> %r" % (key, value))
def delete_entry(self, path, revision):
print "Delete: %s" % path
print("Delete: %s" % path)
def close(self):
pass
......@@ -52,16 +55,16 @@ class MyDirEditor:
class MyEditor:
def set_target_revision(self, revnum):
print "Target revision: %d" % revnum
print("Target revision: %d" % revnum)
def abort(self):
print "Aborted"
print("Aborted")
def close(self):
print "Closed"
print("Closed")
def open_root(self, base_revnum):
print "/"
print("/")
return MyDirEditor()
......
......@@ -6,25 +6,26 @@ from subvertpy.ra import RemoteAccess
import sys
if len(sys.argv) == 1:
print "Usage: %s <url>" % sys.argv
print("Usage: %s <url>" % sys.argv)
url = sys.argv[1]
conn = RemoteAccess(url)
def log_printer(changed_paths, rev, revprops, has_children=None):
print "=" * 79
print "%d:" % rev
print "Revision properties:"
for entry in revprops.items():
print " %s: %s" % entry
print ""
print("=" * 79)
print("%d:" % rev)
print("Revision properties:")
for entry in revprops.items():
print(" %s: %s" % entry)
print("")
if changed_paths is None:
return
print "Changed paths:"
for path, (action, from_path, from_rev) in changed_paths.iteritems():
print " %s (%s)" % (path, action)
print("Changed paths:")
for path, (action, from_path, from_rev) in changed_paths.items():
print(" %s (%s)" % (path, action))
class RaCmd(cmd.Cmd):
......@@ -44,21 +45,22 @@ class RaCmd(cmd.Cmd):
def do_help(self, args):
for name in sorted(self.__class__.__dict__):
if name.startswith("do_"):
print name[3:]
print(name[3:])
def do_stat(self, args):
path, revnum = self.parse_path_revnum(args)
print conn.stat(path, revnum)
print(conn.stat(path, revnum))
def do_ls(self, args):
path, revnum = self.parse_path_revnum(args)
(dirents, fetched_rev, props) = conn.get_dir(path, revnum)
for name in dirents:
print name
print(name)
def do_cat(self, args):
path, revnum = self.parse_path_revnum(args)
(fetched_rev, props) = conn.get_file(path, sys.stdout, revnum)
outf = getattr(sys.stdout, 'buffer', sys.stdout)
(fetched_rev, props) = conn.get_file(path, outf, revnum)
def do_reparent(self, args):
conn.reparent(args)
......@@ -68,33 +70,32 @@ class RaCmd(cmd.Cmd):
conn.change_rev_prop(int(revnum), name, value)
def do_has_capability(self, args):
print conn.has_capability(args)
print(conn.has_capability(args))
def do_revprops(self, args):
for item in conn.rev_proplist(int(args)).iteritems():
print "%s: %s" % item
for item in conn.rev_proplist(int(args)).items():
print("%s: %s" % item)
def do_check_path(self, args):
path, revnum = self.parse_path_revnum(args)
kind = conn.check_path(path, revnum)
if kind == subvertpy.NODE_DIR:
print "dir"
print("dir")
elif kind == subvertpy.NODE_FILE:
print "file"
print("file")
else:
print "nonexistant"
print("nonexistant")
def do_uuid(self, args):
print conn.get_uuid()
print(conn.get_uuid())
def do_get_repos_root(self, args):
print conn.get_repos_root()
print(conn.get_repos_root())
def do_log(self, args):
conn.get_log(callback=log_printer, paths=None, start=0,
conn.get_log(callback=log_printer, paths=None, start=0,
end=conn.get_latest_revnum(), discover_changed_paths=True)
cmdline = RaCmd()
cmdline.cmdloop()
......@@ -12,7 +12,7 @@ c = client.Client(auth=Auth([get_username_provider()]))
c.checkout("file://" + os.getcwd() + "/tmprepo", "tmpco", "HEAD")
w = wc.WorkingCopy(None, "tmpco")
print w
print(w)
entry = w.entry("tmpco")
print entry.revision
print entry.url
print(entry.revision)
print(entry.url)
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2.
.TH SUBVERTPY-FAST-EXPORT "1" "October 2010" "subvertpy-fast-export" "subvertpy"
.SH NAME
subvertpy-fast-export \- generate fastexport stream from a Subversion repository
.SH DESCRIPTION
Generate fastexport stream from a Subversion repository.
.SH SYNOPSIS
.B subvertpy-fast-export
[\fIoptions\fR] \fIREPOS_PATH\fR
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
show a help message and exit
.TP
\fB\-f\fR FINAL_REV, \fB\-\-final\-rev\fR=\fIFINAL_REV\fR
Final revision to import
.TP
\fB\-r\fR FIRST_REV, \fB\-\-first\-rev\fR=\fIFIRST_REV\fR
First revision to import
.TP
\fB\-t\fR TRUNK_PATH, \fB\-\-trunk\-path\fR=\fITRUNK_PATH\fR
Path in repo to /trunk, may be
`regex:/cvs/(trunk)/proj1/(.*)` First group is used as
branchname, second to match files
.TP
\fB\-b\fR BRANCHES_PATH, \fB\-\-branches\-path\fR=\fIBRANCHES_PATH\fR
Path in repo to /branches
.TP
\fB\-T\fR TAGS_PATH, \fB\-\-tags\-path\fR=\fITAGS_PATH\fR
Path in repo to /tags
.TP
\fB\-a\fR hostname, \fB\-\-address\fR=\fIhostname\fR
Domain to put on users for their mail address
.TP
\fB\-\-version\fR
Print version and exit
.SH "SEE ALSO"
.UR https://jelmer.uk/subvertpy/
.BR https://jelmer.uk/subvertpy/
This diff is collapsed.
packages: subvertpy
docformat: restructuredtext
projectname: subvertpy
projecturl: https://jelmer.uk/subvertpy/
htmloutput: apidocs
......@@ -17,7 +17,7 @@
"""Python bindings for Subversion."""
__author__ = "Jelmer Vernooij <jelmer@jelmer.uk>"
__version__ = (0, 9, 3)
__version__ = (0, 10, 0)
NODE_DIR = 2
NODE_FILE = 1
......@@ -77,6 +77,7 @@ ERR_BAD_PROPERTY_VALUE = 125005
ERR_FS_ROOT_DIR = 160021
ERR_WC_NODE_KIND_CHANGE = 155018
ERR_WC_UPGRADE_REQUIRED = 155036
ERR_RA_CANNOT_CREATE_SESSION = 170013
ERR_APR_OS_START_EAIERR = 670000
ERR_APR_OS_ERRSPACE_SIZE = 50000
......@@ -91,10 +92,10 @@ AUTH_PARAM_DEFAULT_USERNAME = 'svn:auth:username'
AUTH_PARAM_DEFAULT_PASSWORD = 'svn:auth:password'
SSL_NOTYETVALID = 0x00000001
SSL_EXPIRED = 0x00000002
SSL_CNMISMATCH = 0x00000004
SSL_UNKNOWNCA = 0x00000008
SSL_OTHER = 0x40000000
SSL_EXPIRED = 0x00000002
SSL_CNMISMATCH = 0x00000004
SSL_UNKNOWNCA = 0x00000008
SSL_OTHER = 0x40000000
class SubversionException(Exception):
......@@ -108,7 +109,7 @@ class SubversionException(Exception):
def _check_mtime(m):
"""Check whether a C extension is out of date.
:param m: Python module that is a C extension
"""
import os
......@@ -120,6 +121,7 @@ def _check_mtime(m):
return False
return True
try:
from subvertpy import client, _ra, repos, wc
for x in client, _ra, repos, wc:
......@@ -127,7 +129,5 @@ try:
from warnings import warn
warn("subvertpy extensions are outdated and need to be rebuilt")
break
except ImportError, e:
except ImportError as e:
raise ImportError("Unable to load subvertpy extensions: %s" % e)
This diff is collapsed.
......@@ -24,7 +24,7 @@ struct log_entry {
};
typedef struct {
PyObject_HEAD
PyObject_VAR_HEAD
svn_revnum_t start, end;
svn_boolean_t discover_changed_paths;
svn_boolean_t strict_node_history;
......@@ -114,60 +114,23 @@ static PyObject *py_iter_append(LogIteratorObject *iter, PyObject *tuple)
}
PyTypeObject LogIterator_Type = {
PyObject_HEAD_INIT(NULL) 0,
PyVarObject_HEAD_INIT(NULL, 0)
"_ra.LogIterator", /* const char *tp_name; For printing, in format "<module>.<name>" */
sizeof(LogIteratorObject),
0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
/* Methods to implement standard operations */
(destructor)log_iter_dealloc, /* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
NULL, /* reprfunc tp_repr; */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
NULL, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
.tp_dealloc = (destructor)log_iter_dealloc, /* destructor tp_dealloc; */
#if PY_MAJOR_VERSION < 3
/* Flags to define presence of optional/expanded features */
Py_TPFLAGS_HAVE_ITER, /* long tp_flags; */
NULL, /* const char *tp_doc; Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */