Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit 988faed744ec8cd86c269cf71a9235b0e6eaec7b
Author: Miroslav Suchý <msuchy(a)redhat.com>
Date: Thu Nov 28 16:34:42 2013 +0100
initial support for SCL
add column copr_chroot.buildroot_pkgs
pass it to backend job
backend - modify mock config to include those packages in minimal buildroot
frontend - allow to add packages to chroot
---------------------------------------------------------------
backend/dispatcher.py | 3 +-
backend/mockremote.py | 21 +++++++-
.../versions/3a415c6392bc_add_buildroot_pkgs_c.py | 22 +++++++++
coprs_frontend/coprs/__init__.py | 1 +
coprs_frontend/coprs/forms.py | 4 ++
coprs_frontend/coprs/logic/coprs_logic.py | 8 +++
coprs_frontend/coprs/models.py | 20 ++++++++
.../coprs/templates/coprs/_coprs_forms.html | 12 ++++-
.../coprs/templates/coprs/detail/edit2.html | 13 +++++
.../coprs/templates/coprs/detail/edit_chroot.html | 19 +++++++
.../coprs/views/backend_ns/backend_general.py | 1 +
.../coprs/views/coprs_ns/coprs_chroots.py | 50 ++++++++++++++++++++
12 files changed, 169 insertions(+), 5 deletions(-)
diff --git a/backend/dispatcher.py b/backend/dispatcher.py
index e194d8d..5e1e496 100644
--- a/backend/dispatcher.py
+++ b/backend/dispatcher.py
@@ -214,6 +214,7 @@ class Worker(multiprocessing.Process):
jobdata.pkgs = build['pkgs'].split(' ')
jobdata.repos = [r for r in build['repos'].split(' ') if
r.strip() ]
jobdata.chroot = build['chroot']
+ jobdata.buildroot_pkgs = build['buildroot_pkgs']
jobdata.memory_reqs = build['memory_reqs']
jobdata.timeout = build['timeout']
jobdata.destdir = os.path.normpath(self.opts.destdir + '/' +
build['copr']['owner']['name'] + '/' +
build['copr']['name'])
@@ -354,7 +355,7 @@ class Worker(multiprocessing.Process):
'copr_projectname': job.copr_name}
mr = mockremote.MockRemote(builder=ip, timeout=job.timeout,
destdir=job.destdir, chroot=job.chroot, cont=True,
recurse=True,
- repos=chroot_repos, macros=macros,
+ repos=chroot_repos, macros=macros,
buildroot_pkgs=job.buildroot_pkgs,
callback=mockremote.CliLogCallBack(quiet=True,logfn=chrootlogfile))
mr.build_pkgs(job.pkgs)
except mockremote.MockRemoteError, e:
diff --git a/backend/mockremote.py b/backend/mockremote.py
index 4d8d160..a968e03 100755
--- a/backend/mockremote.py
+++ b/backend/mockremote.py
@@ -49,6 +49,7 @@ DEF_CHROOT = None
DEF_USER = 'mockbuilder'
DEF_DESTDIR = os.getcwd()
DEF_MACROS = {}
+DEF_BUILDROOT_PKGS = ''
class SortedOptParser(optparse.OptionParser):
'''Optparser which sorts the options by opt before outputting
--help'''
@@ -212,13 +213,14 @@ class CliLogCallBack(DefaultCallBack):
print msg
class Builder(object):
- def __init__(self, hostname, username, timeout, mockremote):
+ def __init__(self, hostname, username, timeout, mockremote, buildroot_pkgs):
self.hostname = hostname
self.username = username
self.timeout = timeout
self.chroot = mockremote.chroot
self.repos = mockremote.repos
self.mockremote = mockremote
+ self.buildroot_pkgs = buildroot_pkgs
self.checked = False
self._tempdir = None
# if we're at this point we've connected and done stuff on the host
@@ -269,6 +271,17 @@ class Builder(object):
remote_pkg_dir = os.path.normpath(self.remote_build_dir + '/results/' +
self.chroot + '/' + pdn)
return remote_pkg_dir
+ def modify_base_buildroot(self):
+ """ modify mock config for current chroot
+
+ packages in buildroot_pkgs are added to minimal buildroot """
+ command = 'sed -i
"1,\$s/config_opts\[\'chroot_setup_cmd\'\].*/config_opts\[\'chroot_setup_cmd\'\]
= \'install @build %s\'/" /etc/mock/%s.cfg' % (self.buildroot_pkgs,
self.chroot)
+ self.mockremote.callback.log('executing: %r' % command)
+ self.conn.module_name = "shell"
+ self.conn.module_args = command
+ # FIXME should probably check this but <shrug>
+ results = self.conn.run()
+
def build(self, pkg):
# build the pkg passed in
@@ -278,6 +291,7 @@ class Builder(object):
# returns success_bool, out, err
success = False
+ self.modify_base_buildroot()
# check if pkg is local or http
dest = None
@@ -407,7 +421,8 @@ class MockRemote(object):
destdir=DEF_DESTDIR, chroot=DEF_CHROOT, cont=False, recurse=False,
repos=DEF_REPOS, callback=None,
remote_basedir=DEF_REMOTE_BASEDIR, remote_tempdir=None,
- macros=DEF_MACROS):
+ macros=DEF_MACROS,
+ buildroot_pkgs=DEF_BUILDROOT_PKGS):
self.destdir = destdir
self.chroot = chroot
@@ -423,7 +438,7 @@ class MockRemote(object):
self.callback = DefaultCallBack()
self.callback.log("Setting up builder: %s" % builder)
- self.builder = Builder(builder, user, timeout, self)
+ self.builder = Builder(builder, user, timeout, self, buildroot_pkgs)
if not self.chroot:
raise MockRemoteError("No chroot specified!")
diff --git a/coprs_frontend/alembic/versions/3a415c6392bc_add_buildroot_pkgs_c.py
b/coprs_frontend/alembic/versions/3a415c6392bc_add_buildroot_pkgs_c.py
new file mode 100644
index 0000000..3da52f0
--- /dev/null
+++ b/coprs_frontend/alembic/versions/3a415c6392bc_add_buildroot_pkgs_c.py
@@ -0,0 +1,22 @@
+"""add buildroot_pkgs column
+
+Revision ID: 3a415c6392bc
+Revises: 52e53e7b413e
+Create Date: 2013-11-28 15:46:24.860025
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '3a415c6392bc'
+down_revision = '52e53e7b413e'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.add_column('copr_chroot', sa.Column('buildroot_pkgs', sa.Text(),
nullable=True))
+
+
+def downgrade():
+ op.drop_column('copr_chroot', 'buildroot_pkgs')
diff --git a/coprs_frontend/coprs/__init__.py b/coprs_frontend/coprs/__init__.py
index bb2157f..47a4411 100644
--- a/coprs_frontend/coprs/__init__.py
+++ b/coprs_frontend/coprs/__init__.py
@@ -37,6 +37,7 @@ from coprs.views.api_ns import api_general
from coprs.views import coprs_ns
from coprs.views.coprs_ns import coprs_builds
from coprs.views.coprs_ns import coprs_general
+from coprs.views.coprs_ns import coprs_chroots
from coprs.views import backend_ns
from coprs.views.backend_ns import backend_general
from coprs.views import misc
diff --git a/coprs_frontend/coprs/forms.py b/coprs_frontend/coprs/forms.py
index b2db8e9..d898654 100644
--- a/coprs_frontend/coprs/forms.py
+++ b/coprs_frontend/coprs/forms.py
@@ -186,6 +186,10 @@ class BuildForm(wtf.Form):
max=constants.MAX_BUILD_TIMEOUT)],
default=constants.DEFAULT_BUILD_TIMEOUT)
+class ChrootForm(wtf.Form):
+ """ Validator for editing chroots in project (adding packages to
minimal chroot) """
+ buildroot_pkgs = wtforms.TextField('Additional packages to be always present in
minimal buildroot')
+
class CoprLegalFlagForm(wtf.Form):
comment = wtforms.TextAreaField('Comment')
diff --git a/coprs_frontend/coprs/logic/coprs_logic.py
b/coprs_frontend/coprs/logic/coprs_logic.py
index 5129a82..a34fd1e 100644
--- a/coprs_frontend/coprs/logic/coprs_logic.py
+++ b/coprs_frontend/coprs/logic/coprs_logic.py
@@ -258,6 +258,14 @@ class CoprChrootsLogic(object):
db.session.add(models.CoprChroot(copr=copr, mock_chroot=mock_chroot))
@classmethod
+ def update_buildroot_pkgs(cls, copr, chroot, buildroot_pkgs):
+ current_chroots = copr.mock_chroots
+ copr_chroot = copr.check_copr_chroot(chroot)
+ if copr_chroot:
+ copr_chroot.buildroot_pkgs = buildroot_pkgs
+ db.session.add(copr_chroot)
+
+ @classmethod
def update_from_names(cls, user, copr, names):
current_chroots = copr.mock_chroots
new_chroots = cls.mock_chroots_from_names(user, names)
diff --git a/coprs_frontend/coprs/models.py b/coprs_frontend/coprs/models.py
index 1ea63b5..e7881c0 100644
--- a/coprs_frontend/coprs/models.py
+++ b/coprs_frontend/coprs/models.py
@@ -183,6 +183,25 @@ class Copr(db.Model, Serializer):
"""Returns list of active mock_chroots of this
copr"""
return filter(lambda x: x.is_active, self.mock_chroots)
+ def check_copr_chroot(self, chroot):
+ """Return object of chroot, if is related to our copr or
None"""
+ result = None
+ # there will be max ~10 chroots per build, iteration will be probably faster than
sql query
+ for copr_chroot in self.copr_chroots:
+ if copr_chroot.mock_chroot_id == chroot.id:
+ result = copr_chroot
+ break
+ return result
+
+ def buildroot_pkgs(self, chroot):
+ """Returns packages in minimal buildroot for given
chroot."""
+ result = ''
+ # this is ugly as user can remove chroot after he submit build, but lets call
this feature
+ copr_chroot = self.check_copr_chroot(chroot)
+ if copr_chroot:
+ result = copr_chroot.buildroot_pkgs
+ return result
+
class CoprPermission(db.Model, Serializer):
"""Association class for Copr<->Permission
relation"""
## see helpers.PermissionEnum for possible values of the fields below
@@ -284,6 +303,7 @@ class MockChroot(db.Model, Serializer):
class CoprChroot(db.Model, Serializer):
"""Representation of Copr<->MockChroot
relation"""
+ buildroot_pkgs = db.Column(db.Text)
mock_chroot_id = db.Column(db.Integer, db.ForeignKey('mock_chroot.id'),
primary_key = True)
mock_chroot = db.relationship('MockChroot', backref =
db.backref('copr_chroots'))
copr_id = db.Column(db.Integer, db.ForeignKey('copr.id'), primary_key =
True)
diff --git a/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
b/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
index 5d2f519..6abe22f 100644
--- a/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
+++ b/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
@@ -29,7 +29,17 @@
<table class="chroots-set">
{% for ch in chs %}
<tr>
- <td>{{ form|attr(ch)|attr('label') }}</td><td>{{
form|attr(ch) }}</td>
+ <td>
+ {{ form|attr(ch)|attr('label') }}
+ {% if form|attr(ch)|attr('label') %}
+ {% else %}
+ {{ form|attr(ch)|attr('label') }}
+ {% endif %}
+ </td><td>{{ form|attr(ch) }}
+ {% if copr and form|attr(ch)|attr('data') %}
+ </td><td><a href="{{
url_for('coprs_ns.chroot_edit', username = copr.owner.name, coprname = copr.name,
chrootname =
form|attr(ch)|attr('label')|attr('text'))}}">[Edit]</a>
+ {% endif %}
+ </td>
</tr>
{% endfor %}
</table>
diff --git a/coprs_frontend/coprs/templates/coprs/detail/edit2.html
b/coprs_frontend/coprs/templates/coprs/detail/edit2.html
new file mode 100644
index 0000000..3127b20
--- /dev/null
+++ b/coprs_frontend/coprs/templates/coprs/detail/edit2.html
@@ -0,0 +1,13 @@
+{% extends "coprs/detail.html" %}
+
+{% block detail_body %}
+
+ <div class="horizontal-menu">
+ <ul>
+ <li class="{% block edit_chroot_selected %}unselected{% endblock
%}">
+ <a href="#">Chroot</a>
+ </li>
+ </ul>
+ </div>
+ {% block detail_body2 %}{% endblock %}
+{% endblock %}
diff --git a/coprs_frontend/coprs/templates/coprs/detail/edit_chroot.html
b/coprs_frontend/coprs/templates/coprs/detail/edit_chroot.html
new file mode 100644
index 0000000..9f0905c
--- /dev/null
+++ b/coprs_frontend/coprs/templates/coprs/detail/edit_chroot.html
@@ -0,0 +1,19 @@
+{% extends "coprs/detail/edit2.html" %}
+{% from "_helpers.html" import render_field %}
+{% block title %}Editing {{ copr.owner.name }}/{{ copr.name }}/{{ chroot.chroot_name }}{%
endblock %}
+{% block edit_selected %}selected{% endblock %}
+{% block edit_chroot_selected %}selected{% endblock %}
+
+{% block detail_body2 %}
+
+ <h2>Edit chroot '{{ chroot.chroot_name }}'</h2>
+ <form action="{{ url_for('coprs_ns.chroot_update', username =
copr.owner.name, coprname = copr.name, chrootname = chroot.chroot_name) }}"
method=post class=add-entry>
+ <dl>
+ {{ form.csrf_token }}
+ {{ render_field(form.buildroot_pkgs, size=80, placeholder='Space separeted list
of packages. E.g.: scl-utils-build rubu193-build') }}
+ <dt><input type="submit"
value="Update"></dt>
+ </dl>
+ </form>
+
+
+{% endblock %}
diff --git a/coprs_frontend/coprs/views/backend_ns/backend_general.py
b/coprs_frontend/coprs/views/backend_ns/backend_general.py
index fbc009a..c76c5fb 100644
--- a/coprs_frontend/coprs/views/backend_ns/backend_general.py
+++ b/coprs_frontend/coprs/views/backend_ns/backend_general.py
@@ -37,6 +37,7 @@ def waiting():
for chroot in build.chroots:
build_dict_copy = build_dict.copy()
build_dict_copy['chroot'] = chroot.chroot_name
+ build_dict_copy['buildroot_pkgs'] =
build.copr.buildroot_pkgs(chroot)
builds_list.append(build_dict_copy)
return flask.jsonify({'actions': actions_list, 'builds':
builds_list})
diff --git a/coprs_frontend/coprs/views/coprs_ns/coprs_chroots.py
b/coprs_frontend/coprs/views/coprs_ns/coprs_chroots.py
new file mode 100644
index 0000000..45baf4a
--- /dev/null
+++ b/coprs_frontend/coprs/views/coprs_ns/coprs_chroots.py
@@ -0,0 +1,50 @@
+import flask
+
+from coprs import db
+from coprs import exceptions
+from coprs import forms
+from coprs import helpers
+from coprs import models
+
+from coprs.logic import builds_logic
+from coprs.logic import coprs_logic
+
+from coprs.views.misc import login_required, page_not_found
+from coprs.views.coprs_ns import coprs_ns
+
+
+@coprs_ns.route('/<username>/<coprname>/edit_chroot/<chrootname>/')
+@login_required
+def chroot_edit(username, coprname, chrootname):
+ copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first()
+ chroot = coprs_logic.MockChrootsLogic.get_from_name(chrootname,
active_only=True).first()
+ if not copr:
+ return page_not_found('Project with name {0} does not
exist.'.format(coprname))
+ if not chroot:
+ return page_not_found('Chroot name {0} does not
exist.'.format(chrootname))
+ form = forms.ChrootForm(buildroot_pkgs=copr.buildroot_pkgs(chroot))
+ #FIXME - test if chroot belongs to copr
+ if flask.g.user.can_build_in(copr):
+ return flask.render_template('coprs/detail/edit_chroot.html', form=form,
copr=copr, chroot=chroot)
+ else:
+ return page_not_found("You are not allowed to modify chroots in project
${0}." % coprname)
+
+@coprs_ns.route('/<username>/<coprname>/update_chroot/<chrootname>/',
methods=['POST'])
+@login_required
+def chroot_update(username, coprname, chrootname):
+ form = forms.ChrootForm()
+ copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first()
+ chroot = coprs_logic.MockChrootsLogic.get_from_name(chrootname,
active_only=True).first()
+ if not copr: # hey, this Copr doesn't exist
+ return page_not_found('Projec with name {0} does not
exist.'.format(coprname))
+ if form.validate_on_submit() and flask.g.user.can_build_in(copr):
+ coprs_logic.CoprChrootsLogic.update_buildroot_pkgs(copr, chroot,
form.buildroot_pkgs.data)
+ flask.flash("Buildroot {0} for project {1} was
updated".format(chrootname, coprname))
+ db.session.commit()
+
+ return flask.redirect(flask.url_for('coprs_ns.copr_edit', username =
username, coprname = copr.name))
+ else:
+ if form.validate_on_submit():
+ flask.flash("You are not allowed to modify chroots.")
+ else:
+ return chroot_edit(username, coprname, chrootname)