Merge lp:~cjwatson/launchpad-buildd/extended-snap-status into lp:launchpad-buildd

Proposed by Colin Watson
Status: Merged
Merged at revision: 216
Proposed branch: lp:~cjwatson/launchpad-buildd/extended-snap-status
Merge into: lp:launchpad-buildd
Diff against target: 199 lines (+78/-5)
5 files modified
buildsnap (+33/-5)
debian/changelog (+7/-0)
lpbuildd/slave.py (+11/-0)
lpbuildd/snap.py (+17/-0)
lpbuildd/tests/test_snap.py (+10/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad-buildd/extended-snap-status
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+321689@code.launchpad.net

Commit message

Record the branch revision used to build a snap and return it along with other XML-RPC status information (LP: #1679157).

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'buildsnap'
2--- buildsnap 2017-02-10 14:53:12 +0000
3+++ buildsnap 2017-04-03 12:38:12 +0000
4@@ -9,6 +9,7 @@
5 __metaclass__ = type
6
7 import base64
8+import json
9 from optparse import OptionParser
10 import os
11 import subprocess
12@@ -50,11 +51,12 @@
13 # appropriate certificate for your codehosting system.
14 self.ssl_verify = True
15
16- def chroot(self, args, echo=False):
17+ def chroot(self, args, echo=False, get_output=False):
18 """Run a command in the chroot.
19
20 :param args: the command and arguments to run.
21 :param echo: if True, print the command before executing it.
22+ :param get_output: if True, return the output from the command.
23 """
24 args = set_personality(self.options.arch, args)
25 if echo:
26@@ -62,10 +64,14 @@
27 "Running in chroot: %s" % ' '.join(
28 "'%s'" % arg for arg in args))
29 sys.stdout.flush()
30- subprocess.check_call([
31- "/usr/bin/sudo", "/usr/sbin/chroot", self.chroot_path] + args)
32+ cmd = ["/usr/bin/sudo", "/usr/sbin/chroot", self.chroot_path] + args
33+ if get_output:
34+ return subprocess.check_output(cmd, universal_newlines=True)
35+ else:
36+ subprocess.check_call(cmd)
37
38- def run_build_command(self, args, path="/build", env=None, echo=False):
39+ def run_build_command(self, args, path="/build", env=None, echo=False,
40+ get_output=False):
41 """Run a build command in the chroot.
42
43 This is unpleasant because we need to run it in /build under sudo
44@@ -77,6 +83,7 @@
45 :param path: the working directory to use in the chroot.
46 :param env: dictionary of additional environment variables to set.
47 :param echo: if True, print the command before executing it.
48+ :param get_output: if True, return the output from the command.
49 """
50 args = [shell_escape(arg) for arg in args]
51 path = shell_escape(path)
52@@ -89,7 +96,19 @@
53 "%s=%s" % (key, shell_escape(value))
54 for key, value in full_env.items()] + args
55 command = "cd %s && %s" % (path, " ".join(args))
56- self.chroot(["/bin/sh", "-c", command], echo=echo)
57+ return self.chroot(
58+ ["/bin/sh", "-c", command], echo=echo, get_output=get_output)
59+
60+ def save_status(self, status):
61+ """Save a dictionary of status information about this build.
62+
63+ This will be picked up by the build manager and included in XML-RPC
64+ status responses.
65+ """
66+ status_path = get_build_path(self.options.build_id, "status")
67+ with open("%s.tmp" % status_path, "w") as status_file:
68+ json.dump(status, status_file)
69+ os.rename("%s.tmp" % status_path, status_path)
70
71 def install(self):
72 print("Running install phase...")
73@@ -122,6 +141,15 @@
74 if not self.ssl_verify:
75 env["GIT_SSL_NO_VERIFY"] = "1"
76 self.run_build_command(cmd, env=env)
77+ status = {}
78+ if self.options.branch is not None:
79+ status["revision_id"] = self.run_build_command(
80+ ["bzr", "revno", self.name], get_output=True).rstrip("\n")
81+ else:
82+ status["revision_id"] = self.run_build_command(
83+ ["git", "-C", self.name, "rev-parse", self.options.git_path],
84+ get_output=True).rstrip("\n")
85+ self.save_status(status)
86
87 def pull(self):
88 """Run pull phase."""
89
90=== modified file 'debian/changelog'
91--- debian/changelog 2017-02-10 14:55:42 +0000
92+++ debian/changelog 2017-04-03 12:38:12 +0000
93@@ -1,3 +1,10 @@
94+launchpad-buildd (143) UNRELEASED; urgency=medium
95+
96+ * Record the branch revision used to build a snap and return it along with
97+ other XML-RPC status information (LP: #1679157).
98+
99+ -- Colin Watson <cjwatson@ubuntu.com> Fri, 31 Mar 2017 15:31:10 +0100
100+
101 launchpad-buildd (142) trusty; urgency=medium
102
103 * lpbuildd.binarypackage: Pass DEB_BUILD_OPTIONS=noautodbgsym if we have
104
105=== modified file 'lpbuildd/slave.py'
106--- lpbuildd/slave.py 2016-12-09 18:04:00 +0000
107+++ lpbuildd/slave.py 2017-04-03 12:38:12 +0000
108@@ -199,6 +199,14 @@
109
110 self.runSubProcess(self._preppath, ["slave-prep"])
111
112+ def status(self):
113+ """Return extra status for this build manager, as a dictionary.
114+
115+ This may be used to return manager-specific information from the
116+ XML-RPC status call.
117+ """
118+ return {}
119+
120 def iterate(self, success):
121 """Perform an iteration of the slave.
122
123@@ -309,6 +317,7 @@
124 self.waitingfiles = {}
125 self.builddependencies = ""
126 self._log = None
127+ self.manager = None
128
129 if not os.path.isdir(self._cachepath):
130 raise ValueError("FileCache path is not a dir")
131@@ -665,6 +674,8 @@
132 if self._version is not None:
133 ret["builder_version"] = self._version
134 ret.update(func())
135+ if self.slave.manager is not None:
136+ ret.update(self.slave.manager.status())
137 return ret
138
139 def status_IDLE(self):
140
141=== modified file 'lpbuildd/snap.py'
142--- lpbuildd/snap.py 2016-08-30 12:47:03 +0000
143+++ lpbuildd/snap.py 2017-04-03 12:38:12 +0000
144@@ -1,10 +1,14 @@
145 # Copyright 2015-2016 Canonical Ltd. This software is licensed under the
146 # GNU Affero General Public License version 3 (see the file LICENSE).
147
148+from __future__ import print_function
149+
150 __metaclass__ = type
151
152+import json
153 import os
154 import shutil
155+import sys
156
157 from lpbuildd.debian import (
158 DebianBuildManager,
159@@ -51,6 +55,19 @@
160
161 super(SnapBuildManager, self).initiate(files, chroot, extra_args)
162
163+ def status(self):
164+ status_path = get_build_path(self.home, self._buildid, "status")
165+ try:
166+ with open(status_path) as status_file:
167+ return json.load(status_file)
168+ except IOError:
169+ pass
170+ except Exception as e:
171+ print(
172+ "Error deserialising status from buildsnap: %s" % e,
173+ file=sys.stderr)
174+ return {}
175+
176 def doRunBuild(self):
177 """Run the process to build the snap."""
178 args = [
179
180=== modified file 'lpbuildd/tests/test_snap.py'
181--- lpbuildd/tests/test_snap.py 2016-08-30 12:47:03 +0000
182+++ lpbuildd/tests/test_snap.py 2017-04-03 12:38:12 +0000
183@@ -82,6 +82,16 @@
184 self.buildmanager.iterate, self.buildmanager.iterators[-1])
185 self.assertFalse(self.slave.wasCalled("chrootFail"))
186
187+ def test_status(self):
188+ # The build manager returns saved status information on request.
189+ self.assertEqual({}, self.buildmanager.status())
190+ status_path = os.path.join(
191+ self.working_dir, "home", "build-%s" % self.buildid, "status")
192+ os.makedirs(os.path.dirname(status_path))
193+ with open(status_path, "w") as status_file:
194+ status_file.write('{"revision_id": "dummy"}')
195+ self.assertEqual({"revision_id": "dummy"}, self.buildmanager.status())
196+
197 def test_iterate(self):
198 # The build manager iterates a normal build from start to finish.
199 self.startBuild()

Subscribers

People subscribed via source and target branches

to all changes: