blob: e0478d8670bac60a4e470464687120ce8a75734c [file] [log] [blame]
Xiaochu Liudeed0232018-06-26 10:25:34 -07001# -*- coding: utf-8 -*-
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Xiaochu Liudeed0232018-06-26 10:25:34 -07005"""Script to generate a DLC (Downloadable Content) artifact."""
6
Mike Frysinger93e8ffa2019-07-03 20:24:18 -04007from __future__ import division
Xiaochu Liudeed0232018-06-26 10:25:34 -07008from __future__ import print_function
9
10import hashlib
11import json
12import math
13import os
Amin Hassanibc1a4792019-10-24 14:39:57 -070014import re
Amin Hassani11a88cf2019-01-29 15:31:24 -080015import shutil
Andreweff865f2020-04-24 13:39:44 -070016import sys
Xiaochu Liudeed0232018-06-26 10:25:34 -070017
18from chromite.lib import commandline
19from chromite.lib import cros_build_lib
Amin Hassanib97a5ee2019-01-23 14:44:43 -080020from chromite.lib import cros_logging as logging
Xiaochu Liudeed0232018-06-26 10:25:34 -070021from chromite.lib import osutils
Mike Frysingerd0960812020-06-09 01:53:32 -040022from chromite.lib import pformat
Xiaochu Liudeed0232018-06-26 10:25:34 -070023
Andrew06a5f812020-01-23 08:08:32 -080024from chromite.licensing import licenses_lib
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080025from chromite.scripts import cros_set_lsb_release
Xiaochu Liudeed0232018-06-26 10:25:34 -070026
Andreweff865f2020-04-24 13:39:44 -070027assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
28
Amin Hassani2af75a92019-01-22 21:07:45 -080029DLC_META_DIR = 'opt/google/dlc/'
Andrew67b5fa72020-02-05 14:14:48 -080030DLC_TMP_META_DIR = 'meta'
31DLC_BUILD_DIR = 'build/rootfs/dlc/'
Andrew06a5f812020-01-23 08:08:32 -080032LICENSE = 'LICENSE'
Amin Hassanid5742d32019-01-22 21:13:34 -080033LSB_RELEASE = 'etc/lsb-release'
Jae Hoon Kim5f411e42020-01-09 13:30:56 -080034DLC_IMAGE = 'dlc.img'
35IMAGELOADER_JSON = 'imageloader.json'
Andrew67b5fa72020-02-05 14:14:48 -080036EBUILD_PARAMETERS = 'ebuild_parameters.json'
Amin Hassanid5742d32019-01-22 21:13:34 -080037
Amin Hassani11a88cf2019-01-29 15:31:24 -080038# This file has major and minor version numbers that the update_engine client
39# supports. These values are needed for generating a delta/full payload.
40UPDATE_ENGINE_CONF = 'etc/update_engine.conf'
41
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -080042_EXTRA_RESOURCES = (UPDATE_ENGINE_CONF,)
Amin Hassani11a88cf2019-01-29 15:31:24 -080043
Amin Hassanid5742d32019-01-22 21:13:34 -080044DLC_ID_KEY = 'DLC_ID'
Amin Hassanib5a48042019-03-18 14:30:51 -070045DLC_PACKAGE_KEY = 'DLC_PACKAGE'
Amin Hassanid5742d32019-01-22 21:13:34 -080046DLC_NAME_KEY = 'DLC_NAME'
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080047DLC_APPID_KEY = 'DLC_RELEASE_APPID'
Amin Hassani2af75a92019-01-22 21:07:45 -080048
Amin Hassani22a25eb2019-01-11 14:25:02 -080049_SQUASHFS_TYPE = 'squashfs'
50_EXT4_TYPE = 'ext4'
51
Amin Hassani160e12e2020-04-13 14:29:36 -070052_USED_BY_USER = 'user'
53_USED_BY_SYSTEM = 'system'
54
Amin Hassanibc1a4792019-10-24 14:39:57 -070055MAX_ID_NAME = 40
Amin Hassanid5742d32019-01-22 21:13:34 -080056
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -080057
Xiaochu Liudeed0232018-06-26 10:25:34 -070058def HashFile(file_path):
59 """Calculate the sha256 hash of a file.
60
61 Args:
62 file_path: (str) path to the file.
63
64 Returns:
65 [str]: The sha256 hash of the file.
66 """
67 sha256 = hashlib.sha256()
68 with open(file_path, 'rb') as f:
69 for b in iter(lambda: f.read(2048), b''):
70 sha256.update(b)
71 return sha256.hexdigest()
72
73
Jae Hoon Kim5f411e42020-01-09 13:30:56 -080074def GetValueInJsonFile(json_path, key, default_value=None):
75 """Reads file containing JSON and returns value or default_value for key.
76
77 Args:
78 json_path: (str) File containing JSON.
79 key: (str) The desired key to lookup.
80 default_value: (default:None) The default value returned in case of missing
81 key.
82 """
83 with open(json_path) as fd:
84 return json.load(fd).get(key, default_value)
85
86
Andrew67b5fa72020-02-05 14:14:48 -080087class EbuildParams(object):
88 """Object to store and retrieve DLC ebuild parameters.
89
90 Attributes:
91 dlc_id: (str) DLC ID.
92 dlc_package: (str) DLC package.
93 fs_type: (str) file system type.
94 pre_allocated_blocks: (int) number of blocks pre-allocated on device.
95 version: (str) DLC version.
96 name: (str) DLC name.
Jae Hoon Kim6ef63172020-04-06 12:39:04 -070097 description: (str) DLC description.
Andrew67b5fa72020-02-05 14:14:48 -080098 preload: (bool) allow for preloading DLC.
Amin Hassani160e12e2020-04-13 14:29:36 -070099 used_by: (str) The user of this DLC, e.g. "system" or "user"
Andrew06a5f812020-01-23 08:08:32 -0800100 fullnamerev: (str) The full package & version name.
Andrew67b5fa72020-02-05 14:14:48 -0800101 """
102
103 def __init__(self, dlc_id, dlc_package, fs_type, pre_allocated_blocks,
Andrew06a5f812020-01-23 08:08:32 -0800104 version, name, description, preload, used_by, fullnamerev):
Andrew67b5fa72020-02-05 14:14:48 -0800105 self.dlc_id = dlc_id
106 self.dlc_package = dlc_package
107 self.fs_type = fs_type
108 self.pre_allocated_blocks = pre_allocated_blocks
109 self.version = version
110 self.name = name
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700111 self.description = description
Andrew67b5fa72020-02-05 14:14:48 -0800112 self.preload = preload
Amin Hassani160e12e2020-04-13 14:29:36 -0700113 self.used_by = used_by
Andrew06a5f812020-01-23 08:08:32 -0800114 self.fullnamerev = fullnamerev
Andrew67b5fa72020-02-05 14:14:48 -0800115
116 def StoreDlcParameters(self, install_root_dir, sudo):
117 """Store DLC parameters defined in the ebuild.
118
119 Store DLC parameters defined in the ebuild in a temporary file so they can
120 be retrieved in the build_image phase.
121
122 Args:
123 install_root_dir: (str) The path to the root installation directory.
124 sudo: (bool) Use sudo to write the file.
125 """
126 ebuild_params_path = EbuildParams.GetParamsPath(install_root_dir,
127 self.dlc_id,
128 self.dlc_package)
129 osutils.WriteFile(ebuild_params_path,
130 json.dumps(self.__dict__),
131 makedirs=True, sudo=sudo)
132
133 @staticmethod
134 def GetParamsPath(install_root_dir, dlc_id, dlc_package):
135 """Get the path to the file storing the ebuild parameters.
136
137 Args:
138 install_root_dir: (str) The path to the root installation directory.
139 dlc_id: (str) DLC ID.
140 dlc_package: (str) DLC package.
141
142 Returns:
143 [str]: Path to |EBUILD_PARAMETERS|.
144 """
145 return os.path.join(install_root_dir, DLC_BUILD_DIR, dlc_id, dlc_package,
146 EBUILD_PARAMETERS)
147
148 @classmethod
Jae Hoon Kim264b8d22020-04-06 11:49:19 -0700149 def LoadEbuildParams(cls, sysroot, dlc_id, dlc_package):
Andrew67b5fa72020-02-05 14:14:48 -0800150 """Read the stored ebuild parameters file and return a class instance.
151
152 Args:
153 dlc_id: (str) DLC ID.
154 dlc_package: (str) DLC package.
155 sysroot: (str) The path to the build root directory.
156
157 Returns:
158 [bool] : True if |ebuild_params_path| exists, False otherwise.
159 """
160 path = cls.GetParamsPath(sysroot, dlc_id, dlc_package)
161 if not os.path.exists(path):
162 return None
163
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700164 with open(path, 'rb') as fp:
Andrew67b5fa72020-02-05 14:14:48 -0800165 return cls(**json.load(fp))
166
167 def __str__(self):
168 return str(self.__dict__)
169
170
Amin Hassani174eb7e2019-01-18 11:11:24 -0800171class DlcGenerator(object):
Xiaochu Liudeed0232018-06-26 10:25:34 -0700172 """Object to generate DLC artifacts."""
173 # Block size for the DLC image.
174 # We use 4K for various reasons:
175 # 1. it's what imageloader (linux kernel) supports.
176 # 2. it's what verity supports.
177 _BLOCK_SIZE = 4096
178 # Blocks in the initial sparse image.
179 _BLOCKS = 500000
180 # Version of manifest file.
181 _MANIFEST_VERSION = 1
182
Amin Hassanicc7ffce2019-01-11 14:57:52 -0800183 # The DLC root path inside the DLC module.
184 _DLC_ROOT_DIR = 'root'
185
Andrew06a5f812020-01-23 08:08:32 -0800186 def __init__(self, ebuild_params, sysroot, install_root_dir, board,
187 src_dir=None):
Xiaochu Liudeed0232018-06-26 10:25:34 -0700188 """Object initializer.
189
190 Args:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800191 sysroot: (str) The path to the build root directory.
Amin Hassani2af75a92019-01-22 21:07:45 -0800192 install_root_dir: (str) The path to the root installation directory.
Andrew67b5fa72020-02-05 14:14:48 -0800193 ebuild_params: (EbuildParams) Ebuild variables.
Andrew06a5f812020-01-23 08:08:32 -0800194 board: (str) The target board we are building for.
Andrew67b5fa72020-02-05 14:14:48 -0800195 src_dir: (str) Optional path to the DLC source root directory. When None,
196 the default directory in |DLC_BUILD_DIR| is used.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700197 """
Andrew67b5fa72020-02-05 14:14:48 -0800198 # Use a temporary directory to avoid having to use sudo every time we write
199 # into the build directory.
200 self.temp_root = osutils.TempDir(prefix='dlc', sudo_rm=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700201 self.src_dir = src_dir
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800202 self.sysroot = sysroot
Amin Hassani2af75a92019-01-22 21:07:45 -0800203 self.install_root_dir = install_root_dir
Andrew06a5f812020-01-23 08:08:32 -0800204 self.board = board
Andrew67b5fa72020-02-05 14:14:48 -0800205 self.ebuild_params = ebuild_params
206 # If the client is not overriding the src_dir, use the default one.
207 if not self.src_dir:
208 self.src_dir = os.path.join(self.sysroot, DLC_BUILD_DIR,
209 self.ebuild_params.dlc_id,
210 self.ebuild_params.dlc_package,
211 self._DLC_ROOT_DIR)
Amin Hassani2af75a92019-01-22 21:07:45 -0800212
Andrew67b5fa72020-02-05 14:14:48 -0800213 self.image_dir = os.path.join(self.temp_root.tempdir,
214 DLC_BUILD_DIR,
215 self.ebuild_params.dlc_id,
216 self.ebuild_params.dlc_package)
217
218 self.meta_dir = os.path.join(self.image_dir, DLC_TMP_META_DIR)
Amin Hassani2af75a92019-01-22 21:07:45 -0800219
Xiaochu Liudeed0232018-06-26 10:25:34 -0700220 # Create path for all final artifacts.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800221 self.dest_image = os.path.join(self.image_dir, DLC_IMAGE)
Amin Hassani2af75a92019-01-22 21:07:45 -0800222 self.dest_table = os.path.join(self.meta_dir, 'table')
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800223 self.dest_imageloader_json = os.path.join(self.meta_dir, IMAGELOADER_JSON)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700224
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700225 # Log out the member variable values initially set.
226 logging.debug('Initial internal values of DlcGenerator: %s',
Andrew67b5fa72020-02-05 14:14:48 -0800227 repr({k:str(i) for k, i in self.__dict__.items()}))
228
229 def CopyTempContentsToBuildDir(self):
230 """Copy the temp files to the build directory using sudo."""
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700231 src = self.temp_root.tempdir.rstrip('/') + '/.'
232 dst = self.install_root_dir
233 logging.info(
234 'Copy files from temporary directory (%s) to build directory (%s).',
235 src, dst)
236 cros_build_lib.sudo_run(['cp', '-dR', src, dst])
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700237
Xiaochu Liudeed0232018-06-26 10:25:34 -0700238 def SquashOwnerships(self, path):
239 """Squash the owernships & permissions for files.
240
241 Args:
242 path: (str) path that contains all files to be processed.
243 """
Mike Frysinger45602c72019-09-22 02:15:11 -0400244 cros_build_lib.sudo_run(['chown', '-R', '0:0', path])
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800245 cros_build_lib.sudo_run([
246 'find', path, '-exec', 'touch', '-h', '-t', '197001010000.00', '{}', '+'
247 ])
Xiaochu Liudeed0232018-06-26 10:25:34 -0700248
249 def CreateExt4Image(self):
250 """Create an ext4 image."""
251 with osutils.TempDir(prefix='dlc_') as temp_dir:
252 mount_point = os.path.join(temp_dir, 'mount_point')
Andrew67b5fa72020-02-05 14:14:48 -0800253 # Create the directory where the image is located if it doesn't exist.
254 osutils.SafeMakedirs(os.path.split(self.dest_image)[0])
Xiaochu Liudeed0232018-06-26 10:25:34 -0700255 # Create a raw image file.
256 with open(self.dest_image, 'w') as f:
257 f.truncate(self._BLOCKS * self._BLOCK_SIZE)
258 # Create an ext4 file system on the raw image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800259 cros_build_lib.run([
260 '/sbin/mkfs.ext4', '-b',
261 str(self._BLOCK_SIZE), '-O', '^has_journal', self.dest_image
262 ],
263 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700264 # Create the mount_point directory.
265 osutils.SafeMakedirs(mount_point)
266 # Mount the ext4 image.
267 osutils.MountDir(self.dest_image, mount_point, mount_opts=('loop', 'rw'))
Amin Hassanicc7ffce2019-01-11 14:57:52 -0800268
Xiaochu Liudeed0232018-06-26 10:25:34 -0700269 try:
Amin Hassani11a88cf2019-01-29 15:31:24 -0800270 self.SetupDlcImageFiles(mount_point)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700271 finally:
272 # Unmount the ext4 image.
273 osutils.UmountDir(mount_point)
274 # Shrink to minimum size.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800275 cros_build_lib.run(['/sbin/e2fsck', '-y', '-f', self.dest_image],
276 capture_output=True)
277 cros_build_lib.run(['/sbin/resize2fs', '-M', self.dest_image],
278 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700279
280 def CreateSquashfsImage(self):
281 """Create a squashfs image."""
282 with osutils.TempDir(prefix='dlc_') as temp_dir:
Amin Hassani22a25eb2019-01-11 14:25:02 -0800283 squashfs_root = os.path.join(temp_dir, 'squashfs-root')
Amin Hassani11a88cf2019-01-29 15:31:24 -0800284 self.SetupDlcImageFiles(squashfs_root)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800285
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800286 cros_build_lib.run([
287 'mksquashfs', squashfs_root, self.dest_image, '-4k-align', '-noappend'
288 ],
289 capture_output=True)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800290
291 # We changed the ownership and permissions of the squashfs_root
292 # directory. Now we need to remove it manually.
293 osutils.RmDir(squashfs_root, sudo=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700294
Amin Hassani11a88cf2019-01-29 15:31:24 -0800295 def SetupDlcImageFiles(self, dlc_dir):
296 """Prepares the directory dlc_dir with all the files a DLC needs.
297
298 Args:
299 dlc_dir: (str) The path to where to setup files inside the DLC.
300 """
301 dlc_root_dir = os.path.join(dlc_dir, self._DLC_ROOT_DIR)
302 osutils.SafeMakedirs(dlc_root_dir)
Jae Hoon Kimd14646b2019-08-21 14:49:26 -0700303 osutils.CopyDirContents(self.src_dir, dlc_root_dir, symlinks=True)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800304 self.PrepareLsbRelease(dlc_dir)
Andrew06a5f812020-01-23 08:08:32 -0800305 self.AddLicensingFile(dlc_dir)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800306 self.CollectExtraResources(dlc_dir)
307 self.SquashOwnerships(dlc_dir)
308
Amin Hassanid5742d32019-01-22 21:13:34 -0800309 def PrepareLsbRelease(self, dlc_dir):
310 """Prepare the file /etc/lsb-release in the DLC module.
311
312 This file is used dropping some identification parameters for the DLC.
313
314 Args:
Andrew06a5f812020-01-23 08:08:32 -0800315 dlc_dir: (str) The path to the mounted point during image creation.
Amin Hassanid5742d32019-01-22 21:13:34 -0800316 """
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800317 # Reading the platform APPID and creating the DLC APPID.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800318 platform_lsb_release = osutils.ReadFile(
319 os.path.join(self.sysroot, LSB_RELEASE))
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800320 app_id = None
321 for line in platform_lsb_release.split('\n'):
322 if line.startswith(cros_set_lsb_release.LSB_KEY_APPID_RELEASE):
323 app_id = line.split('=')[1]
324 if app_id is None:
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800325 raise Exception(
326 '%s does not have a valid key %s' %
327 (platform_lsb_release, cros_set_lsb_release.LSB_KEY_APPID_RELEASE))
Amin Hassanid5742d32019-01-22 21:13:34 -0800328
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400329 fields = (
Andrew67b5fa72020-02-05 14:14:48 -0800330 (DLC_ID_KEY, self.ebuild_params.dlc_id),
331 (DLC_PACKAGE_KEY, self.ebuild_params.dlc_package),
332 (DLC_NAME_KEY, self.ebuild_params.name),
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800333 # The DLC appid is generated by concatenating the platform appid with
334 # the DLC ID using an underscore. This pattern should never be changed
335 # once set otherwise it can break a lot of things!
Andrew67b5fa72020-02-05 14:14:48 -0800336 (DLC_APPID_KEY, '%s_%s' % (app_id, self.ebuild_params.dlc_id)),
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400337 )
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800338
339 lsb_release = os.path.join(dlc_dir, LSB_RELEASE)
340 osutils.SafeMakedirs(os.path.dirname(lsb_release))
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400341 content = ''.join('%s=%s\n' % (k, v) for k, v in fields)
Amin Hassanid5742d32019-01-22 21:13:34 -0800342 osutils.WriteFile(lsb_release, content)
343
Andrew06a5f812020-01-23 08:08:32 -0800344 def AddLicensingFile(self, dlc_dir):
345 """Add the licensing file for this DLC.
346
347 Args:
348 dlc_dir: (str) The path to the mounted point during image creation.
349 """
350 if not self.ebuild_params.fullnamerev:
351 return
352
353 licensing = licenses_lib.Licensing(self.board,
354 [self.ebuild_params.fullnamerev], True)
355 licensing.LoadPackageInfo()
356 licensing.ProcessPackageLicenses()
357 license_path = os.path.join(dlc_dir, LICENSE)
358 # The first (and only) item contains the values for |self.fullnamerev|.
359 _, license_txt = next(iter(licensing.GenerateLicenseText().items()))
360 osutils.WriteFile(license_path, license_txt)
361
Amin Hassani11a88cf2019-01-29 15:31:24 -0800362 def CollectExtraResources(self, dlc_dir):
363 """Collect the extra resources needed by the DLC module.
364
365 Look at the documentation around _EXTRA_RESOURCES.
366
367 Args:
Andrew06a5f812020-01-23 08:08:32 -0800368 dlc_dir: (str) The path to the mounted point during image creation.
Amin Hassani11a88cf2019-01-29 15:31:24 -0800369 """
370 for r in _EXTRA_RESOURCES:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800371 source_path = os.path.join(self.sysroot, r)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800372 target_path = os.path.join(dlc_dir, r)
373 osutils.SafeMakedirs(os.path.dirname(target_path))
374 shutil.copyfile(source_path, target_path)
375
Xiaochu Liudeed0232018-06-26 10:25:34 -0700376 def CreateImage(self):
377 """Create the image and copy the DLC files to it."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700378 logging.info('Creating the DLC image.')
Andrew67b5fa72020-02-05 14:14:48 -0800379 if self.ebuild_params.fs_type == _EXT4_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700380 self.CreateExt4Image()
Andrew67b5fa72020-02-05 14:14:48 -0800381 elif self.ebuild_params.fs_type == _SQUASHFS_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700382 self.CreateSquashfsImage()
383 else:
Andrew67b5fa72020-02-05 14:14:48 -0800384 raise ValueError('Wrong fs type: %s used:' % self.ebuild_params.fs_type)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700385
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700386 def VerifyImageSize(self):
Xiaochu Liu36b30592019-08-06 09:39:54 -0700387 """Verify the image can fit to the reserved file."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700388 logging.info('Verifying the DLC image size.')
389 image_bytes = os.path.getsize(self.dest_image)
Andrew67b5fa72020-02-05 14:14:48 -0800390 preallocated_bytes = (self.ebuild_params.pre_allocated_blocks *
391 self._BLOCK_SIZE)
Xiaochu Liu36b30592019-08-06 09:39:54 -0700392 # Verifies the actual size of the DLC image is NOT smaller than the
393 # preallocated space.
394 if preallocated_bytes < image_bytes:
395 raise ValueError(
396 'The DLC_PREALLOC_BLOCKS (%s) value set in DLC ebuild resulted in a '
397 'max size of DLC_PREALLOC_BLOCKS * 4K (%s) bytes the DLC image is '
398 'allowed to occupy. The value is smaller than the actual image size '
399 '(%s) required. Increase DLC_PREALLOC_BLOCKS in your ebuild to at '
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800400 'least %d.' %
Andrew67b5fa72020-02-05 14:14:48 -0800401 (self.ebuild_params.pre_allocated_blocks, preallocated_bytes,
402 image_bytes, self.GetOptimalImageBlockSize(image_bytes)))
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700403
404 def GetOptimalImageBlockSize(self, image_bytes):
405 """Given the image bytes, get the least amount of blocks required."""
406 return int(math.ceil(image_bytes / self._BLOCK_SIZE))
Xiaochu Liu36b30592019-08-06 09:39:54 -0700407
Xiaochu Liudeed0232018-06-26 10:25:34 -0700408 def GetImageloaderJsonContent(self, image_hash, table_hash, blocks):
409 """Return the content of imageloader.json file.
410
411 Args:
412 image_hash: (str) sha256 hash of the DLC image.
413 table_hash: (str) sha256 hash of the DLC table file.
414 blocks: (int) number of blocks in the DLC image.
415
416 Returns:
417 [str]: content of imageloader.json file.
418 """
419 return {
Andrew67b5fa72020-02-05 14:14:48 -0800420 'fs-type': self.ebuild_params.fs_type,
421 'id': self.ebuild_params.dlc_id,
422 'package': self.ebuild_params.dlc_package,
Xiaochu Liudeed0232018-06-26 10:25:34 -0700423 'image-sha256-hash': image_hash,
424 'image-type': 'dlc',
425 'is-removable': True,
426 'manifest-version': self._MANIFEST_VERSION,
Andrew67b5fa72020-02-05 14:14:48 -0800427 'name': self.ebuild_params.name,
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700428 'description': self.ebuild_params.description,
Andrew67b5fa72020-02-05 14:14:48 -0800429 'pre-allocated-size':
430 str(self.ebuild_params.pre_allocated_blocks * self._BLOCK_SIZE),
Jae Hoon Kimbd8ae6e2020-02-03 18:54:29 -0800431 'size': str(blocks * self._BLOCK_SIZE),
Xiaochu Liudeed0232018-06-26 10:25:34 -0700432 'table-sha256-hash': table_hash,
Andrew67b5fa72020-02-05 14:14:48 -0800433 'version': self.ebuild_params.version,
434 'preload-allowed': self.ebuild_params.preload,
Amin Hassani160e12e2020-04-13 14:29:36 -0700435 'used-by': self.ebuild_params.used_by,
Xiaochu Liudeed0232018-06-26 10:25:34 -0700436 }
437
438 def GenerateVerity(self):
439 """Generate verity parameters and hashes for the image."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700440 logging.info('Generating DLC image verity.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700441 with osutils.TempDir(prefix='dlc_') as temp_dir:
442 hash_tree = os.path.join(temp_dir, 'hash_tree')
443 # Get blocks in the image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800444 blocks = math.ceil(os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
445 result = cros_build_lib.run([
446 'verity', 'mode=create', 'alg=sha256', 'payload=' + self.dest_image,
447 'payload_blocks=' + str(blocks), 'hashtree=' + hash_tree,
448 'salt=random'
449 ],
450 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700451 table = result.output
452
453 # Append the merkle tree to the image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800454 osutils.WriteFile(
455 self.dest_image, osutils.ReadFile(hash_tree, mode='rb'), mode='a+b')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700456
457 # Write verity parameter to table file.
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400458 osutils.WriteFile(self.dest_table, table, mode='wb')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700459
460 # Compute image hash.
461 image_hash = HashFile(self.dest_image)
462 table_hash = HashFile(self.dest_table)
463 # Write image hash to imageloader.json file.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800464 blocks = math.ceil(os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700465 imageloader_json_content = self.GetImageloaderJsonContent(
466 image_hash, table_hash, int(blocks))
Mike Frysingerd0960812020-06-09 01:53:32 -0400467 pformat.json(imageloader_json_content, fp=self.dest_imageloader_json)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700468
469 def GenerateDLC(self):
470 """Generate a DLC artifact."""
Andrew67b5fa72020-02-05 14:14:48 -0800471 # Create directories.
472 osutils.SafeMakedirs(self.image_dir)
473 osutils.SafeMakedirs(self.meta_dir)
474
475 # Create the image into |self.temp_root| and copy the DLC files to it.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700476 self.CreateImage()
Andrew67b5fa72020-02-05 14:14:48 -0800477 # Verify the image created is within pre-allocated size.
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700478 self.VerifyImageSize()
Andrew67b5fa72020-02-05 14:14:48 -0800479 # Generate hash tree and other metadata and save them under
480 # |self.temp_root|.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700481 self.GenerateVerity()
Andrew67b5fa72020-02-05 14:14:48 -0800482 # Copy the files from |self.temp_root| into the build directory.
483 self.CopyTempContentsToBuildDir()
484
485 # Now that the image was successfully generated, delete |ebuild_params_path|
486 # to indicate that the image in the build directory is in sync with the
487 # files installed during the build_package phase.
488 ebuild_params_path = EbuildParams.GetParamsPath(
489 self.sysroot, self.ebuild_params.dlc_id, self.ebuild_params.dlc_package)
490 osutils.SafeUnlink(ebuild_params_path, sudo=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700491
492
Andrew67b5fa72020-02-05 14:14:48 -0800493def IsDlcPreloadingAllowed(dlc_id, dlc_build_dir):
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800494 """Validates that DLC and it's packages all were built with DLC_PRELOAD=true.
495
496 Args:
497 dlc_id: (str) DLC ID.
Andrew67b5fa72020-02-05 14:14:48 -0800498 dlc_build_dir: (str) the root path where DLC build files reside.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800499 """
500
Andrew67b5fa72020-02-05 14:14:48 -0800501 dlc_id_meta_dir = os.path.join(dlc_build_dir, dlc_id)
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800502 if not os.path.exists(dlc_id_meta_dir):
Andrew67b5fa72020-02-05 14:14:48 -0800503 logging.error('DLC build directory (%s) does not exist for preloading '
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800504 'check, will not preload', dlc_id_meta_dir)
505 return False
506
507 packages = os.listdir(dlc_id_meta_dir)
508 if not packages:
Andrew67b5fa72020-02-05 14:14:48 -0800509 logging.error('DLC ID build directory (%s) does not have any '
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800510 'packages, will not preload.', dlc_id_meta_dir)
511 return False
512
Andrew67b5fa72020-02-05 14:14:48 -0800513 for package in packages:
514 image_loader_json = os.path.join(dlc_id_meta_dir, package, DLC_TMP_META_DIR,
515 IMAGELOADER_JSON)
516 if not os.path.exists(image_loader_json):
517 logging.error('DLC metadata file (%s) does not exist, will not preload.',
518 image_loader_json)
519 return False
520 if not GetValueInJsonFile(json_path=image_loader_json,
521 key='preload-allowed', default_value=False):
522 return False
523 # All packages support preload.
524 return True
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800525
526
Andrew06a5f812020-01-23 08:08:32 -0800527def InstallDlcImages(sysroot, board, dlc_id=None, install_root_dir=None,
528 preload=False, rootfs=None, src_dir=None):
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800529 """Copies all DLC image files into the images directory.
530
531 Copies the DLC image files in the given build directory into the given DLC
532 image directory. If the DLC build directory does not exist, or there is no DLC
533 for that board, this function does nothing.
534
535 Args:
536 sysroot: Path to directory containing DLC images, e.g /build/<board>.
Andrew06a5f812020-01-23 08:08:32 -0800537 board: The target board we are building for.
Andrew67b5fa72020-02-05 14:14:48 -0800538 dlc_id: (str) DLC ID. If None, all the DLCs will be installed.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800539 install_root_dir: Path to DLC output directory, e.g.
Andrew67b5fa72020-02-05 14:14:48 -0800540 src/build/images/<board>/<version>. If None, the image will be generated
541 but will not be copied to a destination.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800542 preload: When true, only copies DLC(s) if built with DLC_PRELOAD=true.
Andrew67b5fa72020-02-05 14:14:48 -0800543 rootfs: (str) Path to the platform rootfs.
544 src_dir: (str) Path to the DLC source root directory.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800545 """
Andrew67b5fa72020-02-05 14:14:48 -0800546 dlc_build_dir = os.path.join(sysroot, DLC_BUILD_DIR)
547 if not os.path.exists(dlc_build_dir):
548 logging.info('DLC build directory (%s) does not exist, ignoring.',
549 dlc_build_dir)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800550 return
551
Andrew67b5fa72020-02-05 14:14:48 -0800552 if dlc_id is not None:
553 if not os.path.exists(os.path.join(dlc_build_dir, dlc_id)):
554 raise Exception(
555 'DLC "%s" does not exist in the build directory %s.' %
556 (dlc_id, dlc_build_dir))
557 dlc_ids = [dlc_id]
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800558 else:
Andrew67b5fa72020-02-05 14:14:48 -0800559 # Process all DLCs.
560 dlc_ids = os.listdir(dlc_build_dir)
561 if not dlc_ids:
562 logging.info('There are no DLC(s) to copy to output, ignoring.')
563 return
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800564
Andrew67b5fa72020-02-05 14:14:48 -0800565 logging.info('Detected the following DLCs: %s', ', '.join(dlc_ids))
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800566
Andrew67b5fa72020-02-05 14:14:48 -0800567 for d_id in dlc_ids:
568 dlc_id_path = os.path.join(dlc_build_dir, d_id)
569 dlc_packages = [direct for direct in os.listdir(dlc_id_path)
570 if os.path.isdir(os.path.join(dlc_id_path, direct))]
571 for d_package in dlc_packages:
572 logging.info('Building image: DLC %s', d_id)
Jae Hoon Kim264b8d22020-04-06 11:49:19 -0700573 params = EbuildParams.LoadEbuildParams(sysroot=sysroot, dlc_id=d_id,
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700574 dlc_package=d_package)
Andrew67b5fa72020-02-05 14:14:48 -0800575 # Because portage sandboxes every ebuild package during build_packages
576 # phase, we cannot delete the old image during that phase, but we can use
577 # the existence of the file |EBUILD_PARAMETERS| to know if the image
578 # has to be generated or not.
579 if not params:
580 logging.info('The ebuild parameters file (%s) for DLC (%s) does not '
581 'exist. This means that the image was already '
582 'generated and there is no need to create it again.',
583 EbuildParams.GetParamsPath(sysroot, d_id, d_package), d_id)
584 else:
585 dlc_generator = DlcGenerator(
586 src_dir=src_dir,
587 sysroot=sysroot,
588 install_root_dir=sysroot,
Andrew06a5f812020-01-23 08:08:32 -0800589 board=board,
Andrew67b5fa72020-02-05 14:14:48 -0800590 ebuild_params=params)
591 dlc_generator.GenerateDLC()
592
593 # Copy the dlc images to install_root_dir.
594 if install_root_dir:
595 if preload and not IsDlcPreloadingAllowed(d_id, dlc_build_dir):
596 logging.info('Skipping installation of DLC %s because the preload '
597 'flag is set and the DLC does not support preloading.',
598 d_id)
599 else:
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700600 osutils.SafeMakedirsNonRoot(install_root_dir)
Andrew67b5fa72020-02-05 14:14:48 -0800601 install_dlc_dir = os.path.join(install_root_dir, d_id, d_package)
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700602 osutils.SafeMakedirsNonRoot(install_dlc_dir)
603 source_dlc_dir = os.path.join(dlc_build_dir, d_id, d_package)
Andrew67b5fa72020-02-05 14:14:48 -0800604 for filepath in (os.path.join(source_dlc_dir, fname) for fname in
605 os.listdir(source_dlc_dir) if
606 fname.endswith('.img')):
607 logging.info('Copying DLC(%s) image from %s to %s: ', d_id,
608 filepath, install_dlc_dir)
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700609 shutil.copy(filepath, install_dlc_dir)
Andrew67b5fa72020-02-05 14:14:48 -0800610 logging.info('Done copying DLC to %s.', install_dlc_dir)
611 else:
612 logging.info('install_root_dir value was not provided. Copying dlc'
613 ' image skipped.')
614
615 # Create metadata directory in rootfs.
616 if rootfs:
617 meta_rootfs = os.path.join(rootfs, DLC_META_DIR, d_id, d_package)
618 osutils.SafeMakedirs(meta_rootfs, sudo=True)
619 # Copy the metadata files to rootfs.
620 meta_dir_src = os.path.join(dlc_build_dir, d_id, d_package,
621 DLC_TMP_META_DIR)
622 logging.info('Copying DLC(%s) metadata from %s to %s: ', d_id,
623 meta_dir_src, meta_rootfs)
624 # Use sudo_run since osutils.CopyDirContents doesn't support sudo.
625 cros_build_lib.sudo_run(['cp', '-dR',
626 meta_dir_src.rstrip('/') + '/.',
627 meta_rootfs], print_cmd=False, stderr=True)
628
629 else:
630 logging.info('rootfs value was not provided. Copying metadata skipped.')
631
632 logging.info('Done installing DLCs.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800633
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800634
Xiaochu Liudeed0232018-06-26 10:25:34 -0700635def GetParser():
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800636 """Creates an argument parser and returns it."""
Xiaochu Liudeed0232018-06-26 10:25:34 -0700637 parser = commandline.ArgumentParser(description=__doc__)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800638 # This script is used both for building an individual DLC or copying all final
639 # DLCs images to their final destination nearby chromiumsos_test_image.bin,
640 # etc. These two arguments are required in both cases.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800641 parser.add_argument(
642 '--sysroot',
643 type='path',
644 metavar='DIR',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800645 help="The root path to the board's build root, e.g. "
646 '/build/eve')
Andrew67b5fa72020-02-05 14:14:48 -0800647 # TODO(andrewlassalle): Remove src-dir in the future(2021?) if nobody uses it.
648 parser.add_argument(
649 '--src-dir',
650 type='path',
651 metavar='SRC_DIR_PATH',
652 help='Override the default Root directory path that contains all DLC '
653 'files to be packed.')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800654 parser.add_argument(
655 '--install-root-dir',
656 type='path',
657 metavar='DIR',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800658 help='If building a specific DLC, it is the root path to'
659 ' install DLC images (%s) and metadata (%s). Otherwise it'
660 ' is the target directory where the Chrome OS images gets'
661 ' dropped in build_image, e.g. '
Andrew67b5fa72020-02-05 14:14:48 -0800662 'src/build/images/<board>/latest.' % (DLC_BUILD_DIR, DLC_META_DIR))
Amin Hassani22a25eb2019-01-11 14:25:02 -0800663
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800664 one_dlc = parser.add_argument_group('Arguments required for building only '
665 'one DLC')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800666 one_dlc.add_argument(
Andrew67b5fa72020-02-05 14:14:48 -0800667 '--rootfs',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800668 type='path',
Andrew67b5fa72020-02-05 14:14:48 -0800669 metavar='ROOT_FS_PATH',
670 help='Path to the platform rootfs.')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800671 one_dlc.add_argument(
672 '--pre-allocated-blocks',
673 type=int,
674 metavar='PREALLOCATEDBLOCKS',
675 help='Number of blocks (block size is 4k) that need to'
676 'be pre-allocated on device.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800677 one_dlc.add_argument('--version', metavar='VERSION', help='DLC Version.')
678 one_dlc.add_argument('--id', metavar='ID', help='DLC ID (unique per DLC).')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800679 one_dlc.add_argument(
680 '--package',
681 metavar='PACKAGE',
682 help='The package ID that is unique within a DLC, One'
683 ' DLC cannot have duplicate package IDs.')
684 one_dlc.add_argument(
685 '--name', metavar='NAME', help='A human-readable name for the DLC.')
686 one_dlc.add_argument(
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700687 '--description',
688 help='The description for the DLC.')
689 one_dlc.add_argument(
Andrew06a5f812020-01-23 08:08:32 -0800690 '--board', metavar='BOARD', help='The target board we are building for.')
691 one_dlc.add_argument('--fullnamerev', metavar='FULL_NAME_REV',
692 help='The full ebuild package name.')
693 one_dlc.add_argument(
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800694 '--fs-type',
695 metavar='FS_TYPE',
696 default=_SQUASHFS_TYPE,
697 choices=(_SQUASHFS_TYPE, _EXT4_TYPE),
698 help='File system type of the image.')
699 one_dlc.add_argument(
700 '--preload',
701 default=False,
702 action='store_true',
703 help='Allow preloading of DLC.')
Andrew67b5fa72020-02-05 14:14:48 -0800704 one_dlc.add_argument(
Amin Hassani160e12e2020-04-13 14:29:36 -0700705 '--used-by', default=_USED_BY_SYSTEM,
706 choices=(_USED_BY_USER, _USED_BY_SYSTEM),
707 help='Defines how this DLC will be used so dlcservice can take proper '
708 'actions based on the type of usage. For example, if "user" is passed, '
709 'dlcservice does ref counting when DLC is installed/uninstalled. For '
710 '"system", there will be no such provisions.')
711 one_dlc.add_argument(
Andrew67b5fa72020-02-05 14:14:48 -0800712 '--build-package',
713 default=False,
714 action='store_true',
715 help='Flag to indicate if the script is executed during the '
716 'build_packages phase.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700717 return parser
718
719
Andrew67b5fa72020-02-05 14:14:48 -0800720def ValidateDlcIdentifier(parser, name):
Amin Hassanibc1a4792019-10-24 14:39:57 -0700721 """Validates the DLC identifiers like ID and package names.
722
723 The name specifications are:
724 - No underscore.
725 - First character should be only alphanumeric.
726 - Other characters can be alphanumeric and '-' (dash).
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800727 - Maximum length of 40 (MAX_ID_NAME) characters.
Amin Hassanibc1a4792019-10-24 14:39:57 -0700728
729 For more info see:
730 https://chromium.googlesource.com/chromiumos/platform2/+/master/dlcservice/docs/developer.md#create-a-dlc-module
731
732 Args:
Andrew67b5fa72020-02-05 14:14:48 -0800733 parser: Arguments parser.
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800734 name: The value of the string to be validated.
Amin Hassanibc1a4792019-10-24 14:39:57 -0700735 """
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800736 errors = []
737 if not name:
738 errors.append('Must not be empty.')
739 if not name[0].isalnum():
740 errors.append('Must start with alphanumeric character.')
741 if not re.match(r'^[a-zA-Z0-9][a-zA-Z0-9-]*$', name):
742 errors.append('Must only use alphanumeric and - (dash).')
743 if len(name) > MAX_ID_NAME:
744 errors.append('Must be within %d characters.' % MAX_ID_NAME)
745
746 if errors:
747 msg = '%s is invalid:\n%s' % (name, '\n'.join(errors))
Andrew67b5fa72020-02-05 14:14:48 -0800748 parser.error(msg)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700749
750
Andrew67b5fa72020-02-05 14:14:48 -0800751def ValidateArguments(parser, opts, req_flags, invalid_flags):
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800752 """Validates the correctness of the passed arguments.
753
754 Args:
Andrew67b5fa72020-02-05 14:14:48 -0800755 parser: Arguments parser.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800756 opts: Parsed arguments.
Andrew67b5fa72020-02-05 14:14:48 -0800757 req_flags: all the required flags.
758 invalid_flags: all the flags that are not allowed.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800759 """
760 # Make sure if the intention is to build one DLC, all the required arguments
Andrew67b5fa72020-02-05 14:14:48 -0800761 # are passed and none of the invalid ones are passed. This will ensure the
762 # script is called twice per DLC.
763 if opts.id:
764 if not all(vars(opts)[x] is not None for x in req_flags):
765 parser.error('If the intention is to build only one DLC, all the flags'
766 '%s required for it should be passed.' % req_flags)
767 if any(vars(opts)[x] is not None for x in invalid_flags):
768 parser.error('If the intention is to build only one DLC, all the flags'
769 '%s should be passed in the build_packages phase, not in '
770 'the build_image phase.' % invalid_flags)
771
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800772 if opts.fs_type == _EXT4_TYPE:
Andrew67b5fa72020-02-05 14:14:48 -0800773 parser.error('ext4 unsupported for DLC, see https://crbug.com/890060')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800774
Amin Hassanibc1a4792019-10-24 14:39:57 -0700775 if opts.id:
Andrew67b5fa72020-02-05 14:14:48 -0800776 ValidateDlcIdentifier(parser, opts.id)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700777 if opts.package:
Andrew67b5fa72020-02-05 14:14:48 -0800778 ValidateDlcIdentifier(parser, opts.package)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700779
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800780
Xiaochu Liudeed0232018-06-26 10:25:34 -0700781def main(argv):
Andrew67b5fa72020-02-05 14:14:48 -0800782 parser = GetParser()
783 opts = parser.parse_args(argv)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700784 opts.Freeze()
Andrew67b5fa72020-02-05 14:14:48 -0800785 per_dlc_req_args = ['id']
786 per_dlc_invalid_args = []
787 if opts.build_package:
788 per_dlc_req_args += ['pre_allocated_blocks', 'version', 'name',
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700789 'description', 'package', 'install_root_dir']
Andrew67b5fa72020-02-05 14:14:48 -0800790 per_dlc_invalid_args += ['src_dir', 'sysroot']
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800791 else:
Andrew06a5f812020-01-23 08:08:32 -0800792 per_dlc_req_args += ['sysroot', 'board']
Andrew67b5fa72020-02-05 14:14:48 -0800793 per_dlc_invalid_args += ['name', 'pre_allocated_blocks', 'version',
794 'package']
795
796 ValidateArguments(parser, opts, per_dlc_req_args, per_dlc_invalid_args)
797
798 if opts.build_package:
799 logging.info('Building package: DLC %s', opts.id)
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700800 params = EbuildParams(
801 dlc_id=opts.id,
802 dlc_package=opts.package,
803 fs_type=opts.fs_type,
804 name=opts.name,
805 description=opts.description,
806 pre_allocated_blocks=opts.pre_allocated_blocks,
807 version=opts.version,
Amin Hassani160e12e2020-04-13 14:29:36 -0700808 preload=opts.preload,
Andrew06a5f812020-01-23 08:08:32 -0800809 used_by=opts.used_by,
810 fullnamerev=opts.fullnamerev)
Andrew67b5fa72020-02-05 14:14:48 -0800811 params.StoreDlcParameters(install_root_dir=opts.install_root_dir, sudo=True)
812
813 else:
814 InstallDlcImages(
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800815 sysroot=opts.sysroot,
Andrew67b5fa72020-02-05 14:14:48 -0800816 dlc_id=opts.id,
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800817 install_root_dir=opts.install_root_dir,
Andrew67b5fa72020-02-05 14:14:48 -0800818 preload=opts.preload,
819 src_dir=opts.src_dir,
Andrew06a5f812020-01-23 08:08:32 -0800820 rootfs=opts.rootfs,
821 board=opts.board)