build_tool.py revision f2a3ef46f75d2196a93d3ed27f4d1fcf22b54fbe
1#!/usr/bin/python 2"""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""" 26 27__author__ = 'shenhan@google.com (Han Shen)' 28 29import optparse 30import os 31import re 32import sys 33 34import repo_to_repo 35from utils import command_executer 36from utils import logger 37from utils import misc 38 39REPO_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 44 45class Bootstrapper(object): 46 """Class that handles bootstrap process. 47 """ 48 49 def __init__(self, 50 chromeos_root, 51 gcc_branch=None, 52 gcc_dir=None, 53 binutils_branch=None, 54 binutils_dir=None, 55 board=None, 56 disable_2nd_bootstrap=False, 57 setup_tool_ebuild_file_only=False): 58 self._chromeos_root = chromeos_root 59 60 self._gcc_branch = gcc_branch 61 self._gcc_branch_tree = None 62 self._gcc_dir = gcc_dir 63 self._gcc_ebuild_file = None 64 self._gcc_ebuild_file_name = None 65 66 self._binutils_branch = binutils_branch 67 self._binutils_branch_tree = None 68 self._binutils_dir = binutils_dir 69 self._binutils_ebuild_file = None 70 self._binutils_ebuild_file_name = None 71 72 self._setup_tool_ebuild_file_only = setup_tool_ebuild_file_only 73 74 self._ce = command_executer.GetCommandExecuter() 75 self._logger = logger.GetLogger() 76 self._board = board 77 self._disable_2nd_bootstrap = disable_2nd_bootstrap 78 79 def IsTreeSame(self, t1, t2): 80 diff = 'diff -qr -x .git -x .svn "{0}" "{1}"'.format(t1, t2) 81 if self._ce.RunCommand(diff, print_to_console=False) == 0: 82 self._logger.LogOutput('"{0}" and "{1}" are the same."'.format(t1, t2)) 83 return True 84 self._logger.LogWarning('"{0}" and "{1}" are different."'.format(t1, t2)) 85 return False 86 87 def SubmitToLocalBranch(self): 88 """Copy source code to the chromium source tree and submit it locally.""" 89 if self._gcc_dir: 90 if not self.SubmitToolToLocalBranch(tool_name='gcc', 91 tool_dir=self._gcc_dir): 92 return False 93 self._gcc_branch = TEMP_BRANCH_NAME 94 95 if self._binutils_dir: 96 if not self.SubmitToolToLocalBranch(tool_name='binutils', 97 tool_dir=self._binutils_dir): 98 return False 99 self._binutils_branch = TEMP_BRANCH_NAME 100 101 return True 102 103 def SubmitToolToLocalBranch(self, tool_name, tool_dir): 104 """Copy the source code to local chromium source tree. 105 106 Args: 107 tool_name: either 'gcc' or 'binutils' 108 tool_dir: the tool source dir to be used 109 Returns: 110 True if all succeeded False otherwise. 111 """ 112 113 # The next few steps creates an internal branch to sync with the tool dir 114 # user provided. 115 chrome_tool_dir = self.GetChromeOsToolDir(tool_name) 116 117 # 0. Test to see if git tree is free of local changes. 118 if not misc.IsGitTreeClean(chrome_tool_dir): 119 self._logger.LogError('Git repository "{0}" not clean, aborted.'.format( 120 chrome_tool_dir)) 121 return False 122 123 # 1. Checkout/create a (new) branch for testing. 124 command = 'cd "{0}" && git checkout -B {1}'.format(chrome_tool_dir, 125 TEMP_BRANCH_NAME) 126 ret = self._ce.RunCommand(command) 127 if ret: 128 self._logger.LogError('Failed to create a temp branch for test, aborted.') 129 return False 130 131 if self.IsTreeSame(tool_dir, chrome_tool_dir): 132 self._logger.LogOutput( 133 '"{0}" and "{1}" are the same, sync skipped.'.format(tool_dir, 134 chrome_tool_dir)) 135 return True 136 137 # 2. Sync sources from user provided tool dir to chromiumos tool git. 138 local_tool_repo = repo_to_repo.FileRepo(tool_dir) 139 chrome_tool_repo = repo_to_repo.GitRepo(chrome_tool_dir, TEMP_BRANCH_NAME) 140 chrome_tool_repo._root_dir = chrome_tool_dir 141 # Delete all stuff except '.git' before start mapping. 142 self._ce.RunCommand( 143 'cd {0} && find . -maxdepth 1 -not -name ".git" -not -name "." ' 144 r'\( -type f -exec rm {{}} \; -o ' 145 r' -type d -exec rm -fr {{}} \; \)'.format(chrome_tool_dir)) 146 local_tool_repo.MapSources(chrome_tool_repo.GetRoot()) 147 148 # 3. Ensure after sync tree is the same. 149 if self.IsTreeSame(tool_dir, chrome_tool_dir): 150 self._logger.LogOutput('Sync successfully done.') 151 else: 152 self._logger.LogError('Sync not successful, aborted.') 153 return False 154 155 # 4. Commit all changes. 156 # 4.1 Try to get some information about the tool dir we are using. 157 cmd = 'cd {0} && git log -1 --pretty=oneline'.format(tool_dir) 158 tool_dir_extra_info = None 159 ret, tool_dir_extra_info, _ = self._ce.RunCommandWOutput( 160 cmd, 161 print_to_console=False) 162 commit_message = 'Synced with tool source tree at - "{0}".'.format(tool_dir) 163 if not ret: 164 commit_message += '\nGit log for {0}:\n{1}'.format(tool_dir, 165 tool_dir_extra_info) 166 167 if chrome_tool_repo.CommitLocally(commit_message): 168 self._logger.LogError( 169 'Commit to local branch "{0}" failed, aborted.'.format( 170 TEMP_BRANCH_NAME)) 171 return False 172 return True 173 174 def CheckoutBranch(self): 175 """Checkout working branch for the tools. 176 177 Returns: 178 True: if operation succeeds. 179 """ 180 181 if self._gcc_branch: 182 rv = self.CheckoutToolBranch('gcc', self._gcc_branch) 183 if rv: 184 self._gcc_branch_tree = rv 185 else: 186 return False 187 188 if self._binutils_branch: 189 rv = self.CheckoutToolBranch('binutils', self._binutils_branch) 190 if rv: 191 self._binutils_branch_tree = rv 192 else: 193 return False 194 195 return True 196 197 def CheckoutToolBranch(self, tool_name, tool_branch): 198 """Checkout the tool branch for a certain tool. 199 200 Args: 201 tool_name: either 'gcc' or 'binutils' 202 tool_branch: tool branch to use 203 Returns: 204 True: if operation succeeds. Otherwise False. 205 """ 206 207 chrome_tool_dir = self.GetChromeOsToolDir(tool_name) 208 command = 'cd "{0}" && git checkout {1}'.format(chrome_tool_dir, 209 tool_branch) 210 if not self._ce.RunCommand(command, print_to_console=True): 211 # Get 'TREE' value of this commit 212 command = ('cd "{0}" && git cat-file -p {1} ' 213 '| grep -E "^tree [a-f0-9]+$" ' 214 '| cut -d" " -f2').format(chrome_tool_dir, tool_branch) 215 ret, stdout, _ = self._ce.RunCommandWOutput(command, 216 print_to_console=False) 217 # Pipe operation always has a zero return value. So need to check if 218 # stdout is valid. 219 if not ret and stdout and re.match('[0-9a-h]{40}', stdout.strip(), 220 re.IGNORECASE): 221 tool_branch_tree = stdout.strip() 222 self._logger.LogOutput('Find tree for {0} branch "{1}" - "{2}"'.format( 223 tool_name, tool_branch, tool_branch_tree)) 224 return tool_branch_tree 225 self._logger.LogError(('Failed to checkout "{0}" or failed to ' 226 'get tree value, aborted.').format(tool_branch)) 227 return None 228 229 def FindEbuildFile(self): 230 """Find the ebuild files for the tools. 231 232 Returns: 233 True: if operation succeeds. 234 """ 235 236 if self._gcc_branch: 237 (rv, ef, efn) = self.FindToolEbuildFile('gcc') 238 if rv: 239 self._gcc_ebuild_file = ef 240 self._gcc_ebuild_file_name = efn 241 else: 242 return False 243 244 if self._binutils_branch: 245 (rv, ef, efn) = self.FindToolEbuildFile('binutils') 246 if rv: 247 self._binutils_ebuild_file = ef 248 self._binutils_ebuild_file_name = efn 249 else: 250 return False 251 252 return True 253 254 def FindToolEbuildFile(self, tool_name): 255 """Find ebuild file for a specific tool. 256 257 Args: 258 tool_name: either "gcc" or "binutils". 259 Returns: 260 A triplet that consisits of whether operation succeeds or not, 261 tool ebuild file full path and tool ebuild file name. 262 """ 263 264 # To get the active gcc ebuild file, we need a workable chroot first. 265 if not os.path.exists(os.path.join( 266 self._chromeos_root, 'chroot')) and self._ce.RunCommand( 267 'cd "{0}" && cros_sdk --create'.format(self._chromeos_root)): 268 self._logger.LogError(('Failed to install a initial chroot, aborted.\n' 269 'If previous bootstrap failed, do a ' 270 '"cros_sdk --delete" to remove ' 271 'in-complete chroot.')) 272 return (False, None, None) 273 274 rv, stdout, _ = self._ce.ChrootRunCommandWOutput( 275 self._chromeos_root, 276 'equery w sys-devel/{0}'.format(tool_name), 277 print_to_console=True) 278 if rv: 279 self._logger.LogError(('Failed to execute inside chroot ' 280 '"equery w sys-devel/{0}", aborted.').format( 281 tool_name)) 282 return (False, None, None) 283 m = re.match(r'^.*/({0}/(.*\.ebuild))$'.format(EBUILD_PATH_PATTERN.format( 284 tool_name)), stdout) 285 if not m: 286 self._logger.LogError( 287 ('Failed to find {0} ebuild file, aborted. ' 288 'If previous bootstrap failed, do a "cros_sdk --delete" to remove ' 289 'in-complete chroot.').format(tool_name)) 290 return (False, None, None) 291 tool_ebuild_file = os.path.join(self._chromeos_root, m.group(1)) 292 tool_ebuild_file_name = m.group(2) 293 294 return (True, tool_ebuild_file, tool_ebuild_file_name) 295 296 def InplaceModifyEbuildFile(self): 297 """Modify the ebuild file. 298 299 Returns: 300 True if operation succeeds. 301 """ 302 303 # Note we shall not use remote branch name (eg. "cros/gcc.gnu.org/...") in 304 # CROS_WORKON_COMMIT, we have to use GITHASH. So we call GitGetCommitHash on 305 # tool_branch. 306 if self._gcc_branch: 307 tool_branch_githash = misc.GitGetCommitHash( 308 self.GetChromeOsToolDir('gcc'), self._gcc_branch) 309 if not tool_branch_githash: 310 return False 311 if not self.InplaceModifyToolEbuildFile( 312 tool_branch_githash, self._gcc_branch_tree, self._gcc_ebuild_file): 313 return False 314 315 if self._binutils_branch: 316 tool_branch_githash = misc.GitGetCommitHash( 317 self.GetChromeOsToolDir('binutils'), self._binutils_branch) 318 if not self.InplaceModifyToolEbuildFile(tool_branch_githash, 319 self._binutils_branch_tree, 320 self._binutils_ebuild_file): 321 return False 322 return True 323 324 @staticmethod 325 def ResetToolEbuildFile(chromeos_root, tool_name): 326 """Reset tool ebuild file to clean state. 327 328 Args: 329 chromeos_root: chromeos source tree 330 tool_name: either "gcc" or "binutils" 331 Returns: 332 True if operation succeds. 333 """ 334 rv = misc.GetGitChangesAsList( 335 os.path.join(chromeos_root, CHROMIUMOS_OVERLAY_PATH), 336 path=('sys-devel/{0}/{0}-*.ebuild'.format(tool_name)), 337 staged=False) 338 if rv: 339 cmd = 'cd {0} && git checkout --'.format(os.path.join( 340 chromeos_root, CHROMIUMOS_OVERLAY_PATH)) 341 for g in rv: 342 cmd += ' ' + g 343 rv = command_executer.GetCommandExecuter().RunCommand(cmd) 344 if rv: 345 logger.GetLogger().LogWarning( 346 'Failed to reset the ebuild file. Please refer to log above.') 347 return False 348 else: 349 logger.GetLogger().LogWarning( 350 'Note - did not find any modified {0} ebuild file.'.format(tool_name)) 351 # Fall through 352 return True 353 354 def GetChromeOsToolDir(self, tool_name): 355 """Return the chromeos git dir for a specific tool. 356 357 Args: 358 tool_name: either 'gcc' or 'binutils'. 359 Returns: 360 Absolute git path for the tool. 361 """ 362 363 return os.path.join(self._chromeos_root, 364 REPO_PATH_PATTERN.format(tool_name)) 365 366 def InplaceModifyToolEbuildFile(self, tool_branch_githash, tool_branch_tree, 367 tool_ebuild_file): 368 """Using sed to fill properly values into the ebuild file. 369 370 Args: 371 tool_branch_githash: githash for tool_branch 372 tool_branch_tree: treeish for the tool branch 373 tool_ebuild_file: tool ebuild file 374 Returns: 375 True: if operation succeeded. 376 """ 377 378 command = ('sed -i ' 379 '-e \'/^CROS_WORKON_COMMIT=".*"/i' 380 ' # The following line is modified by script.\' ' 381 '-e \'s!^CROS_WORKON_COMMIT=".*"$!CROS_WORKON_COMMIT="{0}"!\' ' 382 '-e \'/^CROS_WORKON_TREE=".*"/i' 383 ' # The following line is modified by script.\' ' 384 '-e \'s!^CROS_WORKON_TREE=".*"$!CROS_WORKON_TREE="{1}"!\' ' 385 '{2}').format(tool_branch_githash, tool_branch_tree, 386 tool_ebuild_file) 387 rv = self._ce.RunCommand(command) 388 if rv: 389 self._logger.LogError( 390 'Failed to modify commit and tree value for "{0}"", aborted.'.format( 391 tool_ebuild_file)) 392 return False 393 394 # Warn that the ebuild file has been modified. 395 self._logger.LogWarning( 396 ('Ebuild file "{0}" is modified, to revert the file - \n' 397 'bootstrap_compiler.py --chromeos_root={1} ' 398 '--reset_tool_ebuild_file').format(tool_ebuild_file, 399 self._chromeos_root)) 400 return True 401 402 def DoBuildForBoard(self): 403 """Build tool for a specific board. 404 405 Returns: 406 True if operation succeeds. 407 """ 408 409 if self._gcc_branch: 410 if not self.DoBuildToolForBoard('gcc'): 411 return False 412 if self._binutils_branch: 413 if not self.DoBuildToolForBoard('binutils'): 414 return False 415 return True 416 417 def DoBuildToolForBoard(self, tool_name): 418 """Build a specific tool for a specific board. 419 420 Args: 421 tool_name: either "gcc" or "binutils" 422 Returns: 423 True if operation succeeds. 424 """ 425 426 boards_to_build = self._board.split(',') 427 428 failed = [] 429 for board in boards_to_build: 430 if board == 'host': 431 command = 'sudo emerge sys-devel/{0}'.format(tool_name) 432 else: 433 target = misc.GetCtargetFromBoard(board, self._chromeos_root) 434 if not target: 435 self._logger.LogError('Unsupported board "{0}", skip.'.format(board)) 436 failed.append(board) 437 continue 438 command = 'sudo emerge cross-{0}/{1}'.format(target, tool_name) 439 440 rv = self._ce.ChrootRunCommand(self._chromeos_root, 441 command, 442 print_to_console=True) 443 if rv: 444 self._logger.LogError('Build {0} failed for {1}, aborted.'.format( 445 tool_name, board)) 446 failed.append(board) 447 else: 448 self._logger.LogOutput('Successfully built {0} for board {1}.'.format( 449 tool_name, board)) 450 451 if failed: 452 self._logger.LogError( 453 'Failed to build {0} for the following board(s): "{1}"'.format( 454 tool_name, ' '.join(failed))) 455 return False 456 # All boards build successfully 457 return True 458 459 def DoBootstrapping(self): 460 """Do bootstrapping the chroot. 461 462 This step firstly downloads a prestine sdk, then use this sdk to build the 463 new sdk, finally use the new sdk to build every host package. 464 465 Returns: 466 True if operation succeeds. 467 """ 468 469 logfile = os.path.join(self._chromeos_root, 'bootstrap.log') 470 command = 'cd "{0}" && cros_sdk --delete --bootstrap |& tee "{1}"'.format( 471 self._chromeos_root, logfile) 472 rv = self._ce.RunCommand(command, print_to_console=True) 473 if rv: 474 self._logger.LogError('Bootstrapping failed, log file - "{0}"\n'.format( 475 logfile)) 476 return False 477 478 self._logger.LogOutput('Bootstrap succeeded.') 479 return True 480 481 def BuildAndInstallAmd64Host(self): 482 """Build amd64-host (host) packages. 483 484 Build all host packages in the newly-bootstrapped 'chroot' using *NEW* 485 toolchain. 486 487 So actually we perform 2 builds of all host packages - 488 1. build new toolchain using old toolchain and build all host packages 489 using the newly built toolchain 490 2. build the new toolchain again but using new toolchain built in step 1, 491 and build all host packages using the newly built toolchain 492 493 Returns: 494 True if operation succeeds. 495 """ 496 497 cmd = ('cd {0} && cros_sdk -- -- ./setup_board --board=amd64-host ' 498 '--accept_licenses=@CHROMEOS --skip_chroot_upgrade --nousepkg ' 499 '--reuse_pkgs_from_local_boards').format(self._chromeos_root) 500 rv = self._ce.RunCommand(cmd, print_to_console=True) 501 if rv: 502 self._logger.LogError('Build amd64-host failed.') 503 return False 504 505 # Package amd64-host into 'built-sdk.tar.xz'. 506 sdk_package = os.path.join(self._chromeos_root, 'built-sdk.tar.xz') 507 cmd = ('cd {0}/chroot/build/amd64-host && sudo XZ_OPT="-e9" ' 508 'tar --exclude="usr/lib/debug/*" --exclude="packages/*" ' 509 '--exclude="tmp/*" --exclude="usr/local/build/autotest/*" ' 510 '--sparse -I xz -vcf {1} . && sudo chmod a+r {1}').format( 511 self._chromeos_root, sdk_package) 512 rv = self._ce.RunCommand(cmd, print_to_console=True) 513 if rv: 514 self._logger.LogError('Failed to create "built-sdk.tar.xz".') 515 return False 516 517 # Install amd64-host into a new chroot. 518 cmd = ('cd {0} && cros_sdk --chroot new-sdk-chroot --download --replace ' 519 '--nousepkg --url file://{1}').format(self._chromeos_root, 520 sdk_package) 521 rv = self._ce.RunCommand(cmd, print_to_console=True) 522 if rv: 523 self._logger.LogError('Failed to install "built-sdk.tar.xz".') 524 return False 525 self._logger.LogOutput( 526 'Successfully installed built-sdk.tar.xz into a new chroot.\nAll done.') 527 528 # Rename the newly created new-sdk-chroot to chroot. 529 cmd = ('cd {0} && sudo mv chroot chroot-old && ' 530 'sudo mv new-sdk-chroot chroot').format(self._chromeos_root) 531 rv = self._ce.RunCommand(cmd, print_to_console=True) 532 return rv == 0 533 534 def Do(self): 535 """Entrance of the class. 536 537 Returns: 538 True if everything is ok. 539 """ 540 541 if (self.SubmitToLocalBranch() and self.CheckoutBranch() and 542 self.FindEbuildFile() and self.InplaceModifyEbuildFile()): 543 if self._setup_tool_ebuild_file_only: 544 # Everything is done, we are good. 545 ret = True 546 else: 547 if self._board: 548 ret = self.DoBuildForBoard() 549 else: 550 # This implies '--bootstrap'. 551 ret = (self.DoBootstrapping() and (self._disable_2nd_bootstrap or 552 self.BuildAndInstallAmd64Host())) 553 else: 554 ret = False 555 return ret 556 557 558def Main(argv): 559 parser = optparse.OptionParser() 560 parser.add_option('-c', 561 '--chromeos_root', 562 dest='chromeos_root', 563 help=('Optional. ChromeOs root dir. ' 564 'When not specified, chromeos root will be deduced ' 565 'from current working directory.')) 566 parser.add_option('--gcc_branch', 567 dest='gcc_branch', 568 help=('The branch to test against. ' 569 'This branch must be a local branch ' 570 'inside "src/third_party/gcc". ' 571 'Notice, this must not be used with "--gcc_dir".')) 572 parser.add_option('--binutils_branch', 573 dest='binutils_branch', 574 help=('The branch to test against binutils. ' 575 'This branch must be a local branch ' 576 'inside "src/third_party/binutils". ' 577 'Notice, this must not be used with ' 578 '"--binutils_dir".')) 579 parser.add_option('-g', 580 '--gcc_dir', 581 dest='gcc_dir', 582 help=('Use a local gcc tree to do bootstrapping. ' 583 'Notice, this must not be used with "--gcc_branch".')) 584 parser.add_option('--binutils_dir', 585 dest='binutils_dir', 586 help=('Use a local binutils tree to do bootstrapping. ' 587 'Notice, this must not be used with ' 588 '"--binutils_branch".')) 589 parser.add_option('--fixperm', 590 dest='fixperm', 591 default=False, 592 action='store_true', 593 help=('Fix the (notorious) permission error ' 594 'while trying to bootstrap the chroot. ' 595 'Note this takes an extra 10-15 minutes ' 596 'and is only needed once per chromiumos tree.')) 597 parser.add_option('--setup_tool_ebuild_file_only', 598 dest='setup_tool_ebuild_file_only', 599 default=False, 600 action='store_true', 601 help=('Setup gcc and/or binutils ebuild file ' 602 'to pick up the branch (--gcc/binutils_branch) or ' 603 'use gcc and/or binutils source (--gcc/binutils_dir) ' 604 'and exit. Keep chroot as is. This should not be ' 605 'used with --gcc/binutils_dir/branch options.')) 606 parser.add_option('--reset_tool_ebuild_file', 607 dest='reset_tool_ebuild_file', 608 default=False, 609 action='store_true', 610 help=('Reset the modification that is done by this script.' 611 'Note, when this script is running, it will modify ' 612 'the active gcc/binutils ebuild file. Use this ' 613 'option to reset (what this script has done) ' 614 'and exit. This should not be used with -- ' 615 'gcc/binutils_dir/branch options.')) 616 parser.add_option('--board', 617 dest='board', 618 default=None, 619 help=('Only build toolchain for specific board(s). ' 620 'Use "host" to build for host. ' 621 'Use "," to seperate multiple boards. ' 622 'This does not perform a chroot bootstrap.')) 623 parser.add_option('--bootstrap', 624 dest='bootstrap', 625 default=False, 626 action='store_true', 627 help=('Performs a chroot bootstrap. ' 628 'Note, this will *destroy* your current chroot.')) 629 parser.add_option('--disable-2nd-bootstrap', 630 dest='disable_2nd_bootstrap', 631 default=False, 632 action='store_true', 633 help=('Disable a second bootstrap ' 634 '(build of amd64-host stage).')) 635 636 options = parser.parse_args(argv)[0] 637 # Trying to deduce chromeos root from current directory. 638 if not options.chromeos_root: 639 logger.GetLogger().LogOutput('Trying to deduce chromeos root ...') 640 wdir = os.getcwd() 641 while wdir and wdir != '/': 642 if misc.IsChromeOsTree(wdir): 643 logger.GetLogger().LogOutput('Find chromeos_root: {}'.format(wdir)) 644 options.chromeos_root = wdir 645 break 646 wdir = os.path.dirname(wdir) 647 648 if not options.chromeos_root: 649 parser.error('Missing or failing to deduce mandatory option "--chromeos".') 650 return 1 651 652 options.chromeos_root = os.path.abspath(os.path.expanduser( 653 options.chromeos_root)) 654 655 if not os.path.isdir(options.chromeos_root): 656 logger.GetLogger().LogError('"{0}" does not exist.'.format( 657 options.chromeos_root)) 658 return 1 659 660 if options.fixperm: 661 # Fix perm error before continuing. 662 cmd = ( 663 r'sudo find "{0}" \( -name ".cache" -type d -prune \) -o ' 664 r'\( -name "chroot" -type d -prune \) -o ' 665 r'\( -type f -exec chmod a+r {{}} \; \) -o ' 666 r'\( -type d -exec chmod a+rx {{}} \; \)').format(options.chromeos_root) 667 logger.GetLogger().LogOutput( 668 'Fixing perm issues for chromeos root, this might take some time.') 669 command_executer.GetCommandExecuter().RunCommand(cmd) 670 671 if options.reset_tool_ebuild_file: 672 if (options.gcc_dir or options.gcc_branch or options.binutils_dir or 673 options.binutils_branch): 674 logger.GetLogger().LogWarning( 675 'Ignoring any "--gcc/binutils_dir" and/or "--gcc/binutils_branch".') 676 if options.setup_tool_ebuild_file_only: 677 logger.GetLogger().LogError( 678 ('Conflict options "--reset_tool_ebuild_file" ' 679 'and "--setup_tool_ebuild_file_only".')) 680 return 1 681 rv = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'gcc') 682 rv1 = Bootstrapper.ResetToolEbuildFile(options.chromeos_root, 'binutils') 683 return 0 if (rv and rv1) else 1 684 685 if options.gcc_dir: 686 options.gcc_dir = os.path.abspath(os.path.expanduser(options.gcc_dir)) 687 if not os.path.isdir(options.gcc_dir): 688 logger.GetLogger().LogError('"{0}" does not exist.'.format( 689 options.gcc_dir)) 690 return 1 691 692 if options.gcc_branch and options.gcc_dir: 693 parser.error('Only one of "--gcc_dir" and "--gcc_branch" can be specified.') 694 return 1 695 696 if options.binutils_dir: 697 options.binutils_dir = os.path.abspath(os.path.expanduser( 698 options.binutils_dir)) 699 if not os.path.isdir(options.binutils_dir): 700 logger.GetLogger().LogError('"{0}" does not exist.'.format( 701 options.binutils_dir)) 702 return 1 703 704 if options.binutils_branch and options.binutils_dir: 705 parser.error('Only one of "--binutils_dir" and ' 706 '"--binutils_branch" can be specified.') 707 return 1 708 709 if (not (options.binutils_branch or options.binutils_dir or options.gcc_branch 710 or options.gcc_dir)): 711 parser.error(('At least one of "--gcc_dir", "--gcc_branch", ' 712 '"--binutils_dir" and "--binutils_branch" must ' 713 'be specified.')) 714 return 1 715 716 if not options.board and not options.bootstrap: 717 parser.error('You must specify either "--board" or "--bootstrap".') 718 return 1 719 720 if (options.board and options.bootstrap and 721 not options.setup_tool_ebuild_file_only): 722 parser.error('You must specify only one of "--board" and "--bootstrap".') 723 return 1 724 725 if not options.bootstrap and options.disable_2nd_bootstrap: 726 parser.error('"--disable-2nd-bootstrap" has no effect ' 727 'without specifying "--bootstrap".') 728 return 1 729 730 if Bootstrapper( 731 options.chromeos_root, 732 gcc_branch=options.gcc_branch, 733 gcc_dir=options.gcc_dir, 734 binutils_branch=options.binutils_branch, 735 binutils_dir=options.binutils_dir, 736 board=options.board, 737 disable_2nd_bootstrap=options.disable_2nd_bootstrap, 738 setup_tool_ebuild_file_only=options.setup_tool_ebuild_file_only).Do(): 739 return 0 740 return 1 741 742 743if __name__ == '__main__': 744 retval = Main(sys.argv) 745 sys.exit(retval) 746