blob: b7938734937ee46e3b70833648b41025dc1a8a4a [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.
5
6"""Script to generate a DLC (Downloadable Content) artifact."""
7
Mike Frysinger93e8ffa2019-07-03 20:24:18 -04008from __future__ import division
Xiaochu Liudeed0232018-06-26 10:25:34 -07009from __future__ import print_function
10
11import hashlib
12import json
13import math
14import os
Amin Hassani11a88cf2019-01-29 15:31:24 -080015import shutil
Xiaochu Liudeed0232018-06-26 10:25:34 -070016
17from chromite.lib import commandline
18from chromite.lib import cros_build_lib
Amin Hassanib97a5ee2019-01-23 14:44:43 -080019from chromite.lib import cros_logging as logging
Xiaochu Liudeed0232018-06-26 10:25:34 -070020from chromite.lib import osutils
21
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080022from chromite.scripts import cros_set_lsb_release
Xiaochu Liudeed0232018-06-26 10:25:34 -070023
Amin Hassani2af75a92019-01-22 21:07:45 -080024DLC_META_DIR = 'opt/google/dlc/'
25DLC_IMAGE_DIR = 'build/rootfs/dlc/'
Amin Hassanid5742d32019-01-22 21:13:34 -080026LSB_RELEASE = 'etc/lsb-release'
27
Amin Hassani11a88cf2019-01-29 15:31:24 -080028# This file has major and minor version numbers that the update_engine client
29# supports. These values are needed for generating a delta/full payload.
30UPDATE_ENGINE_CONF = 'etc/update_engine.conf'
31
32_EXTRA_RESOURCES = (
33 UPDATE_ENGINE_CONF,
34)
35
Amin Hassanid5742d32019-01-22 21:13:34 -080036DLC_ID_KEY = 'DLC_ID'
Amin Hassanib5a48042019-03-18 14:30:51 -070037DLC_PACKAGE_KEY = 'DLC_PACKAGE'
Amin Hassanid5742d32019-01-22 21:13:34 -080038DLC_NAME_KEY = 'DLC_NAME'
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080039DLC_APPID_KEY = 'DLC_RELEASE_APPID'
Amin Hassani2af75a92019-01-22 21:07:45 -080040
Amin Hassani22a25eb2019-01-11 14:25:02 -080041_SQUASHFS_TYPE = 'squashfs'
42_EXT4_TYPE = 'ext4'
43
Amin Hassanid5742d32019-01-22 21:13:34 -080044
Xiaochu Liudeed0232018-06-26 10:25:34 -070045def HashFile(file_path):
46 """Calculate the sha256 hash of a file.
47
48 Args:
49 file_path: (str) path to the file.
50
51 Returns:
52 [str]: The sha256 hash of the file.
53 """
54 sha256 = hashlib.sha256()
55 with open(file_path, 'rb') as f:
56 for b in iter(lambda: f.read(2048), b''):
57 sha256.update(b)
58 return sha256.hexdigest()
59
60
Amin Hassani174eb7e2019-01-18 11:11:24 -080061class DlcGenerator(object):
Xiaochu Liudeed0232018-06-26 10:25:34 -070062 """Object to generate DLC artifacts."""
63 # Block size for the DLC image.
64 # We use 4K for various reasons:
65 # 1. it's what imageloader (linux kernel) supports.
66 # 2. it's what verity supports.
67 _BLOCK_SIZE = 4096
68 # Blocks in the initial sparse image.
69 _BLOCKS = 500000
70 # Version of manifest file.
71 _MANIFEST_VERSION = 1
72
Amin Hassanicc7ffce2019-01-11 14:57:52 -080073 # The DLC root path inside the DLC module.
74 _DLC_ROOT_DIR = 'root'
75
Amin Hassanib97a5ee2019-01-23 14:44:43 -080076 def __init__(self, src_dir, sysroot, install_root_dir, fs_type,
Amin Hassanib5a48042019-03-18 14:30:51 -070077 pre_allocated_blocks, version, dlc_id, dlc_package, name):
Xiaochu Liudeed0232018-06-26 10:25:34 -070078 """Object initializer.
79
80 Args:
Xiaochu Liudeed0232018-06-26 10:25:34 -070081 src_dir: (str) path to the DLC source root directory.
Amin Hassanib97a5ee2019-01-23 14:44:43 -080082 sysroot: (str) The path to the build root directory.
Amin Hassani2af75a92019-01-22 21:07:45 -080083 install_root_dir: (str) The path to the root installation directory.
Xiaochu Liudeed0232018-06-26 10:25:34 -070084 fs_type: (str) file system type.
85 pre_allocated_blocks: (int) number of blocks pre-allocated on device.
86 version: (str) DLC version.
87 dlc_id: (str) DLC ID.
Amin Hassanib5a48042019-03-18 14:30:51 -070088 dlc_package: (str) DLC Package.
Xiaochu Liudeed0232018-06-26 10:25:34 -070089 name: (str) DLC name.
90 """
91 self.src_dir = src_dir
Amin Hassanib97a5ee2019-01-23 14:44:43 -080092 self.sysroot = sysroot
Amin Hassani2af75a92019-01-22 21:07:45 -080093 self.install_root_dir = install_root_dir
Xiaochu Liudeed0232018-06-26 10:25:34 -070094 self.fs_type = fs_type
95 self.pre_allocated_blocks = pre_allocated_blocks
96 self.version = version
97 self.dlc_id = dlc_id
Amin Hassanib5a48042019-03-18 14:30:51 -070098 self.dlc_package = dlc_package
Xiaochu Liudeed0232018-06-26 10:25:34 -070099 self.name = name
Amin Hassani2af75a92019-01-22 21:07:45 -0800100
101 self.meta_dir = os.path.join(self.install_root_dir, DLC_META_DIR,
Amin Hassanib5a48042019-03-18 14:30:51 -0700102 self.dlc_id, self.dlc_package)
Amin Hassani2af75a92019-01-22 21:07:45 -0800103 self.image_dir = os.path.join(self.install_root_dir, DLC_IMAGE_DIR,
Amin Hassanib5a48042019-03-18 14:30:51 -0700104 self.dlc_id, self.dlc_package)
Amin Hassani2af75a92019-01-22 21:07:45 -0800105 osutils.SafeMakedirs(self.meta_dir)
106 osutils.SafeMakedirs(self.image_dir)
107
Xiaochu Liudeed0232018-06-26 10:25:34 -0700108 # Create path for all final artifacts.
Amin Hassanib5a48042019-03-18 14:30:51 -0700109 self.dest_image = os.path.join(self.image_dir, 'dlc.img')
Amin Hassani2af75a92019-01-22 21:07:45 -0800110 self.dest_table = os.path.join(self.meta_dir, 'table')
111 self.dest_imageloader_json = os.path.join(self.meta_dir, 'imageloader.json')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700112
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700113 # Log out the member variable values initially set.
114 logging.debug('Initial internal values of DlcGenerator: %s',
115 json.dumps(self.__dict__, sort_keys=True))
116
Xiaochu Liudeed0232018-06-26 10:25:34 -0700117 def SquashOwnerships(self, path):
118 """Squash the owernships & permissions for files.
119
120 Args:
121 path: (str) path that contains all files to be processed.
122 """
Mike Frysinger45602c72019-09-22 02:15:11 -0400123 cros_build_lib.sudo_run(['chown', '-R', '0:0', path])
124 cros_build_lib.sudo_run(
Xiaochu Liudeed0232018-06-26 10:25:34 -0700125 ['find', path, '-exec', 'touch', '-h', '-t', '197001010000.00', '{}',
126 '+'])
127
128 def CreateExt4Image(self):
129 """Create an ext4 image."""
130 with osutils.TempDir(prefix='dlc_') as temp_dir:
131 mount_point = os.path.join(temp_dir, 'mount_point')
132 # Create a raw image file.
133 with open(self.dest_image, 'w') as f:
134 f.truncate(self._BLOCKS * self._BLOCK_SIZE)
135 # Create an ext4 file system on the raw image.
Mike Frysinger45602c72019-09-22 02:15:11 -0400136 cros_build_lib.run(
Xiaochu Liudeed0232018-06-26 10:25:34 -0700137 ['/sbin/mkfs.ext4', '-b', str(self._BLOCK_SIZE), '-O',
138 '^has_journal', self.dest_image], capture_output=True)
139 # Create the mount_point directory.
140 osutils.SafeMakedirs(mount_point)
141 # Mount the ext4 image.
142 osutils.MountDir(self.dest_image, mount_point, mount_opts=('loop', 'rw'))
Amin Hassanicc7ffce2019-01-11 14:57:52 -0800143
Xiaochu Liudeed0232018-06-26 10:25:34 -0700144 try:
Amin Hassani11a88cf2019-01-29 15:31:24 -0800145 self.SetupDlcImageFiles(mount_point)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700146 finally:
147 # Unmount the ext4 image.
148 osutils.UmountDir(mount_point)
149 # Shrink to minimum size.
Mike Frysinger45602c72019-09-22 02:15:11 -0400150 cros_build_lib.run(
Xiaochu Liudeed0232018-06-26 10:25:34 -0700151 ['/sbin/e2fsck', '-y', '-f', self.dest_image], capture_output=True)
Mike Frysinger45602c72019-09-22 02:15:11 -0400152 cros_build_lib.run(
Xiaochu Liudeed0232018-06-26 10:25:34 -0700153 ['/sbin/resize2fs', '-M', self.dest_image], capture_output=True)
154
155 def CreateSquashfsImage(self):
156 """Create a squashfs image."""
157 with osutils.TempDir(prefix='dlc_') as temp_dir:
Amin Hassani22a25eb2019-01-11 14:25:02 -0800158 squashfs_root = os.path.join(temp_dir, 'squashfs-root')
Amin Hassani11a88cf2019-01-29 15:31:24 -0800159 self.SetupDlcImageFiles(squashfs_root)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800160
Mike Frysinger45602c72019-09-22 02:15:11 -0400161 cros_build_lib.run(['mksquashfs', squashfs_root, self.dest_image,
162 '-4k-align', '-noappend'], capture_output=True)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800163
164 # We changed the ownership and permissions of the squashfs_root
165 # directory. Now we need to remove it manually.
166 osutils.RmDir(squashfs_root, sudo=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700167
Amin Hassani11a88cf2019-01-29 15:31:24 -0800168 def SetupDlcImageFiles(self, dlc_dir):
169 """Prepares the directory dlc_dir with all the files a DLC needs.
170
171 Args:
172 dlc_dir: (str) The path to where to setup files inside the DLC.
173 """
174 dlc_root_dir = os.path.join(dlc_dir, self._DLC_ROOT_DIR)
175 osutils.SafeMakedirs(dlc_root_dir)
Jae Hoon Kimd14646b2019-08-21 14:49:26 -0700176 osutils.CopyDirContents(self.src_dir, dlc_root_dir, symlinks=True)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800177 self.PrepareLsbRelease(dlc_dir)
178 self.CollectExtraResources(dlc_dir)
179 self.SquashOwnerships(dlc_dir)
180
Amin Hassanid5742d32019-01-22 21:13:34 -0800181 def PrepareLsbRelease(self, dlc_dir):
182 """Prepare the file /etc/lsb-release in the DLC module.
183
184 This file is used dropping some identification parameters for the DLC.
185
186 Args:
187 dlc_dir: (str) The path to root directory of the DLC. e.g. mounted point
188 when we are creating the image.
189 """
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800190 # Reading the platform APPID and creating the DLC APPID.
191 platform_lsb_release = osutils.ReadFile(os.path.join(self.sysroot,
192 LSB_RELEASE))
193 app_id = None
194 for line in platform_lsb_release.split('\n'):
195 if line.startswith(cros_set_lsb_release.LSB_KEY_APPID_RELEASE):
196 app_id = line.split('=')[1]
197 if app_id is None:
198 raise Exception('%s does not have a valid key %s' %
199 (platform_lsb_release,
200 cros_set_lsb_release.LSB_KEY_APPID_RELEASE))
Amin Hassanid5742d32019-01-22 21:13:34 -0800201
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400202 fields = (
203 (DLC_ID_KEY, self.dlc_id),
204 (DLC_PACKAGE_KEY, self.dlc_package),
205 (DLC_NAME_KEY, self.name),
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800206 # The DLC appid is generated by concatenating the platform appid with
207 # the DLC ID using an underscore. This pattern should never be changed
208 # once set otherwise it can break a lot of things!
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400209 (DLC_APPID_KEY, '%s_%s' % (app_id, self.dlc_id)),
210 )
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800211
212 lsb_release = os.path.join(dlc_dir, LSB_RELEASE)
213 osutils.SafeMakedirs(os.path.dirname(lsb_release))
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400214 content = ''.join('%s=%s\n' % (k, v) for k, v in fields)
Amin Hassanid5742d32019-01-22 21:13:34 -0800215 osutils.WriteFile(lsb_release, content)
216
Amin Hassani11a88cf2019-01-29 15:31:24 -0800217 def CollectExtraResources(self, dlc_dir):
218 """Collect the extra resources needed by the DLC module.
219
220 Look at the documentation around _EXTRA_RESOURCES.
221
222 Args:
223 dlc_dir: (str) The path to root directory of the DLC. e.g. mounted point
224 when we are creating the image.
225 """
226 for r in _EXTRA_RESOURCES:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800227 source_path = os.path.join(self.sysroot, r)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800228 target_path = os.path.join(dlc_dir, r)
229 osutils.SafeMakedirs(os.path.dirname(target_path))
230 shutil.copyfile(source_path, target_path)
231
Xiaochu Liudeed0232018-06-26 10:25:34 -0700232 def CreateImage(self):
233 """Create the image and copy the DLC files to it."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700234 logging.info('Creating the DLC image.')
Amin Hassani22a25eb2019-01-11 14:25:02 -0800235 if self.fs_type == _EXT4_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700236 self.CreateExt4Image()
Amin Hassani22a25eb2019-01-11 14:25:02 -0800237 elif self.fs_type == _SQUASHFS_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700238 self.CreateSquashfsImage()
239 else:
240 raise ValueError('Wrong fs type: %s used:' % self.fs_type)
241
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700242 def VerifyImageSize(self):
Xiaochu Liu36b30592019-08-06 09:39:54 -0700243 """Verify the image can fit to the reserved file."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700244 logging.info('Verifying the DLC image size.')
245 image_bytes = os.path.getsize(self.dest_image)
Xiaochu Liu36b30592019-08-06 09:39:54 -0700246 preallocated_bytes = self.pre_allocated_blocks * self._BLOCK_SIZE
247 # Verifies the actual size of the DLC image is NOT smaller than the
248 # preallocated space.
249 if preallocated_bytes < image_bytes:
250 raise ValueError(
251 'The DLC_PREALLOC_BLOCKS (%s) value set in DLC ebuild resulted in a '
252 'max size of DLC_PREALLOC_BLOCKS * 4K (%s) bytes the DLC image is '
253 'allowed to occupy. The value is smaller than the actual image size '
254 '(%s) required. Increase DLC_PREALLOC_BLOCKS in your ebuild to at '
255 'least %d.' % (
256 self.pre_allocated_blocks, preallocated_bytes, image_bytes,
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700257 self.GetOptimalImageBlockSize(image_bytes)))
258
259 def GetOptimalImageBlockSize(self, image_bytes):
260 """Given the image bytes, get the least amount of blocks required."""
261 return int(math.ceil(image_bytes / self._BLOCK_SIZE))
Xiaochu Liu36b30592019-08-06 09:39:54 -0700262
Xiaochu Liudeed0232018-06-26 10:25:34 -0700263 def GetImageloaderJsonContent(self, image_hash, table_hash, blocks):
264 """Return the content of imageloader.json file.
265
266 Args:
267 image_hash: (str) sha256 hash of the DLC image.
268 table_hash: (str) sha256 hash of the DLC table file.
269 blocks: (int) number of blocks in the DLC image.
270
271 Returns:
272 [str]: content of imageloader.json file.
273 """
274 return {
275 'fs-type': self.fs_type,
276 'id': self.dlc_id,
Amin Hassanib5a48042019-03-18 14:30:51 -0700277 'package': self.dlc_package,
Xiaochu Liudeed0232018-06-26 10:25:34 -0700278 'image-sha256-hash': image_hash,
279 'image-type': 'dlc',
280 'is-removable': True,
281 'manifest-version': self._MANIFEST_VERSION,
282 'name': self.name,
283 'pre-allocated-size': self.pre_allocated_blocks * self._BLOCK_SIZE,
284 'size': blocks * self._BLOCK_SIZE,
285 'table-sha256-hash': table_hash,
286 'version': self.version,
287 }
288
289 def GenerateVerity(self):
290 """Generate verity parameters and hashes for the image."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700291 logging.info('Generating DLC image verity.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700292 with osutils.TempDir(prefix='dlc_') as temp_dir:
293 hash_tree = os.path.join(temp_dir, 'hash_tree')
294 # Get blocks in the image.
295 blocks = math.ceil(
296 os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
Mike Frysinger45602c72019-09-22 02:15:11 -0400297 result = cros_build_lib.run(
Xiaochu Liudeed0232018-06-26 10:25:34 -0700298 ['verity', 'mode=create', 'alg=sha256', 'payload=' + self.dest_image,
299 'payload_blocks=' + str(blocks), 'hashtree=' + hash_tree,
300 'salt=random'], capture_output=True)
301 table = result.output
302
303 # Append the merkle tree to the image.
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400304 osutils.WriteFile(self.dest_image, osutils.ReadFile(hash_tree, mode='rb'),
305 mode='a+b')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700306
307 # Write verity parameter to table file.
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400308 osutils.WriteFile(self.dest_table, table, mode='wb')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700309
310 # Compute image hash.
311 image_hash = HashFile(self.dest_image)
312 table_hash = HashFile(self.dest_table)
313 # Write image hash to imageloader.json file.
314 blocks = math.ceil(
315 os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
316 imageloader_json_content = self.GetImageloaderJsonContent(
317 image_hash, table_hash, int(blocks))
318 with open(self.dest_imageloader_json, 'w') as f:
319 json.dump(imageloader_json_content, f)
320
321 def GenerateDLC(self):
322 """Generate a DLC artifact."""
323 # Create the image and copy the DLC files to it.
324 self.CreateImage()
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700325 # Verify the image created is within preallocated size.
326 self.VerifyImageSize()
Xiaochu Liudeed0232018-06-26 10:25:34 -0700327 # Generate hash tree and other metadata.
328 self.GenerateVerity()
329
330
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800331def CopyAllDlcs(sysroot, install_root_dir):
332 """Copies all DLC image files into the images directory.
333
334 Copies the DLC image files in the given build directory into the given DLC
335 image directory. If the DLC build directory does not exist, or there is no DLC
336 for that board, this function does nothing.
337
338 Args:
339 sysroot: Path to directory containing DLC images, e.g /build/<board>.
340 install_root_dir: Path to DLC output directory,
341 e.g. src/build/images/<board>/<version>.
342 """
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800343 build_dir = os.path.join(sysroot, DLC_IMAGE_DIR)
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700344 output_dir = os.path.join(install_root_dir, 'dlc')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800345
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700346 if not os.path.exists(build_dir):
347 logging.info('DLC build directory (%s) does not exists, ignorning.',
348 build_dir)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800349 return
350
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700351 if not os.listdir(build_dir):
352 logging.info('There are no DLC(s) to copy to output, ignoring.')
353 return
354
355 logging.info('Copying all DLC images from %s to %s.', build_dir, output_dir)
Amin Hassani6c0228b2019-03-04 13:42:33 -0800356 logging.info('Detected the following DLCs: %s',
357 ', '.join(os.listdir(build_dir)))
358
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800359 osutils.SafeMakedirs(output_dir)
360 osutils.CopyDirContents(build_dir, output_dir)
361
Amin Hassani6c0228b2019-03-04 13:42:33 -0800362 logging.info('Done copying the DLCs to their destination.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800363
Xiaochu Liudeed0232018-06-26 10:25:34 -0700364def GetParser():
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800365 """Creates an argument parser and returns it."""
Xiaochu Liudeed0232018-06-26 10:25:34 -0700366 parser = commandline.ArgumentParser(description=__doc__)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800367 # This script is used both for building an individual DLC or copying all final
368 # DLCs images to their final destination nearby chromiumsos_test_image.bin,
369 # etc. These two arguments are required in both cases.
370 parser.add_argument('--sysroot', type='path', metavar='DIR', required=True,
371 help="The root path to the board's build root, e.g. "
Mike Frysinger80de5012019-08-01 14:10:53 -0400372 '/build/eve')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800373 parser.add_argument('--install-root-dir', type='path', metavar='DIR',
374 required=True,
375 help='If building a specific DLC, it is the root path to'
376 ' install DLC images (%s) and metadata (%s). Otherwise it'
377 ' is the target directory where the Chrome OS images gets'
378 ' dropped in build_image, e.g. '
379 'src/build/images/<board>/latest.' % (DLC_IMAGE_DIR,
380 DLC_META_DIR))
Amin Hassani22a25eb2019-01-11 14:25:02 -0800381
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800382 one_dlc = parser.add_argument_group('Arguments required for building only '
383 'one DLC')
384 one_dlc.add_argument('--src-dir', type='path', metavar='SRC_DIR_PATH',
385 help='Root directory path that contains all DLC files '
386 'to be packed.')
387 one_dlc.add_argument('--pre-allocated-blocks', type=int,
388 metavar='PREALLOCATEDBLOCKS',
389 help='Number of blocks (block size is 4k) that need to'
390 'be pre-allocated on device.')
391 one_dlc.add_argument('--version', metavar='VERSION', help='DLC Version.')
392 one_dlc.add_argument('--id', metavar='ID', help='DLC ID (unique per DLC).')
Amin Hassanib5a48042019-03-18 14:30:51 -0700393 one_dlc.add_argument('--package', metavar='PACKAGE',
394 help='The package ID that is unique within a DLC, One'
395 ' DLC cannot have duplicate package IDs.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800396 one_dlc.add_argument('--name', metavar='NAME',
397 help='A human-readable name for the DLC.')
398 one_dlc.add_argument('--fs-type', metavar='FS_TYPE', default=_SQUASHFS_TYPE,
399 choices=(_SQUASHFS_TYPE, _EXT4_TYPE),
400 help='File system type of the image.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700401 return parser
402
403
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800404def ValidateArguments(opts):
405 """Validates the correctness of the passed arguments.
406
407 Args:
408 opts: Parsed arguments.
409 """
410 # Make sure if the intention is to build one DLC, all the required arguments
411 # are passed.
412 per_dlc_req_args = ('src_dir', 'pre_allocated_blocks', 'version', 'id',
Amin Hassanib5a48042019-03-18 14:30:51 -0700413 'package', 'name')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800414 if (opts.id and
415 not all(vars(opts)[arg] is not None for arg in per_dlc_req_args)):
416 raise Exception('If the intention is to build only one DLC, all the flags'
417 '%s required for it should be passed .' % per_dlc_req_args)
418
419 if opts.fs_type == _EXT4_TYPE:
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700420 raise Exception('ext4 unsupported for DLC, see https://crbug.com/890060')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800421
422
Xiaochu Liudeed0232018-06-26 10:25:34 -0700423def main(argv):
424 opts = GetParser().parse_args(argv)
425 opts.Freeze()
426
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800427 ValidateArguments(opts)
Amin Hassani2af75a92019-01-22 21:07:45 -0800428
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800429 if opts.id:
430 logging.info('Building DLC %s', opts.id)
431 dlc_generator = DlcGenerator(src_dir=opts.src_dir,
432 sysroot=opts.sysroot,
433 install_root_dir=opts.install_root_dir,
434 fs_type=opts.fs_type,
435 pre_allocated_blocks=opts.pre_allocated_blocks,
436 version=opts.version,
437 dlc_id=opts.id,
Amin Hassanib5a48042019-03-18 14:30:51 -0700438 dlc_package=opts.package,
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800439 name=opts.name)
440 dlc_generator.GenerateDLC()
441 else:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800442 CopyAllDlcs(opts.sysroot, opts.install_root_dir)