diff --git a/pylons_app/config/routing.py b/pylons_app/config/routing.py --- a/pylons_app/config/routing.py +++ b/pylons_app/config/routing.py @@ -171,7 +171,11 @@ def make_map(config): controller='settings', action='index', conditions=dict(function=check_repo)) + map.connect('repo_fork_create_home', '/{repo_name:.*}/fork', + controller='settings', action='fork_create', + conditions=dict(function=check_repo, method=["POST"])) map.connect('repo_fork_home', '/{repo_name:.*}/fork', controller='settings', action='fork', - conditions=dict(function=check_repo)) + conditions=dict(function=check_repo)) + return map diff --git a/pylons_app/controllers/settings.py b/pylons_app/controllers/settings.py --- a/pylons_app/controllers/settings.py +++ b/pylons_app/controllers/settings.py @@ -29,7 +29,7 @@ from pylons.i18n.translation import _ from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAllDecorator from pylons_app.lib.base import BaseController, render from pylons_app.lib.utils import invalidate_cache -from pylons_app.model.forms import RepoSettingsForm +from pylons_app.model.forms import RepoSettingsForm, RepoForkForm from pylons_app.model.repo_model import RepoModel import formencode import logging @@ -140,5 +140,33 @@ class SettingsController(BaseController) ' in order to rescan repositories') % repo_name, category='error') - return redirect(url('hg_home')) + return redirect(url('hg_home')) + return render('settings/repo_fork.html') + + + + def fork_create(self, repo_name): + repo_model = RepoModel() + c.repo_info = repo_model.get(repo_name) + _form = RepoForkForm()() + form_result = {} + try: + form_result = _form.to_python(dict(request.POST)) + form_result.update({'repo_name':repo_name}) + repo_model.create_fork(form_result, c.hg_app_user) + h.flash(_('fork %s repository as %s task added') \ + % (repo_name, form_result['fork_name']), + category='success') + + except formencode.Invalid as errors: + c.new_repo = errors.value['fork_name'] + r = render('settings/repo_fork.html') + + return htmlfill.render( + r, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8") + return redirect(url('hg_home')) diff --git a/pylons_app/lib/celerylib/tasks.py b/pylons_app/lib/celerylib/tasks.py --- a/pylons_app/lib/celerylib/tasks.py +++ b/pylons_app/lib/celerylib/tasks.py @@ -271,6 +271,24 @@ def send_email(recipients, subject, body return False return True +@task +def create_repo_fork(form_data, cur_user): + import os + from pylons_app.lib.utils import invalidate_cache + from pylons_app.model.repo_model import RepoModel + sa = get_session() + rm = RepoModel(sa) + + rm.create(form_data, cur_user, just_db=True, fork=True) + + repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '') + repo_path = os.path.join(repos_path, form_data['repo_name']) + repo_fork_path = os.path.join(repos_path, form_data['fork_name']) + + MercurialRepository(str(repo_fork_path), True, clone_url=str(repo_path)) + #invalidate_cache('cached_repo_list') + + def __get_codes_stats(repo_name): LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx', 'aspx', 'asx', 'axd', 'c', 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el', 'erl', diff --git a/pylons_app/model/db.py b/pylons_app/model/db.py --- a/pylons_app/model/db.py +++ b/pylons_app/model/db.py @@ -81,8 +81,10 @@ class Repository(Base): user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None) private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None) description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None) user = relation('User') + fork = relation('Repository', remote_side=repo_id) repo_to_perm = relation('RepoToPerm', cascade='all') def __repr__(self): diff --git a/pylons_app/model/forms.py b/pylons_app/model/forms.py --- a/pylons_app/model/forms.py +++ b/pylons_app/model/forms.py @@ -307,6 +307,16 @@ def RepoForm(edit=False, old_data={}): chained_validators = [ValidPerms] return _RepoForm +def RepoForkForm(edit=False, old_data={}): + class _RepoForkForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + fork_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data)) + description = UnicodeString(strip=True, min=1, not_empty=True) + private = StringBoolean(if_missing=False) + + return _RepoForkForm + def RepoSettingsForm(edit=False, old_data={}): class _RepoForm(formencode.Schema): allow_extra_fields = True diff --git a/pylons_app/model/repo_model.py b/pylons_app/model/repo_model.py --- a/pylons_app/model/repo_model.py +++ b/pylons_app/model/repo_model.py @@ -27,6 +27,7 @@ from pylons_app.lib.utils import check_r from pylons_app.model.db import Repository, RepoToPerm, User, Permission from pylons_app.model.meta import Session from pylons_app.model.user_model import UserModel +from pylons_app.lib.celerylib.tasks import create_repo_fork, run_task import logging import os import shutil @@ -35,11 +36,15 @@ log = logging.getLogger(__name__) class RepoModel(object): - def __init__(self): - self.sa = Session() + def __init__(self, sa=None): + if not sa: + self.sa = Session() + else: + self.sa = sa def get(self, id): - return self.sa.query(Repository).filter(Repository.repo_name == id).scalar() + return self.sa.query(Repository)\ + .filter(Repository.repo_name == id).scalar() def get_users_js(self): @@ -100,20 +105,32 @@ class RepoModel(object): self.sa.rollback() raise - def create(self, form_data, cur_user, just_db=False): + def create(self, form_data, cur_user, just_db=False, fork=False): try: - repo_name = form_data['repo_name'] + if fork: + repo_name = str(form_data['fork_name']) + org_name = str(form_data['repo_name']) + + else: + org_name = repo_name = str(form_data['repo_name']) new_repo = Repository() for k, v in form_data.items(): + if k == 'repo_name': + v = repo_name setattr(new_repo, k, v) + if fork: + parent_repo = self.sa.query(Repository)\ + .filter(Repository.repo_name == org_name).scalar() + new_repo.fork = parent_repo + new_repo.user_id = cur_user.user_id self.sa.add(new_repo) #create default permission repo_to_perm = RepoToPerm() default = 'repository.read' - for p in UserModel().get_default().user_perms: + for p in UserModel(self.sa).get_default().user_perms: if p.permission.permission_name.startswith('repository.'): default = p.permission.permission_name break @@ -136,7 +153,10 @@ class RepoModel(object): log.error(traceback.format_exc()) self.sa.rollback() raise - + + def create_fork(self, form_data, cur_user): + run_task(create_repo_fork, form_data, cur_user) + def delete(self, repo): try: self.sa.delete(repo) diff --git a/pylons_app/model/user_model.py b/pylons_app/model/user_model.py --- a/pylons_app/model/user_model.py +++ b/pylons_app/model/user_model.py @@ -36,8 +36,11 @@ class DefaultUserException(Exception):pa class UserModel(object): - def __init__(self): - self.sa = Session() + def __init__(self, sa=None): + if not sa: + self.sa = Session() + else: + self.sa = sa def get_default(self): return self.sa.query(User).filter(User.username == 'default').scalar() diff --git a/pylons_app/templates/settings/repo_fork.html b/pylons_app/templates/settings/repo_fork.html --- a/pylons_app/templates/settings/repo_fork.html +++ b/pylons_app/templates/settings/repo_fork.html @@ -20,7 +20,7 @@
${self.breadcrumbs()}
- ${h.form(url('repos'))} + ${h.form(url('repo_fork_create_home',repo_name=c.repo_info.repo_name))}
@@ -49,7 +49,7 @@
- ${h.submit('fork','fork this repository',class_="ui-button ui-widget ui-state-default ui-corner-all")} + ${h.submit('','fork this repository',class_="ui-button ui-widget ui-state-default ui-corner-all")}