blob: 5ee797e06e20d980ae0cce6fc79e2a9d90fa7a2c [file] [log] [blame]
Han Shen91445322013-03-20 13:43:31 -07001#!/usr/bin/python
Han Shen819f8622014-04-08 16:57:38 -07002"""Script to bootstrap the chroot using new toolchain.
3
4This script allows you to build/install a customized version of gcc/binutils,
5either by specifying branch or a local directory.
6
7This script must be executed outside chroot.
8
9Below is some typical usage -
10
11## Build gcc located at /local/gcc/dir and do a bootstrap using the new compiler
12## for the chromeos root. The script tries to find a valid chromeos tree all
13## the way up from your current working directory.
14./build_tool.py --gcc_dir=/loca/gcc/dir --bootstrap
15
16## Build binutils, using remote branch "mobile_toolchain_v17" and do a bootstrap
17## using the new binutils for the chromeos root. The script tries to find a
18## valid chromeos tree all the way up from your current working directory.
19./build_tool.py --binutils_branch=cros/mobile_toolchain_v17 \
20 --chromeos_root=/chromeos/dir --bootstrap
21
22## Same as above except only do it for board daisy - no bootstrapping involved.
23./build_tool.py --binutils_branch=cros/mobile_toolchain_v16 \
24 --chromeos_root=/chromeos/dir --board=daisy
25"""
Han Shen91445322013-03-20 13:43:31 -070026
27__author__ = 'shenhan@google.com (Han Shen)'
28
29import optparse
30import os
31import re
Han Shen91445322013-03-20 13:43:31 -070032import sys
33
Han Shen819f8622014-04-08 16:57:38 -070034import repo_to_repo
Han Shen91445322013-03-20 13:43:31 -070035from utils import command_executer
36from utils import logger
37from utils import misc
38
Han Shen819f8622014-04-08 16:57:38 -070039REPO_PATH_PATTERN = 'src/third_party/{0}'
40TEMP_BRANCH_NAME = 'internal_testing_branch_no_use'
41CHROMIUMOS_OVERLAY_PATH = 'src/third_party/chromiumos-overlay'
42EBUILD_PATH_PATTERN = 'src/third_party/chromiumos-overlay/sys-devel/{0}'
43
Han Shen91445322013-03-20 13:43:31 -070044
45class Bootstrapper(object):
Han Shen819f8622014-04-08 16:57:38 -070046 """Class that handles bootstrap process.
47 """
48
49 def __init__(self, chromeos_root, gcc_branch=None, gcc_dir=None,
50 binutils_branch=None, binutils_dir=None,
Han Shen03d30982014-06-12 11:22:29 -070051 board=None, disable_2nd_bootstrap=False,
52 setup_tool_ebuild_file_only=False):
Han Shen91445322013-03-20 13:43:31 -070053 self._chromeos_root = chromeos_root
Han Shen819f8622014-04-08 16:57:38 -070054
55 self._gcc_branch = gcc_branch
56 self._gcc_branch_tree = None
Han Shen91445322013-03-20 13:43:31 -070057 self._gcc_dir = gcc_dir
Han Shen91445322013-03-20 13:43:31 -070058 self._gcc_ebuild_file = None
59 self._gcc_ebuild_file_name = None
Han Shen819f8622014-04-08 16:57:38 -070060
61 self._binutils_branch = binutils_branch
62 self._binutils_branch_tree = None
63 self._binutils_dir = binutils_dir
64 self._binutils_ebuild_file = None
65 self._binutils_ebuild_file_name = None
66
67 self._setup_tool_ebuild_file_only = setup_tool_ebuild_file_only
68
69 self._ce = command_executer.GetCommandExecuter()
70 self._logger = logger.GetLogger()
71 self._board = board
Han Shen03d30982014-06-12 11:22:29 -070072 self._disable_2nd_bootstrap = disable_2nd_bootstrap
Han Shen819f8622014-04-08 16:57:38 -070073
74 def IsTreeSame(self, t1, t2):
75 diff = 'diff -qr -x .git -x .svn "{0}" "{1}"'.format(t1, t2)
76 if self._ce.RunCommand(diff, print_to_console=False) == 0:
77 self._logger.LogOutput('"{0}" and "{1}" are the same."'.format(t1, t2))
78 return True
79 self._logger.LogWarning('"{0}" and "{1}" are different."'.format(t1, t2))
80 return False
Han Shen91445322013-03-20 13:43:31 -070081
82 def SubmitToLocalBranch(self):
Han Shen819f8622014-04-08 16:57:38 -070083 """Copy source code to the chromium source tree and submit it locally."""
84 if self._gcc_dir:
85 if not self.SubmitToolToLocalBranch(
86 tool_name='gcc', tool_dir=self._gcc_dir):
87 return False
88 self._gcc_branch = TEMP_BRANCH_NAME
Han Shen91445322013-03-20 13:43:31 -070089
Han Shen819f8622014-04-08 16:57:38 -070090 if self._binutils_dir:
91 if not self.SubmitToolToLocalBranch(
92 tool_name='binutils', tool_dir=self._binutils_dir):
93 return False
94 self._binutils_branch = TEMP_BRANCH_NAME
95
96 return True
97
98 def SubmitToolToLocalBranch(self, tool_name, tool_dir):
99 """Copy the source code to local chromium source tree.
100
101 Args:
102 tool_name: either 'gcc' or 'binutils'
103 tool_dir: the tool source dir to be used
104 Returns:
105 True if all succeeded False otherwise.
106 """
107
108 # The next few steps creates an internal branch to sync with the tool dir
Han Shen91445322013-03-20 13:43:31 -0700109 # user provided.
Han Shen819f8622014-04-08 16:57:38 -0700110 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
Han Shen91445322013-03-20 13:43:31 -0700111
112 # 0. Test to see if git tree is free of local changes.
Han Shen819f8622014-04-08 16:57:38 -0700113 if not misc.IsGitTreeClean(chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700114 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700115 'Git repository "{0}" not clean, aborted.'.format(chrome_tool_dir))
Han Shen91445322013-03-20 13:43:31 -0700116 return False
117
118 # 1. Checkout/create a (new) branch for testing.
Han Shen819f8622014-04-08 16:57:38 -0700119 command = 'cd "{0}" && git checkout -B {1}'.format(
120 chrome_tool_dir, TEMP_BRANCH_NAME)
Han Shen91445322013-03-20 13:43:31 -0700121 ret = self._ce.RunCommand(command)
122 if ret:
123 self._logger.LogError('Failed to create a temp branch for test, aborted.')
124 return False
125
Han Shen819f8622014-04-08 16:57:38 -0700126 if self.IsTreeSame(tool_dir, chrome_tool_dir):
127 self._logger.LogOutput(
128 '"{0}" and "{1}" are the same, sync skipped.'.format(
129 tool_dir, chrome_tool_dir))
130 return True
Han Shen91445322013-03-20 13:43:31 -0700131
Han Shen819f8622014-04-08 16:57:38 -0700132 # 2. Sync sources from user provided tool dir to chromiumos tool git.
133 local_tool_repo = repo_to_repo.FileRepo(tool_dir)
134 chrome_tool_repo = repo_to_repo.GitRepo(chrome_tool_dir, TEMP_BRANCH_NAME)
135 chrome_tool_repo._root_dir = chrome_tool_dir
Han Shen03d30982014-06-12 11:22:29 -0700136 # Delete all stuff except '.git' before start mapping.
137 self._ce.RunCommand(
138 'cd {0} && find . -maxdepth 1 -not -name ".git" -not -name "." '
139 r'\( -type f -exec rm {{}} \; -o '
140 r' -type d -exec rm -fr {{}} \; \)'.format(
141 chrome_tool_dir))
Han Shen819f8622014-04-08 16:57:38 -0700142 local_tool_repo.MapSources(chrome_tool_repo.GetRoot())
143
144 # 3. Ensure after sync tree is the same.
145 if self.IsTreeSame(tool_dir, chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700146 self._logger.LogOutput('Sync successfully done.')
Han Shen819f8622014-04-08 16:57:38 -0700147 else:
148 self._logger.LogError('Sync not successful, aborted.')
149 return False
Han Shen91445322013-03-20 13:43:31 -0700150
151 # 4. Commit all changes.
Han Shen03d30982014-06-12 11:22:29 -0700152 # 4.1 Try to get some information about the tool dir we are using.
153 cmd = 'cd {0} && git log -1 --pretty=oneline'.format(tool_dir)
154 tool_dir_extra_info = None
155 ret, tool_dir_extra_info, _ = self._ce.RunCommand(
156 cmd, return_output=True, print_to_console=False)
157 commit_message = 'Synced with tool source tree at - "{0}".'.format(tool_dir)
158 if not ret:
159 commit_message += '\nGit log for {0}:\n{1}'.format(
160 tool_dir, tool_dir_extra_info)
161
162 if chrome_tool_repo.CommitLocally(commit_message):
Han Shen91445322013-03-20 13:43:31 -0700163 self._logger.LogError('Commit to local branch "{0}" failed, aborted.'.
Han Shen819f8622014-04-08 16:57:38 -0700164 format(TEMP_BRANCH_NAME))
Han Shen91445322013-03-20 13:43:31 -0700165 return False
166 return True
167
168 def CheckoutBranch(self):
Han Shen819f8622014-04-08 16:57:38 -0700169 """Checkout working branch for the tools.
Han Shen91445322013-03-20 13:43:31 -0700170
Han Shen819f8622014-04-08 16:57:38 -0700171 Returns:
172 True: if operation succeeds.
173 """
Han Shen91445322013-03-20 13:43:31 -0700174
Han Shen819f8622014-04-08 16:57:38 -0700175 if self._gcc_branch:
176 rv = self.CheckoutToolBranch('gcc', self._gcc_branch)
177 if rv:
178 self._gcc_branch_tree = rv
179 else:
180 return False
181
182 if self._binutils_branch:
183 rv = self.CheckoutToolBranch('binutils', self._binutils_branch)
184 if rv:
185 self._binutils_branch_tree = rv
186 else:
187 return False
188
Han Shen91445322013-03-20 13:43:31 -0700189 return True
190
Han Shen819f8622014-04-08 16:57:38 -0700191 def CheckoutToolBranch(self, tool_name, tool_branch):
192 """Checkout the tool branch for a certain tool.
193
194 Args:
195 tool_name: either 'gcc' or 'binutils'
196 tool_branch: tool branch to use
197 Returns:
198 True: if operation succeeds. Otherwise False.
Han Shen91445322013-03-20 13:43:31 -0700199 """
Han Shen819f8622014-04-08 16:57:38 -0700200
201 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
202 command = 'cd "{0}" && git checkout {1}'.format(
203 chrome_tool_dir, tool_branch)
204 if not self._ce.RunCommand(command, print_to_console=True):
205 # Get 'TREE' value of this commit
206 command = ('cd "{0}" && git cat-file -p {1} '
207 '| grep -E "^tree [a-f0-9]+$" '
208 '| cut -d" " -f2').format(chrome_tool_dir, tool_branch)
209 ret, stdout, _ = self._ce.RunCommand(
210 command, return_output=True, print_to_console=False)
211 # Pipe operation always has a zero return value. So need to check if
212 # stdout is valid.
213 if not ret and stdout and re.match(
214 '[0-9a-h]{40}', stdout.strip(), re.IGNORECASE):
215 tool_branch_tree = stdout.strip()
216 self._logger.LogOutput('Find tree for {0} branch "{1}" - "{2}"'.format(
217 tool_name, tool_branch, tool_branch_tree))
218 return tool_branch_tree
219 self._logger.LogError(('Failed to checkout "{0}" or failed to '
220 'get tree value, aborted.').format(tool_branch))
221 return None
222
223 def FindEbuildFile(self):
224 """Find the ebuild files for the tools.
225
226 Returns:
227 True: if operation succeeds.
228 """
229
230 if self._gcc_branch:
231 (rv, ef, efn) = self.FindToolEbuildFile('gcc')
232 if rv:
233 self._gcc_ebuild_file = ef
234 self._gcc_ebuild_file_name = efn
235 else:
236 return False
237
238 if self._binutils_branch:
239 (rv, ef, efn) = self.FindToolEbuildFile('binutils')
240 if rv:
241 self._binutils_ebuild_file = ef
242 self._binutils_ebuild_file_name = efn
243 else:
244 return False
245
246 return True
247
248 def FindToolEbuildFile(self, tool_name):
249 """Find ebuild file for a specific tool.
250
251 Args:
252 tool_name: either "gcc" or "binutils".
253 Returns:
254 A triplet that consisits of whether operation succeeds or not,
255 tool ebuild file full path and tool ebuild file name.
256 """
257
258 # To get the active gcc ebuild file, we need a workable chroot first.
259 if not os.path.exists(
260 os.path.join(self._chromeos_root, 'chroot')) and self._ce.RunCommand(
261 'cd "{0}" && cros_sdk --create'.format(self._chromeos_root)):
262 self._logger.LogError(('Failed to install a initial chroot, aborted.\n'
263 'If previous bootstrap failed, do a '
264 '"cros_sdk --delete" to remove '
265 'in-complete chroot.'))
266 return (False, None, None)
267
268 rv, stdout, _ = self._ce.ChrootRunCommand(
269 self._chromeos_root, 'equery w sys-devel/{0}'.format(tool_name),
270 return_output=True, print_to_console=True)
271 if rv:
272 self._logger.LogError(
273 ('Failed to execute inside chroot '
274 '"equery w sys-devel/{0}", aborted.').format(tool_name))
275 return (False, None, None)
276 m = re.match(r'^.*/({0}/(.*\.ebuild))$'.format(
277 EBUILD_PATH_PATTERN.format(tool_name)), stdout)
278 if not m:
279 self._logger.LogError(
280 ('Failed to find {0} ebuild file, aborted. '
281 'If previous bootstrap failed, do a "cros_sdk --delete" to remove '
282 'in-complete chroot.').format(tool_name))
283 return (False, None, None)
284 tool_ebuild_file = os.path.join(self._chromeos_root, m.group(1))
285 tool_ebuild_file_name = m.group(2)
286
287 return (True, tool_ebuild_file, tool_ebuild_file_name)
288
289 def InplaceModifyEbuildFile(self):
290 """Modify the ebuild file.
291
292 Returns:
293 True if operation succeeds.
294 """
295
296 # Note we shall not use remote branch name (eg. "cros/gcc.gnu.org/...") in
297 # CROS_WORKON_COMMIT, we have to use GITHASH. So we call GitGetCommitHash on
298 # tool_branch.
299 if self._gcc_branch:
300 tool_branch_githash = misc.GitGetCommitHash(
301 self.GetChromeOsToolDir('gcc'), self._gcc_branch)
302 if not tool_branch_githash:
303 return False
304 if not self.InplaceModifyToolEbuildFile(
305 tool_branch_githash, self._gcc_branch_tree, self._gcc_ebuild_file):
306 return False
307
308 if self._binutils_branch:
309 tool_branch_githash = misc.GitGetCommitHash(
310 self.GetChromeOsToolDir('binutils'), self._binutils_branch)
311 if not self.InplaceModifyToolEbuildFile(
312 tool_branch_githash, self._binutils_branch_tree,
313 self._binutils_ebuild_file):
314 return False
315 return True
316
317 @staticmethod
318 def ResetToolEbuildFile(chromeos_root, tool_name):
319 """Reset tool ebuild file to clean state.
320
321 Args:
322 chromeos_root: chromeos source tree
323 tool_name: either "gcc" or "binutils"
324 Returns:
325 True if operation succeds.
326 """
327 rv = misc.GetGitChangesAsList(
328 os.path.join(chromeos_root, CHROMIUMOS_OVERLAY_PATH),
329 path=('sys-devel/{0}/{0}-*.ebuild'.format(tool_name)),
330 staged=False)
331 if rv:
332 cmd = 'cd {0} && git checkout --'.format(os.path.join(
333 chromeos_root, CHROMIUMOS_OVERLAY_PATH))
334 for g in rv:
335 cmd += ' ' + g
336 rv = command_executer.GetCommandExecuter().RunCommand(cmd)
337 if rv:
338 logger.GetLogger().LogWarning(
339 'Failed to reset the ebuild file. Please refer to log above.')
340 return False
341 else:
342 logger.GetLogger().LogWarning(
343 'Note - did not find any modified {0} ebuild file.'.format(tool_name))
344 # Fall through
345 return True
346
347 def GetChromeOsToolDir(self, tool_name):
348 """Return the chromeos git dir for a specific tool.
349
350 Args:
351 tool_name: either 'gcc' or 'binutils'.
352 Returns:
353 Absolute git path for the tool.
354 """
355
356 return os.path.join(
357 self._chromeos_root, REPO_PATH_PATTERN.format(tool_name))
358
359 def InplaceModifyToolEbuildFile(
360 self, tool_branch_githash, tool_branch_tree, tool_ebuild_file):
361 """Using sed to fill properly values into the ebuild file.
362
363 Args:
364 tool_branch_githash: githash for tool_branch
365 tool_branch_tree: treeish for the tool branch
366 tool_ebuild_file: tool ebuild file
367 Returns:
368 True: if operation succeeded.
369 """
370
371 command = ('sed -i '
372 '-e \'/^CROS_WORKON_COMMIT=".*"/i'
373 ' # The following line is modified by script.\' '
374 '-e \'s!^CROS_WORKON_COMMIT=".*"$!CROS_WORKON_COMMIT="{0}"!\' '
375 '-e \'/^CROS_WORKON_TREE=".*"/i'
376 ' # The following line is modified by script.\' '
377 '-e \'s!^CROS_WORKON_TREE=".*"$!CROS_WORKON_TREE="{1}"!\' '
378 '{2}').format(tool_branch_githash,
379 tool_branch_tree,
380 tool_ebuild_file)
Han Shen91445322013-03-20 13:43:31 -0700381 rv = self._ce.RunCommand(command)
382 if rv:
383 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700384 'Failed to modify commit and tree value for "{0}"", aborted.'.format(
385 tool_ebuild_file))
386 return False
387
388 # Warn that the ebuild file has been modified.
389 self._logger.LogWarning(
390 ('Ebuild file "{0}" is modified, to revert the file - \n'
391 'bootstrap_compiler.py --chromeos_root={1} '
392 '--reset_tool_ebuild_file').format(
393 tool_ebuild_file, self._chromeos_root))
394 return True
395
396 def DoBuildForBoard(self):
397 """Build tool for a specific board.
398
399 Returns:
400 True if operation succeeds.
401 """
402
403 if self._gcc_branch:
404 if not self.DoBuildToolForBoard('gcc'):
405 return False
406 if self._binutils_branch:
407 if not self.DoBuildToolForBoard('binutils'):
408 return False
409 return True
410
411 def DoBuildToolForBoard(self, tool_name):
412 """Build a specific tool for a specific board.
413
414 Args:
415 tool_name: either "gcc" or "binutils"
416 Returns:
417 True if operation succeeds.
418 """
419
Han Shenfe3001c2014-04-28 16:36:28 -0700420 boards_to_build = self._board.split(',')
Han Shen819f8622014-04-08 16:57:38 -0700421
Han Shenfe3001c2014-04-28 16:36:28 -0700422 failed = []
423 for board in boards_to_build:
424 if board == 'host':
425 command = 'sudo emerge sys-devel/{0}'.format(tool_name)
426 else:
427 target = misc.GetCtargetFromBoard(board, self._chromeos_root)
428 if not target:
429 self._logger.LogError(
430 'Unsupported board "{0}", skip.'.format(board))
431 failed.append(board)
432 continue
433 command = 'sudo emerge cross-{0}/{1}'.format(target, tool_name)
434
435 rv = self._ce.ChrootRunCommand(self._chromeos_root, command,
436 return_output=False, print_to_console=True)
437 if rv:
438 self._logger.LogError(
Han Shen03d30982014-06-12 11:22:29 -0700439 'Build {0} failed for {1}, aborted.'.format(tool_name, board))
Han Shenfe3001c2014-04-28 16:36:28 -0700440 failed.append(board)
441 else:
442 self._logger.LogOutput(
Han Shen03d30982014-06-12 11:22:29 -0700443 'Successfully built {0} for board {1}.'.format(tool_name, board))
Han Shenfe3001c2014-04-28 16:36:28 -0700444
Han Shen8dfdabd2014-05-08 10:15:09 -0700445 if failed:
Han Shen819f8622014-04-08 16:57:38 -0700446 self._logger.LogError(
Han Shenfe3001c2014-04-28 16:36:28 -0700447 'Failed to build {0} for the following board(s): "{1}"'.format(
448 tool_name, ' '.join(failed)))
Han Shen91445322013-03-20 13:43:31 -0700449 return False
Han Shenfe3001c2014-04-28 16:36:28 -0700450 # All boards build successfully
Han Shen91445322013-03-20 13:43:31 -0700451 return True
452
453 def DoBootstrapping(self):
Han Shen819f8622014-04-08 16:57:38 -0700454 """Do bootstrapping the chroot.
455
Han Shen03d30982014-06-12 11:22:29 -0700456 This step firstly downloads a prestine sdk, then use this sdk to build the
457 new sdk, finally use the new sdk to build every host package.
458
Han Shen819f8622014-04-08 16:57:38 -0700459 Returns:
460 True if operation succeeds.
461 """
462
Han Shen91445322013-03-20 13:43:31 -0700463 logfile = os.path.join(self._chromeos_root, 'bootstrap.log')
Han Shen819f8622014-04-08 16:57:38 -0700464 command = 'cd "{0}" && cros_sdk --delete --bootstrap |& tee "{1}"'.format(
465 self._chromeos_root, logfile)
466 rv = self._ce.RunCommand(command, return_output=False,
467 print_to_console=True)
Han Shen91445322013-03-20 13:43:31 -0700468 if rv:
469 self._logger.LogError('Bootstrapping failed, log file - "{0}"\n'.format(
470 logfile))
471 return False
472
473 self._logger.LogOutput('Bootstrap succeeded.')
474 return True
475
Han Shen03d30982014-06-12 11:22:29 -0700476 def BuildAndInstallAmd64Host(self):
477 """Build amd64-host (host) packages.
478
479 Build all host packages in the newly-bootstrapped 'chroot' using *NEW*
480 toolchain.
481
482 So actually we perform 2 builds of all host packages -
483 1. build new toolchain using old toolchain and build all host packages
484 using the newly built toolchain
485 2. build the new toolchain again but using new toolchain built in step 1,
486 and build all host packages using the newly built toolchain
487
488 Returns:
489 True if operation succeeds.
490 """
491
492 cmd = ('cd {0} && cros_sdk -- -- ./setup_board --board=amd64-host '
493 '--accept_licenses=@CHROMEOS --skip_chroot_upgrade --nousepkg '
494 '--reuse_pkgs_from_local_boards').format(self._chromeos_root)
495 rv = self._ce.RunCommand(cmd, return_output=False, print_to_console=True)
496 if rv:
497 self._logger.LogError('Build amd64-host failed.')
498 return False
499
500 # Package amd64-host into 'built-sdk.tar.xz'.
501 sdk_package = os.path.join(self._chromeos_root, 'built-sdk.tar.xz')
502 cmd = ('cd {0}/chroot/build/amd64-host && sudo XZ_OPT="-e9" '
503 'tar --exclude="usr/lib/debug/*" --exclude="packages/*" '
504 '--exclude="tmp/*" --exclude="usr/local/build/autotest/*" '
505 '--sparse -I xz -vcf {1} . && sudo chmod a+r {1}').format(
506 self._chromeos_root, sdk_package)
507 rv = self._ce.RunCommand(cmd, return_output=False, print_to_console=True)
508 if rv:
509 self._logger.LogError('Failed to create "built-sdk.tar.xz".')
510 return False
511
512 # Install amd64-host into a new chroot.
513 cmd = ('cd {0} && cros_sdk --chroot new-sdk-chroot --download --replace '
514 '--nousepkg --url file://{1}').format(
515 self._chromeos_root, sdk_package)
516 rv = self._ce.RunCommand(cmd, return_output=False, print_to_console=True)
517 if rv:
518 self._logger.LogError('Failed to install "built-sdk.tar.xz".')
519 return False
520 self._logger.LogOutput(
521 'Successfully installed built-sdk.tar.xz into a new chroot.\nAll done.')
522
523 # Rename the newly created new-sdk-chroot to chroot.
524 cmd = ('cd {0} && sudo mv chroot chroot-old && '
525 'sudo mv new-sdk-chroot chroot').format(self._chromeos_root)
526 rv = self._ce.RunCommand(cmd, return_output=False, print_to_console=True)
527 return rv == 0
528
Han Shen91445322013-03-20 13:43:31 -0700529 def Do(self):
Han Shen819f8622014-04-08 16:57:38 -0700530 """Entrance of the class.
531
532 Returns:
533 True if everything is ok.
534 """
535
536 if (self.SubmitToLocalBranch() and
537 self.CheckoutBranch() and
538 self.FindEbuildFile() and
539 self.InplaceModifyEbuildFile()):
540 if self._setup_tool_ebuild_file_only:
541 # Everything is done, we are good.
542 ret = True
543 else:
544 if self._board:
545 ret = self.DoBuildForBoard()
546 else:
547 # This implies '--bootstrap'.
Han Shen03d30982014-06-12 11:22:29 -0700548 ret = (self.DoBootstrapping() and
549 (self._disable_2nd_bootstrap or
550 self.BuildAndInstallAmd64Host()))
Han Shen91445322013-03-20 13:43:31 -0700551 else:
552 ret = False
Han Shen91445322013-03-20 13:43:31 -0700553 return ret
554
555
556def Main(argv):
557 parser = optparse.OptionParser()
558 parser.add_option('-c', '--chromeos_root', dest='chromeos_root',
Han Shen819f8622014-04-08 16:57:38 -0700559 help=('Optional. ChromeOs root dir. '
560 'When not specified, chromeos root will be deduced '
561 'from current working directory.'))
562 parser.add_option('--gcc_branch', dest='gcc_branch',
Han Shen91445322013-03-20 13:43:31 -0700563 help=('The branch to test against. '
564 'This branch must be a local branch '
565 'inside "src/third_party/gcc". '
Han Shen819f8622014-04-08 16:57:38 -0700566 'Notice, this must not be used with "--gcc_dir".'))
567 parser.add_option('--binutils_branch', dest='binutils_branch',
568 help=('The branch to test against binutils. '
569 'This branch must be a local branch '
570 'inside "src/third_party/binutils". '
571 'Notice, this must not be used with '
572 '"--binutils_dir".'))
Han Shen91445322013-03-20 13:43:31 -0700573 parser.add_option('-g', '--gcc_dir', dest='gcc_dir',
574 help=('Use a local gcc tree to do bootstrapping. '
Han Shen819f8622014-04-08 16:57:38 -0700575 'Notice, this must not be used with "--gcc_branch".'))
576 parser.add_option('--binutils_dir', dest='binutils_dir',
577 help=('Use a local binutils tree to do bootstrapping. '
578 'Notice, this must not be used with '
579 '"--binutils_branch".'))
Han Shen91445322013-03-20 13:43:31 -0700580 parser.add_option('--fixperm', dest='fixperm',
581 default=False, action='store_true',
582 help=('Fix the (notorious) permission error '
583 'while trying to bootstrap the chroot. '
584 'Note this takes an extra 10-15 minutes '
585 'and is only needed once per chromiumos tree.'))
Han Shen819f8622014-04-08 16:57:38 -0700586 parser.add_option('--setup_tool_ebuild_file_only',
587 dest='setup_tool_ebuild_file_only',
Han Shen91445322013-03-20 13:43:31 -0700588 default=False, action='store_true',
Han Shen819f8622014-04-08 16:57:38 -0700589 help=('Setup gcc and/or binutils ebuild file '
590 'to pick up the branch (--gcc/binutils_branch) or '
591 'use gcc and/or binutils source (--gcc/binutils_dir) '
592 'and exit. Keep chroot as is. This should not be '
593 'used with --gcc/binutils_dir/branch options.'))
594 parser.add_option('--reset_tool_ebuild_file', dest='reset_tool_ebuild_file',
Han Shen91445322013-03-20 13:43:31 -0700595 default=False, action='store_true',
596 help=('Reset the modification that is done by this script.'
597 'Note, when this script is running, it will modify '
Han Shen819f8622014-04-08 16:57:38 -0700598 'the active gcc/binutils ebuild file. Use this '
599 'option to reset (what this script has done) '
600 'and exit. This should not be used with -- '
601 'gcc/binutils_dir/branch options.'))
602 parser.add_option('--board', dest='board', default=None,
Han Shenfe3001c2014-04-28 16:36:28 -0700603 help=('Only build toolchain for specific board(s). '
Han Shen819f8622014-04-08 16:57:38 -0700604 'Use "host" to build for host. '
Han Shenfe3001c2014-04-28 16:36:28 -0700605 'Use "," to seperate multiple boards. '
Han Shen819f8622014-04-08 16:57:38 -0700606 'This does not perform a chroot bootstrap.'))
607 parser.add_option('--bootstrap', dest='bootstrap',
608 default=False, action='store_true',
609 help=('Performs a chroot bootstrap. '
610 'Note, this will *destroy* your current chroot.'))
Han Shen03d30982014-06-12 11:22:29 -0700611 parser.add_option('--disable-2nd-bootstrap', dest='disable_2nd_bootstrap',
612 default=False, action='store_true',
613 help=('Disable a second bootstrap '
614 '(build of amd64-host stage).'))
Han Shen819f8622014-04-08 16:57:38 -0700615
Han Shen91445322013-03-20 13:43:31 -0700616 options = parser.parse_args(argv)[0]
Han Shen819f8622014-04-08 16:57:38 -0700617 # Trying to deduce chromeos root from current directory.
Han Shen91445322013-03-20 13:43:31 -0700618 if not options.chromeos_root:
Han Shen819f8622014-04-08 16:57:38 -0700619 logger.GetLogger().LogOutput('Trying to deduce chromeos root ...')
620 wdir = os.getcwd()
621 while wdir and wdir != '/':
622 if misc.IsChromeOsTree(wdir):
623 logger.GetLogger().LogOutput('Find chromeos_root: {}'.format(wdir))
624 options.chromeos_root = wdir
625 break
626 wdir = os.path.dirname(wdir)
627
628 if not options.chromeos_root:
629 parser.error('Missing or failing to deduce mandatory option "--chromeos".')
Han Shen91445322013-03-20 13:43:31 -0700630 return 1
631
632 options.chromeos_root = os.path.abspath(
Han Shen819f8622014-04-08 16:57:38 -0700633 os.path.expanduser(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700634
635 if not os.path.isdir(options.chromeos_root):
636 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700637 '"{0}" does not exist.'.format(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700638 return 1
639
640 if options.fixperm:
641 # Fix perm error before continuing.
Han Shen819f8622014-04-08 16:57:38 -0700642 cmd = (r'sudo find "{0}" \( -name ".cache" -type d -prune \) -o '
643 r'\( -name "chroot" -type d -prune \) -o '
644 r'\( -type f -exec chmod a+r {{}} \; \) -o '
645 r'\( -type d -exec chmod a+rx {{}} \; \)').format(
646 options.chromeos_root)
Han Shen91445322013-03-20 13:43:31 -0700647 logger.GetLogger().LogOutput(
Han Shen819f8622014-04-08 16:57:38 -0700648 'Fixing perm issues for chromeos root, this might take some time.')
Han Shen91445322013-03-20 13:43:31 -0700649 command_executer.GetCommandExecuter().RunCommand(cmd)
650
Han Shen819f8622014-04-08 16:57:38 -0700651 if options.reset_tool_ebuild_file:
652 if (options.gcc_dir or options.gcc_branch or
653 options.binutils_dir or options.binutils_branch):
Han Shen91445322013-03-20 13:43:31 -0700654 logger.GetLogger().LogWarning(
Han Shen819f8622014-04-08 16:57:38 -0700655 'Ignoring any "--gcc/binutils_dir" and/or "--gcc/binutils_branch".')
656 if options.setup_tool_ebuild_file_only:
657 logger.GetLogger().LogError(
658 ('Conflict options "--reset_tool_ebuild_file" '
659 'and "--setup_tool_ebuild_file_only".'))
Han Shen91445322013-03-20 13:43:31 -0700660 return 1
Han Shen819f8622014-04-08 16:57:38 -0700661 rv = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'gcc')
662 rv1 = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'binutils')
663 return 0 if (rv and rv1) else 1
Han Shen91445322013-03-20 13:43:31 -0700664
665 if options.gcc_dir:
666 options.gcc_dir = os.path.abspath(os.path.expanduser(options.gcc_dir))
667 if not os.path.isdir(options.gcc_dir):
668 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700669 '"{0}" does not exist.'.format(options.gcc_dir))
Han Shen91445322013-03-20 13:43:31 -0700670 return 1
671
Han Shen819f8622014-04-08 16:57:38 -0700672 if options.gcc_branch and options.gcc_dir:
673 parser.error('Only one of "--gcc_dir" and "--gcc_branch" can be specified.')
Han Shen91445322013-03-20 13:43:31 -0700674 return 1
Han Shen819f8622014-04-08 16:57:38 -0700675
676 if options.binutils_dir:
677 options.binutils_dir = os.path.abspath(
678 os.path.expanduser(options.binutils_dir))
679 if not os.path.isdir(options.binutils_dir):
680 logger.GetLogger().LogError(
681 '"{0}" does not exist.'.format(options.binutils_dir))
682 return 1
683
684 if options.binutils_branch and options.binutils_dir:
685 parser.error('Only one of "--binutils_dir" and '
686 '"--binutils_branch" can be specified.')
687 return 1
688
689 if (not (options.binutils_branch or options.binutils_dir or
690 options.gcc_branch or options.gcc_dir)):
691 parser.error(('At least one of "--gcc_dir", "--gcc_branch", '
692 '"--binutils_dir" and "--binutils_branch" must '
693 'be specified.'))
694 return 1
695
696 if not options.board and not options.bootstrap:
697 parser.error('You must specify either "--board" or "--bootstrap".')
698 return 1
699
Han Shen03d30982014-06-12 11:22:29 -0700700 if (options.board and options.bootstrap and
701 not options.setup_tool_ebuild_file_only):
Han Shen819f8622014-04-08 16:57:38 -0700702 parser.error('You must specify only one of "--board" and "--bootstrap".')
Han Shen91445322013-03-20 13:43:31 -0700703 return 1
704
Han Shen03d30982014-06-12 11:22:29 -0700705 if not options.bootstrap and options.disable_2nd_bootstrap:
706 parser.error('"--disable-2nd-bootstrap" has no effect '
707 'without specifying "--bootstrap".')
708 return 1
709
Han Shen91445322013-03-20 13:43:31 -0700710 if Bootstrapper(
Han Shen819f8622014-04-08 16:57:38 -0700711 options.chromeos_root,
712 gcc_branch=options.gcc_branch, gcc_dir=options.gcc_dir,
713 binutils_branch=options.binutils_branch,
714 binutils_dir=options.binutils_dir,
715 board=options.board,
Han Shen03d30982014-06-12 11:22:29 -0700716 disable_2nd_bootstrap=options.disable_2nd_bootstrap,
Han Shen819f8622014-04-08 16:57:38 -0700717 setup_tool_ebuild_file_only=options.setup_tool_ebuild_file_only).Do():
Han Shen91445322013-03-20 13:43:31 -0700718 return 0
719 return 1
720
721
722if __name__ == '__main__':
723 retval = Main(sys.argv)
724 sys.exit(retval)