repositories: enabled support for maintenance commands.
- maintenance commands does things like git gc or mercurial verify to check integrity of repositories.
This commit is contained in:
parent
e959f4e89a
commit
8f4818db12
8 changed files with 294 additions and 1 deletions
33
rhodecode/apps/repository/__init__.py
Normal file
33
rhodecode/apps/repository/__init__.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2016-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
||||
config.add_route(
|
||||
name='repo_maintenance',
|
||||
pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True)
|
||||
|
||||
config.add_route(
|
||||
name='repo_maintenance_execute',
|
||||
pattern='/{repo_name:.*?[^/]}/maintenance/execute', repo_route=True)
|
||||
|
||||
# Scan module for configuration decorators.
|
||||
config.scan()
|
||||
19
rhodecode/apps/repository/views/__init__.py
Normal file
19
rhodecode/apps/repository/views/__init__.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2011-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
70
rhodecode/apps/repository/views/repo_maintainance.py
Normal file
70
rhodecode/apps/repository/views/repo_maintainance.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2011-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import logging
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
||||
from rhodecode.apps._base import RepoAppView
|
||||
from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator,
|
||||
NotAnonymous)
|
||||
from rhodecode.lib import repo_maintenance
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoMaintenanceView(RepoAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
|
||||
# TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
|
||||
c.repo_info = self.db_repo
|
||||
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator('repository.admin')
|
||||
@view_config(
|
||||
route_name='repo_maintenance', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repos/repo_edit.mako')
|
||||
def repo_maintenance(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'maintenance'
|
||||
maintenance = repo_maintenance.RepoMaintenance()
|
||||
c.executable_tasks = maintenance.get_tasks_for_repo(self.db_repo)
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator('repository.admin')
|
||||
@view_config(
|
||||
route_name='repo_maintenance_execute', request_method='GET',
|
||||
renderer='json', xhr=True)
|
||||
def repo_maintenance_execute(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'maintenance'
|
||||
_ = self.request.translate
|
||||
|
||||
maintenance = repo_maintenance.RepoMaintenance()
|
||||
executed_types = maintenance.execute(self.db_repo)
|
||||
|
||||
return executed_types
|
||||
|
|
@ -288,6 +288,7 @@ def includeme(config):
|
|||
config.include('rhodecode.apps.admin')
|
||||
config.include('rhodecode.apps.channelstream')
|
||||
config.include('rhodecode.apps.login')
|
||||
config.include('rhodecode.apps.repository')
|
||||
config.include('rhodecode.apps.user_profile')
|
||||
config.include('rhodecode.apps.my_account')
|
||||
config.include('rhodecode.apps.svn_support')
|
||||
|
|
|
|||
109
rhodecode/lib/repo_maintenance.py
Normal file
109
rhodecode/lib/repo_maintenance.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2017-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MaintenanceTask(object):
|
||||
human_name = 'undefined'
|
||||
|
||||
def __init__(self, db_repo):
|
||||
self.db_repo = db_repo
|
||||
|
||||
def run(self):
|
||||
"""Execute task and return task human value"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class GitGC(MaintenanceTask):
|
||||
human_name = 'GIT Garbage collect'
|
||||
|
||||
def _count_objects(self, repo):
|
||||
stdout, stderr = repo.run_git_command(
|
||||
['count-objects', '-v'], fail_on_stderr=False)
|
||||
|
||||
errors = ' '
|
||||
objects = ' '.join(stdout.splitlines())
|
||||
|
||||
if stderr:
|
||||
errors = '\nSTD ERR:' + '\n'.join(stderr.splitlines())
|
||||
return objects + errors
|
||||
|
||||
def run(self):
|
||||
output = []
|
||||
instance = self.db_repo.scm_instance()
|
||||
|
||||
objects = self._count_objects(instance)
|
||||
output.append(objects)
|
||||
log.debug('GIT objects:%s', objects)
|
||||
|
||||
stdout, stderr = instance.run_git_command(
|
||||
['gc', '--aggressive'], fail_on_stderr=False)
|
||||
|
||||
out = 'executed git gc --aggressive'
|
||||
if stderr:
|
||||
out = ''.join(stderr.splitlines())
|
||||
|
||||
elif stdout:
|
||||
out = ''.join(stdout.splitlines())
|
||||
|
||||
output.append(out)
|
||||
|
||||
objects = self._count_objects(instance)
|
||||
log.debug('GIT objects:%s', objects)
|
||||
output.append(objects)
|
||||
|
||||
return '\n'.join(output)
|
||||
|
||||
|
||||
class HGVerify(MaintenanceTask):
|
||||
human_name = 'HG Verify repo'
|
||||
|
||||
def run(self):
|
||||
instance = self.db_repo.scm_instance()
|
||||
res = instance.verify()
|
||||
return res
|
||||
|
||||
|
||||
class RepoMaintenance(object):
|
||||
"""
|
||||
Performs maintenance of repository based on it's type
|
||||
"""
|
||||
tasks = {
|
||||
'hg': [HGVerify],
|
||||
'git': [GitGC],
|
||||
'svn': [],
|
||||
}
|
||||
|
||||
def get_tasks_for_repo(self, db_repo):
|
||||
"""
|
||||
fetches human names of tasks pending for execution for given type of repo
|
||||
"""
|
||||
tasks = []
|
||||
for task in self.tasks[db_repo.repo_type]:
|
||||
tasks.append(task.human_name)
|
||||
return tasks
|
||||
|
||||
def execute(self, db_repo):
|
||||
executed_tasks = []
|
||||
for task in self.tasks[db_repo.repo_type]:
|
||||
executed_tasks.append(task(db_repo).run())
|
||||
return executed_tasks
|
||||
|
|
@ -71,6 +71,9 @@
|
|||
<li class="${'active' if c.active=='integrations' else ''}">
|
||||
<a href="${h.route_path('repo_integrations_home', repo_name=c.repo_name)}">${_('Integrations')}</a>
|
||||
</li>
|
||||
<li class="${'active' if c.active=='maintenance' else ''}">
|
||||
<a href="${h.route_path('repo_maintenance', repo_name=c.repo_name)}">${_('Maintenance')}</a>
|
||||
</li>
|
||||
## TODO: dan: replace repo navigation with navlist registry like with
|
||||
## admin menu. First must find way to allow runtime configuration
|
||||
## it to account for the c.repo_info.repo_type != 'svn' call above
|
||||
|
|
|
|||
58
rhodecode/templates/admin/repos/repo_edit_maintenance.mako
Normal file
58
rhodecode/templates/admin/repos/repo_edit_maintenance.mako
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('Maintenance')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<p>
|
||||
% if c.executable_tasks:
|
||||
${_('Perform maintenance tasks for this repo, following tasks will be performed')}:
|
||||
<ol>
|
||||
% for task in c.executable_tasks:
|
||||
<li>${task}</li>
|
||||
% endfor
|
||||
</ol>
|
||||
% else:
|
||||
${_('No maintenance tasks for this repo available')}
|
||||
% endif
|
||||
</p>
|
||||
|
||||
<div id="results" style="display:none; padding: 10px 0px;"></div>
|
||||
|
||||
% if c.executable_tasks:
|
||||
<div class="form">
|
||||
<div class="fields">
|
||||
<button class="btn btn-small btn-primary" onclick="executeTask();return false">
|
||||
${_('Run Maintenance')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
executeTask = function() {
|
||||
var btn = $(this);
|
||||
$('#results').show();
|
||||
$('#results').html('<h4>${_('Performing Maintenance')}...</h4>');
|
||||
|
||||
btn.attr('disabled', 'disabled');
|
||||
btn.addClass('disabled');
|
||||
|
||||
var url = "${h.route_path('repo_maintenance_execute', repo_name=c.repo_info.repo_name)}";
|
||||
var success = function (data) {
|
||||
var displayHtml = $('<pre></pre>');
|
||||
|
||||
$(displayHtml).append(data);
|
||||
$('#results').html(displayHtml);
|
||||
btn.removeAttr('disabled');
|
||||
btn.removeClass('disabled');
|
||||
};
|
||||
ajaxGET(url, success, null);
|
||||
|
||||
}
|
||||
</script>
|
||||
|
|
@ -209,7 +209,7 @@ ${h.end_form()}
|
|||
<%text filter="h">
|
||||
<script>
|
||||
// Server announcement displayed on the top of the page.
|
||||
// This can be used to send a global maintainance messages or other
|
||||
// This can be used to send a global maintenance messages or other
|
||||
// important messages to all users of the RhodeCode Enterprise system.
|
||||
|
||||
$(document).ready(function(e){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue