Esempio n. 1
0
 def _get_repo(self,
               create,
               src_url=None,
               update_after_clone=False,
               bare=False):
     if create and os.path.exists(self.path):
         raise RepositoryError("Location already exist")
     if src_url and not create:
         raise RepositoryError("Create should be set to True if src_url is "
                               "given (clone operation creates repository)")
     try:
         if create and src_url:
             GitRepository._check_url(src_url)
             self.clone(src_url, update_after_clone, bare)
             return Repo(self.path)
         elif create:
             os.mkdir(self.path)
             if bare:
                 return Repo.init_bare(self.path)
             else:
                 return Repo.init(self.path)
         else:
             return self._repo
     except (NotGitRepository, OSError), err:
         raise RepositoryError(err)
Esempio n. 2
0
 def get_branch(self):
     headpath = self.repository._repo.refs.refpath('HEAD')
     try:
         content = open(headpath).read()
         match = re.match(r'^ref: refs/heads/(?P<branch>.+)\n$', content)
         if match:
             return match.groupdict()['branch']
         else:
             raise RepositoryError("Couldn't compute workdir's branch")
     except IOError:
         # Try naive way...
         raise RepositoryError("Couldn't compute workdir's branch")
Esempio n. 3
0
    def tag(self, name, user, revision=None, message=None, date=None,
            **kwargs):
        """
        Creates and returns a tag for the given ``revision``.

        :param name: name for new tag
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param revision: changeset id for which new tag would be created
        :param message: message of the tag's commit
        :param date: date of tag's commit

        :raises TagAlreadyExistError: if tag with same name already exists
        """
        if name in self.tags:
            raise TagAlreadyExistError("Tag %s already exists" % name)
        changeset = self.get_changeset(revision)
        local = kwargs.setdefault('local', False)

        if message is None:
            message = "Added tag %s for changeset %s" % (name,
                changeset.short_id)

        if date is None:
            date = datetime.datetime.now().ctime()

        try:
            self._repo.tag(name, changeset._ctx.node(), message, local, user,
                date)
        except Abort, e:
            raise RepositoryError(e.message)
Esempio n. 4
0
        def filectxfn(_repo, memctx, path):
            """
            Marks given path as added/changed/removed in a given _repo. This is
            for internal mercurial commit function.
            """

            # check if this path is removed
            if path in (node.path for node in self.removed):
                # Raising exception is a way to mark node for removal
                raise IOError(errno.ENOENT, '%s is deleted' % path)

            # check if this path is added
            for node in self.added:
                if node.path == path:
                    return memfilectx(
                        path=node.path,
                        data=(node.content.encode('utf8')
                              if not node.is_binary else node.content),
                        islink=False,
                        isexec=node.is_executable,
                        copied=False)

            # or changed
            for node in self.changed:
                if node.path == path:
                    return memfilectx(
                        path=node.path,
                        data=(node.content.encode('utf8')
                              if not node.is_binary else node.content),
                        islink=False,
                        isexec=node.is_executable,
                        copied=False)

            raise RepositoryError("Given path haven't been marked as added,"
                                  "changed or removed (%s)" % path)
Esempio n. 5
0
 def pull(self, url):
     """
     Tries to pull changes from external location.
     """
     url = self._get_url(url)
     try:
         pull(self.baseui, self._repo, url)
     except Abort, err:
         # Propagate error but with vcs's type
         raise RepositoryError(str(err))
Esempio n. 6
0
 def get_tree_for_dir(tree, dirname):
     for name, mode, id in tree.iteritems():
         if name == dirname:
             obj = self.repository._repo[id]
             if isinstance(obj, objects.Tree):
                 return obj
             else:
                 raise RepositoryError("Cannot create directory %s "
                 "at tree %s as path is occupied and is not a "
                 "Tree" % (dirname, tree))
     return None
Esempio n. 7
0
    def get_changesets(self,
                       start=None,
                       end=None,
                       start_date=None,
                       end_date=None,
                       branch_name=None,
                       reverse=False):
        """
        Returns iterator of ``MercurialChangeset`` objects from start to end
        (both are inclusive)

        :param start: None, str, int or mercurial lookup format
        :param end:  None, str, int or mercurial lookup format
        :param start_date:
        :param end_date:
        :param branch_name:
        :param reversed: return changesets in reversed order
        """

        start_raw_id = self._get_revision(start)
        start_pos = self.revisions.index(start_raw_id) if start else None
        end_raw_id = self._get_revision(end)
        end_pos = self.revisions.index(end_raw_id) if end else None

        if None not in [start, end] and start_pos > end_pos:
            raise RepositoryError("Start revision '%s' cannot be "
                                  "after end revision '%s'" % (start, end))

        if branch_name and branch_name not in self.allbranches.keys():
            raise BranchDoesNotExistError('Branch %s not found in'
                                          ' this repository' % branch_name)
        if end_pos is not None:
            end_pos += 1
        #filter branches
        filter_ = []
        if branch_name:
            filter_.append('branch("%s")' % (branch_name))

        if start_date:
            filter_.append('date(">%s")' % start_date)
        if end_date:
            filter_.append('date("<%s")' % end_date)
        if filter_:
            revisions = scmutil.revrange(self._repo, [" and ".join(filter_)])
        else:
            revisions = self.revisions

        revs = revisions[start_pos:end_pos]
        if reverse:
            revs = reversed(revs)

        return CollectionGenerator(self, revs)
Esempio n. 8
0
    def _run_git_command(cls, cmd, **opts):
        """
        Runs given ``cmd`` as git command and returns tuple
        (stdout, stderr).

        :param cmd: git command to be executed
        :param opts: env options to pass into Subprocess command
        """

        if '_bare' in opts:
            _copts = []
            del opts['_bare']
        else:
            _copts = [
                '-c',
                'core.quotepath=false',
            ]
        safe_call = False
        if '_safe' in opts:
            #no exc on failure
            del opts['_safe']
            safe_call = True

        _str_cmd = False
        if isinstance(cmd, basestring):
            cmd = [cmd]
            _str_cmd = True

        gitenv = os.environ
        # need to clean fix GIT_DIR !
        if 'GIT_DIR' in gitenv:
            del gitenv['GIT_DIR']
        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'

        _git_path = settings.GIT_EXECUTABLE_PATH
        cmd = [_git_path] + _copts + cmd
        if _str_cmd:
            cmd = ' '.join(cmd)
        try:
            _opts = dict(
                env=gitenv,
                shell=False,
            )
            _opts.update(opts)
            p = subprocessio.SubprocessIOChunker(cmd, **_opts)
        except (EnvironmentError, OSError), err:
            tb_err = ("Couldn't run git command (%s).\n"
                      "Original error was:%s\n" % (cmd, err))
            if safe_call:
                return '', err
            else:
                raise RepositoryError(tb_err)
Esempio n. 9
0
    def remove_tag(self, name, user, message=None, date=None):
        """
        Removes tag with the given ``name``.

        :param name: name of the tag to be removed
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param message: message of the tag's removal commit
        :param date: date of tag's removal commit

        :raises TagDoesNotExistError: if tag with given name does not exists
        """
        if name not in self.tags:
            raise TagDoesNotExistError("Tag %s does not exist" % name)
        tagpath = posixpath.join(self._repo.refs.path, 'refs', 'tags', name)
        try:
            os.remove(tagpath)
            self._parsed_refs = self._get_parsed_refs()
            self.tags = self._get_tags()
        except OSError, e:
            raise RepositoryError(e.strerror)
Esempio n. 10
0
    def _get_repo(self, create, src_url=None, update_after_clone=False):
        """
        Function will check for mercurial repository in given path and return
        a localrepo object. If there is no repository in that path it will
        raise an exception unless ``create`` parameter is set to True - in
        that case repository would be created and returned.
        If ``src_url`` is given, would try to clone repository from the
        location at given clone_point. Additionally it'll make update to
        working copy accordingly to ``update_after_clone`` flag
        """

        try:
            if src_url:
                url = str(self._get_url(src_url))
                opts = {}
                if not update_after_clone:
                    opts.update({'noupdate': True})
                try:
                    MercurialRepository._check_url(url)
                    clone(self.baseui, url, self.path, **opts)
#                except urllib2.URLError:
#                    raise Abort("Got HTTP 404 error")
                except Exception:
                    raise

                # Don't try to create if we've already cloned repo
                create = False
            return localrepository(self.baseui, self.path, create=create)
        except (Abort, RepoError), err:
            if create:
                msg = "Cannot create repository at %s. Original error was %s"\
                    % (self.path, err)
            else:
                msg = "Not valid repository at %s. Original error was %s"\
                    % (self.path, err)
            raise RepositoryError(msg)
Esempio n. 11
0
    def remove_tag(self, name, user, message=None, date=None):
        """
        Removes tag with the given ``name``.

        :param name: name of the tag to be removed
        :param user: full username, i.e.: "Joe Doe <*****@*****.**>"
        :param message: message of the tag's removal commit
        :param date: date of tag's removal commit

        :raises TagDoesNotExistError: if tag with given name does not exists
        """
        if name not in self.tags:
            raise TagDoesNotExistError("Tag %s does not exist" % name)
        if message is None:
            message = "Removed tag %s" % name
        if date is None:
            date = datetime.datetime.now().ctime()
        local = False

        try:
            self._repo.tag(name, nullid, message, local, user, date)
            self.tags = self._get_tags()
        except Abort as e:
            raise RepositoryError(e.message)
Esempio n. 12
0
    def __init__(self, repository, revision):
        self._stat_modes = {}
        self.repository = repository

        try:
            commit = self.repository._repo[revision]
            if isinstance(commit, objects.Tag):
                revision = commit.object[1]
                commit = self.repository._repo.get_object(commit.object[1])
        except KeyError:
            raise RepositoryError("Cannot get object with id %s" % revision)
        self.raw_id = revision
        self.id = self.raw_id
        self.short_id = self.raw_id[:12]
        self._commit = commit
        self._tree_id = commit.tree
        self._committer_property = 'committer'
        self._author_property = 'author'
        self._date_property = 'commit_time'
        self._date_tz_property = 'commit_timezone'
        self.revision = repository.revisions.index(revision)

        self.nodes = {}
        self._paths = {}
Esempio n. 13
0
    def get_changesets(self, start=None, end=None, start_date=None,
           end_date=None, branch_name=None, reverse=False):
        """
        Returns iterator of ``GitChangeset`` objects from start to end (both
        are inclusive), in ascending date order (unless ``reverse`` is set).

        :param start: changeset ID, as str; first returned changeset
        :param end: changeset ID, as str; last returned changeset
        :param start_date: if specified, changesets with commit date less than
          ``start_date`` would be filtered out from returned set
        :param end_date: if specified, changesets with commit date greater than
          ``end_date`` would be filtered out from returned set
        :param branch_name: if specified, changesets not reachable from given
          branch would be filtered out from returned set
        :param reverse: if ``True``, returned generator would be reversed
          (meaning that returned changesets would have descending date order)

        :raise BranchDoesNotExistError: If given ``branch_name`` does not
            exist.
        :raise ChangesetDoesNotExistError: If changeset for given ``start`` or
          ``end`` could not be found.

        """
        if branch_name and branch_name not in self.branches:
            raise BranchDoesNotExistError("Branch '%s' not found" \
                                          % branch_name)
        # %H at format means (full) commit hash, initial hashes are retrieved
        # in ascending date order
        cmd_template = 'log --date-order --reverse --pretty=format:"%H"'
        cmd_params = {}
        if start_date:
            cmd_template += ' --since "$since"'
            cmd_params['since'] = start_date.strftime('%m/%d/%y %H:%M:%S')
        if end_date:
            cmd_template += ' --until "$until"'
            cmd_params['until'] = end_date.strftime('%m/%d/%y %H:%M:%S')
        if branch_name:
            cmd_template += ' $branch_name'
            cmd_params['branch_name'] = branch_name
        else:
            rev_filter = _git_path = settings.GIT_REV_FILTER
            cmd_template += ' %s' % (rev_filter)

        cmd = string.Template(cmd_template).safe_substitute(**cmd_params)
        revs = self.run_git_command(cmd)[0].splitlines()
        start_pos = 0
        end_pos = len(revs)
        if start:
            _start = self._get_revision(start)
            try:
                start_pos = revs.index(_start)
            except ValueError:
                pass

        if end is not None:
            _end = self._get_revision(end)
            try:
                end_pos = revs.index(_end)
            except ValueError:
                pass

        if None not in [start, end] and start_pos > end_pos:
            raise RepositoryError('start cannot be after end')

        if end_pos is not None:
            end_pos += 1

        revs = revs[start_pos:end_pos]
        if reverse:
            revs = reversed(revs)
        return CollectionGenerator(self, revs)
Esempio n. 14
0
    def commit(self,
               message,
               author,
               parents=None,
               branch=None,
               date=None,
               **kwargs):
        """
        Performs in-memory commit (doesn't check workdir in any way) and
        returns newly created ``Changeset``. Updates repository's
        ``revisions``.

        :param message: message of the commit
        :param author: full username, i.e. "Joe Doe <*****@*****.**>"
        :param parents: single parent or sequence of parents from which commit
          would be derieved
        :param date: ``datetime.datetime`` instance. Defaults to
          ``datetime.datetime.now()``.
        :param branch: branch name, as string. If none given, default backend's
          branch would be used.

        :raises ``CommitError``: if any error occurs while committing
        """
        self.check_integrity(parents)

        from .repository import MercurialRepository
        if not isinstance(message, unicode) or not isinstance(author, unicode):
            raise RepositoryError('Given message and author needs to be '
                                  'an <unicode> instance got %r & %r instead' %
                                  (type(message), type(author)))

        if branch is None:
            branch = MercurialRepository.DEFAULT_BRANCH_NAME
        kwargs['branch'] = branch

        def filectxfn(_repo, memctx, path):
            """
            Marks given path as added/changed/removed in a given _repo. This is
            for internal mercurial commit function.
            """

            # check if this path is removed
            if path in (node.path for node in self.removed):
                # Raising exception is a way to mark node for removal
                raise IOError(errno.ENOENT, '%s is deleted' % path)

            # check if this path is added
            for node in self.added:
                if node.path == path:
                    return memfilectx(
                        path=node.path,
                        data=(node.content.encode('utf8')
                              if not node.is_binary else node.content),
                        islink=False,
                        isexec=node.is_executable,
                        copied=False)

            # or changed
            for node in self.changed:
                if node.path == path:
                    return memfilectx(
                        path=node.path,
                        data=(node.content.encode('utf8')
                              if not node.is_binary else node.content),
                        islink=False,
                        isexec=node.is_executable,
                        copied=False)

            raise RepositoryError("Given path haven't been marked as added,"
                                  "changed or removed (%s)" % path)

        parents = [None, None]
        for i, parent in enumerate(self.parents):
            if parent is not None:
                parents[i] = parent._ctx.node()

        if date and isinstance(date, datetime.datetime):
            date = date.ctime()

        commit_ctx = memctx(repo=self.repository._repo,
                            parents=parents,
                            text='',
                            files=self.get_paths(),
                            filectxfn=filectxfn,
                            user=author,
                            date=date,
                            extra=kwargs)

        loc = lambda u: tolocal(u.encode('utf-8'))

        # injecting given _repo params
        commit_ctx._text = loc(message)
        commit_ctx._user = loc(author)
        commit_ctx._date = date

        # TODO: Catch exceptions!
        n = self.repository._repo.commitctx(commit_ctx)
        # Returns mercurial node
        self._commit_ctx = commit_ctx  # For reference
        # Update vcs repository object & recreate mercurial _repo
        # new_ctx = self.repository._repo[node]
        # new_tip = self.repository.get_changeset(new_ctx.hex())
        new_id = hex(n)
        self.repository.revisions.append(new_id)
        self._repo = self.repository._get_repo(create=False)
        self.repository.branches = self.repository._get_branches()
        tip = self.repository.get_changeset()
        self.reset()
        return tip