blob: 525c0ae4e111e47c1657a4be6a38ba88dc6c7f89 [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)
176 osutils.CopyDirContents(self.src_dir, dlc_root_dir)
177 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
202 fields = {
203 DLC_ID_KEY: self.dlc_id,
Amin Hassanib5a48042019-03-18 14:30:51 -0700204 DLC_PACKAGE_KEY: self.dlc_package,
Amin Hassanid5742d32019-01-22 21:13:34 -0800205 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!
209 DLC_APPID_KEY: '%s_%s' % (app_id, self.dlc_id),
Amin Hassanid5742d32019-01-22 21:13:34 -0800210 }
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))
Amin Hassanid5742d32019-01-22 21:13:34 -0800214 content = ''.join(['%s=%s\n' % (k, v) for k, v in fields.items()])
215 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.
304 osutils.WriteFile(self.dest_image, osutils.ReadFile(hash_tree), 'a+')
305
306 # Write verity parameter to table file.
307 osutils.WriteFile(self.dest_table, table)
308
309 # Compute image hash.
310 image_hash = HashFile(self.dest_image)
311 table_hash = HashFile(self.dest_table)
312 # Write image hash to imageloader.json file.
313 blocks = math.ceil(
314 os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
315 imageloader_json_content = self.GetImageloaderJsonContent(
316 image_hash, table_hash, int(blocks))
317 with open(self.dest_imageloader_json, 'w') as f:
318 json.dump(imageloader_json_content, f)
319
320 def GenerateDLC(self):
321 """Generate a DLC artifact."""
322 # Create the image and copy the DLC files to it.
323 self.CreateImage()
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700324 # Verify the image created is within preallocated size.
325 self.VerifyImageSize()
Xiaochu Liudeed0232018-06-26 10:25:34 -0700326 # Generate hash tree and other metadata.
327 self.GenerateVerity()
328
329
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800330def CopyAllDlcs(sysroot, install_root_dir):
331 """Copies all DLC image files into the images directory.
332
333 Copies the DLC image files in the given build directory into the given DLC
334 image directory. If the DLC build directory does not exist, or there is no DLC
335 for that board, this function does nothing.
336
337 Args:
338 sysroot: Path to directory containing DLC images, e.g /build/<board>.
339 install_root_dir: Path to DLC output directory,
340 e.g. src/build/images/<board>/<version>.
341 """
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800342 build_dir = os.path.join(sysroot, DLC_IMAGE_DIR)
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700343 output_dir = os.path.join(install_root_dir, 'dlc')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800344
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700345 if not os.path.exists(build_dir):
346 logging.info('DLC build directory (%s) does not exists, ignorning.',
347 build_dir)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800348 return
349
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700350 if not os.listdir(build_dir):
351 logging.info('There are no DLC(s) to copy to output, ignoring.')
352 return
353
354 logging.info('Copying all DLC images from %s to %s.', build_dir, output_dir)
Amin Hassani6c0228b2019-03-04 13:42:33 -0800355 logging.info('Detected the following DLCs: %s',
356 ', '.join(os.listdir(build_dir)))
357
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800358 osutils.SafeMakedirs(output_dir)
359 osutils.CopyDirContents(build_dir, output_dir)
360
Amin Hassani6c0228b2019-03-04 13:42:33 -0800361 logging.info('Done copying the DLCs to their destination.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800362
Xiaochu Liudeed0232018-06-26 10:25:34 -0700363def GetParser():
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800364 """Creates an argument parser and returns it."""
Xiaochu Liudeed0232018-06-26 10:25:34 -0700365 parser = commandline.ArgumentParser(description=__doc__)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800366 # This script is used both for building an individual DLC or copying all final
367 # DLCs images to their final destination nearby chromiumsos_test_image.bin,
368 # etc. These two arguments are required in both cases.
369 parser.add_argument('--sysroot', type='path', metavar='DIR', required=True,
370 help="The root path to the board's build root, e.g. "
Mike Frysinger80de5012019-08-01 14:10:53 -0400371 '/build/eve')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800372 parser.add_argument('--install-root-dir', type='path', metavar='DIR',
373 required=True,
374 help='If building a specific DLC, it is the root path to'
375 ' install DLC images (%s) and metadata (%s). Otherwise it'
376 ' is the target directory where the Chrome OS images gets'
377 ' dropped in build_image, e.g. '
378 'src/build/images/<board>/latest.' % (DLC_IMAGE_DIR,
379 DLC_META_DIR))
Amin Hassani22a25eb2019-01-11 14:25:02 -0800380
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800381 one_dlc = parser.add_argument_group('Arguments required for building only '
382 'one DLC')
383 one_dlc.add_argument('--src-dir', type='path', metavar='SRC_DIR_PATH',
384 help='Root directory path that contains all DLC files '
385 'to be packed.')
386 one_dlc.add_argument('--pre-allocated-blocks', type=int,
387 metavar='PREALLOCATEDBLOCKS',
388 help='Number of blocks (block size is 4k) that need to'
389 'be pre-allocated on device.')
390 one_dlc.add_argument('--version', metavar='VERSION', help='DLC Version.')
391 one_dlc.add_argument('--id', metavar='ID', help='DLC ID (unique per DLC).')
Amin Hassanib5a48042019-03-18 14:30:51 -0700392 one_dlc.add_argument('--package', metavar='PACKAGE',
393 help='The package ID that is unique within a DLC, One'
394 ' DLC cannot have duplicate package IDs.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800395 one_dlc.add_argument('--name', metavar='NAME',
396 help='A human-readable name for the DLC.')
397 one_dlc.add_argument('--fs-type', metavar='FS_TYPE', default=_SQUASHFS_TYPE,
398 choices=(_SQUASHFS_TYPE, _EXT4_TYPE),
399 help='File system type of the image.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700400 return parser
401
402
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800403def ValidateArguments(opts):
404 """Validates the correctness of the passed arguments.
405
406 Args:
407 opts: Parsed arguments.
408 """
409 # Make sure if the intention is to build one DLC, all the required arguments
410 # are passed.
411 per_dlc_req_args = ('src_dir', 'pre_allocated_blocks', 'version', 'id',
Amin Hassanib5a48042019-03-18 14:30:51 -0700412 'package', 'name')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800413 if (opts.id and
414 not all(vars(opts)[arg] is not None for arg in per_dlc_req_args)):
415 raise Exception('If the intention is to build only one DLC, all the flags'
416 '%s required for it should be passed .' % per_dlc_req_args)
417
418 if opts.fs_type == _EXT4_TYPE:
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700419 raise Exception('ext4 unsupported for DLC, see https://crbug.com/890060')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800420
421
Xiaochu Liudeed0232018-06-26 10:25:34 -0700422def main(argv):
423 opts = GetParser().parse_args(argv)
424 opts.Freeze()
425
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800426 ValidateArguments(opts)
Amin Hassani2af75a92019-01-22 21:07:45 -0800427
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800428 if opts.id:
429 logging.info('Building DLC %s', opts.id)
430 dlc_generator = DlcGenerator(src_dir=opts.src_dir,
431 sysroot=opts.sysroot,
432 install_root_dir=opts.install_root_dir,
433 fs_type=opts.fs_type,
434 pre_allocated_blocks=opts.pre_allocated_blocks,
435 version=opts.version,
436 dlc_id=opts.id,
Amin Hassanib5a48042019-03-18 14:30:51 -0700437 dlc_package=opts.package,
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800438 name=opts.name)
439 dlc_generator.GenerateDLC()
440 else:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800441 CopyAllDlcs(opts.sysroot, opts.install_root_dir)