blob: e81b77c419b137d50243027aaa783f82207306b6 [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,
51 board=None, setup_tool_ebuild_file_only=False):
Han Shen91445322013-03-20 13:43:31 -070052 self._chromeos_root = chromeos_root
Han Shen819f8622014-04-08 16:57:38 -070053
54 self._gcc_branch = gcc_branch
55 self._gcc_branch_tree = None
Han Shen91445322013-03-20 13:43:31 -070056 self._gcc_dir = gcc_dir
Han Shen91445322013-03-20 13:43:31 -070057 self._gcc_ebuild_file = None
58 self._gcc_ebuild_file_name = None
Han Shen819f8622014-04-08 16:57:38 -070059
60 self._binutils_branch = binutils_branch
61 self._binutils_branch_tree = None
62 self._binutils_dir = binutils_dir
63 self._binutils_ebuild_file = None
64 self._binutils_ebuild_file_name = None
65
66 self._setup_tool_ebuild_file_only = setup_tool_ebuild_file_only
67
68 self._ce = command_executer.GetCommandExecuter()
69 self._logger = logger.GetLogger()
70 self._board = board
71
72 def IsTreeSame(self, t1, t2):
73 diff = 'diff -qr -x .git -x .svn "{0}" "{1}"'.format(t1, t2)
74 if self._ce.RunCommand(diff, print_to_console=False) == 0:
75 self._logger.LogOutput('"{0}" and "{1}" are the same."'.format(t1, t2))
76 return True
77 self._logger.LogWarning('"{0}" and "{1}" are different."'.format(t1, t2))
78 return False
Han Shen91445322013-03-20 13:43:31 -070079
80 def SubmitToLocalBranch(self):
Han Shen819f8622014-04-08 16:57:38 -070081 """Copy source code to the chromium source tree and submit it locally."""
82 if self._gcc_dir:
83 if not self.SubmitToolToLocalBranch(
84 tool_name='gcc', tool_dir=self._gcc_dir):
85 return False
86 self._gcc_branch = TEMP_BRANCH_NAME
Han Shen91445322013-03-20 13:43:31 -070087
Han Shen819f8622014-04-08 16:57:38 -070088 if self._binutils_dir:
89 if not self.SubmitToolToLocalBranch(
90 tool_name='binutils', tool_dir=self._binutils_dir):
91 return False
92 self._binutils_branch = TEMP_BRANCH_NAME
93
94 return True
95
96 def SubmitToolToLocalBranch(self, tool_name, tool_dir):
97 """Copy the source code to local chromium source tree.
98
99 Args:
100 tool_name: either 'gcc' or 'binutils'
101 tool_dir: the tool source dir to be used
102 Returns:
103 True if all succeeded False otherwise.
104 """
105
106 # The next few steps creates an internal branch to sync with the tool dir
Han Shen91445322013-03-20 13:43:31 -0700107 # user provided.
Han Shen819f8622014-04-08 16:57:38 -0700108 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
Han Shen91445322013-03-20 13:43:31 -0700109
110 # 0. Test to see if git tree is free of local changes.
Han Shen819f8622014-04-08 16:57:38 -0700111 if not misc.IsGitTreeClean(chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700112 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700113 'Git repository "{0}" not clean, aborted.'.format(chrome_tool_dir))
Han Shen91445322013-03-20 13:43:31 -0700114 return False
115
116 # 1. Checkout/create a (new) branch for testing.
Han Shen819f8622014-04-08 16:57:38 -0700117 command = 'cd "{0}" && git checkout -B {1}'.format(
118 chrome_tool_dir, TEMP_BRANCH_NAME)
Han Shen91445322013-03-20 13:43:31 -0700119 ret = self._ce.RunCommand(command)
120 if ret:
121 self._logger.LogError('Failed to create a temp branch for test, aborted.')
122 return False
123
Han Shen819f8622014-04-08 16:57:38 -0700124 if self.IsTreeSame(tool_dir, chrome_tool_dir):
125 self._logger.LogOutput(
126 '"{0}" and "{1}" are the same, sync skipped.'.format(
127 tool_dir, chrome_tool_dir))
128 return True
Han Shen91445322013-03-20 13:43:31 -0700129
Han Shen819f8622014-04-08 16:57:38 -0700130 # 2. Sync sources from user provided tool dir to chromiumos tool git.
131 local_tool_repo = repo_to_repo.FileRepo(tool_dir)
132 chrome_tool_repo = repo_to_repo.GitRepo(chrome_tool_dir, TEMP_BRANCH_NAME)
133 chrome_tool_repo._root_dir = chrome_tool_dir
134 # Delete all stuff before start mapping.
135 self._ce.RunCommand('cd {0} && rm -rf *'.format(chrome_tool_dir))
136 local_tool_repo.MapSources(chrome_tool_repo.GetRoot())
137
138 # 3. Ensure after sync tree is the same.
139 if self.IsTreeSame(tool_dir, chrome_tool_dir):
Han Shen91445322013-03-20 13:43:31 -0700140 self._logger.LogOutput('Sync successfully done.')
Han Shen819f8622014-04-08 16:57:38 -0700141 else:
142 self._logger.LogError('Sync not successful, aborted.')
143 return False
Han Shen91445322013-03-20 13:43:31 -0700144
145 # 4. Commit all changes.
Han Shen819f8622014-04-08 16:57:38 -0700146 ret = chrome_tool_repo.CommitLocally(
147 'Synced with tool source tree at - "{0}".'.format(tool_dir))
Han Shen91445322013-03-20 13:43:31 -0700148 if ret:
149 self._logger.LogError('Commit to local branch "{0}" failed, aborted.'.
Han Shen819f8622014-04-08 16:57:38 -0700150 format(TEMP_BRANCH_NAME))
Han Shen91445322013-03-20 13:43:31 -0700151 return False
152 return True
153
154 def CheckoutBranch(self):
Han Shen819f8622014-04-08 16:57:38 -0700155 """Checkout working branch for the tools.
Han Shen91445322013-03-20 13:43:31 -0700156
Han Shen819f8622014-04-08 16:57:38 -0700157 Returns:
158 True: if operation succeeds.
159 """
Han Shen91445322013-03-20 13:43:31 -0700160
Han Shen819f8622014-04-08 16:57:38 -0700161 if self._gcc_branch:
162 rv = self.CheckoutToolBranch('gcc', self._gcc_branch)
163 if rv:
164 self._gcc_branch_tree = rv
165 else:
166 return False
167
168 if self._binutils_branch:
169 rv = self.CheckoutToolBranch('binutils', self._binutils_branch)
170 if rv:
171 self._binutils_branch_tree = rv
172 else:
173 return False
174
Han Shen91445322013-03-20 13:43:31 -0700175 return True
176
Han Shen819f8622014-04-08 16:57:38 -0700177 def CheckoutToolBranch(self, tool_name, tool_branch):
178 """Checkout the tool branch for a certain tool.
179
180 Args:
181 tool_name: either 'gcc' or 'binutils'
182 tool_branch: tool branch to use
183 Returns:
184 True: if operation succeeds. Otherwise False.
Han Shen91445322013-03-20 13:43:31 -0700185 """
Han Shen819f8622014-04-08 16:57:38 -0700186
187 chrome_tool_dir = self.GetChromeOsToolDir(tool_name)
188 command = 'cd "{0}" && git checkout {1}'.format(
189 chrome_tool_dir, tool_branch)
190 if not self._ce.RunCommand(command, print_to_console=True):
191 # Get 'TREE' value of this commit
192 command = ('cd "{0}" && git cat-file -p {1} '
193 '| grep -E "^tree [a-f0-9]+$" '
194 '| cut -d" " -f2').format(chrome_tool_dir, tool_branch)
195 ret, stdout, _ = self._ce.RunCommand(
196 command, return_output=True, print_to_console=False)
197 # Pipe operation always has a zero return value. So need to check if
198 # stdout is valid.
199 if not ret and stdout and re.match(
200 '[0-9a-h]{40}', stdout.strip(), re.IGNORECASE):
201 tool_branch_tree = stdout.strip()
202 self._logger.LogOutput('Find tree for {0} branch "{1}" - "{2}"'.format(
203 tool_name, tool_branch, tool_branch_tree))
204 return tool_branch_tree
205 self._logger.LogError(('Failed to checkout "{0}" or failed to '
206 'get tree value, aborted.').format(tool_branch))
207 return None
208
209 def FindEbuildFile(self):
210 """Find the ebuild files for the tools.
211
212 Returns:
213 True: if operation succeeds.
214 """
215
216 if self._gcc_branch:
217 (rv, ef, efn) = self.FindToolEbuildFile('gcc')
218 if rv:
219 self._gcc_ebuild_file = ef
220 self._gcc_ebuild_file_name = efn
221 else:
222 return False
223
224 if self._binutils_branch:
225 (rv, ef, efn) = self.FindToolEbuildFile('binutils')
226 if rv:
227 self._binutils_ebuild_file = ef
228 self._binutils_ebuild_file_name = efn
229 else:
230 return False
231
232 return True
233
234 def FindToolEbuildFile(self, tool_name):
235 """Find ebuild file for a specific tool.
236
237 Args:
238 tool_name: either "gcc" or "binutils".
239 Returns:
240 A triplet that consisits of whether operation succeeds or not,
241 tool ebuild file full path and tool ebuild file name.
242 """
243
244 # To get the active gcc ebuild file, we need a workable chroot first.
245 if not os.path.exists(
246 os.path.join(self._chromeos_root, 'chroot')) and self._ce.RunCommand(
247 'cd "{0}" && cros_sdk --create'.format(self._chromeos_root)):
248 self._logger.LogError(('Failed to install a initial chroot, aborted.\n'
249 'If previous bootstrap failed, do a '
250 '"cros_sdk --delete" to remove '
251 'in-complete chroot.'))
252 return (False, None, None)
253
254 rv, stdout, _ = self._ce.ChrootRunCommand(
255 self._chromeos_root, 'equery w sys-devel/{0}'.format(tool_name),
256 return_output=True, print_to_console=True)
257 if rv:
258 self._logger.LogError(
259 ('Failed to execute inside chroot '
260 '"equery w sys-devel/{0}", aborted.').format(tool_name))
261 return (False, None, None)
262 m = re.match(r'^.*/({0}/(.*\.ebuild))$'.format(
263 EBUILD_PATH_PATTERN.format(tool_name)), stdout)
264 if not m:
265 self._logger.LogError(
266 ('Failed to find {0} ebuild file, aborted. '
267 'If previous bootstrap failed, do a "cros_sdk --delete" to remove '
268 'in-complete chroot.').format(tool_name))
269 return (False, None, None)
270 tool_ebuild_file = os.path.join(self._chromeos_root, m.group(1))
271 tool_ebuild_file_name = m.group(2)
272
273 return (True, tool_ebuild_file, tool_ebuild_file_name)
274
275 def InplaceModifyEbuildFile(self):
276 """Modify the ebuild file.
277
278 Returns:
279 True if operation succeeds.
280 """
281
282 # Note we shall not use remote branch name (eg. "cros/gcc.gnu.org/...") in
283 # CROS_WORKON_COMMIT, we have to use GITHASH. So we call GitGetCommitHash on
284 # tool_branch.
285 if self._gcc_branch:
286 tool_branch_githash = misc.GitGetCommitHash(
287 self.GetChromeOsToolDir('gcc'), self._gcc_branch)
288 if not tool_branch_githash:
289 return False
290 if not self.InplaceModifyToolEbuildFile(
291 tool_branch_githash, self._gcc_branch_tree, self._gcc_ebuild_file):
292 return False
293
294 if self._binutils_branch:
295 tool_branch_githash = misc.GitGetCommitHash(
296 self.GetChromeOsToolDir('binutils'), self._binutils_branch)
297 if not self.InplaceModifyToolEbuildFile(
298 tool_branch_githash, self._binutils_branch_tree,
299 self._binutils_ebuild_file):
300 return False
301 return True
302
303 @staticmethod
304 def ResetToolEbuildFile(chromeos_root, tool_name):
305 """Reset tool ebuild file to clean state.
306
307 Args:
308 chromeos_root: chromeos source tree
309 tool_name: either "gcc" or "binutils"
310 Returns:
311 True if operation succeds.
312 """
313 rv = misc.GetGitChangesAsList(
314 os.path.join(chromeos_root, CHROMIUMOS_OVERLAY_PATH),
315 path=('sys-devel/{0}/{0}-*.ebuild'.format(tool_name)),
316 staged=False)
317 if rv:
318 cmd = 'cd {0} && git checkout --'.format(os.path.join(
319 chromeos_root, CHROMIUMOS_OVERLAY_PATH))
320 for g in rv:
321 cmd += ' ' + g
322 rv = command_executer.GetCommandExecuter().RunCommand(cmd)
323 if rv:
324 logger.GetLogger().LogWarning(
325 'Failed to reset the ebuild file. Please refer to log above.')
326 return False
327 else:
328 logger.GetLogger().LogWarning(
329 'Note - did not find any modified {0} ebuild file.'.format(tool_name))
330 # Fall through
331 return True
332
333 def GetChromeOsToolDir(self, tool_name):
334 """Return the chromeos git dir for a specific tool.
335
336 Args:
337 tool_name: either 'gcc' or 'binutils'.
338 Returns:
339 Absolute git path for the tool.
340 """
341
342 return os.path.join(
343 self._chromeos_root, REPO_PATH_PATTERN.format(tool_name))
344
345 def InplaceModifyToolEbuildFile(
346 self, tool_branch_githash, tool_branch_tree, tool_ebuild_file):
347 """Using sed to fill properly values into the ebuild file.
348
349 Args:
350 tool_branch_githash: githash for tool_branch
351 tool_branch_tree: treeish for the tool branch
352 tool_ebuild_file: tool ebuild file
353 Returns:
354 True: if operation succeeded.
355 """
356
357 command = ('sed -i '
358 '-e \'/^CROS_WORKON_COMMIT=".*"/i'
359 ' # The following line is modified by script.\' '
360 '-e \'s!^CROS_WORKON_COMMIT=".*"$!CROS_WORKON_COMMIT="{0}"!\' '
361 '-e \'/^CROS_WORKON_TREE=".*"/i'
362 ' # The following line is modified by script.\' '
363 '-e \'s!^CROS_WORKON_TREE=".*"$!CROS_WORKON_TREE="{1}"!\' '
364 '{2}').format(tool_branch_githash,
365 tool_branch_tree,
366 tool_ebuild_file)
Han Shen91445322013-03-20 13:43:31 -0700367 rv = self._ce.RunCommand(command)
368 if rv:
369 self._logger.LogError(
Han Shen819f8622014-04-08 16:57:38 -0700370 'Failed to modify commit and tree value for "{0}"", aborted.'.format(
371 tool_ebuild_file))
372 return False
373
374 # Warn that the ebuild file has been modified.
375 self._logger.LogWarning(
376 ('Ebuild file "{0}" is modified, to revert the file - \n'
377 'bootstrap_compiler.py --chromeos_root={1} '
378 '--reset_tool_ebuild_file').format(
379 tool_ebuild_file, self._chromeos_root))
380 return True
381
382 def DoBuildForBoard(self):
383 """Build tool for a specific board.
384
385 Returns:
386 True if operation succeeds.
387 """
388
389 if self._gcc_branch:
390 if not self.DoBuildToolForBoard('gcc'):
391 return False
392 if self._binutils_branch:
393 if not self.DoBuildToolForBoard('binutils'):
394 return False
395 return True
396
397 def DoBuildToolForBoard(self, tool_name):
398 """Build a specific tool for a specific board.
399
400 Args:
401 tool_name: either "gcc" or "binutils"
402 Returns:
403 True if operation succeeds.
404 """
405
Han Shenfe3001c2014-04-28 16:36:28 -0700406 boards_to_build = self._board.split(',')
Han Shen819f8622014-04-08 16:57:38 -0700407
Han Shenfe3001c2014-04-28 16:36:28 -0700408 failed = []
409 for board in boards_to_build:
410 if board == 'host':
411 command = 'sudo emerge sys-devel/{0}'.format(tool_name)
412 else:
413 target = misc.GetCtargetFromBoard(board, self._chromeos_root)
414 if not target:
415 self._logger.LogError(
416 'Unsupported board "{0}", skip.'.format(board))
417 failed.append(board)
418 continue
419 command = 'sudo emerge cross-{0}/{1}'.format(target, tool_name)
420
421 rv = self._ce.ChrootRunCommand(self._chromeos_root, command,
422 return_output=False, print_to_console=True)
423 if rv:
424 self._logger.LogError(
425 'Build "{0}" failed for "{1}", aborted.'.format(tool_name, board))
426 failed.append(board)
427 else:
428 self._logger.LogOutput(
429 'Successfully built "{0}" for board "{1}".'.format(tool_name, board))
430
431 if not failed:
Han Shen819f8622014-04-08 16:57:38 -0700432 self._logger.LogError(
Han Shenfe3001c2014-04-28 16:36:28 -0700433 'Failed to build {0} for the following board(s): "{1}"'.format(
434 tool_name, ' '.join(failed)))
Han Shen91445322013-03-20 13:43:31 -0700435 return False
Han Shenfe3001c2014-04-28 16:36:28 -0700436 # All boards build successfully
Han Shen91445322013-03-20 13:43:31 -0700437 return True
438
439 def DoBootstrapping(self):
Han Shen819f8622014-04-08 16:57:38 -0700440 """Do bootstrapping the chroot.
441
442 Returns:
443 True if operation succeeds.
444 """
445
Han Shen91445322013-03-20 13:43:31 -0700446 logfile = os.path.join(self._chromeos_root, 'bootstrap.log')
Han Shen819f8622014-04-08 16:57:38 -0700447 command = 'cd "{0}" && cros_sdk --delete --bootstrap |& tee "{1}"'.format(
448 self._chromeos_root, logfile)
449 rv = self._ce.RunCommand(command, return_output=False,
450 print_to_console=True)
Han Shen91445322013-03-20 13:43:31 -0700451 if rv:
452 self._logger.LogError('Bootstrapping failed, log file - "{0}"\n'.format(
453 logfile))
454 return False
455
Han Shen819f8622014-04-08 16:57:38 -0700456 ## Workaround for - crbug/331713.
457 ## We do not test for success, failure is not important at this step.
458 self._ce.ChrootRunCommand(
459 self._chromeos_root, 'sudo emerge dev-util/pkgconfig',
460 return_output=False, print_to_console=True)
461
Han Shen91445322013-03-20 13:43:31 -0700462 self._logger.LogOutput('Bootstrap succeeded.')
463 return True
464
465 def Do(self):
Han Shen819f8622014-04-08 16:57:38 -0700466 """Entrance of the class.
467
468 Returns:
469 True if everything is ok.
470 """
471
472 if (self.SubmitToLocalBranch() and
473 self.CheckoutBranch() and
474 self.FindEbuildFile() and
475 self.InplaceModifyEbuildFile()):
476 if self._setup_tool_ebuild_file_only:
477 # Everything is done, we are good.
478 ret = True
479 else:
480 if self._board:
481 ret = self.DoBuildForBoard()
482 else:
483 # This implies '--bootstrap'.
484 ret = self.DoBootstrapping()
Han Shen91445322013-03-20 13:43:31 -0700485 else:
486 ret = False
Han Shen91445322013-03-20 13:43:31 -0700487 return ret
488
489
490def Main(argv):
491 parser = optparse.OptionParser()
492 parser.add_option('-c', '--chromeos_root', dest='chromeos_root',
Han Shen819f8622014-04-08 16:57:38 -0700493 help=('Optional. ChromeOs root dir. '
494 'When not specified, chromeos root will be deduced '
495 'from current working directory.'))
496 parser.add_option('--gcc_branch', dest='gcc_branch',
Han Shen91445322013-03-20 13:43:31 -0700497 help=('The branch to test against. '
498 'This branch must be a local branch '
499 'inside "src/third_party/gcc". '
Han Shen819f8622014-04-08 16:57:38 -0700500 'Notice, this must not be used with "--gcc_dir".'))
501 parser.add_option('--binutils_branch', dest='binutils_branch',
502 help=('The branch to test against binutils. '
503 'This branch must be a local branch '
504 'inside "src/third_party/binutils". '
505 'Notice, this must not be used with '
506 '"--binutils_dir".'))
Han Shen91445322013-03-20 13:43:31 -0700507 parser.add_option('-g', '--gcc_dir', dest='gcc_dir',
508 help=('Use a local gcc tree to do bootstrapping. '
Han Shen819f8622014-04-08 16:57:38 -0700509 'Notice, this must not be used with "--gcc_branch".'))
510 parser.add_option('--binutils_dir', dest='binutils_dir',
511 help=('Use a local binutils tree to do bootstrapping. '
512 'Notice, this must not be used with '
513 '"--binutils_branch".'))
Han Shen91445322013-03-20 13:43:31 -0700514 parser.add_option('--fixperm', dest='fixperm',
515 default=False, action='store_true',
516 help=('Fix the (notorious) permission error '
517 'while trying to bootstrap the chroot. '
518 'Note this takes an extra 10-15 minutes '
519 'and is only needed once per chromiumos tree.'))
Han Shen819f8622014-04-08 16:57:38 -0700520 parser.add_option('--setup_tool_ebuild_file_only',
521 dest='setup_tool_ebuild_file_only',
Han Shen91445322013-03-20 13:43:31 -0700522 default=False, action='store_true',
Han Shen819f8622014-04-08 16:57:38 -0700523 help=('Setup gcc and/or binutils ebuild file '
524 'to pick up the branch (--gcc/binutils_branch) or '
525 'use gcc and/or binutils source (--gcc/binutils_dir) '
526 'and exit. Keep chroot as is. This should not be '
527 'used with --gcc/binutils_dir/branch options.'))
528 parser.add_option('--reset_tool_ebuild_file', dest='reset_tool_ebuild_file',
Han Shen91445322013-03-20 13:43:31 -0700529 default=False, action='store_true',
530 help=('Reset the modification that is done by this script.'
531 'Note, when this script is running, it will modify '
Han Shen819f8622014-04-08 16:57:38 -0700532 'the active gcc/binutils ebuild file. Use this '
533 'option to reset (what this script has done) '
534 'and exit. This should not be used with -- '
535 'gcc/binutils_dir/branch options.'))
536 parser.add_option('--board', dest='board', default=None,
Han Shenfe3001c2014-04-28 16:36:28 -0700537 help=('Only build toolchain for specific board(s). '
Han Shen819f8622014-04-08 16:57:38 -0700538 'Use "host" to build for host. '
Han Shenfe3001c2014-04-28 16:36:28 -0700539 'Use "," to seperate multiple boards. '
Han Shen819f8622014-04-08 16:57:38 -0700540 'This does not perform a chroot bootstrap.'))
541 parser.add_option('--bootstrap', dest='bootstrap',
542 default=False, action='store_true',
543 help=('Performs a chroot bootstrap. '
544 'Note, this will *destroy* your current chroot.'))
545
Han Shen91445322013-03-20 13:43:31 -0700546 options = parser.parse_args(argv)[0]
Han Shen819f8622014-04-08 16:57:38 -0700547 # Trying to deduce chromeos root from current directory.
Han Shen91445322013-03-20 13:43:31 -0700548 if not options.chromeos_root:
Han Shen819f8622014-04-08 16:57:38 -0700549 logger.GetLogger().LogOutput('Trying to deduce chromeos root ...')
550 wdir = os.getcwd()
551 while wdir and wdir != '/':
552 if misc.IsChromeOsTree(wdir):
553 logger.GetLogger().LogOutput('Find chromeos_root: {}'.format(wdir))
554 options.chromeos_root = wdir
555 break
556 wdir = os.path.dirname(wdir)
557
558 if not options.chromeos_root:
559 parser.error('Missing or failing to deduce mandatory option "--chromeos".')
Han Shen91445322013-03-20 13:43:31 -0700560 return 1
561
562 options.chromeos_root = os.path.abspath(
Han Shen819f8622014-04-08 16:57:38 -0700563 os.path.expanduser(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700564
565 if not os.path.isdir(options.chromeos_root):
566 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700567 '"{0}" does not exist.'.format(options.chromeos_root))
Han Shen91445322013-03-20 13:43:31 -0700568 return 1
569
570 if options.fixperm:
571 # Fix perm error before continuing.
Han Shen819f8622014-04-08 16:57:38 -0700572 cmd = (r'sudo find "{0}" \( -name ".cache" -type d -prune \) -o '
573 r'\( -name "chroot" -type d -prune \) -o '
574 r'\( -type f -exec chmod a+r {{}} \; \) -o '
575 r'\( -type d -exec chmod a+rx {{}} \; \)').format(
576 options.chromeos_root)
Han Shen91445322013-03-20 13:43:31 -0700577 logger.GetLogger().LogOutput(
Han Shen819f8622014-04-08 16:57:38 -0700578 'Fixing perm issues for chromeos root, this might take some time.')
Han Shen91445322013-03-20 13:43:31 -0700579 command_executer.GetCommandExecuter().RunCommand(cmd)
580
Han Shen819f8622014-04-08 16:57:38 -0700581 if options.reset_tool_ebuild_file:
582 if (options.gcc_dir or options.gcc_branch or
583 options.binutils_dir or options.binutils_branch):
Han Shen91445322013-03-20 13:43:31 -0700584 logger.GetLogger().LogWarning(
Han Shen819f8622014-04-08 16:57:38 -0700585 'Ignoring any "--gcc/binutils_dir" and/or "--gcc/binutils_branch".')
586 if options.setup_tool_ebuild_file_only:
587 logger.GetLogger().LogError(
588 ('Conflict options "--reset_tool_ebuild_file" '
589 'and "--setup_tool_ebuild_file_only".'))
Han Shen91445322013-03-20 13:43:31 -0700590 return 1
Han Shen819f8622014-04-08 16:57:38 -0700591 rv = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'gcc')
592 rv1 = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'binutils')
593 return 0 if (rv and rv1) else 1
Han Shen91445322013-03-20 13:43:31 -0700594
595 if options.gcc_dir:
596 options.gcc_dir = os.path.abspath(os.path.expanduser(options.gcc_dir))
597 if not os.path.isdir(options.gcc_dir):
598 logger.GetLogger().LogError(
Han Shen819f8622014-04-08 16:57:38 -0700599 '"{0}" does not exist.'.format(options.gcc_dir))
Han Shen91445322013-03-20 13:43:31 -0700600 return 1
601
Han Shen819f8622014-04-08 16:57:38 -0700602 if options.gcc_branch and options.gcc_dir:
603 parser.error('Only one of "--gcc_dir" and "--gcc_branch" can be specified.')
Han Shen91445322013-03-20 13:43:31 -0700604 return 1
Han Shen819f8622014-04-08 16:57:38 -0700605
606 if options.binutils_dir:
607 options.binutils_dir = os.path.abspath(
608 os.path.expanduser(options.binutils_dir))
609 if not os.path.isdir(options.binutils_dir):
610 logger.GetLogger().LogError(
611 '"{0}" does not exist.'.format(options.binutils_dir))
612 return 1
613
614 if options.binutils_branch and options.binutils_dir:
615 parser.error('Only one of "--binutils_dir" and '
616 '"--binutils_branch" can be specified.')
617 return 1
618
619 if (not (options.binutils_branch or options.binutils_dir or
620 options.gcc_branch or options.gcc_dir)):
621 parser.error(('At least one of "--gcc_dir", "--gcc_branch", '
622 '"--binutils_dir" and "--binutils_branch" must '
623 'be specified.'))
624 return 1
625
626 if not options.board and not options.bootstrap:
627 parser.error('You must specify either "--board" or "--bootstrap".')
628 return 1
629
630 if options.board and options.bootstrap:
631 parser.error('You must specify only one of "--board" and "--bootstrap".')
Han Shen91445322013-03-20 13:43:31 -0700632 return 1
633
634 if Bootstrapper(
Han Shen819f8622014-04-08 16:57:38 -0700635 options.chromeos_root,
636 gcc_branch=options.gcc_branch, gcc_dir=options.gcc_dir,
637 binutils_branch=options.binutils_branch,
638 binutils_dir=options.binutils_dir,
639 board=options.board,
640 setup_tool_ebuild_file_only=options.setup_tool_ebuild_file_only).Do():
Han Shen91445322013-03-20 13:43:31 -0700641 return 0
642 return 1
643
644
645if __name__ == '__main__':
646 retval = Main(sys.argv)
647 sys.exit(retval)