Использовался Python 2.4 и модуль pysvn
(устанавливается пакетом python-svn).
Большую часть кода занимает
разбор командной строки. К сожалению, модуль pysvn не умеет указывать
ревизии аналогично тому, как это сделано в клиенте командной строки svn.
Для решения этой задачи пришлось написать некрасивую функцию.
Дальше все просто. Получается список изменений с измененными файлами. Строится множество измененных файлов. Получается тело каждого файла. Создается каталог и содержимое файла копируется в него. Исключения перехватываются, чтобы получить по возможности больше файлов.
Файл /home/gelin/bin/svn-get.py:
#!/usr/bin/python
# (c) 2007 Denis Nelubin aka Gelin
# This script gets files from SVN repository changed between (inclusive) specified revisions
import sys
import pysvn
import time
import os
import os.path
SVN_REPOS = "file:///home/gelin/svn"
def revision_from_string(arg):
""" Creates revision from command line argument as it's done by svn client """
#check for date
DATE_FORMAT = "{%Y-%m-%d}"
try:
return pysvn.Revision(pysvn.opt_revision_kind.date,
time.mktime(time.strptime(arg, DATE_FORMAT)))
except ValueError:
pass
#check for integer
try:
return pysvn.Revision(pysvn.opt_revision_kind.number,
int(arg))
except ValueError:
pass
#other special values
return pysvn.Revision(getattr(pysvn.opt_revision_kind, arg.lower(),
pysvn.opt_revision_kind.unspecified)) #get revision kind by name
if len(sys.argv) < 3:
print "Usage: %s PATH_IN_REPOSITORY FROM_REVISION TO_REVISION" % sys.argv[0]
sys.exit(1)
repos_path, from_rev = sys.argv[1:3]
from_rev = revision_from_string(from_rev)
if from_rev.kind == pysvn.opt_revision_kind.unspecified:
from_rev = pysvn.Revision(pysvn.opt_revision_kind.number, 0)
if len(sys.argv) >= 4:
to_rev = sys.argv[3]
else:
to_rev = "HEAD"
to_rev = revision_from_string(to_rev)
if to_rev.kind == pysvn.opt_revision_kind.unspecified:
to_rev = pysvn.Revision(pysvn.opt_revision_kind.head)
client = pysvn.Client()
log = client.log(SVN_REPOS + "/" + repos_path,
discover_changed_paths=True,
revision_start=from_rev,
revision_end=to_rev)
files = set()
for record in log:
for path in record["changed_paths"]:
if (path["action"] in ("A", "M")): #file is added or modified
files.add(path["path"])
for file in files:
print file
try:
os.makedirs(os.path.dirname("." + file))
except OSError:
pass
try:
content = client.cat(SVN_REPOS + file, revision=to_rev)
f = open("." + file, "w")
f.write(content)
f.close()
except (pysvn.ClientError, IOError), e: #don't break execution
print "WARNING: " + str(e)