[SCM] build.samba.org - branch master updated

Jelmer Vernooij jelmer at samba.org
Tue Nov 2 02:48:41 MDT 2010


The branch, master has been updated
       via  0c4399c Move build_status onto Build.
       via  846f498 Move revision_details onto Build.
       via  8f5f5f6 Move read_log and read_err onto Build.
       via  5b5e222 Move age_mtime/age_ctime onto Build.
       via  29cee7a Add Build object.
      from  9e71906 Raise NoSuchBuildError rather than silently pretending files are empty.

http://gitweb.samba.org/?p=build-farm.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 0c4399c4712a8d7eb8407b654270c3f080063f6d
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Nov 2 09:48:57 2010 +0100

    Move build_status onto Build.

commit 846f498b80e05b3031bd9724121a6bd90c1d54d3
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Nov 2 09:46:07 2010 +0100

    Move revision_details onto Build.

commit 8f5f5f676389096345def353a1c0f14cba56447b
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Nov 2 09:35:20 2010 +0100

    Move read_log and read_err onto Build.

commit 5b5e2224772636e45f785c3cca88c6a2816e0d14
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Nov 2 09:32:48 2010 +0100

    Move age_mtime/age_ctime onto Build.

commit 29cee7a9abac3c8fc2c59831438d393af0c69220
Author: Jelmer Vernooij <jelmer at samba.org>
Date:   Tue Nov 2 09:31:01 2010 +0100

    Add Build object.

-----------------------------------------------------------------------

Summary of changes:
 buildfarm/data.py            |  282 +++++++++++++++++++++---------------------
 buildfarm/tests/test_data.py |   23 ++--
 web/build.py                 |   30 +++--
 3 files changed, 170 insertions(+), 165 deletions(-)


Changeset truncated at 500 lines:

diff --git a/buildfarm/data.py b/buildfarm/data.py
index d083698..426f50a 100644
--- a/buildfarm/data.py
+++ b/buildfarm/data.py
@@ -82,6 +82,131 @@ class Tree(object):
         return "<%s %r>" % (self.__class__.__name__, self.name)
 
 
+class Build(object):
+    """A single build of a tree on a particular host using a particular compiler.
+    """
+
+    def __init__(self, store, tree, host, compiler, rev=None):
+        self._store = store
+        self.tree = tree
+        self.host = host
+        self.compiler = compiler
+        self.rev = rev
+
+    ###################
+    # the mtime age is used to determine if builds are still happening
+    # on a host.
+    # the ctime age is used to determine when the last real build happened
+
+    def age_mtime(self):
+        """get the age of build from mtime"""
+        file = self._store.build_fname(self.tree, self.host, self.compiler, self.rev)
+
+        st = os.stat("%s.log" % file)
+        return time.time() - st.st_mtime
+
+    def age_ctime(self):
+        """get the age of build from ctime"""
+        file = self._store.build_fname(self.tree, self.host, self.compiler, self.rev)
+
+        st = os.stat("%s.log" % file)
+        return time.time() - st.st_ctime
+
+    def read_log(self):
+        """read full log file"""
+        f = open(self._store.build_fname(self.tree, self.host, self.compiler, self.rev)+".log", "r")
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def read_err(self):
+        """read full err file"""
+        return util.FileLoad(self._store.build_fname(self.tree, self.host, self.compiler, self.rev)+".err")
+
+    def build_revision_details(self):
+        """get the revision of build
+        
+        :return: Tuple with revision id and timestamp (if available)
+        """
+        file = self._store.build_fname(self.tree, self.host, self.compiler, self.rev)
+        cachef = self._store.cache_fname(self.tree, self.host, self.compiler, self.rev)
+
+        # don't fast-path for trees with git repository:
+        # we get the timestamp as rev and want the details
+        if self.rev:
+            if self.tree not in self._store.trees:
+                return self.rev
+            if self.trees[self.tree].scm != "git":
+                return self.rev
+
+        st1 = os.stat("%s.log" % file)
+
+        try:
+            st2 = os.stat("%s.revision" % cachef)
+        except OSError:
+            # File does not exist
+            st2 = None
+
+        # the ctime/mtime asymmetry is needed so we don't get fooled by
+        # the mtime update from rsync
+        if st2 and st1.st_ctime <= st2.st_mtime:
+            (revid, timestamp) = util.FileLoad("%s.revision" % cachef).split(":", 1)
+            if timestamp == "":
+                return (revid, None)
+            else:
+                return (revid, timestamp)
+
+        revid = None
+        timestamp = None
+        f = open("%s.log" % file, 'r')
+        try:
+            for l in f.readlines():
+                if l.startswith("BUILD COMMIT REVISION: "):
+                    revid = l.split(":", 1)[1].strip()
+                elif l.startswith("BUILD REVISION: "):
+                    revid = l.split(":", 1)[1].strip()
+                elif l.startswith("BUILD COMMIT TIME"):
+                    timestamp = l.split(":", 1)[1].strip()
+        finally:
+            f.close()
+
+        if not self.readonly:
+            util.FileSave("%s.revision" % cachef, "%s:%s" % (revid, timestamp or ""))
+
+        return (revid, timestamp)
+
+    def status(self):
+        """get status of build
+
+        :return: string with build status
+        """
+        # FIXME: This should return a tuple
+
+        file = self._store.build_fname(self.tree, self.host, self.compiler, self.rev)
+        cachefile = self._store.cache_fname(self.tree, self.host, self.compiler, self.rev)+".status"
+        st1 = os.stat("%s.log" % file)
+
+        try:
+            st2 = os.stat(cachefile)
+        except OSError:
+            # No such file
+            st2 = None
+
+        if st2 and st1.st_ctime <= st2.st_mtime:
+            return util.FileLoad(cachefile)
+
+        log = self.read_log()
+        err = self.read_err()
+
+        ret = self._store.build_status_from_logs(log, err)
+
+        if not self.readonly:
+            util.FileSave(cachefile, ret)
+
+        return ret
+
+
 def read_trees_from_conf(path):
     """Read trees from a configuration file."""
     ret = {}
@@ -126,6 +251,12 @@ class BuildResultStore(object):
 
         self.trees = read_trees_from_conf(os.path.join(self.webdir, "trees.conf"))
 
+    def get_build(self, tree, host, compiler, rev=None):
+        logf = self.build_fname(tree, host, compiler, rev) + ".log"
+        if not os.path.exists(logf):
+            raise NoSuchBuildError(tree, host, compiler, rev)
+        return Build(self, tree, host, compiler, rev)
+
     def cache_fname(self, tree, host, compiler, rev=None):
         if rev is not None:
             return os.path.join(self.cachedir, "build.%s.%s.%s-%s" % (tree,host,compiler,rev))
@@ -138,92 +269,14 @@ class BuildResultStore(object):
             return os.path.join(self.datadir, "oldrevs/build.%s.%s.%s-%s" % (tree, host, compiler, rev))
         return os.path.join(self.datadir, "upload/build.%s.%s.%s" % (tree, host, compiler))
 
-    ###################
-    # the mtime age is used to determine if builds are still happening
-    # on a host.
-    # the ctime age is used to determine when the last real build happened
-
-    def build_age_mtime(self, tree, host, compiler, rev=None):
-        """get the age of build from mtime"""
-        file = self.build_fname(tree, host, compiler, rev=rev)
-
-        try:
-            st = os.stat("%s.log" % file)
-        except OSError:
-            # File does not exist
-            raise NoSuchBuildError(tree, host, compiler, rev)
-        else:
-            return time.time() - st.st_mtime
-
-    def build_age_ctime(self, tree, host, compiler, rev=None):
-        """get the age of build from ctime"""
-        file = self.build_fname(tree, host, compiler, rev=rev)
-
-        try:
-            st = os.stat("%s.log" % file)
-        except OSError:
-            raise NoSuchBuildError(tree, host, compiler, rev)
-        else:
-            return time.time() - st.st_ctime
-
-    def build_revision_details(self, tree, host, compiler, rev=None):
-        """get the revision of build"""
-        file = self.build_fname(tree, host, compiler, rev)
-        cachef = self.cache_fname(tree, host, compiler, rev)
-
-        # don't fast-path for trees with git repository:
-        # we get the timestamp as rev and want the details
-        if rev:
-            if tree not in self.trees:
-                return rev
-            if self.trees[tree].scm != "git":
-                return rev
-
-        try:
-            st1 = os.stat("%s.log" % file)
-        except OSError:
-            # File does not exist
-            raise NoSuchBuildError(tree, host, compiler, rev)
-
-        try:
-            st2 = os.stat("%s.revision" % cachef)
-        except OSError:
-            # File does not exist
-            st2 = None
-
-        # the ctime/mtime asymmetry is needed so we don't get fooled by
-        # the mtime update from rsync 
-        if st2 and st1.st_ctime <= st2.st_mtime:
-            return util.FileLoad("%s.revision" % cachef)
-
-        log = util.FileLoad("%s.log" % file)
-
-        m = re.search("BUILD COMMIT REVISION: (.*)", log)
-        if m:
-            ret = m.group(1)
-        else:
-            m = re.search("BUILD REVISION: (.*)", log)
-            if m:
-                ret = m.group(1)
-            else:
-                ret = ""
-
-        m = re.search("BUILD COMMIT TIME: (.*)", log)
-        if m:
-            ret += ":" + m.group(1)
-
-        if not self.readonly:
-            util.FileSave("%s.revision" % cachef, ret)
-
-        return ret
 
     def build_revision(self, tree, host, compiler, rev=None):
-        r = self.build_revision_details(tree, host, compiler, rev=rev)
-        return r.split(":")[0]
+        build = self.get_build(tree, host, compiler, rev)
+        return build.revision_details()[0]
 
     def build_revision_time(self, tree, host, compiler, rev=None):
-        r = self.build_revision_details(tree, host, compiler, rev)
-        return r.split(":", 1)[1]
+        build = self.get_build(tree, host, compiler, rev)
+        return build.revision_details()[1]
 
     def build_status_from_logs(self, log, err):
         """get status of build"""
@@ -289,48 +342,6 @@ class BuildResultStore(object):
         return "%s/%s/%s/%s%s%s%s" % (
                 cstatus, bstatus, istatus, tstatus, sstatus, dstatus, tostatus)
 
-    def build_status(self, tree, host, compiler, rev=None):
-        """get status of build
-
-        :param tree: Tree name
-        :param host: Host name
-        :param compiler: Compiler name
-        :param rev: Revision
-        :return: string with build status
-        """
-        # FIXME: This should return a tuple
-
-        file = self.build_fname(tree, host, compiler, rev)
-        cachefile = self.cache_fname(tree, host, compiler, rev)+".status"
-        try:
-            st1 = os.stat("%s.log" % file)
-        except OSError:
-            # No such file
-            raise NoSuchBuildError(tree, host, compiler, rev)
-
-        try:
-            st2 = os.stat(cachefile)
-        except OSError:
-            # No such file
-            st2 = None
-
-        if st2 and st1.st_ctime <= st2.st_mtime:
-            return util.FileLoad(cachefile)
-
-        log = util.FileLoad("%s.log" % file)
-        try:
-            err = util.FileLoad("%s.err" % file)
-        except OSError:
-            # No such file
-            err = ""
-
-        ret = self.build_status_from_logs(log, err)
-
-        if not self.readonly:
-            util.FileSave(cachefile, ret)
-
-        return ret
-
     def build_status_info_from_string(self, rev_seq, rev, status_raw):
         """find the build status as an perl object
 
@@ -381,8 +392,9 @@ class BuildResultStore(object):
 
         the 'value' gets one point for passing each stage
         """
-        rev = self.build_revision(tree, host, compiler, rev_seq)
-        status_html = self.build_status(tree, host, compiler, rev_seq)
+        build = self.get_build(tree, host, compiler, rev_seq)
+        rev, rev_time = build.revision_details()
+        status_html = build.status()
         return self.build_status_info_from_html(rev_seq, rev, status_html)
 
     def lcov_status(self, tree):
@@ -446,18 +458,6 @@ class BuildResultStore(object):
 
         return ret
 
-    def read_log(self, tree, host, compiler, rev=None):
-        """read full log file"""
-        f = open(self.build_fname(tree, host, compiler, rev)+".log", "r")
-        try:
-            return f.read()
-        finally:
-            f.close()
-
-    def read_err(self, tree, host, compiler, rev=None):
-        """read full err file"""
-        return util.FileLoad(self.build_fname(tree, host, compiler, rev)+".err")
-
     def get_old_revs(self, tree, host, compiler):
         """get a list of old builds and their status."""
         ret = []
@@ -471,8 +471,9 @@ class BuildResultStore(object):
                 # skip the current build
                 if stat.st_nlink == 2:
                     continue
+                build = self.get_build(tree, host, compiler, rev)
                 r = {
-                    "STATUS": self.build_status(tree, host, compiler, rev),
+                    "STATUS": build.status(),
                     "REVISION": rev,
                     "TIMESTAMP": stat.st_ctime
                     }
@@ -491,7 +492,8 @@ class BuildResultStore(object):
         for compiler in self.compilers:
             for tree in self.trees:
                 try:
-                    age = self.db.build_age_mtime(tree, host, compiler)
+                    build = self.get_build(tree, host, compiler)
+                    age = build.age_mtime()
                 except NoSuchBuildError:
                     pass
                 else:
diff --git a/buildfarm/tests/test_data.py b/buildfarm/tests/test_data.py
index d265125..d54206e 100755
--- a/buildfarm/tests/test_data.py
+++ b/buildfarm/tests/test_data.py
@@ -62,32 +62,31 @@ class BuildResultStoreTests(BuildFarmTestCase):
         path = self.create_mock_logfile("tdb", "charis", "cc")
         # Set mtime to something in the past
         os.utime(path, (time.time(), time.time() - 990))
-        age = self.x.build_age_mtime("tdb", "charis", "cc")
+        build = self.x.get_build("tdb", "charis", "cc")
+        age = build.age_mtime()
         self.assertTrue(age >= 990 and age <= 1000, "age was %d" % age)
 
-    def test_build_age_mtime_nonexistant(self):
-        self.assertRaises(data.NoSuchBuildError, self.x.build_age_mtime, "tdb",
+    def test_get_build_nonexistant(self):
+        self.assertRaises(data.NoSuchBuildError, self.x.get_build, "tdb",
             "charis", "cc")
 
     def test_build_age_ctime(self):
         path = self.create_mock_logfile("tdb", "charis", "cc")
         # Set mtime to something in the past
-        age = self.x.build_age_ctime("tdb", "charis", "cc")
+        build = self.x.get_build("tdb", "charis", "cc")
+        age = build.age_ctime()
         self.assertTrue(age >= 0 and age <= 10, "age was %d" % age)
 
-    def test_build_age_ctime_nonexistant(self):
-        self.assertRaises(data.NoSuchBuildError, self.x.build_age_ctime, "tdb",
-            "charis", "cc")
-
     def test_read_log(self):
         path = self.create_mock_logfile("tdb", "charis", "cc",
             contents="This is what a log file looks like.")
-        log = self.x.read_log("tdb", "charis", "cc")
-        self.assertEquals("This is what a log file looks like.", log)
+        build = self.x.get_build("tdb", "charis", "cc")
+        self.assertEquals("This is what a log file looks like.", build.read_log())
 
     def test_read_err(self):
+        self.create_mock_logfile("tdb", "charis", "cc")
         path = self.create_mock_logfile("tdb", "charis", "cc",
             kind="stderr",
             contents="This is what an stderr file looks like.")
-        log = self.x.read_err("tdb", "charis", "cc")
-        self.assertEquals("This is what an stderr file looks like.", log)
+        build = self.x.get_build("tdb", "charis", "cc")
+        self.assertEquals("This is what an stderr file looks like.", build.read_err())
diff --git a/web/build.py b/web/build.py
index df583aa..71d4bae 100755
--- a/web/build.py
+++ b/web/build.py
@@ -79,7 +79,8 @@ def build_link(myself, tree, host, compiler, rev, status):
 
 
 def build_status(myself, tree, host, compiler, rev):
-    status = db.build_status(tree, host, compiler, rev)
+    build = db.get_build(tree, host, compiler, rev)
+    status = build.build_status()
     return build_link(myself, tree, host, compiler, rev, status)
 
 
@@ -130,10 +131,11 @@ def view_summary(myself, output_type):
         for compiler in compilers:
             for tree in trees:
                 try:
+                    build = db.get_build(tree, host, compiler)
                     status = build_status(myself, tree, host, compiler)
                 except data.NoSuchBuildError:
                     continue
-                age_mtime = db.build_age_mtime(tree, host, compiler)
+                age_mtime = build.age_mtime()
                 host_count[tree]+=1
 
                 if "status failed" in status:
@@ -243,13 +245,13 @@ def view_recent_builds(myself, tree, sort_by):
         for compiler in compilers:
             try:
                 status = build_status(myself, tree, host, compiler)
+                build = db.get_build(tree, host, compiler)
             except data.NoSuchBuildError:
                 pass
             else:
-                age_mtime = db.build_age_mtime(tree, host, compiler)
-                age_ctime = db.build_age_ctime(tree, host, compiler)
-                revision = db.build_revision(tree, host, compiler)
-                revision_time = db.build_revision_time(tree, host, compiler)
+                age_mtime = build.age_mtime()
+                age_ctime = build.age_ctime()
+                (revision, revision_time) = build.revision_details()
                 all_builds.append([age_ctime, hosts[host], "<a href='%s?function=View+Host;host=%s;tree=%s;compiler=%s#%s'>%s</a>" % (myself, host, tree, compiler, host, host), compiler, tree, status, revision_link(myself, revision, tree), revision_time])
 
     all_builds.sort(cmp_funcs[sort_by])
@@ -347,14 +349,15 @@ def view_build(myself, tree, host, compiler, rev, plain_logs=False):
     uname = ""
     cflags = ""
     config = ""
-    age_mtime = db.build_age_mtime(tree, host, compiler, rev)
-    revision = db.build_revision(tree, host, compiler, rev)
+    build = db.get_build(tree, host, compiler, rev)
+    age_mtime = build.age_mtime()
+    (revision, revision_time) = build.revision_details()
     status = build_status(myself, tree, host, compiler, rev)
 
     assert re.match("^[0-9a-fA-F]*$", rev)
 
-    log = db.read_log(tree, host, compiler, rev)
-    err = db.read_err(tree, host, compiler, rev)
+    log = build.read_log()
+    err = build.read_err()
 
     if log:
         log = cgi.escape(log)
@@ -455,13 +458,14 @@ def view_host(myself, output_type, *requested_hosts):
 
         for compiler in compilers:
             for tree in sorted(trees.keys()):
-                revision = db.build_revision(tree, host, compiler)
                 try:
-                    age_mtime = db.build_age_mtime(tree, host, compiler)
+                    build = db.get_build(tree, host, compiler)
                 except data.NoSuchBuildError:
                     pass
                 else:
-                    age_ctime = db.build_age_ctime(tree, host, compiler)
+                    revision, revision_time = build.revision_details()
+                    age_mtime = build.age_mtime()
+                    age_ctime = build.age_ctime()
                     warnings = db.err_count(tree, host, compiler)
                     status = build_status(myself, tree, host, compiler)
                     if row == 0:


-- 
build.samba.org


More information about the samba-cvs mailing list