~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/canonical/buildd/sourcepackagerecipe.py

  • Committer: mbp at canonical
  • Date: 2011-11-20 23:37:23 UTC
  • mto: This revision was merged to the branch mainline in revision 14344.
  • Revision ID: mbp@canonical.com-20111120233723-370p96db2crru5tm
Delete canonical.buildd again

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
# pylint: disable-msg=E1002
4
 
 
5
 
"""The manager class for building packages from recipes."""
6
 
 
7
 
import os
8
 
import re
9
 
 
10
 
from canonical.buildd.debian import (
11
 
    DebianBuildManager,
12
 
    DebianBuildState,
13
 
    get_build_path,
14
 
)
15
 
RETCODE_SUCCESS = 0
16
 
RETCODE_FAILURE_INSTALL = 200
17
 
RETCODE_FAILURE_BUILD_TREE = 201
18
 
RETCODE_FAILURE_INSTALL_BUILD_DEPS = 202
19
 
RETCODE_FAILURE_BUILD_SOURCE_PACKAGE = 203
20
 
 
21
 
 
22
 
def splat_file(path, contents):
23
 
    """Write a string to the specified path.
24
 
 
25
 
    :param path: The path to store the string in.
26
 
    :param contents: The string to write to the file.
27
 
    """
28
 
    file_obj = open(path, 'w')
29
 
    try:
30
 
        file_obj.write(contents)
31
 
    finally:
32
 
        file_obj.close()
33
 
 
34
 
 
35
 
def get_chroot_path(build_id, *extra):
36
 
    """Return a path within the chroot.
37
 
 
38
 
    :param build_id: The build_id of the build.
39
 
    :param extra: Additional path elements.
40
 
    """
41
 
    return get_build_path(
42
 
        build_id, 'chroot-autobuild', os.environ['HOME'][1:], *extra)
43
 
 
44
 
 
45
 
class SourcePackageRecipeBuildState(DebianBuildState):
46
 
    """The set of states that a recipe build can be in."""
47
 
    BUILD_RECIPE = "BUILD_RECIPE"
48
 
 
49
 
 
50
 
class SourcePackageRecipeBuildManager(DebianBuildManager):
51
 
    """Build a source package from a bzr-builder recipe."""
52
 
 
53
 
    initial_build_state = SourcePackageRecipeBuildState.BUILD_RECIPE
54
 
 
55
 
    def __init__(self, slave, buildid):
56
 
        """Constructor.
57
 
 
58
 
        :param slave: A build slave device.
59
 
        :param buildid: The id of the build (a str).
60
 
        """
61
 
        DebianBuildManager.__init__(self, slave, buildid)
62
 
        self.build_recipe_path = slave._config.get(
63
 
            "sourcepackagerecipemanager", "buildrecipepath")
64
 
 
65
 
    def initiate(self, files, chroot, extra_args):
66
 
        """Initiate a build with a given set of files and chroot.
67
 
 
68
 
        :param files: The files sent by the manager with the request.
69
 
        :param chroot: The sha1sum of the chroot to use.
70
 
        :param extra_args: A dict of extra arguments.
71
 
        """
72
 
        self.recipe_text = extra_args['recipe_text']
73
 
        self.suite = extra_args['suite']
74
 
        self.component = extra_args['ogrecomponent']
75
 
        self.author_name = extra_args['author_name']
76
 
        self.author_email = extra_args['author_email']
77
 
        self.archive_purpose = extra_args['archive_purpose']
78
 
        self.distroseries_name = extra_args['distroseries_name']
79
 
 
80
 
        super(SourcePackageRecipeBuildManager, self).initiate(
81
 
            files, chroot, extra_args)
82
 
 
83
 
    def doRunBuild(self):
84
 
        """Run the build process to build the source package."""
85
 
        os.makedirs(get_chroot_path(self._buildid, 'work'))
86
 
        recipe_path = get_chroot_path(self._buildid, 'work/recipe')
87
 
        splat_file(recipe_path, self.recipe_text)
88
 
        args = [
89
 
            "buildrecipe", self._buildid, self.author_name.encode('utf-8'),
90
 
            self.author_email, self.suite, self.distroseries_name,
91
 
            self.component, self.archive_purpose]
92
 
        self.runSubProcess(self.build_recipe_path, args)
93
 
 
94
 
    def iterate_BUILD_RECIPE(self, retcode):
95
 
        """Move from BUILD_RECIPE to the next logical state."""
96
 
        if retcode == RETCODE_SUCCESS:
97
 
            self.gatherResults()
98
 
            print("Returning build status: OK")
99
 
        elif retcode == RETCODE_FAILURE_INSTALL_BUILD_DEPS:
100
 
            if not self.alreadyfailed:
101
 
                tmpLog = self.getTmpLogContents()
102
 
                rx = (
103
 
                    'The following packages have unmet dependencies:\n'
104
 
                    '.*: Depends: ([^ ]*( \([^)]*\))?)')
105
 
                mo = re.search(rx, tmpLog, re.M)
106
 
                if mo:
107
 
                    self._slave.depFail(mo.group(1))
108
 
                    print("Returning build status: DEPFAIL")
109
 
                    print("Dependencies: " + mo.group(1))
110
 
                else:
111
 
                    print("Returning build status: Build failed")
112
 
                    self._slave.buildFail()
113
 
            self.alreadyfailed = True
114
 
        elif (
115
 
            retcode >= RETCODE_FAILURE_INSTALL and
116
 
            retcode <= RETCODE_FAILURE_BUILD_SOURCE_PACKAGE):
117
 
            # XXX AaronBentley 2009-01-13: We should handle depwait separately
118
 
            if not self.alreadyfailed:
119
 
                self._slave.buildFail()
120
 
                print("Returning build status: Build failed.")
121
 
            self.alreadyfailed = True
122
 
        else:
123
 
            if not self.alreadyfailed:
124
 
                self._slave.builderFail()
125
 
                print("Returning build status: Builder failed.")
126
 
            self.alreadyfailed = True
127
 
        self._state = DebianBuildState.REAP
128
 
        self.doReapProcesses()
129
 
 
130
 
    def getChangesFilename(self):
131
 
        """Return the path to the changes file."""
132
 
        work_path = get_build_path(self._buildid)
133
 
        for name in os.listdir(work_path):
134
 
            if name.endswith('_source.changes'):
135
 
                return os.path.join(work_path, name)
136
 
 
137
 
    def gatherResults(self):
138
 
        """Gather the results of the build and add them to the file cache.
139
 
 
140
 
        The primary file we care about is the .changes file.
141
 
        The manifest is also a useful record.
142
 
        """
143
 
        DebianBuildManager.gatherResults(self)
144
 
        self._slave.addWaitingFile(get_build_path(self._buildid, 'manifest'))