@@ -101,13 +101,13 @@ class GitChangeset(BaseChangeset):
"""
if path.endswith('/'):
path = path.rstrip('/')
return path
def _get_id_for_path(self, path):
path = safe_str(path)
# FIXME: Please, spare a couple of minutes and make those codes cleaner;
if not path in self._paths:
path = path.strip('/')
# set root tree
tree = self.repository._repo[self._tree_id]
if path == '':
@@ -151,13 +151,13 @@ class GitChangeset(BaseChangeset):
name = item
self._paths[name] = id
self._stat_modes[name] = stat
raise NodeDoesNotExistError("There is no file nor directory "
"at the given path '%s' at revision %s"
% (path, self.short_id))
% (path, safe_str(self.short_id)))
return self._paths[path]
def _get_kind(self, path):
obj = self.repository._repo[self._get_id_for_path(path)]
if isinstance(obj, objects.Blob):
return NodeKind.FILE
@@ -251,12 +251,13 @@ class GitChangeset(BaseChangeset):
def get_file_mode(self, path):
Returns stat mode of the file at the given ``path``.
# ensure path is traversed
self._get_id_for_path(path)
return self._stat_modes[path]
def get_file_content(self, path):
Returns content of the file at given ``path``.
@@ -43,13 +43,13 @@ class GitInMemoryChangeset(BaseInMemoryC
# Create tree and populates it with blobs
commit_tree = self.parents[0] and repo[self.parents[0]._commit.tree] or\
objects.Tree()
for node in self.added + self.changed:
# Compute subdirs if needed
dirpath, nodename = posixpath.split(node.path)
dirnames = dirpath and dirpath.split('/') or []
dirnames = map(safe_str, dirpath and dirpath.split('/') or [])
parent = commit_tree
ancestors = [('', parent)]
# Tries to dig for the deepest existing tree
while dirnames:
curdir = dirnames.pop(0)
@@ -13,13 +13,13 @@ import stat
import posixpath
import mimetypes
from rhodecode.lib.vcs.backends.base import EmptyChangeset
from rhodecode.lib.vcs.exceptions import NodeError, RemovedFileNodeError
from rhodecode.lib.vcs.utils.lazy import LazyProperty
from rhodecode.lib.vcs.utils import safe_unicode
from rhodecode.lib.vcs.utils import safe_unicode, safe_str
class NodeKind:
SUBMODULE = -1
DIR = 1
FILE = 2
@@ -97,14 +97,14 @@ class Node(object):
so it cannot end with slash, too. Otherwise, path could lead to mistakes.
def __init__(self, path, kind):
if path.startswith('/'):
raise NodeError("Cannot initialize Node objects with slash at "
"the beginning as only relative paths are supported")
self.path = path.rstrip('/')
self.path = safe_str(path.rstrip('/')) # we store paths as str
if path == '' and kind != NodeKind.DIR:
raise NodeError("Only DirNode and its subclasses may be "
"initialized with empty path")
self.kind = kind
#self.dirs, self.files = [], []
if self.is_root() and not self.is_dir():
@@ -577,14 +577,14 @@ class ScmModel(BaseModel):
processed_nodes = []
for f_path in nodes:
if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path:
raise NonRelativePathError('%s is not an relative path' % f_path)
if f_path:
f_path = os.path.normpath(f_path)
content = nodes[f_path]['content']
f_path = safe_str(f_path)
# decoding here will force that we have proper encoded values
# in any other case this will throw exceptions and deny commit
if isinstance(content, (basestring,)):
content = safe_str(content)
elif isinstance(content, (file, cStringIO.OutputType,)):
content = content.read()
# encoding: utf8
from __future__ import with_statement
import time
import datetime
from rhodecode.lib import vcs
from rhodecode.tests.vcs.base import BackendTestMixin
@@ -299,12 +300,13 @@ class ChangesetsChangesTestCaseMixin(Bac
{
'message': u'Initial',
'author': u'Joe Doe <joe.doe@example.com>',
'date': datetime.datetime(2010, 1, 1, 20),
'added': [
FileNode('foo/bar', content='foo'),
FileNode('foo/bał', content='foo'),
FileNode('foobar', content='foo'),
FileNode('qwe', content='foo'),
],
},
'message': u'Massive changes',
@@ -320,12 +322,13 @@ class ChangesetsChangesTestCaseMixin(Bac
]
def test_initial_commit(self):
changeset = self.repo.get_changeset(0)
self.assertItemsEqual(changeset.added, [
changeset.get_node('foo/bar'),
changeset.get_node('foo/bał'),
changeset.get_node('foobar'),
changeset.get_node('qwe'),
])
self.assertItemsEqual(changeset.changed, [])
self.assertItemsEqual(changeset.removed, [])
@@ -341,12 +344,20 @@ class ChangesetsChangesTestCaseMixin(Bac
self.assertTrue(isinstance(changeset.removed, RemovedFileNodesGenerator))
self.assertEqual(len(changeset.removed), 1)
self.assertEqual(list(changeset.removed)[0].path, 'qwe')
def test_get_filemode(self):
changeset = self.repo.get_changeset()
self.assertEqual(33188, changeset.get_file_mode('foo/bar'))
def test_get_filemode_non_ascii(self):
self.assertEqual(33188, changeset.get_file_mode('foo/bał'))
self.assertEqual(33188, changeset.get_file_mode(u'foo/bał'))
# For each backend create test case class
for alias in SCM_TESTS:
attrs = {
'backend_alias': alias,
}
Tests so called "in memory changesets" commit API of vcs.
@@ -15,12 +16,13 @@ from rhodecode.lib.vcs.exceptions import
from rhodecode.lib.vcs.exceptions import NodeAlreadyChangedError
from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
from rhodecode.lib.vcs.exceptions import NodeNotChangedError
from rhodecode.lib.vcs.nodes import DirNode
from rhodecode.lib.vcs.nodes import FileNode
from rhodecode.lib.vcs.utils.compat import unittest
class InMemoryChangesetTestMixin(object):
This is a backend independent test case class which should be created
with ``type`` method.
@@ -109,12 +111,34 @@ class InMemoryChangesetTestMixin(object)
self.assertEqual(changeset.get_node('foo/bar/foobaz/bar').content, 'foo')
self.assertEqual(changeset.get_node('foo/bar/another/bar').content, 'foo')
self.assertEqual(changeset.get_node('foo/baz.txt').content, 'foo')
self.assertEqual(changeset.get_node('foobar/foobaz/file').content, 'foo')
self.assertEqual(changeset.get_node('foobar/barbaz').content, 'foo')
def test_add_non_ascii_files(self):
rev_count = len(self.repo.revisions)
to_add = [
FileNode('żółwik/zwierzątko', content='ćććć'),
FileNode(u'żółwik/zwierzątko_uni', content=u'ćććć'),
for node in to_add:
self.imc.add(node)
message = u'Added: %s' % ', '.join((node.path for node in self.nodes))
author = unicode(self.__class__)
changeset = self.imc.commit(message=message, author=author)
newtip = self.repo.get_changeset()
self.assertEqual(changeset, newtip)
self.assertEqual(rev_count + 1, len(self.repo.revisions))
self.assertEqual(newtip.message, message)
self.assertEqual(newtip.author, author)
self.assertTrue(not any((self.imc.added, self.imc.changed,
self.imc.removed)))
self.assertEqual(newtip.get_node(node.path).content, node.content)
def test_add_raise_already_added(self):
node = FileNode('foobar', content='baz')
self.assertRaises(NodeAlreadyAddedError, self.imc.add, node)
def test_check_integrity_raise_already_exist(self):
@@ -137,13 +161,43 @@ class InMemoryChangesetTestMixin(object)
self.imc.commit(u'Changed %s' % node.path, u'joe.doe@example.com')
self.assertNotEqual(tip, newtip)
self.assertNotEqual(tip.id, newtip.id)
self.assertEqual(newtip.get_node('foo/bar/baz').content,
'My **changed** content')
def test_change_non_ascii(self):
tip = self.imc.commit(u'Initial', u'joe.doe@example.com')
# Change node's content
node = FileNode('żółwik/zwierzątko', content='My **changed** content')
self.imc.change(node)
self.imc.commit(u'Changed %s' % safe_unicode(node.path),
u'joe.doe@example.com')
node = FileNode(u'żółwik/zwierzątko_uni', content=u'My **changed** content')
self.assertEqual(newtip.get_node('żółwik/zwierzątko').content,
self.assertEqual(newtip.get_node('żółwik/zwierzątko_uni').content,
def test_change_raise_empty_repository(self):
node = FileNode('foobar')
self.assertRaises(EmptyRepositoryError, self.imc.change, node)
def test_check_integrity_change_raise_node_does_not_exist(self):
Status change: