diff options
Diffstat (limited to 'scripts/contrib/image-manifest')
| -rwxr-xr-x | scripts/contrib/image-manifest | 523 |
1 files changed, 0 insertions, 523 deletions
diff --git a/scripts/contrib/image-manifest b/scripts/contrib/image-manifest deleted file mode 100755 index 4d65a99258..0000000000 --- a/scripts/contrib/image-manifest +++ /dev/null | |||
| @@ -1,523 +0,0 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | |||
| 3 | # Script to extract information from image manifests | ||
| 4 | # | ||
| 5 | # Copyright (C) 2018 Intel Corporation | ||
| 6 | # Copyright (C) 2021 Wind River Systems, Inc. | ||
| 7 | # | ||
| 8 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 9 | # | ||
| 10 | |||
| 11 | import sys | ||
| 12 | import os | ||
| 13 | import argparse | ||
| 14 | import logging | ||
| 15 | import json | ||
| 16 | import shutil | ||
| 17 | import tempfile | ||
| 18 | import tarfile | ||
| 19 | from collections import OrderedDict | ||
| 20 | |||
| 21 | scripts_path = os.path.dirname(__file__) | ||
| 22 | lib_path = scripts_path + '/../lib' | ||
| 23 | sys.path = sys.path + [lib_path] | ||
| 24 | |||
| 25 | import scriptutils | ||
| 26 | logger = scriptutils.logger_create(os.path.basename(__file__)) | ||
| 27 | |||
| 28 | import argparse_oe | ||
| 29 | import scriptpath | ||
| 30 | bitbakepath = scriptpath.add_bitbake_lib_path() | ||
| 31 | if not bitbakepath: | ||
| 32 | logger.error("Unable to find bitbake by searching parent directory of this script or PATH") | ||
| 33 | sys.exit(1) | ||
| 34 | logger.debug('Using standard bitbake path %s' % bitbakepath) | ||
| 35 | scriptpath.add_oe_lib_path() | ||
| 36 | |||
| 37 | import bb.tinfoil | ||
| 38 | import bb.utils | ||
| 39 | import oe.utils | ||
| 40 | import oe.recipeutils | ||
| 41 | |||
| 42 | def get_pkg_list(manifest): | ||
| 43 | pkglist = [] | ||
| 44 | with open(manifest, 'r') as f: | ||
| 45 | for line in f: | ||
| 46 | linesplit = line.split() | ||
| 47 | if len(linesplit) == 3: | ||
| 48 | # manifest file | ||
| 49 | pkglist.append(linesplit[0]) | ||
| 50 | elif len(linesplit) == 1: | ||
| 51 | # build dependency file | ||
| 52 | pkglist.append(linesplit[0]) | ||
| 53 | return sorted(pkglist) | ||
| 54 | |||
| 55 | def list_packages(args): | ||
| 56 | pkglist = get_pkg_list(args.manifest) | ||
| 57 | for pkg in pkglist: | ||
| 58 | print('%s' % pkg) | ||
| 59 | |||
| 60 | def pkg2recipe(tinfoil, pkg): | ||
| 61 | if "-native" in pkg: | ||
| 62 | logger.info('skipping %s' % pkg) | ||
| 63 | return None | ||
| 64 | |||
| 65 | pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR') | ||
| 66 | pkgdatafile = os.path.join(pkgdata_dir, 'runtime-reverse', pkg) | ||
| 67 | logger.debug('pkgdatafile %s' % pkgdatafile) | ||
| 68 | try: | ||
| 69 | f = open(pkgdatafile, 'r') | ||
| 70 | for line in f: | ||
| 71 | if line.startswith('PN:'): | ||
| 72 | recipe = line.split(':', 1)[1].strip() | ||
| 73 | return recipe | ||
| 74 | except Exception: | ||
| 75 | logger.warning('%s is missing' % pkgdatafile) | ||
| 76 | return None | ||
| 77 | |||
| 78 | def get_recipe_list(manifest, tinfoil): | ||
| 79 | pkglist = get_pkg_list(manifest) | ||
| 80 | recipelist = [] | ||
| 81 | for pkg in pkglist: | ||
| 82 | recipe = pkg2recipe(tinfoil,pkg) | ||
| 83 | if recipe: | ||
| 84 | if not recipe in recipelist: | ||
| 85 | recipelist.append(recipe) | ||
| 86 | |||
| 87 | return sorted(recipelist) | ||
| 88 | |||
| 89 | def list_recipes(args): | ||
| 90 | import bb.tinfoil | ||
| 91 | with bb.tinfoil.Tinfoil() as tinfoil: | ||
| 92 | tinfoil.logger.setLevel(logger.getEffectiveLevel()) | ||
| 93 | tinfoil.prepare(config_only=True) | ||
| 94 | recipelist = get_recipe_list(args.manifest, tinfoil) | ||
| 95 | for recipe in sorted(recipelist): | ||
| 96 | print('%s' % recipe) | ||
| 97 | |||
| 98 | def list_layers(args): | ||
| 99 | |||
| 100 | def find_git_repo(pth): | ||
| 101 | checkpth = pth | ||
| 102 | while checkpth != os.sep: | ||
| 103 | if os.path.exists(os.path.join(checkpth, '.git')): | ||
| 104 | return checkpth | ||
| 105 | checkpth = os.path.dirname(checkpth) | ||
| 106 | return None | ||
| 107 | |||
| 108 | def get_git_remote_branch(repodir): | ||
| 109 | try: | ||
| 110 | stdout, _ = bb.process.run(['git', 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], cwd=repodir) | ||
| 111 | except bb.process.ExecutionError as e: | ||
| 112 | stdout = None | ||
| 113 | if stdout: | ||
| 114 | return stdout.strip() | ||
| 115 | else: | ||
| 116 | return None | ||
| 117 | |||
| 118 | def get_git_head_commit(repodir): | ||
| 119 | try: | ||
| 120 | stdout, _ = bb.process.run(['git', 'rev-parse', 'HEAD'], cwd=repodir) | ||
| 121 | except bb.process.ExecutionError as e: | ||
| 122 | stdout = None | ||
| 123 | if stdout: | ||
| 124 | return stdout.strip() | ||
| 125 | else: | ||
| 126 | return None | ||
| 127 | |||
| 128 | def get_git_repo_url(repodir, remote='origin'): | ||
| 129 | import bb.process | ||
| 130 | # Try to get upstream repo location from origin remote | ||
| 131 | try: | ||
| 132 | stdout, _ = bb.process.run(['git', 'remote', '-v'], cwd=repodir) | ||
| 133 | except bb.process.ExecutionError as e: | ||
| 134 | stdout = None | ||
| 135 | if stdout: | ||
| 136 | for line in stdout.splitlines(): | ||
| 137 | splitline = line.split() | ||
| 138 | if len(splitline) > 1: | ||
| 139 | if splitline[0] == remote and scriptutils.is_src_url(splitline[1]): | ||
| 140 | return splitline[1] | ||
| 141 | return None | ||
| 142 | |||
| 143 | with bb.tinfoil.Tinfoil() as tinfoil: | ||
| 144 | tinfoil.logger.setLevel(logger.getEffectiveLevel()) | ||
| 145 | tinfoil.prepare(config_only=False) | ||
| 146 | layers = OrderedDict() | ||
| 147 | for layerdir in tinfoil.config_data.getVar('BBLAYERS').split(): | ||
| 148 | layerdata = OrderedDict() | ||
| 149 | layername = os.path.basename(layerdir) | ||
| 150 | logger.debug('layername %s, layerdir %s' % (layername, layerdir)) | ||
| 151 | if layername in layers: | ||
| 152 | logger.warning('layername %s is not unique in configuration' % layername) | ||
| 153 | layername = os.path.basename(os.path.dirname(layerdir)) + '_' + os.path.basename(layerdir) | ||
| 154 | logger.debug('trying layername %s' % layername) | ||
| 155 | if layername in layers: | ||
| 156 | logger.error('Layer name %s is not unique in configuration' % layername) | ||
| 157 | sys.exit(2) | ||
| 158 | repodir = find_git_repo(layerdir) | ||
| 159 | if repodir: | ||
| 160 | remotebranch = get_git_remote_branch(repodir) | ||
| 161 | remote = 'origin' | ||
| 162 | if remotebranch and '/' in remotebranch: | ||
| 163 | rbsplit = remotebranch.split('/', 1) | ||
| 164 | layerdata['actual_branch'] = rbsplit[1] | ||
| 165 | remote = rbsplit[0] | ||
| 166 | layerdata['vcs_url'] = get_git_repo_url(repodir, remote) | ||
| 167 | if os.path.abspath(repodir) != os.path.abspath(layerdir): | ||
| 168 | layerdata['vcs_subdir'] = os.path.relpath(layerdir, repodir) | ||
| 169 | commit = get_git_head_commit(repodir) | ||
| 170 | if commit: | ||
| 171 | layerdata['vcs_commit'] = commit | ||
| 172 | layers[layername] = layerdata | ||
| 173 | |||
| 174 | json.dump(layers, args.output, indent=2) | ||
| 175 | |||
| 176 | def get_recipe(args): | ||
| 177 | with bb.tinfoil.Tinfoil() as tinfoil: | ||
| 178 | tinfoil.logger.setLevel(logger.getEffectiveLevel()) | ||
| 179 | tinfoil.prepare(config_only=True) | ||
| 180 | |||
| 181 | recipe = pkg2recipe(tinfoil, args.package) | ||
| 182 | print(' %s package provided by %s' % (args.package, recipe)) | ||
| 183 | |||
| 184 | def pkg_dependencies(args): | ||
| 185 | def get_recipe_info(tinfoil, recipe): | ||
| 186 | try: | ||
| 187 | info = tinfoil.get_recipe_info(recipe) | ||
| 188 | except Exception: | ||
| 189 | logger.error('Failed to get recipe info for: %s' % recipe) | ||
| 190 | sys.exit(1) | ||
| 191 | if not info: | ||
| 192 | logger.warning('No recipe info found for: %s' % recipe) | ||
| 193 | sys.exit(1) | ||
| 194 | append_files = tinfoil.get_file_appends(info.fn) | ||
| 195 | appends = True | ||
| 196 | data = tinfoil.parse_recipe_file(info.fn, appends, append_files) | ||
| 197 | data.pn = info.pn | ||
| 198 | data.pv = info.pv | ||
| 199 | return data | ||
| 200 | |||
| 201 | def find_dependencies(tinfoil, assume_provided, recipe_info, packages, rn, order): | ||
| 202 | spaces = ' ' * order | ||
| 203 | data = recipe_info[rn] | ||
| 204 | if args.native: | ||
| 205 | logger.debug('%s- %s' % (spaces, data.pn)) | ||
| 206 | elif "-native" not in data.pn: | ||
| 207 | if "cross" not in data.pn: | ||
| 208 | logger.debug('%s- %s' % (spaces, data.pn)) | ||
| 209 | |||
| 210 | depends = [] | ||
| 211 | for dep in data.depends: | ||
| 212 | if dep not in assume_provided: | ||
| 213 | depends.append(dep) | ||
| 214 | |||
| 215 | # First find all dependencies not in package list. | ||
| 216 | for dep in depends: | ||
| 217 | if dep not in packages: | ||
| 218 | packages.append(dep) | ||
| 219 | dep_data = get_recipe_info(tinfoil, dep) | ||
| 220 | # Do this once now to reduce the number of bitbake calls. | ||
| 221 | dep_data.depends = dep_data.getVar('DEPENDS').split() | ||
| 222 | recipe_info[dep] = dep_data | ||
| 223 | |||
| 224 | # Then recursively analyze all of the dependencies for the current recipe. | ||
| 225 | for dep in depends: | ||
| 226 | find_dependencies(tinfoil, assume_provided, recipe_info, packages, dep, order + 1) | ||
| 227 | |||
| 228 | with bb.tinfoil.Tinfoil() as tinfoil: | ||
| 229 | tinfoil.logger.setLevel(logger.getEffectiveLevel()) | ||
| 230 | tinfoil.prepare() | ||
| 231 | |||
| 232 | assume_provided = tinfoil.config_data.getVar('ASSUME_PROVIDED').split() | ||
| 233 | logger.debug('assumed provided:') | ||
| 234 | for ap in sorted(assume_provided): | ||
| 235 | logger.debug(' - %s' % ap) | ||
| 236 | |||
| 237 | recipe = pkg2recipe(tinfoil, args.package) | ||
| 238 | data = get_recipe_info(tinfoil, recipe) | ||
| 239 | data.depends = [] | ||
| 240 | depends = data.getVar('DEPENDS').split() | ||
| 241 | for dep in depends: | ||
| 242 | if dep not in assume_provided: | ||
| 243 | data.depends.append(dep) | ||
| 244 | |||
| 245 | recipe_info = dict([(recipe, data)]) | ||
| 246 | packages = [] | ||
| 247 | find_dependencies(tinfoil, assume_provided, recipe_info, packages, recipe, order=1) | ||
| 248 | |||
| 249 | print('\nThe following packages are required to build %s' % recipe) | ||
| 250 | for p in sorted(packages): | ||
| 251 | data = recipe_info[p] | ||
| 252 | if "-native" not in data.pn: | ||
| 253 | if "cross" not in data.pn: | ||
| 254 | print(" %s (%s)" % (data.pn,p)) | ||
| 255 | |||
| 256 | if args.native: | ||
| 257 | print('\nThe following native packages are required to build %s' % recipe) | ||
| 258 | for p in sorted(packages): | ||
| 259 | data = recipe_info[p] | ||
| 260 | if "-native" in data.pn: | ||
| 261 | print(" %s(%s)" % (data.pn,p)) | ||
| 262 | if "cross" in data.pn: | ||
| 263 | print(" %s(%s)" % (data.pn,p)) | ||
| 264 | |||
| 265 | def default_config(): | ||
| 266 | vlist = OrderedDict() | ||
| 267 | vlist['PV'] = 'yes' | ||
| 268 | vlist['SUMMARY'] = 'no' | ||
| 269 | vlist['DESCRIPTION'] = 'no' | ||
| 270 | vlist['SECTION'] = 'no' | ||
| 271 | vlist['LICENSE'] = 'yes' | ||
| 272 | vlist['HOMEPAGE'] = 'no' | ||
| 273 | vlist['BUGTRACKER'] = 'no' | ||
| 274 | vlist['PROVIDES'] = 'no' | ||
| 275 | vlist['BBCLASSEXTEND'] = 'no' | ||
| 276 | vlist['DEPENDS'] = 'no' | ||
| 277 | vlist['PACKAGECONFIG'] = 'no' | ||
| 278 | vlist['SRC_URI'] = 'yes' | ||
| 279 | vlist['SRCREV'] = 'yes' | ||
| 280 | vlist['EXTRA_OECONF'] = 'no' | ||
| 281 | vlist['EXTRA_OESCONS'] = 'no' | ||
| 282 | vlist['EXTRA_OECMAKE'] = 'no' | ||
| 283 | vlist['EXTRA_OEMESON'] = 'no' | ||
| 284 | |||
| 285 | clist = OrderedDict() | ||
| 286 | clist['variables'] = vlist | ||
| 287 | clist['filepath'] = 'no' | ||
| 288 | clist['sha256sum'] = 'no' | ||
| 289 | clist['layerdir'] = 'no' | ||
| 290 | clist['layer'] = 'no' | ||
| 291 | clist['inherits'] = 'no' | ||
| 292 | clist['source_urls'] = 'no' | ||
| 293 | clist['packageconfig_opts'] = 'no' | ||
| 294 | clist['patches'] = 'no' | ||
| 295 | clist['packagedir'] = 'no' | ||
| 296 | return clist | ||
| 297 | |||
| 298 | def dump_config(args): | ||
| 299 | config = default_config() | ||
| 300 | f = open('default_config.json', 'w') | ||
| 301 | json.dump(config, f, indent=2) | ||
| 302 | logger.info('Default config list dumped to default_config.json') | ||
| 303 | |||
| 304 | def export_manifest_info(args): | ||
| 305 | |||
| 306 | def handle_value(value): | ||
| 307 | if value: | ||
| 308 | return oe.utils.squashspaces(value) | ||
| 309 | else: | ||
| 310 | return value | ||
| 311 | |||
| 312 | if args.config: | ||
| 313 | logger.debug('config: %s' % args.config) | ||
| 314 | f = open(args.config, 'r') | ||
| 315 | config = json.load(f, object_pairs_hook=OrderedDict) | ||
| 316 | else: | ||
| 317 | config = default_config() | ||
| 318 | if logger.isEnabledFor(logging.DEBUG): | ||
| 319 | print('Configuration:') | ||
| 320 | json.dump(config, sys.stdout, indent=2) | ||
| 321 | print('') | ||
| 322 | |||
| 323 | tmpoutdir = tempfile.mkdtemp(prefix=os.path.basename(__file__)+'-') | ||
| 324 | logger.debug('tmp dir: %s' % tmpoutdir) | ||
| 325 | |||
| 326 | # export manifest | ||
| 327 | shutil.copy2(args.manifest,os.path.join(tmpoutdir, "manifest")) | ||
| 328 | |||
| 329 | with bb.tinfoil.Tinfoil(tracking=True) as tinfoil: | ||
| 330 | tinfoil.logger.setLevel(logger.getEffectiveLevel()) | ||
| 331 | tinfoil.prepare(config_only=False) | ||
| 332 | |||
| 333 | pkglist = get_pkg_list(args.manifest) | ||
| 334 | # export pkg list | ||
| 335 | f = open(os.path.join(tmpoutdir, "pkgs"), 'w') | ||
| 336 | for pkg in pkglist: | ||
| 337 | f.write('%s\n' % pkg) | ||
| 338 | f.close() | ||
| 339 | |||
| 340 | recipelist = [] | ||
| 341 | for pkg in pkglist: | ||
| 342 | recipe = pkg2recipe(tinfoil,pkg) | ||
| 343 | if recipe: | ||
| 344 | if not recipe in recipelist: | ||
| 345 | recipelist.append(recipe) | ||
| 346 | recipelist.sort() | ||
| 347 | # export recipe list | ||
| 348 | f = open(os.path.join(tmpoutdir, "recipes"), 'w') | ||
| 349 | for recipe in recipelist: | ||
| 350 | f.write('%s\n' % recipe) | ||
| 351 | f.close() | ||
| 352 | |||
| 353 | try: | ||
| 354 | rvalues = OrderedDict() | ||
| 355 | for pn in sorted(recipelist): | ||
| 356 | logger.debug('Package: %s' % pn) | ||
| 357 | rd = tinfoil.parse_recipe(pn) | ||
| 358 | |||
| 359 | rvalues[pn] = OrderedDict() | ||
| 360 | |||
| 361 | for varname in config['variables']: | ||
| 362 | if config['variables'][varname] == 'yes': | ||
| 363 | rvalues[pn][varname] = handle_value(rd.getVar(varname)) | ||
| 364 | |||
| 365 | fpth = rd.getVar('FILE') | ||
| 366 | layerdir = oe.recipeutils.find_layerdir(fpth) | ||
| 367 | if config['filepath'] == 'yes': | ||
| 368 | rvalues[pn]['filepath'] = os.path.relpath(fpth, layerdir) | ||
| 369 | if config['sha256sum'] == 'yes': | ||
| 370 | rvalues[pn]['sha256sum'] = bb.utils.sha256_file(fpth) | ||
| 371 | |||
| 372 | if config['layerdir'] == 'yes': | ||
| 373 | rvalues[pn]['layerdir'] = layerdir | ||
| 374 | |||
| 375 | if config['layer'] == 'yes': | ||
| 376 | rvalues[pn]['layer'] = os.path.basename(layerdir) | ||
| 377 | |||
| 378 | if config['inherits'] == 'yes': | ||
| 379 | gr = set(tinfoil.config_data.getVar("__inherit_cache") or []) | ||
| 380 | lr = set(rd.getVar("__inherit_cache") or []) | ||
| 381 | rvalues[pn]['inherits'] = sorted({os.path.splitext(os.path.basename(r))[0] for r in lr if r not in gr}) | ||
| 382 | |||
| 383 | if config['source_urls'] == 'yes': | ||
| 384 | rvalues[pn]['source_urls'] = [] | ||
| 385 | for url in (rd.getVar('SRC_URI') or '').split(): | ||
| 386 | if not url.startswith('file://'): | ||
| 387 | url = url.split(';')[0] | ||
| 388 | rvalues[pn]['source_urls'].append(url) | ||
| 389 | |||
| 390 | if config['packageconfig_opts'] == 'yes': | ||
| 391 | rvalues[pn]['packageconfig_opts'] = OrderedDict() | ||
| 392 | for key in rd.getVarFlags('PACKAGECONFIG').keys(): | ||
| 393 | if key == 'doc': | ||
| 394 | continue | ||
| 395 | rvalues[pn]['packageconfig_opts'][key] = rd.getVarFlag('PACKAGECONFIG', key) | ||
| 396 | |||
| 397 | if config['patches'] == 'yes': | ||
| 398 | patches = oe.recipeutils.get_recipe_patches(rd) | ||
| 399 | rvalues[pn]['patches'] = [] | ||
| 400 | if patches: | ||
| 401 | recipeoutdir = os.path.join(tmpoutdir, pn, 'patches') | ||
| 402 | bb.utils.mkdirhier(recipeoutdir) | ||
| 403 | for patch in patches: | ||
| 404 | # Patches may be in other layers too | ||
| 405 | patchlayerdir = oe.recipeutils.find_layerdir(patch) | ||
| 406 | # patchlayerdir will be None for remote patches, which we ignore | ||
| 407 | # (since currently they are considered as part of sources) | ||
| 408 | if patchlayerdir: | ||
| 409 | rvalues[pn]['patches'].append((os.path.basename(patchlayerdir), os.path.relpath(patch, patchlayerdir))) | ||
| 410 | shutil.copy(patch, recipeoutdir) | ||
| 411 | |||
| 412 | if config['packagedir'] == 'yes': | ||
| 413 | pn_dir = os.path.join(tmpoutdir, pn) | ||
| 414 | bb.utils.mkdirhier(pn_dir) | ||
| 415 | f = open(os.path.join(pn_dir, 'recipe.json'), 'w') | ||
| 416 | json.dump(rvalues[pn], f, indent=2) | ||
| 417 | f.close() | ||
| 418 | |||
| 419 | with open(os.path.join(tmpoutdir, 'recipes.json'), 'w') as f: | ||
| 420 | json.dump(rvalues, f, indent=2) | ||
| 421 | |||
| 422 | if args.output: | ||
| 423 | outname = os.path.basename(args.output) | ||
| 424 | else: | ||
| 425 | outname = os.path.splitext(os.path.basename(args.manifest))[0] | ||
| 426 | if outname.endswith('.tar.gz'): | ||
| 427 | outname = outname[:-7] | ||
| 428 | elif outname.endswith('.tgz'): | ||
| 429 | outname = outname[:-4] | ||
| 430 | |||
| 431 | tarfn = outname | ||
| 432 | if tarfn.endswith(os.sep): | ||
| 433 | tarfn = tarfn[:-1] | ||
| 434 | if not tarfn.endswith(('.tar.gz', '.tgz')): | ||
| 435 | tarfn += '.tar.gz' | ||
| 436 | with open(tarfn, 'wb') as f: | ||
| 437 | with tarfile.open(None, "w:gz", f) as tar: | ||
| 438 | tar.add(tmpoutdir, outname) | ||
| 439 | finally: | ||
| 440 | shutil.rmtree(tmpoutdir) | ||
| 441 | |||
| 442 | |||
| 443 | def main(): | ||
| 444 | parser = argparse_oe.ArgumentParser(description="Image manifest utility", | ||
| 445 | epilog="Use %(prog)s <subcommand> --help to get help on a specific command") | ||
| 446 | parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true') | ||
| 447 | parser.add_argument('-q', '--quiet', help='Print only errors', action='store_true') | ||
| 448 | subparsers = parser.add_subparsers(dest="subparser_name", title='subcommands', metavar='<subcommand>') | ||
| 449 | subparsers.required = True | ||
| 450 | |||
| 451 | # get recipe info | ||
| 452 | parser_get_recipes = subparsers.add_parser('recipe-info', | ||
| 453 | help='Get recipe info', | ||
| 454 | description='Get recipe information for a package') | ||
| 455 | parser_get_recipes.add_argument('package', help='Package name') | ||
| 456 | parser_get_recipes.set_defaults(func=get_recipe) | ||
| 457 | |||
| 458 | # list runtime dependencies | ||
| 459 | parser_pkg_dep = subparsers.add_parser('list-depends', | ||
| 460 | help='List dependencies', | ||
| 461 | description='List dependencies required to build the package') | ||
| 462 | parser_pkg_dep.add_argument('--native', help='also print native and cross packages', action='store_true') | ||
| 463 | parser_pkg_dep.add_argument('package', help='Package name') | ||
| 464 | parser_pkg_dep.set_defaults(func=pkg_dependencies) | ||
| 465 | |||
| 466 | # list recipes | ||
| 467 | parser_recipes = subparsers.add_parser('list-recipes', | ||
| 468 | help='List recipes producing packages within an image', | ||
| 469 | description='Lists recipes producing the packages that went into an image, using the manifest and pkgdata') | ||
| 470 | parser_recipes.add_argument('manifest', help='Manifest file') | ||
| 471 | parser_recipes.set_defaults(func=list_recipes) | ||
| 472 | |||
| 473 | # list packages | ||
| 474 | parser_packages = subparsers.add_parser('list-packages', | ||
| 475 | help='List packages within an image', | ||
| 476 | description='Lists packages that went into an image, using the manifest') | ||
| 477 | parser_packages.add_argument('manifest', help='Manifest file') | ||
| 478 | parser_packages.set_defaults(func=list_packages) | ||
| 479 | |||
| 480 | # list layers | ||
| 481 | parser_layers = subparsers.add_parser('list-layers', | ||
| 482 | help='List included layers', | ||
| 483 | description='Lists included layers') | ||
| 484 | parser_layers.add_argument('-o', '--output', help='Output file - defaults to stdout if not specified', | ||
| 485 | default=sys.stdout, type=argparse.FileType('w')) | ||
| 486 | parser_layers.set_defaults(func=list_layers) | ||
| 487 | |||
| 488 | # dump default configuration file | ||
| 489 | parser_dconfig = subparsers.add_parser('dump-config', | ||
| 490 | help='Dump default config', | ||
| 491 | description='Dump default config to default_config.json') | ||
| 492 | parser_dconfig.set_defaults(func=dump_config) | ||
| 493 | |||
| 494 | # export recipe info for packages in manifest | ||
| 495 | parser_export = subparsers.add_parser('manifest-info', | ||
| 496 | help='Export recipe info for a manifest', | ||
| 497 | description='Export recipe information using the manifest') | ||
| 498 | parser_export.add_argument('-c', '--config', help='load config from json file') | ||
| 499 | parser_export.add_argument('-o', '--output', help='Output file (tarball) - defaults to manifest name if not specified') | ||
| 500 | parser_export.add_argument('manifest', help='Manifest file') | ||
| 501 | parser_export.set_defaults(func=export_manifest_info) | ||
| 502 | |||
| 503 | args = parser.parse_args() | ||
| 504 | |||
| 505 | if args.debug: | ||
| 506 | logger.setLevel(logging.DEBUG) | ||
| 507 | logger.debug("Debug Enabled") | ||
| 508 | elif args.quiet: | ||
| 509 | logger.setLevel(logging.ERROR) | ||
| 510 | |||
| 511 | ret = args.func(args) | ||
| 512 | |||
| 513 | return ret | ||
| 514 | |||
| 515 | |||
| 516 | if __name__ == "__main__": | ||
| 517 | try: | ||
| 518 | ret = main() | ||
| 519 | except Exception: | ||
| 520 | ret = 1 | ||
| 521 | import traceback | ||
| 522 | traceback.print_exc() | ||
| 523 | sys.exit(ret) | ||
