Merge lp:~steve-mcintyre/linaro-chromiumos/python-rewrite into lp:linaro-chromiumos

Proposed by Steve McIntyre
Status: Merged
Merged at revision: 14
Proposed branch: lp:~steve-mcintyre/linaro-chromiumos/python-rewrite
Merge into: lp:linaro-chromiumos
Diff against target: 350 lines (+278/-53)
4 files modified
remote/run_build (+0/-14)
remote/run_build.py (+59/-0)
remote/setup_build (+0/-39)
remote/setup_build.py (+219/-0)
To merge this branch: bzr merge lp:~steve-mcintyre/linaro-chromiumos/python-rewrite
Reviewer Review Type Date Requested Status
Loïc Minier Pending
Review via email: mp+54250@code.launchpad.net

Description of the change

Rewrite in python.
Adding more features for better control of what we're building and where.

To post a comment you must log in.
14. By Steve McIntyre

Add creation of the top-level work area, using sudo to make sure it succeeds.

Revision history for this message
Loïc Minier (lool) wrote :

I submitted a branch based on yours for you to merge, as I felt it was simpler to show the changes in commits rather than explain them, then ask you to do them, then review them etc. These were all very simple changes, and overall your code was really good, thanks! See https://code.launchpad.net/~lool/linaro-chromiumos/python-rewrite/+merge/54551 for the mp.

There is one major issue with the new Python code: usage of os.system() is unchecked, which means we don't fail the run when any command fails. This really must be fixed; with the new run() wrapper I introduced, it should be simpler to add this in a single place.

Other things I had in mind:
- we should have a place to share code between the scripts
- we should move them out of remote and kill my linaro-chromiumos-build frontend
- (low priority) getopt doesn't integrate too nicely with Python in my experience, there are nicer ways to handle flags, but it works with getopt so we can keep it for now
- create_logdir() feels a bit specific; I think we should have an ensure_dir() thin wrapper around os.isdir() + os.makedirs(), and we should setup logdir early; perhaps it's easier to just expose it as an option; this would also allow merging logged_run() with run()
- I think we should use stderr consistently for our own output, but I'm open to discuss this
- the run() interface should take an array of commands rather than a command string; this is nicer to deal with when preparing commands before running them

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'remote/run_build'
2--- remote/run_build 2011-03-09 17:35:56 +0000
3+++ remote/run_build 1970-01-01 00:00:00 +0000
4@@ -1,14 +0,0 @@
5-#!/bin/sh
6-
7-set -e
8-
9-./setup_board --board x86-generic
10-./build_packages --board x86-generic
11-
12-# <wait a long time>
13-
14-./build_image --board x86-generic --noenable_rootfs_verification
15-
16-# <wait a long time>
17-# Success?
18-
19
20=== added file 'remote/run_build.py'
21--- remote/run_build.py 1970-01-01 00:00:00 +0000
22+++ remote/run_build.py 2011-03-23 14:06:22 +0000
23@@ -0,0 +1,59 @@
24+#!/usr/bin/python
25+#
26+# Simple wrapper build script for Chromium OS builds
27+#
28+# Copyright (C) 2011 Linaro
29+#
30+# GPL v2+
31+
32+import os
33+import getopt
34+import sys
35+import warnings
36+import errno
37+import shutil
38+
39+options = {}
40+options['logdir'] = ''
41+options['board-type'] = 'x86-generic'
42+options['nousepkg'] = False
43+
44+try:
45+ opts, args = getopt.getopt(sys.argv[1:], "",
46+ ["logdir=",
47+ "board-type=",
48+ "nousepkg="])
49+except getopt.GetoptError, err:
50+ # print help information and exit:
51+ print str(err) # will print something like "option -a not recognized"
52+ usage()
53+ sys.exit(2)
54+
55+for o, a in opts:
56+ options[o[2:]] = a
57+
58+
59+if not options['logdir'] == '':
60+ os.environ['PORT_LOGDIR'] = options['logdir']
61+ try:
62+ os.environ['FEATURES'] = os.environ['FEATURES'] + ' binpkg-logs'
63+ except:
64+ os.environ['FEATURES'] = 'binpkg-logs'
65+ os.system('sudo rm -rf %s'% options['logdir'])
66+ os.system('sudo mkdir %s' % options['logdir'])
67+
68+build_options = ''
69+build_options += ' --board=%s' % options['board-type']
70+if options['nousepkg']:
71+ build_options += ' --nousepkg'
72+
73+os.system('./setup_board --force %s' % build_options)
74+os.system('./build_packages %s' % build_options)
75+
76+# <wait a long time>
77+image_options = ' --noenable_rootfs_verification '
78+image_options += ' --board=%s' % options['board-type']
79+os.system('./build_image %s' % image_options)
80+
81+# <wait a long time>
82+# Success?
83
84=== removed file 'remote/setup_build'
85--- remote/setup_build 2011-03-09 17:35:56 +0000
86+++ remote/setup_build 1970-01-01 00:00:00 +0000
87@@ -1,39 +0,0 @@
88-#!/bin/sh
89-
90-set -e
91-
92-MANIFEST=$1
93-if [ "$MANIFEST"x = "" ] ; then
94- MANIFEST=http://git.chromium.org/git/manifest
95-fi
96-
97-BASEDIR=`dirname $0`
98-WDIR=/mnt/chromeos
99-
100-# Basic setup
101-export LC_ALL=C
102-sudo apt-get update
103-sudo apt-get install git subversion build-essential
104-
105-# Make working directory
106-if [ ! -d $WDIR ] ; then
107- sudo mkdir $WDIR
108- sudo chown ubuntu: $WDIR
109-fi
110-
111-# Grab basic stuff
112-cd $WDIR
113-svn co http://src.chromium.org/svn/trunk/tools/depot_tools
114-export PATH=$PATH:$PWD/depot_tools
115-
116-# Start grabbing source
117-repo init -u $MANIFEST
118-repo sync
119-
120-# Set up the working chroot
121-/mnt/chromeos/src/scripts/make_chroot --chroot=chroot-x86
122-cp $BASEDIR/run_build chroot-x86/src/scripts
123-
124-# Now chroot into it and do stuff
125-script -c "/mnt/chromeos/src/scripts/enter_chroot.sh --chroot=chroot-x86 -- ./run_build" cros-build.log
126-
127
128=== added file 'remote/setup_build.py'
129--- remote/setup_build.py 1970-01-01 00:00:00 +0000
130+++ remote/setup_build.py 2011-03-23 14:06:22 +0000
131@@ -0,0 +1,219 @@
132+#!/usr/bin/python
133+#
134+# Simple setup script for Chromium OS builds
135+#
136+# Copyright (C) 2011 Linaro
137+#
138+# GPL v2+
139+
140+import os
141+import getopt
142+import sys
143+import warnings
144+import errno
145+import shutil
146+
147+# Set defaults for options
148+options = {}
149+options['build-name'] = 'build'
150+options['board-type'] = 'x86-generic'
151+options['use-network'] = True
152+options['working-dir'] = ''
153+#options['toolchain'] = 'default'
154+options['manifest'] = 'http://git.chromium.org/git/manifest'
155+options['nousepkg'] = False
156+options['build-script'] = 'run_build.py'
157+
158+commands = 'create_tree get_source create_chroot build'.split()
159+
160+def usage():
161+ print "%s\n" % sys.argv[0]
162+ print "usage:\n"
163+ print " setup_build.py [options] <command>\n"
164+ print " options include:\n"
165+ print " --working-dir=<name>"
166+ print " specify a base location for a working directory"
167+ print " (default is \"%s\")" % options['working-dir']
168+ print " --build-name=<name>"
169+ print " specify a name to use for this build"
170+ print " (default is \"%s\")" % options['build-name']
171+ print " --board-type=<board>"
172+ print " specify the target board/platform"
173+ print " (default is \"%s\")" % options['board-type']
174+ print " --use-network=<true|false>"
175+ print " should network access be allowed during the build?"
176+ print " (default is %s)" % options['use-network']
177+ print " --toolchain=<toolchain>"
178+ print " choice of toolchain. Not yet implemented."
179+ print " --manifest=<manifest URL>"
180+ print " specify the manifest file to use"
181+ print " (default is \"%s\")" % options['manifest']
182+ print " --nousepkg=<true|false>"
183+ print " force building of everything from source"
184+ print " needed if --use-network==true or if using a new toolchain"
185+ print " (default is \"%s\")" % options['nousepkg']
186+ print
187+ print "commands:\n"
188+ print " create_tree"
189+ print " create a working tree; necessary for other commands to run"
190+ print " get_source"
191+ print " download / update source code"
192+ print " create_chroot"
193+ print " create a chroot; necessary for later commands to run"
194+ print " build"
195+ print " build Chromium OS"
196+ print
197+
198+def do_install_depot_tools(options, tree_dir):
199+ os.chdir(tree_dir)
200+ os.system('svn co http://src.chromium.org/svn/trunk/tools/depot_tools')
201+
202+def do_create_logdir(options, tree_dir):
203+ logdir = os.path.join(tree_dir, 'logs')
204+ if not os.path.exists(logdir):
205+ os.mkdir(logdir)
206+
207+def do_create_tree(options, tree_dir):
208+ print 'do_create_tree'
209+
210+ if os.path.exists(tree_dir):
211+ print 'do_create_tree: tree %s already exists. Abort.' % tree_dir
212+ return errno.EEXIST
213+
214+ os.makedirs(tree_dir, 0755)
215+ os.system('sudo apt-get update')
216+ os.system('sudo apt-get install -y git subversion build-essential')
217+ do_install_depot_tools(options, tree_dir)
218+ do_create_logdir(options, tree_dir)
219+
220+def do_get_source(options, tree_dir):
221+ print 'do_get_source'
222+
223+ if not os.path.exists(tree_dir):
224+ print 'do_get_source: tree %s does not exist. Abort.' % tree_dir
225+ return errno.ENOENT
226+
227+ basedir = os.path.dirname(os.path.realpath(sys.argv[0]))
228+
229+ do_create_logdir(options, tree_dir)
230+ os.chdir(tree_dir)
231+ # Needs the "echo" piped in here to stop "repo init" asking
232+ # awkward interactive questions that you can't pass on the command
233+ # line.
234+ cmdline = 'script -c "'
235+ cmdline += 'echo | repo init -u %s' % options['manifest']
236+ cmdline += '" logs/repo-init.log'
237+ os.system(cmdline)
238+
239+ cmdline = 'script -c "'
240+ cmdline += 'repo sync'
241+ cmdline += '" logs/repo-sync.log'
242+ os.system(cmdline)
243+
244+ # Copy in our script to do the actual build work inside the chroot
245+ build_script = os.path.join(basedir, options['build-script'])
246+ os.chmod(build_script, 0755)
247+ shutil.copy(build_script, './src/scripts')
248+
249+def do_create_chroot(options, tree_dir):
250+ print 'do_create_chroot'
251+
252+ if not os.path.exists(tree_dir):
253+ print 'do_create_chroot: tree %s does not exist. Abort.' % tree_dir
254+ return errno.ENOENT
255+
256+ do_create_logdir(options, tree_dir)
257+ os.chdir(tree_dir)
258+ cmdline = 'script -c "'
259+ cmdline += './src/scripts/make_chroot'
260+ if options['nousepkg']:
261+ cmdline += ' --nousepkg'
262+ cmdline += '" logs/create-chroot.log'
263+ os.system(cmdline)
264+
265+def do_build(options, tree_dir):
266+ print 'do_build'
267+
268+ if not os.path.exists(tree_dir):
269+ print 'do_build: tree %s does not exist. Abort.' % tree_dir
270+ return errno.ENOENT
271+
272+ chroot_path = os.path.join(tree_dir, 'chroot')
273+ if not os.path.exists(chroot_path):
274+ print 'do_build: chroot %s does not exist. Abort.' % chroot_path
275+ return errno.ENOENT
276+
277+ do_create_logdir(options, tree_dir)
278+ os.chdir(tree_dir)
279+
280+ cmdline = 'script -c "'
281+ cmdline += './src/scripts/enter_chroot.sh -- ./%s' % options['build-script']
282+ if options['nousepkg']:
283+ cmdline += ' --nousepkg=True'
284+ cmdline += ' --board-type=%s' % options['board-type']
285+ cmdline += ' --logdir=/var/log/saved-logs'
286+ cmdline += '" logs/cros-build.log'
287+ os.system(cmdline)
288+
289+ cmdline = 'tar c -C chroot/var/log --lzma -f logs/build-logs.tar.lzma saved-logs'
290+ os.system(cmdline)
291+
292+try:
293+ opts, args = getopt.getopt(sys.argv[1:], "",
294+ ["help",
295+ "working-dir=",
296+ "build-name=",
297+ "board-type=",
298+ "use-network=",
299+ "toolchain=",
300+ "nousepkg=",
301+ "manifest="])
302+except getopt.GetoptError, err:
303+ # print help information and exit:
304+ print str(err) # will print something like "option -a not recognized"
305+ usage()
306+ sys.exit(2)
307+
308+for o, a in opts:
309+ if o in ("--help"):
310+ usage()
311+ sys.exit(0)
312+ else:
313+ options[o[2:]] = a
314+
315+if options['working-dir'] == '':
316+ print 'Need to specify a working dir. Abort.'
317+ usage()
318+ sys.exit(2)
319+
320+if args == []:
321+ print "Not asked to do anything"
322+ usage()
323+ sys.exit(0)
324+
325+for command in args:
326+ if not command in (commands):
327+ print "Unknown command %s" % command
328+ usage()
329+ sys.exit(2)
330+
331+if not os.path.exists(options['working-dir']):
332+ # Create working dir area; likely to be on a separate filesystem
333+ # somewhere, so let's make this as simple as possible using sudo.
334+ os.system('sudo mkdir -p -m 0755 %s' % options['working-dir'])
335+ os.system('sudo chown %s: %s' % (os.environ['LOGNAME'], options['working-dir']))
336+
337+tree_dir = os.path.join(options['working-dir'], options['build-name'])
338+depot_tools_dir = os.path.join(tree_dir, 'depot_tools')
339+os.environ['LC_ALL'] = 'C'
340+os.environ['PATH'] = os.environ['PATH'] + os.pathsep + depot_tools_dir
341+
342+if 'create_tree' in args:
343+ err = do_create_tree(options, tree_dir)
344+if 'get_source' in args:
345+ err = do_get_source(options, tree_dir)
346+if 'create_chroot' in args:
347+ err = do_create_chroot(options, tree_dir)
348+if 'build' in args:
349+ err = do_build(options, tree_dir)
350+

Subscribers

People subscribed via source and target branches