1 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Generates a sysroot tarball for building a specific package.
7 Meant for use after setup_board and build_packages have been run.
10 from __future__ import print_function
14 from chromite.cbuildbot import constants
15 from chromite.lib import cros_build_lib
16 from chromite.lib import commandline
17 from chromite.lib import osutils
18 from chromite.lib import sudo
20 DEFAULT_NAME = 'sysroot_%(package)s.tar.xz'
21 PACKAGE_SEPARATOR = '/'
25 def ParseCommandLine(argv):
26 """Parse args, and run environment-independent checks."""
27 parser = commandline.ArgumentParser(description=__doc__)
28 parser.add_argument('--board', required=True,
29 help=('The board to generate the sysroot for.'))
30 parser.add_argument('--package', required=True,
31 help=('The package to generate the sysroot for.'))
32 parser.add_argument('--out-dir', type=osutils.ExpandPath, required=True,
33 help='Directory to place the generated tarball.')
34 parser.add_argument('--out-file',
35 help=('The name to give to the tarball. Defaults to %r.'
37 options = parser.parse_args(argv)
39 if not options.out_file:
40 options.out_file = DEFAULT_NAME % {
41 'package': options.package.replace(PACKAGE_SEPARATOR, '_')
47 class GenerateSysroot(object):
48 """Wrapper for generation functionality."""
50 PARALLEL_EMERGE = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
52 def __init__(self, sysroot, options):
56 sysroot: Path to sysroot.
57 options: Parsed options.
59 self.sysroot = sysroot
60 self.options = options
61 self.extra_env = {'ROOT': self.sysroot, 'USE': os.environ.get('USE', '')}
63 def _Emerge(self, *args, **kwargs):
64 """Emerge the given packages using parallel_emerge."""
65 cmd = [self.PARALLEL_EMERGE, '--board=%s' % self.options.board,
66 '--usepkgonly', '--noreplace'] + list(args)
67 kwargs.setdefault('extra_env', self.extra_env)
68 cros_build_lib.SudoRunCommand(cmd, **kwargs)
70 def _InstallToolchain(self):
71 cros_build_lib.RunCommand(
72 [os.path.join(constants.CROSUTILS_DIR, 'install_toolchain'),
73 '--noconfigure', '--board_root', self.sysroot, '--board',
76 def _InstallKernelHeaders(self):
77 self._Emerge('sys-kernel/linux-headers')
79 def _InstallBuildDependencies(self):
80 # Calculate buildtime deps that are not runtime deps.
81 raw_sysroot = cros_build_lib.GetSysroot(board=self.options.board)
82 cmd = ['qdepends', '-q', '-C', self.options.package]
83 output = cros_build_lib.RunCommand(
84 cmd, extra_env={'ROOT': raw_sysroot}, capture_output=True).output
86 if output.count('\n') > 1:
87 raise AssertionError('Too many packages matched given package pattern')
89 # qdepend outputs "package: deps", so only grab the deps.
90 atoms = output.partition(':')[2].split()
92 # Install the buildtime deps.
96 def _CreateTarball(self):
97 target = os.path.join(self.options.out_dir, self.options.out_file)
98 cros_build_lib.CreateTarball(target, self.sysroot, sudo=True)
101 """Generate the sysroot."""
102 self._InstallToolchain()
103 self._InstallKernelHeaders()
104 self._InstallBuildDependencies()
105 self._CreateTarball()
108 def FinishParsing(options):
109 """Run environment dependent checks on parsed args."""
110 target = os.path.join(options.out_dir, options.out_file)
111 if os.path.exists(target):
112 cros_build_lib.Die('Output file %r already exists.' % target)
114 if not os.path.isdir(options.out_dir):
116 'Non-existent directory %r specified for --out-dir' % options.out_dir)
120 options = ParseCommandLine(argv)
121 FinishParsing(options)
123 cros_build_lib.AssertInsideChroot()
125 with sudo.SudoKeepAlive(ttyless_sudo=False):
126 with osutils.TempDir(set_global=True, sudo_rm=True) as tempdir:
127 sysroot = os.path.join(tempdir, SYSROOT)
129 GenerateSysroot(sysroot, options).Perform()