Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 1 | # Copyright 2018 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. |
| 4 | |
| 5 | """Choose the profile for a board that has been or is being setup.""" |
| 6 | |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 7 | import functools |
Chris McDonald | 59650c3 | 2021-07-20 15:29:28 -0600 | [diff] [blame] | 8 | import logging |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 9 | import os |
| 10 | |
Mike Frysinger | 06a51c8 | 2021-04-06 11:39:17 -0400 | [diff] [blame] | 11 | from chromite.lib import build_target_lib |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 12 | from chromite.lib import commandline |
| 13 | from chromite.lib import cros_build_lib |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 14 | from chromite.lib import osutils |
| 15 | from chromite.lib import sysroot_lib |
| 16 | |
| 17 | |
| 18 | # Default value constants. |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 19 | _DEFAULT_PROFILE = "base" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 20 | |
| 21 | |
| 22 | def PathPrefixDecorator(f): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 23 | """Add a prefix to the path or paths returned by the decorated function. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 24 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 25 | Will not prepend the prefix if the path already starts with the prefix, so the |
| 26 | decorator may be applied to functions that have mixed sources that may |
| 27 | or may not already have applied them. This is especially useful for allowing |
| 28 | tests and CLI args a little more leniency in how paths are provided. |
| 29 | """ |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 30 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 31 | @functools.wraps(f) |
| 32 | def wrapper(*args, **kwargs): |
| 33 | result = f(*args, **kwargs) |
| 34 | prefix = PathPrefixDecorator.prefix |
Mike Frysinger | 18a4fe2 | 2022-04-21 21:12:23 -0400 | [diff] [blame] | 35 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 36 | if not prefix or not result: |
| 37 | # Nothing to do. |
| 38 | return result |
Mike Frysinger | 18a4fe2 | 2022-04-21 21:12:23 -0400 | [diff] [blame] | 39 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 40 | # Convert Path objects to str. |
| 41 | if isinstance(prefix, os.PathLike): |
| 42 | prefix = str(prefix) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 43 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 44 | if not isinstance(result, str): |
| 45 | # Transform each path in the collection. |
| 46 | new_result = [] |
| 47 | for path in result: |
| 48 | prefixed_path = os.path.join(prefix, path.lstrip(os.sep)) |
| 49 | new_result.append( |
| 50 | path if path.startswith(prefix) else prefixed_path |
| 51 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 52 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 53 | return new_result |
| 54 | elif not result.startswith(prefix): |
| 55 | # Add the prefix. |
| 56 | return os.path.join(prefix, result.lstrip(os.sep)) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 57 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 58 | # An already prefixed path. |
| 59 | return result |
| 60 | |
| 61 | return wrapper |
| 62 | |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 63 | |
| 64 | PathPrefixDecorator.prefix = None |
| 65 | |
| 66 | |
| 67 | class Error(Exception): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 68 | """Base error for custom exceptions in this script.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 69 | |
| 70 | |
| 71 | class InvalidArgumentsError(Error): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 72 | """Invalid arguments.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 73 | |
| 74 | |
| 75 | class MakeProfileIsNotLinkError(Error): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 76 | """The make profile exists but is not a link.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 77 | |
| 78 | |
| 79 | class ProfileDirectoryNotFoundError(Error): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 80 | """Unable to find the profile directory.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 81 | |
| 82 | |
| 83 | def ChooseProfile(board, profile): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 84 | """Make the link to choose the profile, print relevant warnings. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 85 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 86 | Args: |
| 87 | board: Board - the board being used. |
| 88 | profile: Profile - the profile being used. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 89 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 90 | Raises: |
| 91 | OSError when the board's make_profile path exists and is not a link. |
| 92 | """ |
| 93 | if not os.path.isfile(os.path.join(profile.directory, "parent")): |
| 94 | logging.warning( |
| 95 | "Portage profile directory %s has no 'parent' file. " |
| 96 | "This likely means your profile directory is invalid and " |
| 97 | "build_packages will fail.", |
| 98 | profile.directory, |
| 99 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 100 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 101 | current_profile = None |
| 102 | if os.path.exists(board.make_profile): |
| 103 | # Only try to read if it exists; we only want it to raise an error when the |
| 104 | # path exists and is not a link. |
| 105 | try: |
| 106 | current_profile = os.readlink(board.make_profile) |
| 107 | except OSError: |
| 108 | raise MakeProfileIsNotLinkError( |
| 109 | "%s is not a link." % board.make_profile |
| 110 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 111 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 112 | if current_profile == profile.directory: |
| 113 | # The existing link is what we were going to make, so nothing to do. |
| 114 | return |
| 115 | elif current_profile is not None: |
| 116 | # It exists and is changing, emit warning. |
| 117 | fmt = {"board": board.board_variant, "profile": profile.name} |
| 118 | msg = ( |
| 119 | "You are switching profiles for a board that is already setup. This " |
| 120 | "can cause trouble for Portage. If you experience problems with " |
| 121 | "build_packages you may need to run:\n" |
| 122 | "\t'setup_board --board %(board)s --force --profile %(profile)s'\n" |
| 123 | "\nAlternatively, you can correct the dependency graph by using " |
| 124 | "'emerge-%(board)s -c' or 'emerge-%(board)s -C <ebuild>'." |
| 125 | ) |
| 126 | logging.warning(msg, fmt) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 127 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 128 | # Make the symlink, overwrites existing link if one already exists. |
| 129 | osutils.SafeSymlink(profile.directory, board.make_profile, sudo=True) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 130 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 131 | # Update the profile override value. |
| 132 | if profile.override: |
| 133 | board.profile_override = profile.override |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 134 | |
| 135 | |
| 136 | class Profile(object): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 137 | """Simple data container class for the profile data.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 138 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 139 | def __init__(self, name, directory, override): |
| 140 | self.name = name |
| 141 | self._directory = directory |
| 142 | self.override = override |
| 143 | |
| 144 | @property |
| 145 | @PathPrefixDecorator |
| 146 | def directory(self): |
| 147 | return self._directory |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 148 | |
| 149 | |
| 150 | def _GetProfile(opts, board): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 151 | """Get the profile list.""" |
| 152 | # Determine the override value - which profile is being selected. |
| 153 | override = opts.profile if opts.profile else board.profile_override |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 154 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 155 | profile = _DEFAULT_PROFILE |
| 156 | profile_directory = None |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 157 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 158 | if override and os.path.exists(override): |
| 159 | profile_directory = os.path.abspath(override) |
| 160 | profile = os.path.basename(profile_directory) |
| 161 | elif override: |
| 162 | profile = override |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 163 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 164 | if profile_directory is None: |
| 165 | # Build profile directories in reverse order so we can search from most to |
| 166 | # least specific. |
| 167 | profile_dirs = [ |
| 168 | "%s/profiles/%s" % (overlay, profile) |
| 169 | for overlay in reversed(board.overlays) |
| 170 | ] |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 171 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 172 | for profile_dir in profile_dirs: |
| 173 | if os.path.isdir(profile_dir): |
| 174 | profile_directory = profile_dir |
| 175 | break |
| 176 | else: |
| 177 | searched = ", ".join(profile_dirs) |
| 178 | raise ProfileDirectoryNotFoundError( |
| 179 | "Profile directory not found, searched in (%s)." % searched |
| 180 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 181 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 182 | return Profile(profile, profile_directory, override) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 183 | |
| 184 | |
| 185 | class Board(object): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 186 | """Manage the board arguments and configs.""" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 187 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 188 | # Files located on the board. |
| 189 | MAKE_PROFILE = "%(board_root)s/etc/portage/make.profile" |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 190 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 191 | def __init__(self, board=None, variant=None, board_root=None): |
| 192 | """Board constructor. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 193 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 194 | board [+ variant] is given preference when both board and board_root are |
| 195 | provided. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 196 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 197 | Preconditions: |
| 198 | Either board and build_root are not None, or board_root is not None. |
| 199 | With board + build_root [+ variant] we can construct the board root. |
| 200 | With the board root we can have the board[_variant] directory. |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 201 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 202 | Args: |
| 203 | board: str|None - The board name. |
| 204 | variant: str|None - The variant name. |
| 205 | board_root: str|None - The boards fully qualified build directory path. |
| 206 | """ |
| 207 | if not board and not board_root: |
| 208 | # Enforce preconditions. |
| 209 | raise InvalidArgumentsError( |
| 210 | "Either board or board_root must be " "provided." |
| 211 | ) |
| 212 | elif board: |
| 213 | # The board and variant can be specified separately, or can both be |
| 214 | # contained in the board name, separated by an underscore. |
| 215 | board_split = board.split("_") |
| 216 | variant_default = variant |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 217 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 218 | self._board_root = None |
| 219 | else: |
| 220 | self._board_root = os.path.normpath(board_root) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 221 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 222 | board_split = os.path.basename(self._board_root).split("_") |
| 223 | variant_default = None |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 224 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 225 | self.board = board_split.pop(0) |
| 226 | self.variant = board_split.pop(0) if board_split else variant_default |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 227 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 228 | if self.variant: |
| 229 | self.board_variant = "%s_%s" % (self.board, self.variant) |
| 230 | else: |
| 231 | self.board_variant = self.board |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 232 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 233 | self.make_profile = self.MAKE_PROFILE % {"board_root": self.root} |
| 234 | # This must come after the arguments required to build each variant of the |
| 235 | # build root have been processed. |
| 236 | self._sysroot_config = sysroot_lib.Sysroot(self.root) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 237 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 238 | @property |
| 239 | @PathPrefixDecorator |
| 240 | def root(self): |
| 241 | if self._board_root: |
| 242 | return self._board_root |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 243 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 244 | return build_target_lib.get_default_sysroot_path(self.board_variant) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 245 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 246 | @property |
| 247 | @PathPrefixDecorator |
| 248 | def overlays(self): |
| 249 | return self._sysroot_config.GetStandardField( |
| 250 | sysroot_lib.STANDARD_FIELD_BOARD_OVERLAY |
| 251 | ).split() |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 252 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 253 | @property |
| 254 | def profile_override(self): |
| 255 | return self._sysroot_config.GetCachedField("PROFILE_OVERRIDE") |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 256 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 257 | @profile_override.setter |
| 258 | def profile_override(self, value): |
| 259 | self._sysroot_config.SetCachedField("PROFILE_OVERRIDE", value) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 260 | |
| 261 | |
| 262 | def _GetBoard(opts): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 263 | """Factory method to build a Board from the parsed CLI arguments.""" |
| 264 | return Board( |
| 265 | board=opts.board, variant=opts.variant, board_root=opts.board_root |
| 266 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 267 | |
| 268 | |
| 269 | def GetParser(): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 270 | """ArgumentParser builder and argument definitions.""" |
| 271 | parser = commandline.ArgumentParser(description=__doc__) |
| 272 | parser.add_argument( |
| 273 | "-b", |
| 274 | "--board", |
| 275 | default=os.environ.get("DEFAULT_BOARD"), |
| 276 | help="The name of the board to set up.", |
| 277 | ) |
| 278 | parser.add_argument( |
| 279 | "-r", |
| 280 | "--board-root", |
| 281 | type="path", |
| 282 | help="Board root where the profile should be created.", |
| 283 | ) |
| 284 | parser.add_argument( |
| 285 | "-p", "--profile", help="The portage configuration profile to use." |
| 286 | ) |
| 287 | parser.add_argument("--variant", help="Board variant.") |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 288 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 289 | group = parser.add_argument_group("Advanced options") |
| 290 | group.add_argument( |
| 291 | "--filesystem-prefix", |
| 292 | type="path", |
| 293 | help="Force filesystem accesses to be prefixed by the " "given path.", |
| 294 | ) |
| 295 | return parser |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 296 | |
| 297 | |
| 298 | def ParseArgs(argv): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 299 | """Parse and validate the arguments.""" |
| 300 | parser = GetParser() |
| 301 | opts = parser.parse_args(argv) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 302 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 303 | # See Board.__init__ Preconditions. |
| 304 | board_valid = opts.board is not None |
| 305 | board_root_valid = opts.board_root and os.path.exists(opts.board_root) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 306 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 307 | if not board_valid and not board_root_valid: |
| 308 | parser.error("Either board or board_root must be provided.") |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 309 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 310 | PathPrefixDecorator.prefix = opts.filesystem_prefix |
| 311 | del opts.filesystem_prefix |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 312 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 313 | opts.Freeze() |
| 314 | return opts |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 315 | |
| 316 | |
| 317 | def main(argv): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 318 | # Parse arguments. |
| 319 | opts = ParseArgs(argv) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 320 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 321 | # Build and validate the board and profile. |
| 322 | board = _GetBoard(opts) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 323 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 324 | if not os.path.exists(board.root): |
| 325 | cros_build_lib.Die( |
| 326 | "The board has not been setup, please run setup_board " "first." |
| 327 | ) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 328 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 329 | try: |
| 330 | profile = _GetProfile(opts, board) |
| 331 | except ProfileDirectoryNotFoundError as e: |
| 332 | cros_build_lib.Die(e) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 333 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 334 | # Change the profile to the selected. |
| 335 | logging.info("Selecting profile: %s for %s", profile.directory, board.root) |
Alex Klein | a2ceb19 | 2018-08-17 11:19:32 -0600 | [diff] [blame] | 336 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 337 | try: |
| 338 | ChooseProfile(board, profile) |
| 339 | except MakeProfileIsNotLinkError as e: |
| 340 | cros_build_lib.Die(e) |