def next(self, branch=None): if branch and self.branch != branch: raise VCSError('Branch option used on changeset not belonging ' 'to that branch') def _next(changeset, branch): try: next_ = changeset.revision + 1 next_rev = changeset.repository.revisions[next_] except IndexError: raise ChangesetDoesNotExistError cs = changeset.repository.get_changeset(next_rev) if branch and branch != cs.branch: return _next(cs, branch) return cs return _next(self, branch)
def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True): """ Returns git style diff between given ``filenode_old`` and ``filenode_new``. :param ignore_whitespace: ignore whitespaces in diff """ for filenode in (filenode_old, filenode_new): if not isinstance(filenode, FileNode): raise VCSError("Given object should be FileNode object, not %s" % filenode.__class__) old_raw_id = getattr(filenode_old.changeset, 'raw_id', '0' * 40) new_raw_id = getattr(filenode_new.changeset, 'raw_id', '0' * 40) repo = filenode_new.changeset.repository vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path, ignore_whitespace) return vcs_gitdiff
def __init__(self, filenode, annotate_from_changeset_func=None, order=None, **options): """ If ``annotate_from_changeset_func`` is passed it should be a function which returns string from the given changeset. For example, we may pass following function as ``annotate_from_changeset_func``:: def changeset_to_anchor(changeset): return '<a href="/changesets/%s/">%s</a>\n' %\ (changeset.id, changeset.id) :param annotate_from_changeset_func: see above :param order: (default: ``['ls', 'annotate', 'code']``); order of columns; :param options: standard pygment's HtmlFormatter options, there is extra option tough, ``headers``. For instance we can pass:: formatter = AnnotateHtmlFormatter(filenode, headers={ 'ls': '#', 'annotate': 'Annotate', 'code': 'Code', }) """ super(AnnotateHtmlFormatter, self).__init__(**options) self.annotate_from_changeset_func = annotate_from_changeset_func self.order = order or ('ls', 'annotate', 'code') headers = options.pop('headers', None) if headers and not ('ls' in headers and 'annotate' in headers and 'code' in headers): raise ValueError("If headers option dict is specified it must " "all 'ls', 'annotate' and 'code' keys") self.headers = headers if isinstance(filenode, FileNode): self.filenode = filenode else: raise VCSError("This formatter expect FileNode parameter, not %r" % type(filenode))
def _get_paths_for_status(self, status): """ Returns sorted list of paths for given ``status``. :param status: one of: *added*, *modified* or *deleted* """ paths = set() char = status[0].upper() for line in self._diff_name_status.splitlines(): if not line: continue if line.startswith(char): 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, line)) _path = splitted[1].strip() paths.add(_path) return sorted(paths)
def import_class(class_path): """ Returns class from the given path. For example, in order to get class located at ``vcs.backends.hg.MercurialRepository``: try: hgrepo = import_class('vcs.backends.hg.MercurialRepository') except VCSError: # hadle error """ splitted = class_path.split('.') mod_path = '.'.join(splitted[:-1]) class_name = splitted[-1] try: class_mod = __import__(mod_path, {}, {}, [class_name]) except ImportError, err: msg = "There was problem while trying to import backend class. "\ "Original error was:\n%s" % err raise VCSError(msg)
def prev(self, branch=None): if branch and self.branch != branch: raise VCSError('Branch option used on changeset not belonging ' 'to that branch') def _prev(changeset, branch): try: prev_ = changeset.revision - 1 if prev_ < 0: raise IndexError prev_rev = changeset.repository.revisions[prev_] except IndexError: raise ChangesetDoesNotExistError cs = changeset.repository.get_changeset(prev_rev) if branch and branch != cs.branch: return _prev(cs, branch) return cs return _prev(self, branch)
def get_scms_for_path(path): """ Returns all scm's found at the given path. If no scm is recognized - empty list is returned. :param path: path to directory which should be checked. May be callable. :raises VCSError: if given ``path`` is not a directory """ from rhodecode.lib.vcs.backends import get_backend if hasattr(path, '__call__'): path = path() if not os.path.isdir(path): raise VCSError("Given path %r is not a directory" % path) result = [] for key in ALIASES: dirname = os.path.join(path, '.' + key) if os.path.isdir(dirname): result.append(key) continue dirname = os.path.join(path, 'rm__.' + key) if os.path.isdir(dirname): return result # We still need to check if it's not bare repository as # bare repos don't have working directories try: get_backend(key)(path) result.append(key) continue except RepositoryError: # Wrong backend pass except VCSError: # No backend at all pass return result
def fill_archive(self, stream=None, kind='tgz', prefix=None, subrepos=False): """ Fills up given stream. :param stream: file like object. :param kind: one of following: ``zip``, ``tgz`` or ``tbz2``. Default: ``tgz``. :param prefix: name of root directory in archive. Default is repository name and changeset's raw_id joined with dash (``repo-tip.<KIND>``). :param subrepos: include subrepos in this archive. :raise ImproperArchiveTypeError: If given kind is wrong. :raise VcsError: If given stream is None """ allowed_kinds = settings.ARCHIVE_SPECS.keys() if kind not in allowed_kinds: raise ImproperArchiveTypeError( 'Archive kind not supported use one' 'of %s', allowed_kinds) if prefix is None: prefix = '%s-%s' % (self.repository.name, self.short_id) elif prefix.startswith('/'): raise VCSError("Prefix cannot start with leading slash") elif prefix.strip() == '': raise VCSError("Prefix cannot be empty") if kind == 'zip': frmt = 'zip' else: frmt = 'tar' _git_path = rhodecode.CONFIG.get('git_path', 'git') cmd = '%s archive --format=%s --prefix=%s/ %s' % (_git_path, frmt, prefix, self.raw_id) if kind == 'tgz': cmd += ' | gzip -9' elif kind == 'tbz2': cmd += ' | bzip2 -9' if stream is None: raise VCSError('You need to pass in a valid stream for filling' ' with archival data') popen = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, cwd=self.repository.path) buffer_size = 1024 * 8 chunk = popen.stdout.read(buffer_size) while chunk: stream.write(chunk) chunk = popen.stdout.read(buffer_size) # Make sure all descriptors would be read popen.communicate()