]> git.ipfire.org Git - pbs.git/commitdiff
Merge branch 'master' of git://git.ipfire.org/pbs
authorJonatan Schlag <jonatan.schlag@ipfire.org>
Wed, 1 Nov 2017 12:01:10 +0000 (13:01 +0100)
committerJonatan Schlag <jonatan.schlag@ipfire.org>
Wed, 1 Nov 2017 12:01:10 +0000 (13:01 +0100)
55 files changed:
Makefile.am
po/POTFILES.in
src/buildservice/__init__.py
src/buildservice/builders.py
src/buildservice/builds.py
src/buildservice/jobqueue.py
src/buildservice/jobs.py
src/buildservice/ldap.py
src/buildservice/packages.py
src/buildservice/repository.py
src/buildservice/sources.py
src/buildservice/users.py
src/database.sql
src/hub/handlers.py
src/static/css/build-table.css
src/static/images/icons/build-dependency_error.png [deleted file]
src/templates/build-detail.html
src/templates/distro-source-commit-detail.html
src/templates/docs-build.html
src/templates/errors/error.html
src/templates/index.html
src/templates/jobs-filter.html [deleted file]
src/templates/jobs-index.html [deleted file]
src/templates/modules/build-table.html
src/templates/modules/changelog/entry.html
src/templates/modules/commit-message.html [new file with mode: 0644]
src/templates/modules/jobs-table.html
src/templates/modules/jobs/list.html
src/templates/modules/link-to-user.html [new file with mode: 0644]
src/templates/modules/log-entry-comment.html
src/templates/modules/log-entry-small.html
src/templates/modules/log-entry.html
src/templates/modules/maintainer.html [deleted file]
src/templates/modules/package-header.html
src/templates/modules/text.html [new file with mode: 0644]
src/templates/package-detail-list.html
src/templates/package-detail.html
src/templates/packages/index.html [moved from src/templates/packages-list.html with 55% similarity]
src/templates/queue.html [new file with mode: 0644]
src/templates/repository-detail.html
src/web/__init__.py
src/web/api.py [moved from src/web/handlers_api.py with 69% similarity]
src/web/auth.py [moved from src/web/handlers_auth.py with 97% similarity]
src/web/base.py
src/web/builders.py [moved from src/web/handlers_builders.py with 87% similarity]
src/web/builds.py [moved from src/web/handlers_builds.py with 90% similarity]
src/web/distributions.py [moved from src/web/handlers_distro.py with 88% similarity]
src/web/handlers.py
src/web/jobs.py [moved from src/web/handlers_jobs.py with 64% similarity]
src/web/keys.py [moved from src/web/handlers_keys.py with 86% similarity]
src/web/packages.py [moved from src/web/handlers_packages.py with 82% similarity]
src/web/search.py [moved from src/web/handlers_search.py with 78% similarity]
src/web/ui_modules.py
src/web/updates.py [moved from src/web/handlers_updates.py with 100% similarity]
src/web/users.py [moved from src/web/handlers_users.py with 94% similarity]

index f01eaaceb6fa56ed758b653f061fd26975ef53de..bc5cd946890770914f3f44544ec1838a9c23d9b2 100644 (file)
@@ -123,22 +123,22 @@ hubdir = $(buildservicedir)/hub
 
 web_PYTHON = \
        src/web/__init__.py \
+       src/web/api.py \
+       src/web/auth.py \
        src/web/base.py \
+       src/web/builders.py \
+       src/web/builds.py \
+       src/web/distributions.py \
        src/web/errors.py \
        src/web/handlers.py \
-       src/web/handlers_api.py \
-       src/web/handlers_auth.py \
-       src/web/handlers_builders.py \
-       src/web/handlers_builds.py \
-       src/web/handlers_distro.py \
-       src/web/handlers_jobs.py \
-       src/web/handlers_keys.py \
-       src/web/handlers_packages.py \
-       src/web/handlers_search.py \
-       src/web/handlers_updates.py \
-       src/web/handlers_users.py \
+       src/web/jobs.py \
+       src/web/keys.py \
        src/web/mirrors.py \
-       src/web/ui_modules.py
+       src/web/packages.py \
+       src/web/search.py \
+       src/web/ui_modules.py \
+       src/web/updates.py \
+       src/web/users.py
 
 webdir = $(buildservicedir)/web
 
@@ -182,8 +182,6 @@ dist_templates_DATA = \
        src/templates/job-schedule-rebuild.html \
        src/templates/job-schedule-test.html \
        src/templates/jobs-detail.html \
-       src/templates/jobs-filter.html \
-       src/templates/jobs-index.html \
        src/templates/keys-delete.html \
        src/templates/keys-import.html \
        src/templates/keys-list.html \
@@ -192,7 +190,7 @@ dist_templates_DATA = \
        src/templates/package-detail.html \
        src/templates/package-detail-list.html \
        src/templates/package-properties.html \
-       src/templates/packages-list.html \
+       src/templates/queue.html \
        src/templates/register-activation-fail.html \
        src/templates/register-activation-success.html \
        src/templates/register-fail.html \
@@ -261,16 +259,17 @@ dist_templates_modules_DATA = \
        src/templates/modules/build-table.html \
        src/templates/modules/comments-table.html \
        src/templates/modules/commits-table.html \
+       src/templates/modules/commit-message.html \
        src/templates/modules/files-table.html \
        src/templates/modules/footer.html \
        src/templates/modules/jobs-table.html \
+       src/templates/modules/link-to-user.html \
        src/templates/modules/log-entry-comment.html \
        src/templates/modules/log-entry.html \
        src/templates/modules/log-entry-small.html \
        src/templates/modules/log-files-table.html \
        src/templates/modules/log.html \
        src/templates/modules/log-table.html \
-       src/templates/modules/maintainer.html \
        src/templates/modules/modal-base.html \
        src/templates/modules/modal-build-comment.html \
        src/templates/modules/modal-build-push.html \
@@ -282,6 +281,7 @@ dist_templates_modules_DATA = \
        src/templates/modules/repo-actions-table.html \
        src/templates/modules/repository-table.html \
        src/templates/modules/source-table.html \
+       src/templates/modules/text.html \
        src/templates/modules/updates-table.html \
        src/templates/modules/user-table.html \
        src/templates/modules/watchers-sidebar-table.html
@@ -314,6 +314,7 @@ templates_modules_selectdir = $(templates_modulesdir)/select
 
 dist_templates_packages_DATA = \
        src/templates/packages/changelog.html \
+       src/templates/packages/index.html \
        src/templates/packages/view-file.html
 
 templates_packagesdir = $(templatesdir)/packages
@@ -363,7 +364,6 @@ dist_static_font_DATA = \
 static_fontdir = $(staticdir)/font
 
 dist_static_images_DATA = \
-       src/static/images/icons/build-dependency_error.png \
        src/static/images/icons/build-dispatching.png \
        src/static/images/icons/build-failed.png \
        src/static/images/icons/build-finished.png \
index e9682c8bbcd7211bd252c3923ff3c76db438fca8..849e14f27198b5e5f428c79acac0c8cbc74161a4 100644 (file)
@@ -71,8 +71,6 @@ src/templates/jobs-buildroot.html
 src/templates/job-schedule-rebuild.html
 src/templates/job-schedule-test.html
 src/templates/jobs-detail.html
-src/templates/jobs-filter.html
-src/templates/jobs-index.html
 src/templates/keys-delete.html
 src/templates/keys-import.html
 src/templates/keys-list.html
@@ -129,8 +127,9 @@ src/templates/package-properties.html
 src/templates/packages/builds/scratch.html
 src/templates/packages/builds/times.html
 src/templates/packages/changelog.html
-src/templates/packages-list.html
+src/templates/packages/index.html
 src/templates/packages/view-file.html
+src/templates/queue.html
 src/templates/register-activation-fail.html
 src/templates/register-activation-success.html
 src/templates/register-fail.html
@@ -158,19 +157,19 @@ src/templates/user-profile-passwd.html
 src/templates/user-profile-passwd-ok.html
 src/hub/handlers.py
 src/hub/__init__.py
-src/web/handlers_api.py
-src/web/handlers_auth.py
-src/web/handlers_base.py
-src/web/handlers_builders.py
-src/web/handlers_builds.py
-src/web/handlers_distro.py
-src/web/handlers_jobs.py
-src/web/handlers_keys.py
-src/web/handlers_packages.py
-src/web/handlers.py
-src/web/handlers_search.py
-src/web/handlers_updates.py
-src/web/handlers_users.py
 src/web/__init__.py
+src/web/api.py
+src/web/auth.py
+src/web/base.py
+src/web/builders.py
+src/web/builds.py
+src/web/distributions.py
+src/web/handlers.py
+src/web/jobs.py
+src/web/keys.py
 src/web/mirrors.py
+src/web/packages.py
+src/web/search.py
 src/web/ui_modules.py
+src/web/updates.py
+src/web/users.py
index a9ee56e7fa8b759283d8f9b9448f7084503fb7aa..a340aa329790d5bfadd5b062ac1473fd33419395 100644 (file)
@@ -6,7 +6,6 @@ import ConfigParser
 import logging
 import os
 import pakfire
-import shutil
 
 from . import arches
 from . import bugtracker
@@ -138,17 +137,37 @@ class Backend(object):
                        WHERE (not_before IS NULL OR not_before <= NOW())")
 
                for row in query:
+                       if not row.path:
+                               continue
+
                        path = row.path
 
-                       if not path or not paths.startswith("%s/" % PAKFIRE_DIR):
+                       if not path or not path.startswith("%s/" % PAKFIRE_DIR):
                                log.warning("Cannot delete file outside of the tree")
                                continue
 
                        try:
                                logging.debug("Removing %s..." % path)
-                               shutil.rmtree(path)
-                       except shutil.Error as e:
+                               os.unlink(path)
+                       except OSError, e:
                                logging.error("Could not remove %s: %s" % (path, e))
-                               continue
+
+                       while True:                     
+                               path = os.path.dirname(path)
+
+                               # Stop if we are running outside of the tree.
+                               if not path.startswith(PAKFIRE_DIR):
+                                       break
+
+                               # If the directory is not empty, we cannot remove it.
+                               if os.path.exists(path) and os.listdir(path):
+                                       break
+
+                               try:
+                                       logging.debug("Removing %s..." % path)
+                                       os.rmdir(path)
+                               except OSError, e:
+                                       logging.error("Could not remove %s: %s" % (path, e))
+                                       break
 
                        self.db.execute("DELETE FROM queue_delete WHERE id = %s", row.id)
index 861e324e2651f6370881a9c9544e3650f41dbd9b..a2168207a8ba4fc90a810c553ce0666d2b634d3b 100644 (file)
@@ -76,6 +76,18 @@ class Builders(base.Object):
                return self._get_builder("SELECT * FROM builders \
                        WHERE name = %s AND deleted IS FALSE", name)
 
+       def get_for_arch(self, arch):
+               # noarch can be built on any builder
+               if arch == "noarch":
+                       return self
+
+               builds = self._get_builders("SELECT builders.* FROM builders \
+                       LEFT JOIN arches_compat ON builders.cpu_arch = arches_compat.native_arch \
+                       WHERE (builders.cpu_arch = %s OR arches_compat.build_arch = %s) \
+                       AND builders.deleted IS FALSE", arch, arch)
+
+               return builds
+
        def get_history(self, limit=None, offset=None, builder=None, user=None):
                query = "SELECT * FROM builders_history"
                args  = []
@@ -162,6 +174,12 @@ class Builder(base.DataObject):
 
        description = property(lambda s: s.data.description or "", set_description)
 
+       def is_online(self):
+               """
+                       Returns True if the builder is online
+               """
+               return self.keepalive >= datetime.datetime.utcnow() - datetime.timedelta(minutes=1)
+
        @property
        def keepalive(self):
                """
@@ -247,6 +265,20 @@ class Builder(base.DataObject):
        def passphrase(self):
                return self.data.passphrase
 
+       @property
+       def performance_index(self):
+               """
+                       Returns a number that determines how "fast" the builder is
+               """
+               # XXX needs to be something better
+               index = self.cpu_bogomips
+
+               # We devide the performance index by the number of already running
+               # builds to avoid that the fastest builder always gets all the jobs
+               index /= len(self.active_jobs) + 1
+
+               return index
+
        # Load average
 
        @property
@@ -351,8 +383,12 @@ class Builder(base.DataObject):
                return "online"
 
        @lazy_property
-       def active_jobs(self, *args, **kwargs):
-               return self.pakfire.jobs.get_active(builder=self, *args, **kwargs)
+       def active_jobs(self):
+               jobs = self.backend.jobs._get_jobs("SELECT jobs.* FROM jobs \
+                       WHERE time_started IS NOT NULL AND time_finished IS NULL \
+                       AND builder_id = %s ORDER BY time_started", self.id)
+
+               return list(jobs)
 
        @property
        def too_many_jobs(self):
@@ -375,13 +411,24 @@ class Builder(base.DataObject):
 
                # Don't return anything if the builder has already too many jobs running
                if self.too_many_jobs:
+                       logging.debug("%s has too many jobs running" % self)
                        return
 
                for job in self.jobqueue:
+                       logging.debug("Looking at %s..." % job)
                        # Only allow building test jobs in test mode
                        if self.testmode and not job.test:
                                continue
 
+                       # If we are the fastest builder to handle this job, we will
+                       # get it.
+                       if job.candidate_builders:
+                               fastest_builder = job.candidate_builders.pop(0)
+
+                               if not self == fastest_builder:
+                                       logging.debug("We are not the fastest builder for this job (%s is)" % fastest_builder)
+                                       continue
+
                        return job
 
        def get_history(self, *args, **kwargs):
index 7715abb58f21dc4c432774ac2e300701786242a8..ae19952bbe0a01dfc5f9f8bb34cc8a4de94b2ef4 100644 (file)
@@ -213,9 +213,6 @@ class Builds(base.Object):
                # Obsolete all other builds with the same name to track updates.
                build.obsolete_others()
 
-               # Search for possible bug IDs in the commit message.
-               build.search_for_bugs()
-
                return build
 
        def create_from_source_package(self, filename, distro, commit=None, type="release",
@@ -240,6 +237,15 @@ class Builds(base.Object):
                # Create a new build object from the package
                build = self.create(pkg, type=type, owner=owner, distro=distro)
 
+               if commit:
+                       # Import any fixed bugs
+                       for bug in commit.fixed_bugs:
+                               build.add_bug(bug)
+
+                       # Upvote the build for the testers
+                       for tester in commit.testers:
+                               build.upvote(tester)
+
                # Create all automatic jobs
                build.create_autojobs(arches=arches)
 
@@ -537,7 +543,7 @@ class Build(base.DataObject):
                        remove = True
 
                        for job in self.jobs:
-                               if job.state in ("new", "pending", "running", "dependency_error"):
+                               if job.state in ("pending", "running"):
                                        job.state = "aborted"
 
                # If this build is in a repository, it will leave it.
@@ -588,9 +594,6 @@ class Build(base.DataObject):
                if self.pkg and self.pkg.commit:
                        return self.pkg.commit
 
-       def update_message(self, message):
-               self._set_attribute("message", message)
-
        def has_perm(self, user):
                """
                        Check, if the given user has the right to perform administrative
@@ -843,6 +846,14 @@ class Build(base.DataObject):
 
                return res.score or 0
 
+       def upvote(self, user, score=1):
+               # Creates an empty comment with a score
+               self.db.execute("INSERT INTO builds_comments(build_id, user_id, score) \
+                       VALUES(%s, %s, %s)", self.id, user.id, score)
+
+               # Update cache
+               self.score += score
+
        def get_commenters(self):
                users = self.db.query("SELECT DISTINCT users.id AS id FROM builds_comments \
                        JOIN users ON builds_comments.user_id = users.id \
@@ -1004,12 +1015,8 @@ class Build(base.DataObject):
 
                query = self.db.get("SELECT NOW() - time_added AS duration FROM repositories_builds \
                        WHERE build_id = %s", self.id)
-               duration = query.duration
 
-               if duration >= self.repo.time_min:
-                       return True
-
-               return False
+               return query.duration.total_seconds() >= self.repo.time_min
 
        ## Bugs
 
@@ -1039,26 +1046,6 @@ class Build(base.DataObject):
                if log:
                        self.log("bug_removed", user=user, bug_id=bug_id)
 
-       def search_for_bugs(self):
-               if not self.commit:
-                       return
-
-               pattern = re.compile(r"(bug\s?|#)(\d+)")
-
-               for txt in (self.commit.subject, self.commit.message):
-                       for bug in re.finditer(pattern, txt):
-                               try:
-                                       bugid = int(bug.group(2))
-                               except ValueError:
-                                       continue
-
-                               # Check if a bug with the given ID exists in BZ.
-                               bug = self.backend.bugzilla.get_bug(bugid)
-                               if not bug:
-                                       continue
-
-                               self.add_bug(bugid)
-
        def get_bugs(self):
                bugs = []
                for bug_id in self.get_bug_ids():
index 5259ca111c43d52664f0cab7e680a44db8c57392..743f5f9f169256ef1640b6bf0d6d0363ca9464c8 100644 (file)
@@ -79,12 +79,20 @@ class JobQueue(base.Object):
                                                break
 
        def check_build_dependencies(self):
-               jobs = self.backend.jobs._get_jobs("SELECT * FROM jobs \
-                       WHERE state = 'new' OR \
-                               (state = 'dependency_error' AND time_finished < NOW() - '5 minutes'::interval) \
-                       ORDER BY time_finished LIMIT 50")
+               # Check all jobs that have never being checked before
+               self._check_build_dependencies("SELECT * FROM jobs \
+                       WHERE state = %s AND dependency_check_succeeded IS NULL \
+                       ORDER BY time_created", "pending")
+
+               # Redo the check for all jobs that have recently failed
+               self._check_build_dependencies("SELECT * FROM jobs \
+                       WHERE state = %s AND dependency_check_succeeeded IS FALSE \
+                       AND dependency_check_at < NOW() - '5 minutes'::interval \
+                       ORDER BY dependency_check_at", "pending")
+
+       def _check_build_dependencies(self, query, *args):
+               jobs = self.backend.jobs._get_jobs(query, *args)
 
                for job in jobs:
                        with self.db.transaction():
-                               # Resolve the dependencies
-                               job.resolvdep()
\ No newline at end of file
+                               job.resolvdep()
index 1713d2443ffe91475242ee40ab0b6f6d1a77fa0f..b0022c43297ede5bca8959aa38caf5fd9b5196f5 100644 (file)
@@ -54,68 +54,18 @@ class Jobs(base.Object):
        def get_by_uuid(self, uuid):
                return self._get_job("SELECT * FROM jobs WHERE uuid = %s", uuid)
 
-       def get_active(self, host_id=None, builder=None, states=None):
-               if builder:
-                       host_id = builder.id
-
-               if states is None:
-                       states = ["dispatching", "running", "uploading"]
-
-               query = "SELECT * FROM jobs WHERE state IN (%s)" % ", ".join(["%s"] * len(states))
-               args = states
-
-               if host_id:
-                       query += " AND builder_id = %s" % host_id
-
-               query += " ORDER BY \
-                       CASE \
-                               WHEN jobs.state = 'running'     THEN 0 \
-                               WHEN jobs.state = 'uploading'   THEN 1 \
-                               WHEN jobs.state = 'dispatching' THEN 2 \
-                               WHEN jobs.state = 'pending'     THEN 3 \
-                               WHEN jobs.state = 'new'         THEN 4 \
-                       END, time_started ASC"
-
-               return [Job(self.backend, j.id, j) for j in self.db.query(query, *args)]
-
-       def get_latest(self, arch=None, builder=None, limit=None, age=None, date=None):
-               query = "SELECT * FROM jobs"
-               args  = []
-
-               where = ["(state = 'finished' OR state = 'failed' OR state = 'aborted')"]
-
-               if arch:
-                       where.append("arch = %s")
-                       args.append(arch)
-
-               if builder:
-                       where.append("builder_id = %s")
-                       args.append(builder.id)
-
-               if date:
-                       try:
-                               year, month, day = date.split("-", 2)
-                               date = datetime.date(int(year), int(month), int(day))
-                       except ValueError:
-                               pass
-                       else:
-                               where.append("(time_created::date = %s OR \
-                                       time_started::date = %s OR time_finished::date = %s)")
-                               args += (date, date, date)
-
-               if age:
-                       where.append("time_finished >= NOW() - '%s'::interval" % age)
-
-               if where:
-                       query += " WHERE %s" % " AND ".join(where)
+       def get_active(self, limit=None):
+               jobs = self._get_jobs("SELECT jobs.* FROM jobs \
+                       WHERE time_started IS NOT NULL AND time_finished IS NULL \
+                       ORDER BY time_started LIMIT %s", limit)
 
-               query += " ORDER BY time_finished DESC"
+               return jobs
 
-               if limit:
-                       query += " LIMIT %s"
-                       args.append(limit)
+       def get_recently_ended(self, limit=None):
+               jobs = self._get_jobs("SELECT jobs.* FROM jobs \
+                       WHERE time_finished IS NOT NULL ORDER BY time_finished DESC LIMIT %s", limit)
 
-               return [Job(self.backend, j.id, j) for j in self.db.query(query, *args)]
+               return jobs
 
        def restart_failed(self):
                jobs = self._get_jobs("SELECT jobs.* FROM jobs \
@@ -173,15 +123,63 @@ class Job(base.DataObject):
 
                return res.len
 
+       @property
+       def uuid(self):
+               return self.data.uuid
+
+       @property
+       def name(self):
+               return "%s-%s.%s" % (self.pkg.name, self.pkg.friendly_version, self.arch)
+
+       @property
+       def build_id(self):
+               return self.data.build_id
+
+       @lazy_property
+       def build(self):
+               return self.backend.builds.get_by_id(self.build_id)
+
+       @property
+       def test(self):
+               return self.data.test
+
+       @property
+       def related_jobs(self):
+               ret = []
+
+               for job in self.build.jobs:
+                       if job == self:
+                               continue
+
+                       ret.append(job)
+
+               return ret
+
+       @property
+       def pkg(self):
+               return self.build.pkg
+
+       @property
+       def size(self):
+               return sum((p.size for p in self.packages))
+
+       @lazy_property
+       def rank(self):
+               """
+                       Returns the rank in the build queue
+               """
+               if not self.state == "pending":
+                       return
+
+               res = self.db.get("SELECT rank FROM jobs_queue WHERE job_id = %s", self.id)
+
+               if res:
+                       return res.rank
+
        @property
        def distro(self):
                return self.build.distro
 
-       def restart(self):
-               # Copy the job and let it build again
-               return self.backend.jobs.create(self.build, self.arch,
-                       test=self.test, superseeds=self)
-
        def get_superseeded_by(self):
                if self.data.superseeded_by:
                        return self.backend.jobs.get_by_id(self.data.superseeded_by)
@@ -190,10 +188,54 @@ class Job(base.DataObject):
                assert isinstance(superseeded_by, self.__class__)
 
                self._set_attribute("superseeded_by", superseeded_by.id)
-               self.superseeded_by = superseeded_by
 
        superseeded_by = lazy_property(get_superseeded_by, set_superseeded_by)
 
+       def start(self, builder):
+               """
+                       Starts this job on builder
+               """
+               self.builder = builder
+
+               # Start to dispatch the build job
+               self.state = "dispatching"
+
+       def running(self):
+               self.state = "running"
+
+               # Set start time
+               self.time_started  = datetime.datetime.utcnow()
+               self.time_finished = None
+
+       def finished(self):
+               self.state = "finished"
+
+               # Log end time
+               self.time_finished = datetime.datetime.utcnow()
+
+               # Notify users
+               self.send_finished_message()
+
+       def failed(self, message):
+               self.state = "failed"
+               self.message = message
+
+               # Log end time
+               self.time_finished = datetime.datetime.utcnow()
+
+               # Notify users
+               self.send_failed_message()
+
+       def restart(self, test=None, start_not_before=None):
+               # Copy the job and let it build again
+               job = self.backend.jobs.create(self.build, self.arch,
+                       test=test or self.test, superseeds=self)
+
+               if start_not_before:
+                       job.start_not_before = start_not_before
+
+               return job
+
        def delete(self):
                """
                        Deletes a job from the database
@@ -268,59 +310,6 @@ class Job(base.DataObject):
 
                return entries
 
-       @property
-       def uuid(self):
-               return self.data.uuid
-
-       @property
-       def test(self):
-               return self.data.test
-
-       @property
-       def build_id(self):
-               return self.data.build_id
-
-       @lazy_property
-       def build(self):
-               return self.backend.builds.get_by_id(self.build_id)
-
-       @property
-       def related_jobs(self):
-               ret = []
-
-               for job in self.build.jobs:
-                       if job == self:
-                               continue
-
-                       ret.append(job)
-
-               return ret
-
-       @property
-       def pkg(self):
-               return self.build.pkg
-
-       @property
-       def name(self):
-               return "%s-%s.%s" % (self.pkg.name, self.pkg.friendly_version, self.arch)
-
-       @property
-       def size(self):
-               return sum((p.size for p in self.packages))
-
-       @lazy_property
-       def rank(self):
-               """
-                       Returns the rank in the build queue
-               """
-               if not self.state == "pending":
-                       return
-
-               res = self.db.get("SELECT rank FROM jobs_queue WHERE job_id = %s", self.id)
-
-               if res:
-                       return res.rank
-
        def is_running(self):
                """
                        Returns True if job is in a running state.
@@ -330,49 +319,23 @@ class Job(base.DataObject):
        def get_state(self):
                return self.data.state
 
-       def set_state(self, state, user=None, log=True):
-               # Nothing to do if the state remains.
-               if not self.state == state:
-                       self._set_attribute("state", state)
-
-                       # Log the event.
-                       if log and not state == "new":
-                               self.log("state_change", state=state, user=user)
-
-               # Always clear the message when the status is changed.
-               self.update_message(None)
+       def set_state(self, state):
+               self._set_attribute("state", state)
 
-               # Update some more informations.
-               if state == "dispatching":
-                       # Set start time.
-                       self._set_attribute("time_started", datetime.datetime.utcnow())
-
-               elif state in ("aborted", "dependency_error", "finished", "failed"):
-                       self._set_attribute("time_finished", datetime.datetime.utcnow())
-
-                       # Send messages to the user.
-                       if state == "finished":
-                               self.send_finished_message()
-
-                       elif state == "failed":
-                               # Remove all package files if a job is set to failed state.
-                               self.__delete_packages()
-
-                               self.send_failed_message()
-
-               # Automatically update the state of the build (not on test builds).
+               # Automatically update the state of the build (not on test builds)
                if not self.test:
                        self.build.auto_update_state()
 
        state = property(get_state, set_state)
 
-       @property
-       def message(self):
-               return self.data.message
+       def set_message(self, message):
+               if message:
+                       message = "%s" % message
 
-       def update_message(self, message):
                self._set_attribute("message", message)
 
+       message = property(lambda s: s.data.message, set_message)
+
        def get_builder(self):
                if self.data.builder_id:
                        return self.backend.builders.get_by_id(self.data.builder_id)
@@ -386,6 +349,19 @@ class Job(base.DataObject):
 
        builder = lazy_property(get_builder, set_builder)
 
+       @lazy_property
+       def candidate_builders(self):
+               """
+                       Returns all active builders that could build this job
+               """
+               builders = self.backend.builders.get_for_arch(self.arch)
+
+               # Remove all builders that are not available
+               builders = (b for b in builders if b.enabled and b.is_online())
+
+               # Sort them by the fastest builder first
+               return sorted(builders, key=lambda b: -b.performance_index)
+
        @property
        def arch(self):
                return self.data.arch
@@ -406,13 +382,20 @@ class Job(base.DataObject):
        def time_created(self):
                return self.data.time_created
 
-       @property
-       def time_started(self):
-               return self.data.time_started
+       def set_time_started(self, time_started):
+               self._set_attribute("time_started", time_started)
 
-       @property
-       def time_finished(self):
-               return self.data.time_finished
+       time_started = property(lambda s: s.data.time_started, set_time_started)
+
+       def set_time_finished(self, time_finished):
+               self._set_attribute("time_finished", time_finished)
+
+       time_finished = property(lambda s: s.data.time_finished, set_time_finished)
+
+       def set_start_not_before(self, start_not_before):
+               self._set_attribute("start_not_before", start_not_before)
+
+       start_not_before = property(lambda s: s.data.start_not_before, set_start_not_before)
 
        def get_pkg_by_uuid(self, uuid):
                pkg = self.backend.packages._get_package("SELECT packages.id FROM packages \
@@ -596,43 +579,6 @@ class Job(base.DataObject):
                self.backend.messages.send_to_all(self.message_recipients,
                        MSG_BUILD_FAILED_SUBJECT, MSG_BUILD_FAILED, info)
 
-       def set_start_time(self, start_not_before):
-               self._set_attribute("start_not_before", start_not_before)
-
-       def schedule(self, type, start_time=None, user=None):
-               assert type in ("rebuild", "test")
-
-               if type == "rebuild":
-                       if self.state == "finished":
-                               return
-
-                       job = self.restart()
-                       job.set_start_time(start_time)
-
-                       # Log the event.
-                       self.log("schedule_rebuild", user=user)
-
-               elif type == "test":
-                       if not self.state == "finished":
-                               return
-
-                       # Create a new job with same build and arch.
-                       job = self.create(self.backend, self.build, self.arch, test=True)
-                       job.set_start_time(start_time)
-
-                       # Log the event.
-                       self.log("schedule_test_job", test_job=job, user=user)
-
-                       return job
-
-       def schedule_test(self, start_not_before=None, user=None):
-               # XXX to be removed
-               return self.schedule("test", start_time=start_not_before, user=user)
-
-       def schedule_rebuild(self, start_not_before=None, user=None):
-               # XXX to be removed
-               return self.schedule("rebuild", start_time=start_not_before, user=user)
-
        def get_build_repos(self):
                """
                        Returns a list of all repositories that should be used when
@@ -667,7 +613,21 @@ class Job(base.DataObject):
 
                return "\n\n".join(confs)
 
+       def set_dependency_check_succeeded(self, value):
+               self._set_attribute("dependency_check_succeeded", value)
+               self._set_attribute("dependency_check_at", datetime.datetime.utcnow())
+
+               # Reset the message
+               if value is True:
+                       self.message = None
+
+       dependency_check_succeeded = property(
+               lambda s: s.data.dependency_check_succeeded,
+               set_dependency_check_succeeded)
+
        def resolvdep(self):
+               log.info("Processing dependencies for %s..." % self)
+
                config = pakfire.config.Config(files=["general.conf"])
                config.parse(self.get_config(local=True))
 
@@ -685,14 +645,9 @@ class Job(base.DataObject):
 
                # Catch dependency errors and log the problem string.
                except DependencyError, e:
-                       self.state = "dependency_error"
-                       self.update_message("%s" % e)
+                       self.dependency_check_succeeded = False
+                       self.message = e
 
+               # The dependency check has succeeded
                else:
-                       # If the build dependencies can be resolved, we set the build in
-                       # pending state.
-                       if solver.status is True:
-                               if self.state in ("failed",):
-                                       return
-
-                               self.state = "pending"
+                       self.dependency_check_succeeded = True
index 9f5019e55eef103f72a26a8dcfe051cc59c89e17..44f7c7ca3140951f1b929236c5d1ea5c78e51f26 100644 (file)
@@ -34,9 +34,9 @@ class LDAP(base.Object):
        def auth(self, username, password):
                log.debug("Checking credentials for %s" % username)
 
-               dn = self.get_dn_by_uid(username)
+               dn = self.get_dn(username)
                if not dn:
-                       log.debug("Could not resolve username %s to dn" % username)
+                       log.debug("Could not resolve  %s to dn" % username)
                        return False
 
                return self.bind(dn, password)
@@ -61,9 +61,31 @@ class LDAP(base.Object):
                log.debug("DN for uid %s is: %s" % (uid, dn))
                return dn
 
-       def get_user(self, uid, **kwargs):
+       def get_dn_by_mail(self, mail):
+               result = self.search("(&(objectClass=posixAccount)(mail=%s))" % mail, limit=1, attrlist=["uid"])
+
+               for dn, attrs in result:
+                       return dn
+
+               log.debug("DN for mail %s is: %s" % (mail, dn))
+               return None
+
+       def get_dn(self, name):
+               return self.get_dn_by_uid(name) or self.get_dn_by_mail(name)
+
+       def get_user_by_mail(self, mail, **kwargs):
+               result = self.search("(&(objectClass=posixAccount)(mail=%s))" % mail, limit=1, **kwargs)
+               for dn, attrs in result:
+                       return (dn, attrs)
+
+               return None
+
+       def get_user_by_dn(self, uid, **kwargs):
                result = self.search("(&(objectClass=posixAccount)(uid=%s))" % uid, limit=1, **kwargs)
                for dn, attrs in result:
                        return (dn, attrs)
 
-               return (None, None)
\ No newline at end of file
+               return None
+
+       def get_user(self, name, **kwargs):
+               return self.get_user_by_dn(name, **kwargs) or self.get_user_by_mail(name, **kwargs)
index 47dc251326f95b82332e99da03933c9650de327e..de9ce1aeaad9465ddddd7f8b09b3b04b74ce5487 100644 (file)
@@ -35,29 +35,14 @@ class Packages(base.Object):
                return self._get_package("SELECT * FROM packages \
                        WHERE id = %s", pkg_id)
 
-       def get_all_names(self, user=None, states=None):
-               query = "SELECT DISTINCT packages.name AS name, summary FROM packages \
-                       JOIN builds ON builds.pkg_id = packages.id \
-                       WHERE packages.type = 'source'"
-
-               conditions = []
-               args = []
-
-               if user and not user.is_admin():
-                       conditions.append("builds.owner_id = %s")
-                       args.append(user.id)
-
-               if states:
-                       for state in states:
-                               conditions.append("builds.state = %s")
-                               args.append(state)
-
-               if conditions:
-                       query += " AND (%s)" % " OR ".join(conditions)
-               
-               query += " ORDER BY packages.name"
-
-               return [(n.name, n.summary) for n in self.db.query(query, *args)]
+       def get_list(self):
+               """
+                       Returns a list with all package names and the summary line
+                       that have at one time been part of the distribution
+               """
+               return self.db.query("SELECT DISTINCT packages.name AS name, packages.summary AS summary FROM builds \
+                       LEFT JOIN packages ON builds.pkg_id = packages.id \
+                       WHERE builds.type = %s AND builds.state != %s", "release", "obsolete")
 
        def get_by_uuid(self, uuid):
                pkg = self.db.get("SELECT * FROM packages WHERE uuid = %s LIMIT 1", uuid)
@@ -213,6 +198,8 @@ class Package(base.DataObject):
        def delete(self):
                self.backend.delete_file(os.path.join(PACKAGES_DIR, self.path))
 
+               self.db.execute("DELETE FROM packages_deps WHERE pkg_id = %s", self.id)
+
                # Delete all files from the filelist.
                self.db.execute("DELETE FROM filelists WHERE pkg_id = %s", self.id)
 
index 20dd1295adb7b889fa1805317759ad3b74c5f15b..7f9e67e2a4d866856e46ab42f0688a29e6bfc617 100644 (file)
@@ -182,7 +182,7 @@ class Repository(base.DataObject):
                        "[repo:%s]" % self.identifier,
                        "description = %s - %s" % (self.distro.name, self.summary),
                        "enabled = 1",
-                       "baseurl = %s/%{arch}" % (self.path if local else self.url),
+                       "baseurl = %s/%%{arch}" % (self.path if local else self.url),
                ]
 
                if self.mirrored and not local:
index 83fdc13df05a84778be346638d1827b46de3f5c2..2d4e2bbb35709ee5f86a754ffb4e0ba5fd193204 100644 (file)
@@ -5,6 +5,7 @@ import logging
 import os
 import pakfire
 import pakfire.config
+import re
 import shutil
 import subprocess
 import tempfile
@@ -15,6 +16,17 @@ from . import git
 from .constants import *
 from .decorators import *
 
+VALID_TAGS = (
+       "Acked-by",
+       "Cc",
+       "Fixes",
+       "Reported-by",
+       "Reviewed-by",
+       "Signed-off-by",
+       "Suggested-by",
+       "Tested-by",
+)
+
 class Sources(base.Object):
        def _get_source(self, query, *args):
                res = self.db.get(query, *args)
@@ -169,27 +181,127 @@ class Commit(base.DataObject):
 
        state = property(lambda s: s.data.state, set_state)
 
-       @property
+       @lazy_property
        def author(self):
-               return self.data.author
+               return self.backend.users.find_maintainer(self.data.author) or self.data.author
 
-       @property
+       @lazy_property
        def committer(self):
-               return self.data.committer
+               return self.backend.users.find_maintainer(self.data.committer) or self.data.committer
 
        @property
        def subject(self):
                return self.data.subject.strip()
 
        @property
-       def message(self):
+       def body(self):
                return self.data.body.strip()
 
+       @lazy_property
+       def message(self):
+               """
+                       Returns the message without any Git tags
+               """
+               # Compile regex
+               r = re.compile("^(%s):?" % "|".join(VALID_TAGS), re.IGNORECASE)
+
+               message = []
+               for line in self.body.splitlines():
+                       # Find lines that start with a known Git tag
+                       if r.match(line):
+                               continue
+
+                       message.append(line)
+
+               # If all lines are empty lines, we send back an empty message
+               if all((l == "" for l in message)):
+                       return
+
+               # We will now break the message into paragraphs
+               paragraphs = re.split("\n\n+", "\n".join(message))
+               print paragraphs
+
+               message = []
+               for paragraph in paragraphs:
+                       # Remove all line breaks that are not following a colon
+                       # and where the next line does not start with a star.
+                       paragraph = re.sub("(?<=\:)\n(?=[\*\s])", " ", paragraph)
+
+                       message.append(paragraph)
+
+               return "\n\n".join(message)
+
        @property
        def message_full(self):
-               msg = [self.subject, ""] + self.message.splitlines()
+               message = self.subject
+
+               if self.message:
+                       message += "\n\n%s" % self.message
+
+               return message
 
-               return "\n".join(msg)
+       def get_tag(self, tag):
+               """
+                       Returns a list of the values of this Git tag
+               """
+               if not tag in VALID_TAGS:
+                       raise ValueError("Unknown tag: %s" % tag)
+
+               # Compile regex
+               r = re.compile("^%s:? (.*)$" % tag, re.IGNORECASE)
+
+               values = []
+               for line in self.body.splitlines():
+                       # Skip all empty lines
+                       if not line:
+                               continue
+
+                       # Check if line matches the regex
+                       m = r.match(line)
+                       if m:
+                               values.append(m.group(1))
+
+               return values
+
+       @lazy_property
+       def contributors(self):
+               contributors = [
+                       self.data.author,
+                       self.data.committer,
+               ]
+
+               for tag in ("Acked-by", "Cc", "Reported-by", "Reviewed-by", "Signed-off-by", "Suggested-by", "Tested-by"):
+                       contributors += self.get_tag(tag)
+
+               # Get all user accounts that we know
+               users = self.backend.users.find_maintainers(contributors)
+
+               # Add all email addresses where a user could not be found
+               for contributor in contributors[:]:
+                       for user in users:
+                               if user.has_email_address(contributor):
+                                       try:
+                                               contributors.remove(contributor)
+                                       except:
+                                               pass
+
+               return sorted(contributors + users)
+
+       @lazy_property
+       def testers(self):
+               users = []
+
+               for tag in ("Acked-by", "Reviewed-by", "Signed-off-by", "Tested-by"):
+                       users += self.get_tag(tag)
+
+               return self.backend.users.find_maintainers(users)
+
+       @property
+       def fixed_bugs(self):
+               """
+                       Returns a list of all fixed bugs
+               """
+               return self.get_tag("Fixes")
 
        @property
        def date(self):
index 8d731d8e55a4645304f75e0c6fa9064689f13a9a..7c98d4bfcdb7c61d08128e11bf9b7c04ba97ca29 100644 (file)
@@ -150,20 +150,21 @@ class Users(base.Object):
                if None in (name, password):
                        return
 
-               # Search for the username in the database.
-               # The user must not be deleted and must be activated.
-               user = self._get_user("SELECT * FROM users WHERE name = %s AND \
-                       activated IS TRUE AND deleted IS FALSE", name)
+               # usually we will get an email address as name
+               user = self.get_by_email(name) or self.get_by_name(name)
 
-               # If no user could be found, we search for a matching user in
-               # the LDAP database
                if not user:
+                       # If no user could be found, we search for a matching user in
+                       # the LDAP database
                        if not self.ldap.auth(name, password):
                                return
 
                        # If a LDAP user is found (and password matches), we will
                        # create a new local user with the information from LDAP.
-                       user = self.register_from_ldap(name)
+                       user = self.create_from_ldap(name)
+
+               if not user.activated or user.deleted:
+                       return
 
                # Check if the password matches
                if user.check_password(password):
@@ -184,6 +185,23 @@ class Users(base.Object):
                        LEFT JOIN users_emails ON users.id = users_emails.user_id \
                        WHERE users_emails.email = %s", email)
 
+       def find_maintainers(self, maintainers):
+               email_addresses = []
+
+               # Make a unique list of all email addresses
+               for maintainer in maintainers:
+                       name, email_address = email.utils.parseaddr(maintainer)
+
+                       if not email_address in email_addresses:
+                               email_addresses.append(email_address)
+
+               users = self._get_users("SELECT DISTINCT users.* FROM users \
+                       LEFT JOIN users_emails ON users.id = users_emails.user_id \
+                       WHERE users_emails.activated IS TRUE \
+                       AND users_emails.email = ANY(%s)", email_addresses)
+
+               return sorted(users)
+
        def find_maintainer(self, s):
                name, email_address = email.utils.parseaddr(s)
 
@@ -342,6 +360,14 @@ class User(base.DataObject):
                        WHERE user_id = %s AND email = %s AND activated IS TRUE",
                        self.id, email)
 
+       def has_email_address(self, email_address):
+               try:
+                       mail, email_address = email.utils.parseaddr(email_address)
+               except:
+                       pass
+
+               return email_address in self.emails
+
        def activate_email(self, code):
                # Search email by activation code
                email = self.backend.users._get_user_email("SELECT * FROM users_emails \
@@ -415,6 +441,10 @@ class User(base.DataObject):
        def activated(self):
                return self.data.activated
 
+       @property
+       def deleted(self):
+               return self.data.deleted
+
        @property
        def registered(self):
                return self.data.registered
index 7b34ea5eccca154b8d040a242025e7f07c8389bb..b5063af7d053f3f1f4cd64dbbc7301d252deaa1b 100644 (file)
@@ -115,28 +115,6 @@ CREATE TYPE jobs_history_state AS ENUM (
 
 ALTER TYPE jobs_history_state OWNER TO pakfire;
 
---
--- Name: jobs_state; Type: TYPE; Schema: public; Owner: pakfire
---
-
-CREATE TYPE jobs_state AS ENUM (
-    'new',
-    'pending',
-    'running',
-    'finished',
-    'dispatching',
-    'uploading',
-    'failed',
-    'aborted',
-    'temporary_failed',
-    'dependency_error',
-    'download_error',
-    'deleted'
-);
-
-
-ALTER TYPE jobs_state OWNER TO pakfire;
-
 --
 -- Name: mirrors_history_action; Type: TYPE; Schema: public; Owner: pakfire
 --
@@ -513,9 +491,9 @@ CREATE TABLE builds_comments (
     id integer NOT NULL,
     build_id integer NOT NULL,
     user_id integer NOT NULL,
-    text text NOT NULL,
+    text text,
     score integer NOT NULL,
-    time_created timestamp without time zone NOT NULL,
+    time_created timestamp without time zone DEFAULT now() NOT NULL,
     time_updated timestamp without time zone
 );
 
@@ -609,7 +587,7 @@ CREATE TABLE jobs (
     id integer NOT NULL,
     uuid text NOT NULL,
     build_id integer NOT NULL,
-    state jobs_state DEFAULT 'new'::jobs_state NOT NULL,
+    state text DEFAULT 'pending'::text NOT NULL,
     arch text NOT NULL,
     time_created timestamp without time zone DEFAULT now() NOT NULL,
     time_started timestamp without time zone,
@@ -619,7 +597,10 @@ CREATE TABLE jobs (
     aborted_state integer DEFAULT 0 NOT NULL,
     message text,
     test boolean DEFAULT true NOT NULL,
-    superseeded_by integer
+    superseeded_by integer,
+    dependency_check_succeeded boolean,
+    dependency_check_at timestamp without time zone,
+    CONSTRAINT jobs_states CHECK ((state = ANY (ARRAY['pending'::text, 'dispatching'::text, 'running'::text, 'uploading'::text, 'finished'::text, 'aborted'::text, 'download_error'::text, 'failed'::text])))
 );
 
 
@@ -634,7 +615,7 @@ CREATE VIEW builds_times AS
     jobs.arch,
     date_part('epoch'::text, (jobs.time_finished - jobs.time_started)) AS duration
    FROM jobs
-  WHERE ((jobs.test IS FALSE) AND (jobs.state = 'finished'::jobs_state));
+  WHERE ((jobs.test IS FALSE) AND (jobs.state = 'finished'::text));
 
 
 ALTER TABLE builds_times OWNER TO pakfire;
@@ -801,30 +782,6 @@ ALTER TABLE images_types_id_seq OWNER TO pakfire;
 ALTER SEQUENCE images_types_id_seq OWNED BY images_types.id;
 
 
---
--- Name: jobs_active; Type: VIEW; Schema: public; Owner: pakfire
---
-
-CREATE VIEW jobs_active AS
- SELECT jobs.id,
-    jobs.uuid,
-    jobs.build_id,
-    jobs.state,
-    jobs.arch,
-    jobs.time_created,
-    jobs.time_started,
-    jobs.time_finished,
-    jobs.start_not_before,
-    jobs.builder_id,
-    jobs.aborted_state,
-    jobs.message
-   FROM jobs
-  WHERE (jobs.state = ANY (ARRAY['dispatching'::jobs_state, 'running'::jobs_state, 'uploading'::jobs_state]))
-  ORDER BY jobs.time_started;
-
-
-ALTER TABLE jobs_active OWNER TO pakfire;
-
 --
 -- Name: jobs_buildroots; Type: TABLE; Schema: public; Owner: pakfire; Tablespace: 
 --
@@ -920,7 +877,7 @@ CREATE VIEW jobs_queue AS
             rank() OVER (ORDER BY (NOT jobs.test), builds.priority DESC, jobs.time_created) AS rank
            FROM (jobs
              LEFT JOIN builds ON ((jobs.build_id = builds.id)))
-          WHERE (jobs.state = 'pending'::jobs_state)
+          WHERE ((jobs.state = 'pending'::text) AND (jobs.dependency_check_succeeded IS TRUE))
         )
  SELECT queue.id AS job_id,
     queue.rank
@@ -2448,13 +2405,6 @@ CREATE INDEX idx_2198063_build_id ON jobs USING btree (build_id);
 CREATE INDEX idx_2198063_state ON jobs USING btree (state);
 
 
---
--- Name: idx_2198063_time_finished; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
---
-
-CREATE INDEX idx_2198063_time_finished ON jobs USING btree (time_finished);
-
-
 --
 -- Name: idx_2198063_uuid; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
 --
@@ -2604,6 +2554,27 @@ ALTER TABLE jobs_buildroots CLUSTER ON jobs_buildroots_job_id;
 CREATE INDEX jobs_buildroots_pkg_uuid ON jobs_buildroots USING btree (pkg_uuid);
 
 
+--
+-- Name: jobs_queue_ready; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
+--
+
+CREATE INDEX jobs_queue_ready ON jobs USING btree (id) WHERE ((state = 'new'::text) AND (dependency_check_succeeded IS TRUE));
+
+
+--
+-- Name: jobs_time_finished; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
+--
+
+CREATE INDEX jobs_time_finished ON jobs USING btree (time_finished DESC) WHERE (time_finished IS NOT NULL);
+
+
+--
+-- Name: jobs_time_started; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
+--
+
+CREATE INDEX jobs_time_started ON jobs USING btree (time_started) WHERE ((time_started IS NOT NULL) AND (time_finished IS NULL));
+
+
 --
 -- Name: mirrors_checks_sort; Type: INDEX; Schema: public; Owner: pakfire; Tablespace: 
 --
@@ -2859,6 +2830,14 @@ ALTER TABLE ONLY jobs_repos
     ADD CONSTRAINT jobs_repos_repo_id FOREIGN KEY (repo_id) REFERENCES repositories(id);
 
 
+--
+-- Name: jobs_superseeded_by; Type: FK CONSTRAINT; Schema: public; Owner: pakfire
+--
+
+ALTER TABLE ONLY jobs
+    ADD CONSTRAINT jobs_superseeded_by FOREIGN KEY (superseeded_by) REFERENCES jobs(id);
+
+
 --
 -- Name: keys_subkeys_key_id; Type: FK CONSTRAINT; Schema: public; Owner: pakfire
 --
index f53a36454a099adec8516f7955daa78da91b4726..8b9222428927dc75811c77c1a3faa37218b1ed03 100644 (file)
@@ -359,7 +359,7 @@ class JobsGetLatestHandler(JobsBaseHandler):
                limit = self.get_argument_int("limit", 5)
 
                # Get the latest jobs.
-               jobs = self.backend.jobs.get_latest(age="24 HOUR", limit=limit)
+               jobs = self.backend.jobs.get_recently_ended(limit=limit)
 
                args = {
                        "jobs" : [self.job2json(j) for j in jobs],
@@ -524,10 +524,7 @@ class BuildersJobsQueueHandler(BuildersBaseHandler):
                                return self.add_timeout(10, self.callback)
 
                        # We got a job!
-                       job.state = "dispatching"
-
-                       # Set our build host.
-                       job.builder = self.builder
+                       job.start(builder=self.builder)
 
                        ret = {
                                "id"                 : job.uuid,
@@ -552,11 +549,18 @@ class BuildersJobsStateHandler(BuildersBaseHandler):
                if not job.builder == self.builder:
                        raise tornado.web.HTTPError(403, "Altering another builder's build.")
 
-               # Save information to database.
-               job.state = state
-
                message = self.get_argument("message", None)
-               job.update_message(message)
+
+               # Save information to database.
+               with self.db.transaction():
+                       if state == "running":
+                               job.running()
+                       elif state == "failed":
+                               job.failed(message)
+                       elif state == "finished":
+                               job.finished()
+                       else:
+                               job.state = state
 
                self.finish("OK")
 
@@ -601,9 +605,6 @@ class BuildersJobsAddFileHandler(BuildersBaseHandler):
                if not upload.builder == self.builder:
                        raise tornado.web.HTTPError(403, "Using an other host's file.")
 
-               # Remove all files that have to be deleted, first.
-               self.backend.cleanup_files()
-
                try:
                        job.add_file(upload.path)
 
index 0e730717e9bed9ff03d5e29032cedfab61e6acdd..cc9aea49e4ea63f845bb9d56126c079aee2a5724 100644 (file)
@@ -49,10 +49,6 @@ table.builds tr.build td.jobs a.running {
        color: yellow;
 }
 
-table.builds tr.build td.jobs a.dependency_error {
-       color: blue;
-}
-
 table.builds tr.build td.jobs a.failed {
        color: red;
 }
diff --git a/src/static/images/icons/build-dependency_error.png b/src/static/images/icons/build-dependency_error.png
deleted file mode 100644 (file)
index 2230c05..0000000
Binary files a/src/static/images/icons/build-dependency_error.png and /dev/null differ
index 0d53c15849be33a378123d5e203ccb049453cd11..57d06992e0a1a7f5ca641dfa2ca13be72d0b48de 100644 (file)
@@ -95,7 +95,7 @@
                                                        <hr>
 
                                                        <p class="muted">
-                                                               {{ _("Author") }} {% module Maintainer(build.commit.author) %}
+                                                               {{ _("Author") }} {% module LinkToUser(build.commit.author) %}
                                                                &dash;
                                                                {{ _("Commit") }} <a href="/distro/{{ build.distro.identifier }}/source/{{ build.pkg.commit.source.identifier }}/{{ build.pkg.commit.revision }}">{{ build.pkg.commit.revision[:7] }}</a>
                                                        </p>
index e411b6d90a2b8489ecce6a7c43fa98ee2e61c31b..25d98bd1b3c4b62d2421412cfb281fc19d65dac9 100644 (file)
                                        </tr>
                                        <tr>
                                                <td>{{ _("Author") }}</td>
-                                               <td>{% raw format_email(commit.author) %}</td>
+                                               <td>{% module LinkToUser(commit.author) %}</td>
                                        </tr>
                                        <tr>
                                                <td>{{ _("Committer") }}</td>
-                                               <td>{% raw format_email(commit.committer) %}</td>
-                                       </tr>
-                                       <tr>
-                                               <td>{{ _("Subject") }}</td>
-                                               <td>{{ commit.subject }}</td>
+                                               <td>{% module LinkToUser(commit.committer) %}</td>
                                        </tr>
 
                                        {% if commit.message %}
                                                <tr>
                                                        <td colspan="2">
-                                                               {% module Text(commit.message, pre=True) %}
+                                                               {% module CommitMessage(commit) %}
                                                        </td>
                                                </tr>
                                        {% end %}
index 63e29e73b2fb6a998583a0547cd5eaf2837d8662..31001d23db64190971d156104142e58b151833c7 100644 (file)
@@ -36,7 +36,6 @@
                <li><a class="build running" name="#">{{ _("Build is running") }}</a></li>
                <li><a class="build failed" name="#">{{ _("Build has failed") }}</a></li>
                <li><a class="build pending" name="#">{{ _("Build is waiting to be processed") }}</a></li>
-               <li><a class="build dependency_error" name="#">{{ _("There was a dependency error when the package was built") }}</a></li>
                <li><a class="build waiting" name="#">{{ _("Build is waiting for source to go to pending state") }}</a></li>
                <li><a class="build dispatching" name="#">{{ _("Files of this build are transferred to the build server") }}</a></li>
                <li><a class="build uploading" name="#">{{ _("Files are being uploaded to the service") }}</a></li>
index 892acea0cedb1bd1e620a04a807038db05ce2ea9..ab90f74b65b27fe743cb0f2058135287c2b9c7ac 100644 (file)
@@ -37,7 +37,7 @@
                                                                <td colspan="2">
                                                                        {{ _("Exception (traceback):") }}
                                                                        <br><br>
-                                                                       <pre>{{ "\n".join(tb) }}</pre>
+                                                                       <pre>{{ "".join(tb) }}</pre>
                                                                </td>
                                                        </tr>
                                                {% end %}
index 93dc37777a2b398f598803518be54ff012205d0c..da1c8ed81ba70b3d48410aee9b7b4819b7536b07 100644 (file)
 
        <ul class="nav nav-pills">
                <li>
-                       <a href="/jobs">{{ _("Show more build jobs") }}</a>
+                       <a href="/queue">
+                               {{ _("Job Queue") }}
+
+                               <!-- should be a badge -->
+                               ({{ len(backend.jobqueue) }})
+                       </a>
                </li>
        </ul>
 {% end %}
diff --git a/src/templates/jobs-filter.html b/src/templates/jobs-filter.html
deleted file mode 100644 (file)
index 65f215b..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ _("Filter jobs") }}{% end block %}
-
-{% block body %}
-       <ul class="breadcrumb">
-               <li>
-                       <a href="/">{{ _("Home") }}</a>
-                       <span class="divider">/</span>
-               </li>
-               <li>
-                       <a href="/jobs">{{ _("Jobs") }}</a>
-                       <span class="divider">/</span>
-               </li>
-               <li class="active">
-                       <a href="/jobs/filter">{{ _("Filter") }}</a>
-               </li>
-       </ul>
-
-       <div class="page-header">
-               <h2>{{ _("Filter jobs") }}</h2>
-       </div>
-
-       <form class="form-horizontal" method="GET" action="/jobs">
-               <fieldset>
-                       <div class="control-group">
-                               <label class="control-label">{{ _("Builder") }}</label>
-                               <div class="controls">
-                                       <select name="builder">
-                                               <option value="">{{ _("[Choose one]") }}</option>
-                                               {% for b in builders %}
-                                                       <option value="{{ b.name }}">{{ b.name }}</option>
-                                               {% end %}
-                                       </select>
-                                       <span class="help-block">
-                                               {{ _("Only show jobs, that have been built by this builder.") }}
-                                       </span>
-                               </div>
-                       </div>
-
-                       <hr>
-
-                       <div class="control-group">
-                               <label class="control-label">{{ _("Architecture") }}</label>
-                               <div class="controls">
-                                       <select name="arch">
-                                               <option value="">{{ _("[Choose one]") }}</option>
-                                               {% for a in arches %}
-                                                       <option value="{{ a.name }}">{{ a.name }}</option>
-                                               {% end %}
-                                       </select>
-                                       <span class="help-block">
-                                               {{ _("Only show jobs, with this architecture.") }}
-                                       </span>
-                               </div>
-                       </div>
-
-                       <div class="form-actions">
-                               <button type="submit" class="btn btn-primary">{{ _("Go!") }}</button>
-                       </div>
-               </fieldset>
-       </form>
-{% end block %}
diff --git a/src/templates/jobs-index.html b/src/templates/jobs-index.html
deleted file mode 100644 (file)
index 58291ed..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ _("Jobs") }}{% end block %}
-
-{% block body %}
-       <ul class="breadcrumb">
-               <li>
-                       <a href="/">{{ _("Home") }}</a>
-                       <span class="divider">/</span>
-               </li>
-               <li class="active">
-                       <a href="/jobs">{{ _("Jobs") }}</a>
-               </li>
-       </ul>
-
-       <ul class="nav nav-pills pull-right">
-               <li>
-                       <a href="/jobs/filter">{{ _("Filter jobs") }}</a>
-               </li>
-       </ul>
-
-       <div class="page-header">
-               <h2>{{ _("Jobs") }}</h2>
-       </div>
-
-       {% if arch or builder or date %}
-               <ul>
-                       {% if date %}
-                               <li>
-                                       {{ _("Showing only jobs from %s.") % date }}
-                               </li>
-                       {% end %}
-
-                       {% if builder %}
-                               <li>
-                                       <a href="/builder/{{ builder.name }}">
-                                               {{ _("Showing only builds that have been built on %s.") % builder.name }}
-                                       </a>
-                               </li>
-                       {% end %}
-
-                       {% if arch %}
-                               <li>
-                                       <a href="/arch/{{ arch.name }}">
-                                               {{ _("Showing only jobs built for %s.") % arch.name }}
-                                       </a>
-                               </li>
-                       {% end %}
-               </ul>
-
-               <hr>
-       {% end %}
-
-       {% module JobsList(jobs) %}
-{% end block %}
index fe57af8908945a05662f30a53b1caa8778fc566a..a2d5438f7e37c27a4db84f323678236a32e1b362 100644 (file)
                                                {% if show_user %}
                                                        {% if build.type == "scratch" and build.user %}
                                                                <td>
-                                                                       {% module Maintainer(build.user) %}
+                                                                       {% module LinkToUser(build.user) %}
                                                                </td>
                                                        {% elif build.type == "release" %}
-                                                               <td>{% module Maintainer(build.pkg.maintainer) %}</td>
+                                                               <td>{% module LinkToUser(build.pkg.maintainer) %}</td>
                                                        {% else %}
                                                                <td></td>
                                                        {% end %}
index c4a8460f7d93a366a3026a70c57bb78532ec4ceb..1e4ba8280fbc26a414bde2a09fd563d97f212720 100644 (file)
@@ -33,7 +33,7 @@
                                        <hr>
 
                                        <p class="muted">
-                                               {{ _("Author") }} {% module Maintainer(build.commit.author) %}
+                                               {{ _("Author") }} {% module LinkToUser(build.commit.author) %}
                                                <span class="pull-right">{{ locale.format_date(build.created, shorter=True) }}</span>
                                        </p>
                                {% else %}
@@ -45,7 +45,7 @@
 
                        {% elif build.type == "scratch" %}
                                <p class="muted">
-                                       {{ _("Owner") }} {% module Maintainer(build.owner) %}
+                                       {{ _("Owner") }} {% module LinkToUser(build.owner) %}
 
                                        <span class="pull-right">{{ locale.format_date(build.created, shorter=True) }}</span>
                                </p>
diff --git a/src/templates/modules/commit-message.html b/src/templates/modules/commit-message.html
new file mode 100644 (file)
index 0000000..bd57e7d
--- /dev/null
@@ -0,0 +1,3 @@
+<h4>{{ commit.subject }}</h4>
+
+{% module Text(commit.message) %}
\ No newline at end of file
index 2453071864be25baa46d7b09ec05d960ad04f3c9..7170e5fc3b512b9f48f46ed94f52ac3da38f7be6 100644 (file)
@@ -15,9 +15,7 @@
                                                <a href="/job/{{ job.uuid }}">{{ job.arch }}</a>
                                        </td>
                                        <td>
-                                               {% if job.state == "new" %}
-                                                       {{ _("New") }}
-                                               {% elif job.state == "pending" %}
+                                               {% if job.state == "pending" %}
                                                        {{ _("Pending") }}
                                                {% elif job.state == "failed" %}
                                                        {{ _("Failed") }}
@@ -29,8 +27,6 @@
                                                        {{ _("Running") }}
                                                {% elif job.state == "aborted" %}
                                                        {{ _("Aborted") }}
-                                               {% elif job.state == "dependency_error" %}
-                                                       {{ _("Dependency error") }}
                                                {% else %}
                                                        {{ job.state }}
                                                {% end %}
index cdb33f17cd528551728e5e60af57eac6413062d5..4f5bfed1a1255a7ef8d4ff0ca53f06f1cb19f28b 100644 (file)
@@ -14,7 +14,7 @@
                                <tr class="success">
                        {% elif job.state in ("dispatching", "uploading") %}
                                <tr class="info">
-                       {% elif job.state in ("aborted", "dependency_error", "failed") %}
+                       {% elif job.state in ("aborted", "failed") %}
                                <tr class="error">
                        {% else %}
                                <tr>
diff --git a/src/templates/modules/link-to-user.html b/src/templates/modules/link-to-user.html
new file mode 100644 (file)
index 0000000..08460a1
--- /dev/null
@@ -0,0 +1,16 @@
+{% if isinstance(user, users.User) %}
+       {% if user.is_admin() %}
+               <i class="icon-star"></i>
+       {% else %}
+               <i class="icon-user"></i>
+       {% end %}
+       <a href="/user/{{ user.name }}">
+               {{ user.realname }}
+       </a>
+{% elif user %}
+       {% import email.utils %}
+       {% set name, email_address = email.utils.parseaddr(user) %}
+
+       <i class="icon-envelope"></i>
+       <a href="mailto:{{ email_address }}">{{ name or email_address }}</a>
+{% end %}
\ No newline at end of file
index ff425c80377440873268ed2ecaa7f9ccd19ed28d..ca5a4a877518115284d9fe9b4ee53a85b126548c 100644 (file)
@@ -16,7 +16,7 @@
 
 {% block message %}
        {% if entry.get_message(current_user) %}
-               {% module Text(entry.get_message(current_user), remove_linebreaks=False) %}
+               {% module Text(entry.get_message(current_user)) %}
        {% else %}
                <p class="muted">
                        {{ _("No comment given.") }}
index 4ae75f58b36fbbb8e29d0d3ae2c893e9b50407eb..24632b150286c8e9f451caad4b8ac3905e5f70f5 100644 (file)
@@ -6,6 +6,6 @@
                        {{ format_date(entry.time) }}
                </p>
 
-               {% module Text(entry.get_message(current_user), pre=False) %}
+               {% module Text(entry.get_message(current_user)) %}
        </div>
 </li>
index 53edce8f51263addffd38d7986ecaa10a36d7bb6..7b995493b6f188fa833e80a4d59a23b60214ee9d 100644 (file)
@@ -33,7 +33,7 @@
                        {% end block %}
 
                        {% block message %}
-                               {% module Text(entry.get_message(current_user), pre=False) %}
+                               {% module Text(entry.get_message(current_user)) %}
                        {% end block %}
                </div>
        {% end block %}
diff --git a/src/templates/modules/maintainer.html b/src/templates/modules/maintainer.html
deleted file mode 100644 (file)
index be9c251..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{% if type == "string" and maintainer %}
-       <i class="icon-envelope"></i>
-       {% raw format_email(maintainer) %}
-{% elif type == "user" %}
-       {% if maintainer.is_admin() %}
-               <i class="icon-star"></i>
-       {% else %}
-               <i class="icon-user"></i>
-       {% end %}
-       <a href="/user/{{ maintainer.name }}">
-               {{ maintainer.realname }}
-       </a>
-{% end %}
index d3d6c5ba3a14a97ac668b47f212a591f0f246237..0feaa871e628b3fe935219fb32fdddd85f5d3d18 100644 (file)
@@ -22,6 +22,6 @@
 
        {% if pkg.maintainer %}
                <dt>{{ _("Maintainer") }}</dt>
-               <dd>{% module Maintainer(pkg.maintainer) %}</dd>
+               <dd>{% module LinkToUser(pkg.maintainer) %}</dd>
        {% end %}
 </dl>
diff --git a/src/templates/modules/text.html b/src/templates/modules/text.html
new file mode 100644 (file)
index 0000000..0d1dcb0
--- /dev/null
@@ -0,0 +1,7 @@
+{% for paragraph in paragraphs %}
+    <p>
+            {% apply linkify %}
+                {{ paragraph }}
+            {% end %}
+    </p>
+{% end %}
\ No newline at end of file
index 6d33e523a31ec4113f00a84fdf85ae081c25d27c..ee4556b1d5efd692519603253c73c7cc9b91682d 100644 (file)
                                <h4>
                                        <div class="pull-right">
                                                <div class="btn-group">
-                                                       <a class="btn btn-mini" href="{{ bugtracker.enter_url(pkg.name) }}" target="_blank">
+                                                       <a class="btn btn-mini" href="{{ backend.bugzilla.enter_url(pkg.name) }}" target="_blank">
                                                                <i class="icon-asterisk"></i> {{ _("File new bug") }}
                                                        </a>
-                                                       <a class="btn btn-mini" href="{{ bugtracker.buglist_url(pkg.name) }}" target="_blank">
+                                                       <a class="btn btn-mini" href="{{ backend.bugzilla.buglist_url(pkg.name) }}" target="_blank">
                                                                {{ _("Show all bugs") }}
                                                        </a>
                                                </div>
index 8d89a055d13611ef2926ee4775c33b498eaa9284..0f3dc147f94766b09aca5705e127de209101cb18 100644 (file)
@@ -75,7 +75,7 @@
                                        {% if pkg.maintainer %}
                                                <tr>
                                                        <td>{{ _("Maintainer") }}</td>
-                                                       <td>{% module Maintainer(pkg.maintainer) %}</td>
+                                                       <td>{% module LinkToUser(pkg.maintainer) %}</td>
                                                </tr>
                                        {% end %}
                                        <tr>
similarity index 55%
rename from src/templates/packages-list.html
rename to src/templates/packages/index.html
index 05ee8b8040ef37488b4ede85ef1b2f83dedbf98a..6b8f583db27525fef106c14c56a6ee2b2b974b47 100644 (file)
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "../base.html" %}
 
 {% block title %}{{ _("Package list") }}{% end block %}
 
                <h1>{{ _("Package list") }}</h1>
        </div>
 
-       <div class="row">
-               <div class="span6">
-                       <p>
-                               {{ _("This is an alphabetically ordered list of all packages in the distribution.") }}
-                               {{ _("Click on a link to see further information about the package.") }}
-                       </p>
-               </div>
-
-               <div class="span6">
-                       <div class="btn-group">
-                               <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                                       {{ _("Selection") }}
-                                       <span class="caret"></span>
-                               </a>
-                               <ul class="dropdown-menu">
-                                       <li>
-                                               <a href="?show=broken">{{ _("Show broken packages") }}</a>
-                                       </li>
-                                       <li>
-                                               <a href="?show=all">{{ _("Show all packages") }}</a>
-                                       </li>
-                               </ul>
-                       </div>
-               </div>
-       </div>
+       <p>
+               {{ _("This is an alphabetically ordered list of all packages in the distribution.") }}
+               {{ _("Click on a link to see further information about the package.") }}
+       </p>
 
        <div class="row">
                <div class="span12">
                                                <tr>
                                                        <td colspan="2">
                                                                <a name="{{ letter }}"></a>
-                                                               <h2>{{ letter.upper() }} <small>({{ len(pkgs) }})</small></h2>
+                                                               <h2>{{ letter.upper() }}</h2>
                                                        </td>
                                                </tr>
-                                               {% for pkg, summary in pkgs %}
+                                               {% for pkg in pkgs %}
                                                        <tr>
                                                                <td>
-                                                                       <a href="/package/{{ pkg }}">{{ pkg }}</a>
+                                                                       <a href="/package/{{ pkg.name }}">{{ pkg.name }}</a>
                                                                </td>
                                                                <td>
-                                                                       {{ summary }}
+                                                                       {{ pkg.summary }}
                                                                </td>
                                                        </tr>
                                                {% end %}
diff --git a/src/templates/queue.html b/src/templates/queue.html
new file mode 100644 (file)
index 0000000..5ad565f
--- /dev/null
@@ -0,0 +1,41 @@
+{% extends "base.html" %}
+
+{% block title %}{{ _("Job Queue") }} - {{ arch or _("All Architectures") }}{% end block %}
+
+{% block body %}
+       <ul class="breadcrumb">
+               <li>
+                       <a href="/">{{ _("Home") }}</a>
+                       <span class="divider">/</span>
+               </li>
+               <li {% if not arch %}class="active"{% end %}>
+                       <a href="/queue">{{ _("Job Queue") }}</a>
+                       {% if arch %}
+                               <span class="divider">/</span>
+                       {% end %}
+               </li>
+               {% if arch %}
+                       <li class="active">
+                               <a href="/queue/{{ arch }}">{{ arch }}</a>
+                       </li>
+               {% end %}
+       </ul>
+
+       <div class="page-header">
+               <h2>{{ _("Job Queue") }}</h2>
+       </div>
+
+       <ul class="nav nav-pills">
+               <li {% if not arch %}class="active"{% end %}>
+                       <a href="/queue">{{ _("All") }}</a>
+               </li>
+
+               {% for a in backend.arches %}
+                       <li {% if a == arch %}class="active"{% end %}>
+                               <a href="/queue/{{ a }}">{{ a }}</a>
+                       </li>
+               {% end %}
+       </ul>
+
+       {% module JobsList(queue) %}
+{% end block %}
index 4a4db0aeffa6a9c9998c5b8c80564216f7787961..1d8338e41a5d3155760c788fdc914758132bffbd 100644 (file)
@@ -55,7 +55,7 @@
        <div class="row">
                <div class="span8">
                        <blockquote>
-                               {% module Text(repo.description, pre=False) %}
+                               {% module Text(repo.description) %}
                        </blockquote>
 
                        <br><br>
index 01425ba9f904e03d19441c98b89468f6fde891c3..5be08d83bc05dae596b34055cde772915f9020c3 100644 (file)
@@ -13,11 +13,22 @@ from .. import Backend
 from ..constants import *
 from ..decorators import *
 
-from .handlers import *
-
-from . import handlers_api
+# Import all handlers
+from . import api
+from . import auth
+from . import builders
+from . import builds
+from . import distributions
 from . import errors
+from . import jobs
+from . import keys
 from . import mirrors
+from . import packages
+from . import search
+from . import updates
+from . import users
+from .handlers import *
+
 from . import ui_modules
 
 # Enable logging
@@ -69,9 +80,9 @@ class Application(tornado.web.Application):
                                "JobsTable"          : ui_modules.JobsTableModule,
                                "CommentsTable"      : ui_modules.CommentsTableModule,
                                "FilesTable"         : ui_modules.FilesTableModule,
+                               "LinkToUser"         : ui_modules.LinkToUserModule,
                                "LogTable"           : ui_modules.LogTableModule,
                                "LogFilesTable"      : ui_modules.LogFilesTableModule,
-                               "Maintainer"         : ui_modules.MaintainerModule,
                                "PackagesTable"      : ui_modules.PackagesTableModule,
                                "PackageTable2"      : ui_modules.PackageTable2Module,
                                "PackageHeader"      : ui_modules.PackageHeaderModule,
@@ -103,77 +114,78 @@ class Application(tornado.web.Application):
                        (r"/", IndexHandler),
 
                        # Handle all the users logins/logouts/registers and stuff.
-                       (r"/login", LoginHandler),
-                       (r"/logout", LogoutHandler),
-                       (r"/register", RegisterHandler),
-                       (r"/password-recovery", PasswordRecoveryHandler),
+                       (r"/login", auth.LoginHandler),
+                       (r"/logout", auth.LogoutHandler),
+                       (r"/register", auth.RegisterHandler),
+                       (r"/password-recovery", auth.PasswordRecoveryHandler),
 
                        # User profiles
-                       (r"/users", UsersHandler),
-                       (r"/user/(\w+)/impersonate", UserImpersonateHandler),
-                       (r"/user/(\w+)/passwd", UserPasswdHandler),
-                       (r"/user/(\w+)/delete", UserDeleteHandler),
-                       (r"/user/(\w+)/edit", UserEditHandler),
-                       (r"/user/(\w+)/activate", ActivationHandler),
-                       (r"/user/(\w+)", UserHandler),
-                       (r"/profile", UserHandler),
-                       (r"/profile/builds", UsersBuildsHandler),
+                       (r"/users", users.UsersHandler),
+                       (r"/user/(\w+)/impersonate", users.UserImpersonateHandler),
+                       (r"/user/(\w+)/passwd", users.UserPasswdHandler),
+                       (r"/user/(\w+)/delete", users.UserDeleteHandler),
+                       (r"/user/(\w+)/edit", users.UserEditHandler),
+                       (r"/user/(\w+)/activate", auth.ActivationHandler),
+                       (r"/user/(\w+)", users.UserHandler),
+                       (r"/profile", users.UserHandler),
+                       (r"/profile/builds", users.UsersBuildsHandler),
 
                        # Packages
-                       (r"/packages", PackageListHandler),
-                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", PackageDetailHandler),
-                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/download(.*)", PackageFileDownloadHandler),
-                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/view(.*)", PackageFileViewHandler),
-                       (r"/package/([\w\-\+]+)", PackageNameHandler),
-                       (r"/package/([\w\-\+]+)/builds/scratch", PackageScratchBuildsHandler),
-                       (r"/package/([\w\-\+]+)/builds/times", PackageBuildsTimesHandler),
-                       (r"/package/([\w\-\+]+)/changelog", PackageChangelogHandler),
-                       (r"/package/([\w\-\+]+)/properties", PackagePropertiesHandler),
+                       (r"/packages", packages.IndexHandler),
+                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", packages.PackageDetailHandler),
+                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/download(.*)", packages.PackageFileDownloadHandler),
+                       (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/view(.*)", packages.PackageFileViewHandler),
+                       (r"/package/([\w\-\+]+)", packages.PackageNameHandler),
+                       (r"/package/([\w\-\+]+)/builds/scratch", packages.PackageScratchBuildsHandler),
+                       (r"/package/([\w\-\+]+)/builds/times", packages.PackageBuildsTimesHandler),
+                       (r"/package/([\w\-\+]+)/changelog", packages.PackageChangelogHandler),
+                       (r"/package/([\w\-\+]+)/properties", packages.PackagePropertiesHandler),
 
                        # Files
                        (r"/file/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", FileDetailHandler),
 
                        # Builds
-                       (r"/builds", BuildsHandler),
-                       (r"/builds/filter", BuildFilterHandler),
-                       (r"/builds/queue", BuildQueueHandler),
-                       (r"/builds/comments", BuildsCommentsHandler),
-                       (r"/builds/comments/(\w+)", BuildsCommentsHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", BuildDetailHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/bugs", BuildBugsHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/manage", BuildManageHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/comment", BuildDetailCommentHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/priority", BuildPriorityHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/state", BuildStateHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watch", BuildWatchersAddHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watchers", BuildWatchersHandler),
-                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/delete", BuildDeleteHandler),
+                       (r"/builds", builds.BuildsHandler),
+                       (r"/builds/filter", builds.BuildFilterHandler),
+                       (r"/builds/queue", builds.BuildQueueHandler),
+                       (r"/builds/comments", builds.BuildsCommentsHandler),
+                       (r"/builds/comments/(\w+)", builds.BuildsCommentsHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", builds.BuildDetailHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/bugs", builds.BuildBugsHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/manage", builds.BuildManageHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/comment", builds.BuildDetailCommentHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/priority", builds.BuildPriorityHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/state", builds.BuildStateHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watch", builds.BuildWatchersAddHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watchers", builds.BuildWatchersHandler),
+                       (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/delete", builds.BuildDeleteHandler),
+
+                       (r"/queue", jobs.ShowQueueHandler),
+                       (r"/queue/([\w_]+)", jobs.ShowQueueHandler),
 
                        # Jobs
-                       (r"/jobs", JobsIndexHandler),
-                       (r"/jobs/filter", JobsFilterHandler),
-                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", JobDetailHandler),
-                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/abort", JobAbortHandler),
-                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/buildroot", JobBuildrootHandler),
-                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/schedule", JobScheduleHandler),
+                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", jobs.JobDetailHandler),
+                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/abort", jobs.JobAbortHandler),
+                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/buildroot", jobs.JobBuildrootHandler),
+                       (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/schedule", jobs.JobScheduleHandler),
 
                        # Builders
-                       (r"/builders", BuilderListHandler),
-                       (r"/builder/new", BuilderNewHandler),
-                       (r"/builder/([A-Za-z0-9\-\.]+)/enable", BuilderEnableHander),
-                       (r"/builder/([A-Za-z0-9\-\.]+)/disable", BuilderDisableHander),
-                       (r"/builder/([A-Za-z0-9\-\.]+)/delete", BuilderDeleteHandler),
-                       (r"/builder/([A-Za-z0-9\-\.]+)/edit", BuilderEditHandler),
-                       (r"/builder/([A-Za-z0-9\-\.]+)/renew", BuilderRenewPassphraseHandler),
-                       (r"/builder/([A-Za-z0-9\-\.]+)", BuilderDetailHandler),
+                       (r"/builders", builders.BuilderListHandler),
+                       (r"/builder/new", builders.BuilderNewHandler),
+                       (r"/builder/([A-Za-z0-9\-\.]+)/enable", builders.BuilderEnableHander),
+                       (r"/builder/([A-Za-z0-9\-\.]+)/disable", builders.BuilderDisableHander),
+                       (r"/builder/([A-Za-z0-9\-\.]+)/delete", builders.BuilderDeleteHandler),
+                       (r"/builder/([A-Za-z0-9\-\.]+)/edit", builders.BuilderEditHandler),
+                       (r"/builder/([A-Za-z0-9\-\.]+)/renew", builders.BuilderRenewPassphraseHandler),
+                       (r"/builder/([A-Za-z0-9\-\.]+)", builders.BuilderDetailHandler),
 
                        # Distributions
-                       (r"/distros", DistributionListHandler),
-                       (r"/distro/([A-Za-z0-9\-\.]+)", DistributionDetailHandler),
+                       (r"/distros", distributions.DistributionListHandler),
+                       (r"/distro/([A-Za-z0-9\-\.]+)", distributions.DistributionDetailHandler),
 
                        # XXX THOSE URLS ARE DEPRECATED
-                       (r"/distribution/delete/([A-Za-z0-9\-\.]+)", DistributionDetailHandler),
-                       (r"/distribution/edit/([A-Za-z0-9\-\.]+)", DistributionEditHandler),
+                       (r"/distribution/delete/([A-Za-z0-9\-\.]+)", distributions.DistributionDetailHandler),
+                       (r"/distribution/edit/([A-Za-z0-9\-\.]+)", distributions.DistributionEditHandler),
 
                        (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)",
                                RepositoryDetailHandler),
@@ -185,21 +197,21 @@ class Application(tornado.web.Application):
                                RepositoryEditHandler),
 
                        (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)",
-                               DistroSourceDetailHandler),
+                               distributions.DistroSourceDetailHandler),
                        (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/commits",
-                               DistroSourceCommitsHandler),
+                               distributions.DistroSourceCommitsHandler),
                        (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})",
-                               DistroSourceCommitDetailHandler),
+                               distributions.DistroSourceCommitDetailHandler),
                        (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})/reset",
-                               DistroSourceCommitResetHandler),
+                               distributions.DistroSourceCommitResetHandler),
 
                        (r"/distro/([A-Za-z0-9\-\.]+)/update/create",
-                               DistroUpdateCreateHandler),
+                               distributions.DistroUpdateCreateHandler),
                        (r"/distro/([A-Za-z0-9\-\.]+)/update/(\d+)/(\d+)",
-                               DistroUpdateDetailHandler),
+                               distributions.DistroUpdateDetailHandler),
 
                        # Updates
-                       (r"/updates", UpdatesHandler),
+                       (r"/updates", updates.UpdatesHandler),
 
                        # Mirrors
                        (r"/mirrors",                                   mirrors.MirrorListHandler),
@@ -209,10 +221,10 @@ class Application(tornado.web.Application):
                        (r"/mirror/([\w\-\.]+)",                mirrors.MirrorDetailHandler),
 
                        # Key management
-                       (r"/keys", KeysListHandler),
-                       (r"/key/import", KeysImportHandler),
-                       (r"/key/([A-Z0-9]+)", KeysDownloadHandler),
-                       (r"/key/([A-Z0-9]+)/delete", KeysDeleteHandler),
+                       (r"/keys", keys.KeysListHandler),
+                       (r"/key/import", keys.KeysImportHandler),
+                       (r"/key/([A-Z0-9]+)", keys.KeysDownloadHandler),
+                       (r"/key/([A-Z0-9]+)/delete", keys.KeysDeleteHandler),
 
                        # Documents
                        (r"/documents", DocsIndexHandler),
@@ -221,7 +233,7 @@ class Application(tornado.web.Application):
                        (r"/documents/what-is-the-pakfire-build-service", DocsWhatsthisHandler),
 
                        # Search
-                       (r"/search", SearchHandler),
+                       (r"/search", search.SearchHandler),
 
                        # Uploads
                        (r"/uploads", UploadsHandler),
@@ -233,7 +245,7 @@ class Application(tornado.web.Application):
                        (r"/sessions", SessionsHandler),
 
                        # API handlers
-                       (r"/api/packages/autocomplete", handlers_api.ApiPackagesAutocomplete),
+                       (r"/api/packages/autocomplete", api.ApiPackagesAutocomplete),
                ], default_handler_class=errors.Error404Handler, **settings)
 
                logging.info("Successfully initialied application")
similarity index 69%
rename from src/web/handlers_api.py
rename to src/web/api.py
index df84c5122844f3c1360b3e55ff2cb585715ea6ac..ad28fe1c288c1f1e43055f5c990734db4845fb1d 100644 (file)
@@ -4,14 +4,14 @@ import tornado.web
 
 from . import base
 
-class ApiPackagesAutocomplete(base.ApiBaseHandler):
+class ApiPackagesAutocomplete(base.BaseHandler):
        def get(self):
                query = self.get_argument("q")
                if not query:
                        raise tornado.web.HTTPError(400)
 
                # Query database.
-               packages = self.pakfire.packages.autocomplete(query, limit=8)
+               packages = self.backend.packages.autocomplete(query, limit=8)
 
                res = {
                        "query"    : query,
similarity index 97%
rename from src/web/handlers_auth.py
rename to src/web/auth.py
index dd4b7eec619def8a340d6aaa6284ced1bf5b1dbc..4538db54b6842897f30426d684af1178a988a129 100644 (file)
@@ -19,7 +19,7 @@ class LoginHandler(base.BaseHandler):
                passphrase = self.get_argument("pass", None)
 
                # Log in the user
-               user = self.pakfire.users.auth(name, passphrase)
+               user = self.backend.users.auth(name, passphrase)
 
                # If the login was unsuccessful
                if not user:
@@ -107,7 +107,7 @@ class RegisterHandler(base.BaseHandler):
 
 class ActivationHandler(base.BaseHandler):
        def get(self, _user):
-               user = self.pakfire.users.get_by_name(_user)
+               user = self.backend.users.get_by_name(_user)
                if not user:
                        raise tornado.web.HTTPError(404)
 
index 6f77a7ec85bf31b1cc452f46ad3682b0550daece..3ff7fa4b054fe200e1d9cbe986d24a9f359a5a38 100644 (file)
@@ -76,7 +76,7 @@ class BaseHandler(tornado.web.RequestHandler):
                ns = tornado.web.RequestHandler.get_template_namespace(self)
 
                ns.update({
-                       "bugtracker"      : self.pakfire.bugzilla,
+                       "backend"         : self.backend,
                        "hostname"        : self.request.host,
                        "format_date"     : self.format_date,
                        "format_size"     : misc.format_size,
@@ -109,16 +109,4 @@ class BaseHandler(tornado.web.RequestHandler):
                        tb = None
 
                self.render(error_document, status_code=status_code,
-                       status_message=status_message, exc_info=exc_info, tb=tb, **kwargs)
-
-       @property
-       def pakfire(self):
-               return self.backend
-
-       @property
-       def mirrors(self):
-               return self.pakfire.mirrors
-
-
-class ApiBaseHandler(BaseHandler):
-       pass
+                       status_message=status_message, exc_info=exc_info, tb=tb, **kwargs)
\ No newline at end of file
similarity index 87%
rename from src/web/handlers_builders.py
rename to src/web/builders.py
index 3fa039091fd0bd54639cd5bcdd32d928fe984b1a..c8f610d4254466af78eb3134846876f23fc6fbd3 100644 (file)
@@ -2,8 +2,6 @@
 
 import tornado.web
 
-from .. import builders
-
 from . import base
 
 class BuilderListHandler(base.BaseHandler):
@@ -13,11 +11,10 @@ class BuilderListHandler(base.BaseHandler):
 
 class BuilderDetailHandler(base.BaseHandler):
        def get(self, hostname):
-               builder = self.pakfire.builders.get_by_name(hostname)
+               builder = self.backend.builders.get_by_name(hostname)
 
                # Get running and pending jobs.
-               jobs = self.pakfire.jobs.get_active(builder=builder)
-               jobs += builder.jobqueue
+               jobs = builder.active_jobs + list(builder.jobqueue)
 
                # Get log.
                log = builder.get_history(limit=5)
@@ -29,7 +26,7 @@ class BuilderDetailHandler(base.BaseHandler):
                if not self.current_user.has_perm("maintain_mirrors"):
                        raise tornado.web.HTTPError(403, "User is not allowed to do this.")
 
-               builder = self.pakfire.builders.get_by_name(hostname)
+               builder = self.backend.builders.get_by_name(hostname)
 
                with self.db.transaction():
                        builder.description = self.get_argument("description", None)
@@ -59,7 +56,7 @@ class BuilderNewHandler(base.BaseHandler):
 class BuilderEditHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, hostname):
-               builder = self.pakfire.builders.get_by_name(hostname)
+               builder = self.backend.builders.get_by_name(hostname)
                if not builder:
                        raise tornado.web.HTTPError(404, "Builder not found")
 
@@ -67,7 +64,7 @@ class BuilderEditHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, hostname):
-               builder = self.pakfire.builders.get_by_name(hostname)
+               builder = self.backend.builders.get_by_name(hostname)
                if not builder:
                        raise tornado.web.HTTPError(404, "Builder not found: %s" % hostname)
 
@@ -96,7 +93,7 @@ class BuilderEditHandler(base.BaseHandler):
 class BuilderRenewPassphraseHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, name):
-               builder = self.pakfire.builders.get_by_name(name)
+               builder = self.backend.builders.get_by_name(name)
 
                passphrase = builder.regenerate_passphrase()
 
@@ -107,7 +104,7 @@ class BuilderRenewPassphraseHandler(base.BaseHandler):
 class BuilderDeleteHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, name):
-               builder = self.pakfire.builders.get_by_name(name)
+               builder = self.backend.builders.get_by_name(name)
                if not builder:
                        raise tornado.web.HTTPError(404, "Builder not found: %s" % name)
 
@@ -131,7 +128,7 @@ class BuilderStatusChangeHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def get(self, hostname):
-               builder = self.pakfire.builders.get_by_name(hostname)
+               builder = self.backend.builders.get_by_name(hostname)
                if not builder:
                        raise tornado.web.HTTPError(404, "Builder not found: %s" % hostname)
 
similarity index 90%
rename from src/web/handlers_builds.py
rename to src/web/builds.py
index c11a162bbfce8ed6fa8d7cd687fe2febd341b8db..dd28ca058e8908276400fe02f618025fa38e1722 100644 (file)
@@ -25,7 +25,7 @@ class BuildsHandler(base.BaseHandler):
 
 class BuildBaseHandler(base.BaseHandler):
        def get_build(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "No such build: %s" % uuid)
 
@@ -79,7 +79,7 @@ class BuildDeleteHandler(BuildBaseHandler):
 class BuildBugsHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "No such build: %s" % uuid)
 
@@ -91,7 +91,7 @@ class BuildBugsHandler(base.BaseHandler):
                fixed_bugs = build.get_bugs()
                open_bugs = []
 
-               for bug in self.pakfire.bugzilla.get_bugs_from_component(build.pkg.name):
+               for bug in self.backend.bugzilla.get_bugs_from_component(build.pkg.name):
                        if bug in fixed_bugs:
                                continue
 
@@ -102,7 +102,7 @@ class BuildBugsHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "No such build: %s" % uuid)
 
@@ -137,7 +137,7 @@ class BuildsCommentsHandler(base.BaseHandler):
        def get(self, user_name=None):
                user = None
                if user_name:
-                       user = self.pakfire.users.get_by_name(user_name)
+                       user = self.backend.users.get_by_name(user_name)
 
                limit  = self.get_argument("limit", 10)
                offset = self.get_argument("offset", 0)
@@ -150,7 +150,7 @@ class BuildsCommentsHandler(base.BaseHandler):
 
                # Try to get one more comment than requested and check if there
                # is a next page that it to be shown.
-               comments = self.pakfire.builds.get_comments(limit=limit + 1,
+               comments = self.backend.builds.get_comments(limit=limit + 1,
                        offset=offset, user=user)
 
                # Set markers for next and prev pages.
@@ -166,7 +166,7 @@ class BuildsCommentsHandler(base.BaseHandler):
 
 class BuildStateHandler(base.BaseHandler):
        def get(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "No such build: %s" % uuid)
 
@@ -174,7 +174,7 @@ class BuildStateHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "No such build: %s" % uuid)
 
@@ -210,7 +210,7 @@ class BuildQueueHandler(base.BaseHandler):
 class BuildDetailCommentHandler(base.BaseHandler):
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -237,7 +237,7 @@ class BuildDetailCommentHandler(base.BaseHandler):
 class BuildManageHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found: %s" % uuid)
 
@@ -256,7 +256,7 @@ class BuildManageHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found: %s" % uuid)
 
@@ -294,7 +294,7 @@ class BuildManageHandler(base.BaseHandler):
 class BuildPriorityHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -303,7 +303,7 @@ class BuildPriorityHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -328,7 +328,7 @@ class BuildPriorityHandler(base.BaseHandler):
 
 class BuildWatchersHandler(base.BaseHandler):
        def get(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -343,7 +343,7 @@ class BuildWatchersHandler(base.BaseHandler):
 class BuildWatchersAddHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, uuid, error_msg=None):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -352,11 +352,11 @@ class BuildWatchersAddHandler(base.BaseHandler):
                watchers = build.get_watchers()
 
                self.render("builds-watchers-add.html", error_msg=error_msg,
-                       build=build, users=self.pakfire.users, watchers=watchers)
+                       build=build, users=self.backend.users, watchers=watchers)
 
        @tornado.web.authenticated
        def post(self, uuid):
-               build = self.pakfire.builds.get_by_uuid(uuid)
+               build = self.backend.builds.get_by_uuid(uuid)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Build not found")
@@ -368,7 +368,7 @@ class BuildWatchersAddHandler(base.BaseHandler):
                        user_id = self.get_argument("user_id", self.current_user.id)
                assert user_id
 
-               user = self.pakfire.users.get_by_id(user_id)
+               user = self.backend.users.get_by_id(user_id)
                if not user:
                        _ = self.locale.translate
                        error_msg = _("User not found.")
@@ -387,7 +387,7 @@ class BuildListHandler(base.BaseHandler):
                builder = self.get_argument("builder", None)
                state = self.get_argument("state", None)
 
-               builds = self.pakfire.builds.get_latest(state=state, builder=builder,
+               builds = self.backend.builds.get_latest(state=state, builder=builder,
                        limit=25)
 
                self.render("build-list.html", builds=builds)
@@ -395,8 +395,8 @@ class BuildListHandler(base.BaseHandler):
 
 class BuildFilterHandler(base.BaseHandler):
        def get(self):
-               builders = self.pakfire.builders.get_all()
-               distros  = self.pakfire.distros.get_all()
+               builders = self.backend.builders.get_all()
+               distros  = self.backend.distros.get_all()
 
                self.render("build-filter.html", builders=builders, distros=distros)
 
similarity index 88%
rename from src/web/handlers_distro.py
rename to src/web/distributions.py
index 5c8ac88180101fc459a2e572e8580011ea8ef2fc..b85e484a67bc52adfcd3cdf4a96c9b70da078489 100644 (file)
@@ -11,7 +11,7 @@ class DistributionListHandler(base.BaseHandler):
 
 class DistributionDetailHandler(base.BaseHandler):
        def get(self, name):
-               distro = self.pakfire.distros.get_by_name(name)
+               distro = self.backend.distros.get_by_name(name)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distro not found")
 
@@ -20,11 +20,11 @@ class DistributionDetailHandler(base.BaseHandler):
 
 class DistributionEditHandler(base.BaseHandler):
        def prepare(self):
-               self.sources = self.pakfire.sources.get_all()
+               self.sources = self.backend.sources.get_all()
 
        @tornado.web.authenticated
        def get(self, name):
-               distro = self.pakfire.distros.get_by_name(name)
+               distro = self.backend.distros.get_by_name(name)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distro not found")
 
@@ -33,7 +33,7 @@ class DistributionEditHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, name):
-               distro = self.pakfire.distros.get_by_name(name)
+               distro = self.backend.distros.get_by_name(name)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distro not found")
 
@@ -69,7 +69,7 @@ class DistributionEditHandler(base.BaseHandler):
 
 class DistroSourceDetailHandler(base.BaseHandler):
        def get(self, distro_ident, source_ident):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distro not found")
 
@@ -87,7 +87,7 @@ class DistroSourceDetailHandler(base.BaseHandler):
 
 class DistroSourceCommitsHandler(base.BaseHandler):
        def get(self, distro_ident, source_ident):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distro not found")
 
@@ -116,7 +116,7 @@ class DistroSourceCommitsHandler(base.BaseHandler):
 
 class DistroSourceCommitDetailHandler(base.BaseHandler):
        def get(self, distro_ident, source_ident, commit_ident):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distribution '%s' not found" % distro_ident)
 
@@ -137,7 +137,7 @@ class DistroSourceCommitDetailHandler(base.BaseHandler):
 class DistroSourceCommitResetHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, distro_ident, source_ident, commit_ident):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distribution '%s' not found" % distro_ident)
 
@@ -168,14 +168,14 @@ class DistroSourceCommitResetHandler(base.BaseHandler):
 
 class DistroUpdateCreateHandler(base.BaseHandler):
        def get(self, distro_ident):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distribution '%s' not found" % distro_ident)
 
                # Get all preset builds.
                builds = []
                for build in self.get_arguments("builds", []):
-                       build = self.pakfire.builds.get_by_uuid(build)
+                       build = self.backend.builds.get_by_uuid(build)
                        builds.append(build)
 
                builds.sort()
@@ -186,7 +186,7 @@ class DistroUpdateCreateHandler(base.BaseHandler):
 
 class DistroUpdateDetailHandler(base.BaseHandler):
        def get(self, distro_ident, year, num):
-               distro = self.pakfire.distros.get_by_name(distro_ident)
+               distro = self.backend.distros.get_by_name(distro_ident)
                if not distro:
                        raise tornado.web.HTTPError(404, "Distribution '%s' not found" % distro_ident)
 
@@ -200,13 +200,13 @@ class DistroUpdateDetailHandler(base.BaseHandler):
 # XXX currently unused
 class SourceListHandler(base.BaseHandler):
        def get(self):
-               sources = self.pakfire.sources.get_all()
+               sources = self.backend.sources.get_all()
 
                self.render("source-list.html", sources=sources)
 
 
 class SourceDetailHandler(base.BaseHandler):
        def get(self, id):
-               source = self.pakfire.sources.get_by_id(id)
+               source = self.backend.sources.get_by_id(id)
 
                self.render("source-detail.html", source=source)
index dc8803bc0570c474be579bbebb23bcb08cc0203c..0f5250b74aaa7347dc82f6bcf4d041be177013e4 100644 (file)
@@ -1,31 +1,24 @@
 #!/usr/bin/python
 
-import random
 import tornado.web
 
 from . import base
 
-from .handlers_auth import *
-from .handlers_builds import *
-from .handlers_builders import *
-from .handlers_distro import *
-from .handlers_jobs import *
-from .handlers_keys import *
-from .handlers_packages import *
-from .handlers_search import *
-from .handlers_updates import *
-from .handlers_users import *
-
 class IndexHandler(base.BaseHandler):
        def get(self):
-               jobs = self.pakfire.jobs.get_active()
-               jobs += self.pakfire.jobs.get_latest(age="24 hours", limit=5)
+               jobs = []
+
+               # Get all active jobs
+               jobs += self.backend.jobs.get_active()
+
+               # Get some recently finished jobs
+               jobs += self.backend.jobs.get_recently_ended(limit=12)
 
                # Updates
                updates = []
                active = True
                for type in ("stable", "unstable", "testing"):
-                       u = self.pakfire.updates.get_latest(type=type)
+                       u = self.backend.updates.get_latest(type=type)
                        if u:
                                updates.append((type, u, active))
                                active = False
@@ -64,7 +57,7 @@ class DocsWhatsthisHandler(base.BaseHandler):
 
 class FileDetailHandler(base.BaseHandler):
        def get(self, uuid):
-               pkg, file = self.pakfire.packages.get_with_file_by_uuid(uuid)
+               pkg, file = self.backend.packages.get_with_file_by_uuid(uuid)
 
                if not file:
                        raise tornado.web.HTTPError(404, "File not found")
@@ -74,7 +67,7 @@ class FileDetailHandler(base.BaseHandler):
 
 class LogHandler(base.BaseHandler):
        def get(self):
-               self.render("log.html", log=self.pakfire.log)
+               self.render("log.html", log=self.backend.log)
 
 
 class SessionsHandler(base.BaseHandler):
@@ -102,7 +95,7 @@ class SessionsHandler(base.BaseHandler):
 
 class RepositoryDetailHandler(base.BaseHandler):
        def get(self, distro, repo):
-               distro = self.pakfire.distros.get_by_name(distro)
+               distro = self.backend.distros.get_by_name(distro)
                if not distro:
                        raise tornado.web.HTTPError(404)
 
@@ -137,7 +130,7 @@ class RepositoryDetailHandler(base.BaseHandler):
 class RepositoryEditHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, distro, repo):
-               distro = self.pakfire.distros.get_by_name(distro)
+               distro = self.backend.distros.get_by_name(distro)
                if not distro:
                        raise tornado.web.HTTPError(404)
 
@@ -152,7 +145,7 @@ class RepositoryEditHandler(base.BaseHandler):
 
 class RepositoryConfHandler(base.BaseHandler):
        def get(self, distro, repo):
-               distro = self.pakfire.distros.get_by_name(distro)
+               distro = self.backend.distros.get_by_name(distro)
                if not distro:
                        raise tornado.web.HTTPError(404)
 
@@ -172,7 +165,7 @@ class RepositoryConfHandler(base.BaseHandler):
 
 class RepositoryMirrorlistHandler(base.BaseHandler):
        def get(self, distro, repo):
-               distro = self.pakfire.distros.get_by_name(distro)
+               distro = self.backend.distros.get_by_name(distro)
                if not distro:
                        raise tornado.web.HTTPError(404)
 
@@ -197,7 +190,7 @@ class RepositoryMirrorlistHandler(base.BaseHandler):
                }
 
                mirrors = []
-               for mirror in self.mirrors.make_mirrorlist(self.current_address):
+               for mirror in self.backend.mirrors.make_mirrorlist(self.current_address):
                        mirrors.append({
                                "url"       : "/".join((mirror.url, repo.basepath, arch)),
                                "location"  : mirror.country_code,
@@ -219,7 +212,7 @@ class RepoActionHandler(base.BaseHandler):
 
                action_id = self.get_argument("id")
 
-               action = self.pakfire.repos.get_action_by_id(action_id)
+               action = self.backend.repos.get_action_by_id(action_id)
                if not action:
                        raise tornado.web.HTTPError(400)
 
similarity index 64%
rename from src/web/handlers_jobs.py
rename to src/web/jobs.py
index f3f016cfd76688516a88cef8e9a6d25aa5904cfb..162e22a293f39fcae88a15c89f8d254615571021 100644 (file)
@@ -4,41 +4,22 @@ import tornado.web
 
 from . import base
 
-class JobsIndexHandler(base.BaseHandler):
-       def get(self):
-               # Filter for a certain arch.
-               arch = self.get_argument("arch", None)
-               if not arch or not self.backend.arches.exists(arch):
-                       raise tornado.web.HTTPError(400, "Architecture does not exist")
-
-               # Check if we need to filter for a certain builder.
-               builder_name = self.get_argument("builder", None)
-               if builder_name:
-                       builder = self.pakfire.builders.get_by_name(builder_name)
-               else:
-                       builder = None
-
-               # Filter for a certain date.
-               date = self.get_argument("date", None)
-
-               # Get all jobs, that fulfill the criteria.
-               jobs = self.pakfire.jobs.get_latest(limit=50, arch=arch, builder=builder,
-                       date=date)
-
-               self.render("jobs-index.html", jobs=jobs, arch=arch, builder=builder,
-                       date=date)
+class ShowQueueHandler(base.BaseHandler):
+       def get(self, arch=None):
+               if arch:
+                       if not self.backend.arches.exists(arch):
+                               raise tornado.web.HTTPError(400, "Architecture does not exist")
 
+                       queue = self.backend.jobqueue.for_arches([arch, "noarch"])
+               else:
+                       queue = self.backend.jobqueue
 
-class JobsFilterHandler(base.BaseHandler):
-       def get(self):
-               builders = self.pakfire.builders.get_all()
-
-               self.render("jobs-filter.html", arches=self.backend.arches, builders=builders)
+               self.render("queue.html", arch=arch, queue=queue)
 
 
 class JobDetailHandler(base.BaseHandler):
        def get(self, uuid):
-               job = self.pakfire.jobs.get_by_uuid(uuid)
+               job = self.backend.jobs.get_by_uuid(uuid)
                if not job:
                        raise tornado.web.HTTPError(404, "No such job: %s" % job)
 
@@ -50,7 +31,7 @@ class JobDetailHandler(base.BaseHandler):
 
 class JobBuildrootHandler(base.BaseHandler):
        def get(self, uuid):
-               job = self.pakfire.jobs.get_by_uuid(uuid)
+               job = self.backend.jobs.get_by_uuid(uuid)
                if not job:
                        raise tornado.web.HTTPError(404, "Job not found: %s" % uuid)
 
@@ -78,7 +59,7 @@ class JobScheduleHandler(base.BaseHandler):
                type = self.get_argument("type")
                assert type in self.allowed_types
 
-               job = self.pakfire.jobs.get_by_uuid(uuid)
+               job = self.backend.jobs.get_by_uuid(uuid)
                if not job:
                        raise tornado.web.HTTPError(404, "Job not found: %s" % uuid)
 
@@ -89,7 +70,7 @@ class JobScheduleHandler(base.BaseHandler):
                type = self.get_argument("type")
                assert type in self.allowed_types
 
-               job = self.pakfire.jobs.get_by_uuid(uuid)
+               job = self.backend.jobs.get_by_uuid(uuid)
                if not job:
                        raise tornado.web.HTTPError(404, "Job not found: %s" % uuid)
 
@@ -100,19 +81,18 @@ class JobScheduleHandler(base.BaseHandler):
                except TypeError:
                        offset = 0
 
-               # Submit the build.
-               if type == "test":
-                       job = job.schedule_test(offset)
+               # Is this supposed to be a test job?
+               test = (type == "test")
 
-               elif type == "rebuild":
-                       job.schedule_rebuild(offset)
+               with self.db.transaction():
+                       new_job = job.restart(test=test)
 
-               self.redirect("/job/%s" % job.uuid)
+               self.redirect("/job/%s" % new_job.uuid)
 
 
 class JobAbortHandler(base.BaseHandler):
        def get_job(self, uuid):
-               job = self.pakfire.jobs.get_by_uuid(uuid)
+               job = self.backend.jobs.get_by_uuid(uuid)
                if not job:
                        raise tornado.web.HTTPError(404, "Job not found: %s" % uuid)
 
similarity index 86%
rename from src/web/handlers_keys.py
rename to src/web/keys.py
index 99b9442d10f798d87663e2a8b6027aff08a3003d..097aa71af45aa4bff37e46ab2c98ae25ef68aa76 100644 (file)
@@ -19,7 +19,7 @@ class KeysImportHandler(KeysActionHandler):
        def post(self):
                data = self.get_argument("data")
 
-               key = self.pakfire.keys.create(data)
+               key = self.backend.keys.create(data)
                assert key
 
                self.redirect("/keys")
@@ -28,7 +28,7 @@ class KeysImportHandler(KeysActionHandler):
 class KeysDeleteHandler(KeysActionHandler):
        @tornado.web.authenticated
        def get(self, fingerprint):
-               key = self.pakfire.keys.get_by_fpr(fingerprint)
+               key = self.backend.keys.get_by_fpr(fingerprint)
                if not key:
                        raise tornado.web.HTTPError(404, "Could not find key: %s" % fingerprint)
 
@@ -43,14 +43,14 @@ class KeysDeleteHandler(KeysActionHandler):
 
 class KeysListHandler(base.BaseHandler):
        def get(self):
-               keys = self.pakfire.keys.get_all()
+               keys = self.backend.keys.get_all()
 
                self.render("keys-list.html", keys=keys)
 
 
 class KeysDownloadHandler(base.BaseHandler):
        def get(self, fingerprint):
-               key = self.pakfire.keys.get_by_fpr(fingerprint)
+               key = self.backend.keys.get_by_fpr(fingerprint)
                if not key:
                        raise tornado.web.HTTPError(404, "Could not find key: %s" % fingerprint)
 
similarity index 82%
rename from src/web/handlers_packages.py
rename to src/web/packages.py
index 8c0344af514bd85dbc821dde741b281afb939bed..88429310b121b4de3b8b3a39b0aae54e3143f836 100644 (file)
@@ -8,49 +8,35 @@ from . import base
 
 from ..constants import BUFFER_SIZE
 
-class PackageIDDetailHandler(base.BaseHandler):
-       def get(self, id):
-               package = self.packages.get_by_id(id)
-               if not package:
-                       return tornado.web.HTTPError(404, "Package not found: %s" % id)
-
-               self.render("package-detail.html", package=package)
-
-
-class PackageListHandler(base.BaseHandler):
+class IndexHandler(base.BaseHandler):
        def get(self):
+               # Sort all packages in an array like "<first char>" --> [packages, ...]
+               # to print them in a table for each letter of the alphabet.
                packages = {}
 
-               show = self.get_argument("show", None)
-               if show == "all":
-                       states = None
-               elif show == "obsoletes":
-                       states = ["obsolete"]
-               elif show == "broken":
-                       states = ["broken"]
-               else:
-                       states = ["building", "stable", "testing"]
+               for pkg in self.backend.packages.get_list():
+                       c = pkg.name[0].lower()
 
-               # Get all packages that fulfill the required parameters.
-               pkgs = self.pakfire.packages.get_all_names(
-                       user=self.current_user, states=states)
+                       try:
+                               packages[c].append(pkg)
+                       except KeyError:
+                               packages[c] = [pkg]
 
-               # Sort all packages in an array like "<first char>" --> [packages, ...]
-               # to print them in a table for each letter of the alphabet.
-               for pkg in pkgs:
-                       c = pkg[0][0].lower()
+               self.render("packages/index.html", packages=packages)
 
-                       if not packages.has_key(c):
-                               packages[c] = []
 
-                       packages[c].append(pkg)
+class PackageIDDetailHandler(base.BaseHandler):
+       def get(self, id):
+               package = self.packages.get_by_id(id)
+               if not package:
+                       return tornado.web.HTTPError(404, "Package not found: %s" % id)
 
-               self.render("packages-list.html", packages=packages)
+               self.render("package-detail.html", package=package)
 
 
 class PackageNameHandler(base.BaseHandler):
        def get(self, name):
-               builds = self.pakfire.builds.get_active_builds(name)
+               builds = self.backend.builds.get_active_builds(name)
                if not builds:
                        raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
 
@@ -58,7 +44,7 @@ class PackageNameHandler(base.BaseHandler):
                latest_build = builds[0]
 
                # Get the latest bugs from bugzilla.
-               bugs = self.pakfire.bugzilla.get_bugs_from_component(name)
+               bugs = self.backend.bugzilla.get_bugs_from_component(name)
 
                self.render("package-detail-list.html", name=name, builds=builds,
                        latest_build=latest_build, pkg=latest_build.pkg, bugs=bugs)
@@ -69,13 +55,13 @@ class PackageScratchBuildsHandler(base.BaseHandler):
                offset = self.get_argument("offset", 0)
                limit  = self.get_argument("limit", 10)
 
-               scratch_builds = self.pakfire.builds.get_by_name(name, type="scratch",
+               scratch_builds = self.backend.builds.get_by_name(name, type="scratch",
                        limit=limit, offset=offset)
 
                if scratch_builds:
                        latest_build = scratch_builds[0]
                else:
-                       release_builds = self.pakfire.builds.get_by_name(name, type="release", limit=1)
+                       release_builds = self.backend.builds.get_by_name(name, type="release", limit=1)
                        if not release_builds:
                                raise tornado.web.HTTPError(404, "Could not find any build with this name: %s" % name)
 
@@ -90,6 +76,7 @@ class PackageChangelogHandler(base.BaseHandler):
                limit = self.get_argument("limit", 10)
                try:
                        limit = int(limit)
+
                except ValueError:
                        limit = 10
 
@@ -101,7 +88,7 @@ class PackageChangelogHandler(base.BaseHandler):
 
                # Get one more build than requested to find out if there are more items
                # to display (next button).
-               builds = self.pakfire.builds.get_changelog(name, limit=limit + 1, offset=offset)
+               builds = self.backend.builds.get_changelog(name, limit=limit + 1, offset=offset)
 
                if len(builds) >= limit:
                        have_next = True
@@ -122,7 +109,7 @@ class PackageChangelogHandler(base.BaseHandler):
 
 class PackageDetailHandler(base.BaseHandler):
        def get(self, uuid):
-               pkg = self.pakfire.packages.get_by_uuid(uuid)
+               pkg = self.backend.packages.get_by_uuid(uuid)
                if not pkg:
                        raise tornado.web.HTTPError(404, "Package not found: %s" % uuid)
 
@@ -130,7 +117,7 @@ class PackageDetailHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, name, epoch, version, release):
-               pkg = self.pakfire.packages.get_by_tuple(name, epoch, version, release)
+               pkg = self.backend.packages.get_by_tuple(name, epoch, version, release)
 
                action = self.get_argument("action", None)
 
@@ -149,7 +136,7 @@ class PackageDetailHandler(base.BaseHandler):
 class PackagePropertiesHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, name):
-               build = self.pakfire.builds.get_latest_by_name(name)
+               build = self.backend.builds.get_latest_by_name(name)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
@@ -164,7 +151,7 @@ class PackagePropertiesHandler(base.BaseHandler):
 
        @tornado.web.authenticated
        def post(self, name):
-               build = self.pakfire.builds.get_latest_by_name(name)
+               build = self.backend.builds.get_latest_by_name(name)
 
                if not build:
                        raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
@@ -185,7 +172,7 @@ class PackagePropertiesHandler(base.BaseHandler):
 class PackageFileDownloadHandler(base.BaseHandler):
        def get_file(self, pkg_uuid, filename):
                # Fetch package.
-               pkg = self.pakfire.packages.get_by_uuid(pkg_uuid)
+               pkg = self.backend.packages.get_by_uuid(pkg_uuid)
                if not pkg:
                        raise tornado.web.HTTPError(404, "Package not found: %s" % pkg_uuid)
 
@@ -246,14 +233,14 @@ class PackageFileViewHandler(PackageFileDownloadHandler):
 
 class PackageBuildsTimesHandler(base.BaseHandler):
        def get(self, name):
-               latest_build = self.pakfire.builds.get_latest_by_name(name)
+               latest_build = self.backend.builds.get_latest_by_name(name)
 
                # If no build with this name was found, we cannot go on.
                if not latest_build:
                        raise tornado.web.HTTPError(404)
 
                # Get the summary stats.
-               build_times_summary = self.pakfire.builds.get_build_times_summary(name)
+               build_times_summary = self.backend.builds.get_build_times_summary(name)
 
                self.render("packages/builds/times.html", pkg=latest_build.pkg,
                        build_times_summary=build_times_summary)
similarity index 78%
rename from src/web/handlers_search.py
rename to src/web/search.py
index c1a556be61a39cca3aa30c1979f352d36d712272..f9e3b8d7fabd88c08374f49dd5d5f13c07beb9f4 100644 (file)
@@ -16,19 +16,19 @@ class SearchHandler(base.BaseHandler):
                        # Search for a matching object and redirect to it.
 
                        # Search in packages.
-                       pkg = self.pakfire.packages.get_by_uuid(pattern)
+                       pkg = self.backend.packages.get_by_uuid(pattern)
                        if pkg:
                                self.redirect("/package/%s" % pkg.uuid)
                                return
 
                        # Search in builds.
-                       build = self.pakfire.builds.get_by_uuid(pattern)
+                       build = self.backend.builds.get_by_uuid(pattern)
                        if build:
                                self.redirect("/build/%s" % build.uuid)
                                return
 
                        # Search in jobs.
-                       job = self.pakfire.jobs.get_by_uuid(pattern)
+                       job = self.backend.jobs.get_by_uuid(pattern)
                        if job:
                                self.redirect("/job/%s" % job.uuid)
                                return
@@ -37,14 +37,14 @@ class SearchHandler(base.BaseHandler):
 
                if pattern.startswith("/"):
                        # Do a file search.
-                       files = self.pakfire.packages.search_by_filename(pattern, limit=50)
+                       files = self.backend.packages.search_by_filename(pattern, limit=50)
 
                else:
                        # Make fulltext search in the packages.
-                       pkgs = self.pakfire.packages.search(pattern, limit=50)
+                       pkgs = self.backend.packages.search(pattern, limit=50)
 
                        # Search for users.
-                       users = self.pakfire.users.search(pattern, limit=50)
+                       users = self.backend.users.search(pattern, limit=50)
 
                if len(pkgs) == 1 and not files and not users:
                        pkg = pkgs[0]
index ed6c79d281c40dc54cff727b40b536238d62ff2e..f4be0ff07c528d6599d0eff3c8cd9cf61d05d268 100644 (file)
@@ -3,12 +3,9 @@
 from __future__ import division
 
 import datetime
-import itertools
 import math
 import pytz
 import re
-import string
-import tornado.escape
 import tornado.web
 
 from .. import users
@@ -26,22 +23,10 @@ class TextModule(UIModule):
 
        LINK = """<a href="%s" target="_blank" rel="noopener">%s</a>"""
 
-       def split_paragraphs(self, s):
-               for group_seperator, line_iteration in itertools.groupby(s.splitlines(True), key=str.isspace):
-                       if group_seperator:
-                               continue
-
-                       paragraph = "".join(line_iteration)
-                       yield paragraph.replace("\n", " ")
-
-       def render(self, text, pre=False, remove_linebreaks=True):
-               if remove_linebreaks:
-                       text = text.replace("\n", " ")
-
-               # Escape the text and create make urls clickable.
-               text = tornado.escape.xhtml_escape(text)
-               text = tornado.escape.linkify(text, shorten=True,
-                       extra_params="target=\"_blank\" rel=\"noopener\"")
+       def render(self, text):
+               # Handle empty messages
+               if not text:
+                       return ""
 
                # Search for bug ids that need to be linked to bugzilla
                text = re.sub(self.BUGZILLA_PATTERN, self._bugzilla_repl, text, re.I|re.U)
@@ -49,10 +34,7 @@ class TextModule(UIModule):
                # Search for CVE numbers and create hyperlinks.
                text = re.sub(self.CVE_PATTERN, self._cve_repl, text, re.I|re.U)
 
-               if pre:
-                       return "<pre>%s</pre>" % text
-
-               return text
+               return self.render_string("modules/text.html", paragraphs=text.split("\n\n"))
 
        def _bugzilla_repl(self, m):
                bug_id = m.group(1)
@@ -66,14 +48,9 @@ class TextModule(UIModule):
                return self.LINK % ("http://cve.mitre.org/cgi-bin/cvename.cgi?name=%s" % m.group(1), m.group(0))
 
 
-class CommitMessageModule(TextModule):
+class CommitMessageModule(UIModule):
        def render(self, commit):
-               s = "h5. %s\n\n" % commit.subject
-
-               paragraphs = self.split_paragraphs(commit.message)
-               s += "\n\n".join(paragraphs)
-
-               return TextModule.render(self, s, remove_linebreaks=False)
+               return self.render_string("modules/commit-message.html", commit=commit)
 
 
 class ModalModule(UIModule):
@@ -268,11 +245,6 @@ class JobStateModule(UIModule):
                        classes.append("muted")
                        icon = "icon-warning-sign"
 
-               elif state == "dependency_error":
-                       text = _("Dependency problem")
-                       classes.append("text-warning")
-                       icon = "icon-random"
-
                elif state == "dispatching":
                        text = _("Dispatching")
                        classes.append("text-info")
@@ -288,11 +260,6 @@ class JobStateModule(UIModule):
                        classes.append("text-success")
                        icon = "icon-ok"
 
-               elif state == "new":
-                       text = _("New")
-                       classes.append("muted")
-                       icon = "icon-asterisk"
-
                elif state == "pending":
                        text = _("Pending")
                        classes.append("muted")
@@ -403,15 +370,9 @@ class LogEntryCommentModule(LogEntryModule):
                        entry=entry, u=entry.user, show_build=show_build, **args)
 
 
-class MaintainerModule(UIModule):
-       def render(self, maintainer):
-               if isinstance(maintainer, users.User):
-                       type = "user"
-               else:
-                       type = "string"
-
-               return self.render_string("modules/maintainer.html",
-                       type=type, maintainer=maintainer)
+class LinkToUserModule(UIModule):
+       def render(self, user):
+               return self.render_string("modules/link-to-user.html", user=user, users=users)
 
 
 class BuildLogModule(UIModule):
similarity index 94%
rename from src/web/handlers_users.py
rename to src/web/users.py
index 3a8fc28095c91b1757086116c4e2ac8317df3fd5..76e30127327f53ef1a8669d0802cdf8b6d7c232d 100644 (file)
@@ -1,7 +1,5 @@
 #!/usr/bin/python
 
-import datetime
-
 import tornado.locale
 import tornado.web
 
@@ -13,7 +11,7 @@ class UserHandler(base.BaseHandler):
                user = self.current_user
 
                if name:
-                       user = self.pakfire.users.get_by_name(name)
+                       user = self.backend.users.get_by_name(name)
                        if not user:
                                raise tornado.web.HTTPError(404, "User does not exist: %s" % name)
 
@@ -53,7 +51,7 @@ class UserImpersonateHandler(base.BaseHandler):
 
 class UserActionHandler(base.BaseHandler):
        def get_user(self, name):
-               user = self.pakfire.users.get_by_name(name)
+               user = self.backend.users.get_by_name(name)
                if not user:
                        raise tornado.web.HTTPError(404)
 
@@ -132,7 +130,7 @@ class UserPasswdHandler(UserActionHandler):
 class UserEditHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self, name):
-               user = self.pakfire.users.get_by_name(name)
+               user = self.backend.users.get_by_name(name)
                if not user:
                        raise tornado.web.HTTPError(404)
 
@@ -145,7 +143,7 @@ class UserEditHandler(base.BaseHandler):
        def post(self, name):
                _ = self.locale.translate
 
-               user = self.pakfire.users.get_by_name(name)
+               user = self.backend.users.get_by_name(name)
                if not user:
                        raise tornado.web.HTTPError(404)
 
@@ -210,11 +208,11 @@ class UsersBuildsHandler(base.BaseHandler):
                if name is None:
                        user = self.current_user
                else:
-                       user = self.pakfire.users.get_by_name(name)
+                       user = self.backend.users.get_by_name(name)
                        if not user:
                                raise tornado.web.HTTPError(404, "User not found: %s" % name)
 
                # Get a list of the builds this user has built.
-               builds = self.pakfire.builds.get_by_user(user)
+               builds = self.backend.builds.get_by_user(user)
 
                self.render("user-profile-builds.html", user=user, builds=builds)