Changeset 73:06bfa9e5819c in repositorymanagerplugin


Ignore:
Timestamp:
15.05.2015 16:21:46 (4 years ago)
Author:
Tobias Föhst <foehst@…>
Branch:
default
Phase:
public
Tags:
tip
Message:

Adds support for deleting and banning changesets from managed repositories

Location:
repo_mgr
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • repo_mgr/api.py

    r72 r73  
    4343        """Return whether forking is supported by the connector.""" 
    4444 
     45    def can_delete_changesets(repository_type): 
     46        """Return whether deleting changesets is supported.""" 
     47 
     48    def can_ban_changesets(repository_type): 
     49        """Return whether banning changesets is supported.""" 
     50 
    4551    def create(repository): 
    4652        """Create a new empty repository with given attributes.""" 
     
    4854    def fork(repository): 
    4955        """Fork from `origin_url` in the given dict.""" 
     56 
     57    def delete_changeset(repository, revision, ban): 
     58        """Delete (and optionally ban) a changeset from the repository.""" 
    5059 
    5160    def update_auth_files(repositories): 
     
    104113        """Return whether the given repository type can be forked.""" 
    105114        return self._get_repository_connector(type).can_fork(type) 
     115 
     116    def can_delete_changesets(self, type): 
     117        """Return whether the given repository type can delete changesets.""" 
     118        return self._get_repository_connector(type).can_delete_changesets(type) 
     119 
     120    def can_ban_changesets(self, type): 
     121        """Return whether the given repository type can ban changesets.""" 
     122        return self._get_repository_connector(type).can_ban_changesets(type) 
    106123 
    107124    def get_forkable_repositories(self): 
     
    259276        self.update_auth_files() 
    260277 
     278    def delete_changeset(self, repo, rev, ban): 
     279        """Delete a changeset from a managed repository, if supported. 
     280 
     281        Depending on the parameter ban this method also marks the 
     282        changeset to be kept out of the repository. That features needs 
     283        special support by the used scm. 
     284        """ 
     285        convert_managed_repository(self.env, repo) 
     286        self._get_repository_connector(repo.type).delete_changeset(repo, rev, ban) 
     287 
    261288    def add_role(self, repo, role, subject): 
    262289        """Add a role for the given repository.""" 
  • repo_mgr/versioncontrol/hg.py

    r70 r73  
    1919        return True 
    2020 
     21    def can_delete_changesets(self, type): 
     22        return True 
     23 
     24    def can_ban_changesets(self, type): 
     25        try: 
     26            import hgban 
     27            return True 
     28        except: 
     29            return False 
     30 
    2131    def create(self, repo): 
    2232        try: 
     
    3141        except Exception, e: 
    3242            raise TracError(_("Failed to clone repository: ") + str(e)) 
     43 
     44    def delete_changeset(self, repo, rev, ban): 
     45        try: 
     46            from mercurial import ui, hg, repair 
     47            hg_repo = hg.repository(ui.ui(), repo.directory) 
     48            repair.strip(ui.ui(), hg_repo, [ hg_repo[rev].node() ], None) 
     49        except Exception, e: 
     50            raise TracError(_("Failed to strip changesets from repository: ") + str(e)) 
     51 
     52        if ban: 
     53            try: 
     54                import hgban 
     55            except: 
     56                raise TracError(_("Could not import the hgban extension")) 
     57            hgrc_path = os.path.join(repo.directory, '.hg/hgrc') 
     58 
     59            hgrc = ConfigParser() 
     60            hgrc.read(hgrc_path) 
     61 
     62            if not hgrc.has_section('extensions'): 
     63                hgrc.add_section('extensions') 
     64            hgrc.set('extensions', 'hgban', '') 
     65 
     66            revsets = '' 
     67            if hgrc.has_section('hgban'): 
     68                revsets = hgrc.get('hgban', 'revsets') 
     69            else: 
     70                hgrc.add_section('hgban') 
     71            hgrc.set('hgban', 'revsets', revsets  + "\n" + rev) 
     72 
     73            with open(hgrc_path, 'wb') as hgrc_file: 
     74                hgrc.write(hgrc_file) 
     75                try: 
     76                    modes = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP 
     77                    os.chmod(hgrc_path, modes) 
     78                except: 
     79                    pass 
    3380 
    3481    def update_auth_files(self, repositories): 
  • repo_mgr/versioncontrol/svn.py

    r62 r73  
    4242 
    4343    def can_fork(self, type): 
     44        return False 
     45 
     46    def can_delete_changesets(self, type): 
     47        return False 
     48 
     49    def can_ban_changesets(self, type): 
    4450        return False 
    4551 
  • repo_mgr/web_ui.py

    r72 r73  
    497497    except: 
    498498        pass 
     499 
     500class ChangesetModule(Component): 
     501    """Supports deleting and banning of changesets from managed repositories""" 
     502 
     503    implements(IPermissionRequestor, IRequestFilter, IRequestHandler, ITemplateProvider) 
     504 
     505    ### IPermissionRequestor methods 
     506    def get_permission_actions(self): 
     507        return ['CHANGESET_DELETE'] 
     508 
     509    ### IRequestFilter methods 
     510    def pre_process_request(self, req, handler): 
     511        return handler 
     512 
     513    def post_process_request(self, req, template, data, content_type): 
     514        match = re.match(r'^/changeset', req.path_info) 
     515        if 'CHANGESET_DELETE' in req.perm and match: 
     516            rev = req.args.get('new') 
     517            path = req.args.get('new_path') 
     518 
     519            rm = RepositoryManager(self.env) 
     520            if rev and path: 
     521                reponame, repos, path = rm.get_repository_by_path(path) 
     522                convert_managed_repository(self.env, repos) 
     523                if (path == '/' and (repos.owner == req.authname or 
     524                                     'REPOSITORY_ADMIN' in req.perm) 
     525                    and rm.can_delete_changesets(repos.type)): 
     526                    add_ctxtnav(req, _("Delete Changeset"), 
     527                                req.href.deletechangeset(rev, reponame)) 
     528 
     529        return template, data, content_type 
     530 
     531    ### IRequestHandler methods 
     532    def match_request(self, req): 
     533        match = re.match(r'^/deletechangeset/([^/]+)/(.+)$', req.path_info) 
     534        if match: 
     535            rev, reponame = match.groups() 
     536            req.args['rev'] = rev 
     537            req.args['reponame'] = reponame 
     538            return True 
     539 
     540    def process_request(self, req): 
     541        req.perm.require('CHANGESET_DELETE') 
     542 
     543        rm = RepositoryManager(self.env) 
     544        repos = rm.get_repository(req.args['reponame'], True) 
     545        if not repos: 
     546            raise TracError(_('Repository "%(name)s" does not exist.', 
     547                              name=req.args['reponame'])) 
     548 
     549        if not (repos.owner == req.authname or 
     550                'REPOSITORY_ADMIN' in req.perm): 
     551            message = _('You (%(user)s) are not the owner of "%(name)s"', 
     552                        user=req.authname, name=repos.reponame) 
     553            raise PermissionError(message) 
     554 
     555        if req.args.get('confirm'): 
     556            display_rev = repos.display_rev(req.args['rev']) 
     557            rm.delete_changeset(repos, req.args['rev'], req.args.get('ban')) 
     558            add_notice(req, _('The changeset "%(rev)s" has been removed.', 
     559                              rev=display_rev)) 
     560            req.redirect(req.href.log(repos.reponame)) 
     561        elif req.args.get('cancel'): 
     562            LoginModule(self.env)._redirect_back(req) 
     563 
     564        data = {'repository': repos, 
     565                'rev': req.args['rev'], 
     566                'cannot_ban': not rm.can_ban_changesets(repos.type)} 
     567 
     568        add_stylesheet(req, 'common/css/admin.css') 
     569        return 'changeset_delete.html', data, None 
     570 
     571    ### ITemplateProvider methods 
     572    def get_templates_dirs(self): 
     573        from pkg_resources import resource_filename 
     574        return [resource_filename(__name__, 'templates')] 
     575 
     576    def get_htdocs_dirs(self): 
     577        return [] 
Note: See TracChangeset for help on using the changeset viewer.