Marcin Kuzminski avatar Marcin Kuzminski committed 31ebf70

various fixes for git and mercurial with InMemoryCommit backend and non-ascii files
- hg use tolocal for unicode objects
- git use core.quotepath=false for commands

Comments (0)

Files changed (9)


-                                             repo_name=repo_name, cs=c.cs,
-                                             user=self.rhodecode_user,
-                                             author=author, message=message,
-                                             content=content, f_path=node_path)
+                                           repo_name=repo_name, cs=c.cs,
+                                           user=self.rhodecode_user,
+                                           author=author, message=message,
+                                           content=content, f_path=node_path)
                 h.flash(_('Successfully committed to %s' % node_path),
             except NodeAlreadyExistsError, e:


         if ref:
             return safe_unicode(ref)
     def _fix_path(self, path):
         Paths are stored without trailing slash so we need to get rid off it if
                         name = item
                     self._paths[name] = id
                     self._stat_modes[name] = stat
             if not path in self._paths:
                 raise NodeDoesNotExistError("There is no file nor directory "
                     "at the given path %r at revision %r"
     def _diff_name_status(self):
         output = []
         for parent in self.parents:
-            cmd = 'diff --name-status %s %s' % (parent.raw_id, self.raw_id)
+            cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id, self.raw_id)
             so, se = self.repository.run_git_command(cmd)
         return '\n'.join(output)
         for line in self._diff_name_status.splitlines():
             if not line:
             if line.startswith(char):
-                splitted = line.split(char,1)
+                splitted = line.split(char, 1)
                 if not len(splitted) == 2:
                     raise VCSError("Couldn't parse diff result:\n%s\n\n and "
                         "particularly that line: %s" % (self._diff_name_status,
-                paths.add(splitted[1].strip())
+                _path = splitted[1].strip()
+                paths.add(_path)
         return sorted(paths)


 from dulwich.repo import Repo
 from rhodecode.lib.vcs.backends.base import BaseInMemoryChangeset
 from rhodecode.lib.vcs.exceptions import RepositoryError
+from rhodecode.lib.vcs.utils import safe_str
 class GitInMemoryChangeset(BaseInMemoryChangeset):
     def commit(self, message, author, parents=None, branch=None, date=None,
-            **kwargs):
+               **kwargs):
         Performs in-memory commit (doesn't check workdir in any way) and
         returns newly created ``Changeset``. Updates repository's
         commit = objects.Commit()
         commit.tree =
         commit.parents = [ for p in self.parents if p]
- = commit.committer = author
+ = commit.committer = safe_str(author)
         commit.encoding = ENCODING
-        commit.message = message + ' '
+        commit.message = safe_str(message) + ' '
         # Compute date
         if date is None:


         :param cmd: git command to be executed
-        #cmd = '(cd %s && git %s)' % (self.path, cmd)
+        _copts = ['-c', 'core.quotepath=false', ]
         if isinstance(cmd, basestring):
-            cmd = 'GIT_CONFIG_NOGLOBAL=1 git %s' % cmd
-        else:
-            cmd = ['GIT_CONFIG_NOGLOBAL=1', 'git'] + cmd
+            cmd = [cmd]
+        cmd = ['GIT_CONFIG_NOGLOBAL=1', 'git'] + _copts + cmd
             opts = dict(
                 shell=isinstance(cmd, basestring),


 from rhodecode.lib.vcs.backends.base import BaseInMemoryChangeset
 from rhodecode.lib.vcs.exceptions import RepositoryError
-from ...utils.hgcompat import memfilectx, memctx, hex
+from ...utils.hgcompat import memfilectx, memctx, hex, tolocal
 class MercurialInMemoryChangeset(BaseInMemoryChangeset):
         from .repository import MercurialRepository
-        if not isinstance(message, str) or not isinstance(author, str):
+        if not isinstance(message, unicode) or not isinstance(author, unicode):
             raise RepositoryError('Given message and author needs to be '
-                                  'an <str> instance')
+                                  'an <unicode> instance')
         if branch is None:
             branch = MercurialRepository.DEFAULT_BRANCH_NAME
             raise RepositoryError("Given path haven't been marked as added,"
-                "changed or removed (%s)" % path)
+                                  "changed or removed (%s)" % path)
         parents = [None, None]
         for i, parent in enumerate(self.parents):
+        loc = lambda u: tolocal(u.encode('utf-8'))
         # injecting given _repo params
-        commit_ctx._text = message
-        commit_ctx._user = author
+        commit_ctx._text = loc(message)
+        commit_ctx._user = loc(author)
         commit_ctx._date = date
         # TODO: Catch exceptions!


         return None
+    def unicode_path(self):
+        return safe_unicode(self.path)
+    @LazyProperty
     def name(self):
         Returns name of the node so if its path


-"""Mercurial libs compatibility
+Mercurial libs compatibility
 from mercurial import archival, merge as hg_merge, patch, ui
 from mercurial.commands import clone, nullid, pull
 from mercurial.context import memctx, memfilectx
 from mercurial.match import match
 from mercurial.mdiff import diffopts
 from mercurial.node import hex
+from mercurial.encoding import tolocal


 from rhodecode import BACKENDS
 from rhodecode.lib import helpers as h
-from rhodecode.lib.utils2 import safe_str
+from rhodecode.lib.utils2 import safe_str, safe_unicode
 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
     action_logger, EmptyChangeset, REMOVED_REPO_PAT
         # decoding here will force that we have proper encoded values
         # in any other case this will throw exceptions and deny commit
         content = safe_str(content)
-        message = safe_str(message)
         path = safe_str(f_path)
-        author = safe_str(author)
+        # message and author needs to be unicode
+        # proper backend should then translate that into required type
+        message = safe_unicode(message)
+        author = safe_unicode(author)
         m = IMC(repo)
         m.change(FileNode(path, content))
         tip = m.commit(message=message,
-                 author=author,
-                 parents=[cs], branch=cs.branch)
+                       author=author,
+                       parents=[cs], branch=cs.branch)
         new_cs = tip.short_id
         action = 'push_local:%s' % new_cs
-        message = safe_str(message)
+        message = safe_unicode(message)
+        author = safe_unicode(author)
         path = safe_str(f_path)
-        author = safe_str(author)
         m = IMC(repo)
         if isinstance(cs, EmptyChangeset):
-            # Emptychangeset means we we're editing empty repository
+            # EmptyChangeset means we we're editing empty repository
             parents = None
             parents = [cs]
         m.add(FileNode(path, content=content))
         tip = m.commit(message=message,
-                 author=author,
-                 parents=parents, branch=cs.branch)
+                       author=author,
+                       parents=parents, branch=cs.branch)
         new_cs = tip.short_id
         action = 'push_local:%s' % new_cs


                       % endif
-                <div class="commit">${_('Editing file')}: ${c.file.path}</div>
+                <div class="commit">${_('Editing file')}: ${c.file.unicode_path}</div>
 			    <pre id="editor_pre"></pre>
 				<textarea id="editor" name="content" style="display:none">${h.escape(c.file.content)|n}</textarea>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.