summaryrefslogtreecommitdiffstats
path: root/bitbake/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/bin')
-rwxr-xr-xbitbake/bin/bitbake-layers261
1 files changed, 110 insertions, 151 deletions
diff --git a/bitbake/bin/bitbake-layers b/bitbake/bin/bitbake-layers
index 98794981a0..2622bc0927 100755
--- a/bitbake/bin/bitbake-layers
+++ b/bitbake/bin/bitbake-layers
@@ -5,7 +5,7 @@
5# See the help output for details on available commands. 5# See the help output for details on available commands.
6 6
7# Copyright (C) 2011 Mentor Graphics Corporation 7# Copyright (C) 2011 Mentor Graphics Corporation
8# Copyright (C) 2012 Intel Corporation 8# Copyright (C) 2011-2015 Intel Corporation
9# 9#
10# This program is free software; you can redistribute it and/or modify 10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as 11# it under the terms of the GNU General Public License version 2 as
@@ -20,12 +20,12 @@
20# with this program; if not, write to the Free Software Foundation, Inc., 20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 22
23import cmd
24import logging 23import logging
25import os 24import os
26import sys 25import sys
27import fnmatch 26import fnmatch
28from collections import defaultdict 27from collections import defaultdict
28import argparse
29import re 29import re
30 30
31bindir = os.path.dirname(__file__) 31bindir = os.path.dirname(__file__)
@@ -42,23 +42,11 @@ import bb.tinfoil
42logger = logging.getLogger('BitBake') 42logger = logging.getLogger('BitBake')
43 43
44 44
45def main(args):
46 cmds = Commands()
47 if args:
48 # Allow user to specify e.g. show-layers instead of show_layers
49 args = [args[0].replace('-', '_')] + args[1:]
50 cmds.onecmd(' '.join(args))
51 else:
52 cmds.do_help('')
53 return cmds.returncode
54
55 45
56class Commands(cmd.Cmd): 46class Commands():
57 def __init__(self): 47 def __init__(self):
58 self.bbhandler = None 48 self.bbhandler = None
59 self.returncode = 0
60 self.bblayers = [] 49 self.bblayers = []
61 cmd.Cmd.__init__(self)
62 50
63 def init_bbhandler(self, config_only = False): 51 def init_bbhandler(self, config_only = False):
64 if not self.bbhandler: 52 if not self.bbhandler:
@@ -66,27 +54,6 @@ class Commands(cmd.Cmd):
66 self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split() 54 self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split()
67 self.bbhandler.prepare(config_only) 55 self.bbhandler.prepare(config_only)
68 56
69 def default(self, line):
70 """Handle unrecognised commands"""
71 sys.stderr.write("Unrecognised command or option\n")
72 self.do_help('')
73
74 def do_help(self, topic):
75 """display general help or help on a specified command"""
76 if topic:
77 sys.stdout.write('%s: ' % topic)
78 cmd.Cmd.do_help(self, topic.replace('-', '_'))
79 else:
80 sys.stdout.write("usage: bitbake-layers <command> [arguments]\n\n")
81 sys.stdout.write("Available commands:\n")
82 procnames = list(set(self.get_names()))
83 for procname in procnames:
84 if procname[:3] == 'do_':
85 sys.stdout.write(" %s\n" % procname[3:].replace('_', '-'))
86 doc = getattr(self, procname).__doc__
87 if doc:
88 sys.stdout.write(" %s\n" % doc.splitlines()[0])
89
90 def do_show_layers(self, args): 57 def do_show_layers(self, args):
91 """show current configured layers""" 58 """show current configured layers"""
92 self.init_bbhandler(config_only = True) 59 self.init_bbhandler(config_only = True)
@@ -103,29 +70,25 @@ class Commands(cmd.Cmd):
103 logger.plain("%s %s %d" % (layername.ljust(20), layerdir.ljust(40), layerpri)) 70 logger.plain("%s %s %d" % (layername.ljust(20), layerdir.ljust(40), layerpri))
104 71
105 72
106 def do_add_layer(self, dirname): 73 def do_add_layer(self, args):
107 """Add a layer to bblayers.conf 74 """Add a layer to bblayers.conf
108 75
109usage: add-layer <layerdir> 76Adds the specified layer to bblayers.conf
110""" 77"""
111 if not dirname: 78 layerdir = os.path.abspath(args.layerdir)
112 sys.stderr.write("Please specify the layer directory to add\n")
113 return
114
115 layerdir = os.path.abspath(dirname)
116 if not os.path.exists(layerdir): 79 if not os.path.exists(layerdir):
117 sys.stderr.write("Specified layer directory doesn't exist\n") 80 sys.stderr.write("Specified layer directory doesn't exist\n")
118 return 81 return 1
119 82
120 layer_conf = os.path.join(layerdir, 'conf', 'layer.conf') 83 layer_conf = os.path.join(layerdir, 'conf', 'layer.conf')
121 if not os.path.exists(layer_conf): 84 if not os.path.exists(layer_conf):
122 sys.stderr.write("Specified layer directory doesn't contain a conf/layer.conf file\n") 85 sys.stderr.write("Specified layer directory doesn't contain a conf/layer.conf file\n")
123 return 86 return 1
124 87
125 bblayers_conf = os.path.join('conf', 'bblayers.conf') 88 bblayers_conf = os.path.join('conf', 'bblayers.conf')
126 if not os.path.exists(bblayers_conf): 89 if not os.path.exists(bblayers_conf):
127 sys.stderr.write("Unable to find bblayers.conf\n") 90 sys.stderr.write("Unable to find bblayers.conf\n")
128 return 91 return 1
129 92
130 (notadded, _) = bb.utils.edit_bblayers_conf(bblayers_conf, layerdir, None) 93 (notadded, _) = bb.utils.edit_bblayers_conf(bblayers_conf, layerdir, None)
131 if notadded: 94 if notadded:
@@ -133,28 +96,25 @@ usage: add-layer <layerdir>
133 sys.stderr.write("Specified layer %s is already in BBLAYERS\n" % item) 96 sys.stderr.write("Specified layer %s is already in BBLAYERS\n" % item)
134 97
135 98
136 def do_remove_layer(self, dirname): 99 def do_remove_layer(self, args):
137 """Remove a layer from bblayers.conf 100 """Remove a layer from bblayers.conf
138 101
139usage: remove-layer <layerdir> 102Removes the specified layer from bblayers.conf
140""" 103"""
141 if not dirname:
142 sys.stderr.write("Please specify the layer directory to remove\n")
143 return
144
145 bblayers_conf = os.path.join('conf', 'bblayers.conf') 104 bblayers_conf = os.path.join('conf', 'bblayers.conf')
146 if not os.path.exists(bblayers_conf): 105 if not os.path.exists(bblayers_conf):
147 sys.stderr.write("Unable to find bblayers.conf\n") 106 sys.stderr.write("Unable to find bblayers.conf\n")
148 return 107 return 1
149 108
150 if dirname.startswith('*'): 109 if args.layerdir.startswith('*'):
151 layerdir = dirname 110 layerdir = dirname
152 else: 111 else:
153 layerdir = os.path.abspath(dirname) 112 layerdir = os.path.abspath(args.layerdir)
154 (_, notremoved) = bb.utils.edit_bblayers_conf(bblayers_conf, None, layerdir) 113 (_, notremoved) = bb.utils.edit_bblayers_conf(bblayers_conf, None, layerdir)
155 if notremoved: 114 if notremoved:
156 for item in notremoved: 115 for item in notremoved:
157 sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item) 116 sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item)
117 return 1
158 118
159 119
160 def version_str(self, pe, pv, pr = None): 120 def version_str(self, pe, pv, pr = None):
@@ -169,32 +129,13 @@ usage: remove-layer <layerdir>
169 def do_show_overlayed(self, args): 129 def do_show_overlayed(self, args):
170 """list overlayed recipes (where the same recipe exists in another layer) 130 """list overlayed recipes (where the same recipe exists in another layer)
171 131
172usage: show-overlayed [-f] [-s]
173
174Lists the names of overlayed recipes and the available versions in each 132Lists the names of overlayed recipes and the available versions in each
175layer, with the preferred version first. Note that skipped recipes that 133layer, with the preferred version first. Note that skipped recipes that
176are overlayed will also be listed, with a " (skipped)" suffix. 134are overlayed will also be listed, with a " (skipped)" suffix.
177
178Options:
179 -f instead of the default formatting, list filenames of higher priority
180 recipes with the ones they overlay indented underneath
181 -s only list overlayed recipes where the version is the same
182""" 135"""
183 self.init_bbhandler() 136 self.init_bbhandler()
184 137
185 show_filenames = False 138 items_listed = self.list_recipes('Overlayed recipes', None, True, args.same_version, args.filenames, True)
186 show_same_ver_only = False
187 for arg in args.split():
188 if arg == '-f':
189 show_filenames = True
190 elif arg == '-s':
191 show_same_ver_only = True
192 else:
193 sys.stderr.write("show-overlayed: invalid option %s\n" % arg)
194 self.do_help('')
195 return
196
197 items_listed = self.list_recipes('Overlayed recipes', None, True, show_same_ver_only, show_filenames, True)
198 139
199 # Check for overlayed .bbclass files 140 # Check for overlayed .bbclass files
200 classes = defaultdict(list) 141 classes = defaultdict(list)
@@ -221,7 +162,7 @@ Options:
221 overlayed_class_found = True 162 overlayed_class_found = True
222 163
223 mainfile = bb.utils.which(bbpath, os.path.join('classes', classfile)) 164 mainfile = bb.utils.which(bbpath, os.path.join('classes', classfile))
224 if show_filenames: 165 if args.filenames:
225 logger.plain('%s' % mainfile) 166 logger.plain('%s' % mainfile)
226 else: 167 else:
227 # We effectively have to guess the layer here 168 # We effectively have to guess the layer here
@@ -235,7 +176,7 @@ Options:
235 for classdir in classdirs: 176 for classdir in classdirs:
236 fullpath = os.path.join(classdir, classfile) 177 fullpath = os.path.join(classdir, classfile)
237 if fullpath != mainfile: 178 if fullpath != mainfile:
238 if show_filenames: 179 if args.filenames:
239 print(' %s' % fullpath) 180 print(' %s' % fullpath)
240 else: 181 else:
241 print(' %s' % self.get_layer_name(os.path.dirname(classdir))) 182 print(' %s' % self.get_layer_name(os.path.dirname(classdir)))
@@ -250,38 +191,15 @@ Options:
250 def do_show_recipes(self, args): 191 def do_show_recipes(self, args):
251 """list available recipes, showing the layer they are provided by 192 """list available recipes, showing the layer they are provided by
252 193
253usage: show-recipes [-f] [-m] [pnspec] 194Lists the names of recipes and the available versions in each
254
255Lists the names of overlayed recipes and the available versions in each
256layer, with the preferred version first. Optionally you may specify 195layer, with the preferred version first. Optionally you may specify
257pnspec to match a specified recipe name (supports wildcards). Note that 196pnspec to match a specified recipe name (supports wildcards). Note that
258skipped recipes will also be listed, with a " (skipped)" suffix. 197skipped recipes will also be listed, with a " (skipped)" suffix.
259
260Options:
261 -f instead of the default formatting, list filenames of higher priority
262 recipes with other available recipes indented underneath
263 -m only list where multiple recipes (in the same layer or different
264 layers) exist for the same recipe name
265""" 198"""
266 self.init_bbhandler() 199 self.init_bbhandler()
267 200
268 show_filenames = False
269 show_multi_provider_only = False
270 pnspec = None
271 title = 'Available recipes:' 201 title = 'Available recipes:'
272 for arg in args.split(): 202 self.list_recipes(title, args.pnspec, False, False, args.filenames, args.multiple)
273 if arg == '-f':
274 show_filenames = True
275 elif arg == '-m':
276 show_multi_provider_only = True
277 elif not arg.startswith('-'):
278 pnspec = arg
279 title = 'Available recipes matching %s:' % pnspec
280 else:
281 sys.stderr.write("show-recipes: invalid option %s\n" % arg)
282 self.do_help('')
283 return
284 self.list_recipes(title, pnspec, False, False, show_filenames, show_multi_provider_only)
285 203
286 204
287 def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_multi_provider_only): 205 def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_multi_provider_only):
@@ -361,9 +279,7 @@ Options:
361 279
362 280
363 def do_flatten(self, args): 281 def do_flatten(self, args):
364 """flattens layer configuration into a separate output directory. 282 """flatten layer configuration into a separate output directory.
365
366usage: flatten [layer1 layer2 [layer3]...] <outputdir>
367 283
368Takes the specified layers (or all layers in the current layer 284Takes the specified layers (or all layers in the current layer
369configuration if none are specified) and builds a "flattened" directory 285configuration if none are specified) and builds a "flattened" directory
@@ -385,26 +301,19 @@ bbappends in the layers interact, and then attempt to use the new output
385layer together with that other layer, you may no longer get the same 301layer together with that other layer, you may no longer get the same
386build results (as the layer priority order has effectively changed). 302build results (as the layer priority order has effectively changed).
387""" 303"""
388 arglist = args.split() 304 if len(args.layer) == 1:
389 if len(arglist) < 1:
390 logger.error('Please specify an output directory')
391 self.do_help('flatten')
392 return
393
394 if len(arglist) == 2:
395 logger.error('If you specify layers to flatten you must specify at least two') 305 logger.error('If you specify layers to flatten you must specify at least two')
396 self.do_help('flatten') 306 return 1
397 return
398 307
399 outputdir = arglist[-1] 308 outputdir = args.outputdir
400 if os.path.exists(outputdir) and os.listdir(outputdir): 309 if os.path.exists(outputdir) and os.listdir(outputdir):
401 logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir) 310 logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
402 return 311 return 1
403 312
404 self.init_bbhandler() 313 self.init_bbhandler()
405 layers = self.bblayers 314 layers = self.bblayers
406 if len(arglist) > 2: 315 if len(args.layer) > 2:
407 layernames = arglist[:-1] 316 layernames = args.layer
408 found_layernames = [] 317 found_layernames = []
409 found_layerdirs = [] 318 found_layerdirs = []
410 for layerdir in layers: 319 for layerdir in layers:
@@ -553,14 +462,12 @@ build results (as the layer priority order has effectively changed).
553 def do_show_appends(self, args): 462 def do_show_appends(self, args):
554 """list bbappend files and recipe files they apply to 463 """list bbappend files and recipe files they apply to
555 464
556usage: show-appends 465Lists recipes with the bbappends that apply to them as subitems.
557
558Recipes are listed with the bbappends that apply to them as subitems.
559""" 466"""
560 self.init_bbhandler() 467 self.init_bbhandler()
561 if not self.bbhandler.cooker.collection.appendlist: 468 if not self.bbhandler.cooker.collection.appendlist:
562 logger.plain('No append files found') 469 logger.plain('No append files found')
563 return 470 return 0
564 471
565 logger.plain('=== Appended recipes ===') 472 logger.plain('=== Appended recipes ===')
566 473
@@ -599,7 +506,6 @@ Recipes are listed with the bbappends that apply to them as subitems.
599 if best_filename in missing: 506 if best_filename in missing:
600 logger.warn('%s: missing append for preferred version', 507 logger.warn('%s: missing append for preferred version',
601 best_filename) 508 best_filename)
602 self.returncode |= 1
603 509
604 510
605 def get_appends_for_files(self, filenames): 511 def get_appends_for_files(self, filenames):
@@ -618,29 +524,13 @@ Recipes are listed with the bbappends that apply to them as subitems.
618 return appended, notappended 524 return appended, notappended
619 525
620 def do_show_cross_depends(self, args): 526 def do_show_cross_depends(self, args):
621 """figure out the dependency between recipes that crosses a layer boundary. 527 """Show dependencies between recipes that cross layer boundaries.
622
623usage: show-cross-depends [-f] [-i layer1[,layer2[,layer3...]]]
624 528
625Figure out the dependency between recipes that crosses a layer boundary. 529Figure out the dependencies between recipes that cross layer boundaries.
626 530
627Options: 531NOTE: .bbappend files can impact the dependencies.
628 -f show full file path
629 -i ignore dependencies on items in the specified layer(s)
630
631NOTE:
632The .bbappend file can impact the dependency.
633""" 532"""
634 import optparse 533 ignore_layers = (args.ignore or '').split(',')
635
636 parser = optparse.OptionParser(usage="show-cross-depends [-f] [-i layer1[,layer2[,layer3...]]]")
637 parser.add_option("-f", "",
638 action="store_true", dest="show_filenames")
639 parser.add_option("-i", "",
640 action="store", dest="ignore_layers", default="")
641
642 options, args = parser.parse_args(sys.argv)
643 ignore_layers = options.ignore_layers.split(',')
644 534
645 self.init_bbhandler() 535 self.init_bbhandler()
646 536
@@ -666,7 +556,7 @@ The .bbappend file can impact the dependency.
666 self.bbhandler.config_data, 556 self.bbhandler.config_data,
667 self.bbhandler.cooker_data, 557 self.bbhandler.cooker_data,
668 self.bbhandler.cooker_data.pkg_pn) 558 self.bbhandler.cooker_data.pkg_pn)
669 self.check_cross_depends("DEPENDS", layername, f, best[3], options.show_filenames, ignore_layers) 559 self.check_cross_depends("DEPENDS", layername, f, best[3], args.filenames, ignore_layers)
670 560
671 # The RDPENDS 561 # The RDPENDS
672 all_rdeps = self.bbhandler.cooker_data.rundeps[f].values() 562 all_rdeps = self.bbhandler.cooker_data.rundeps[f].values()
@@ -686,7 +576,7 @@ The .bbappend file can impact the dependency.
686 best = bb.providers.filterProvidersRunTime(all_p, rdep, 576 best = bb.providers.filterProvidersRunTime(all_p, rdep,
687 self.bbhandler.config_data, 577 self.bbhandler.config_data,
688 self.bbhandler.cooker_data)[0][0] 578 self.bbhandler.cooker_data)[0][0]
689 self.check_cross_depends("RDEPENDS", layername, f, best, options.show_filenames, ignore_layers) 579 self.check_cross_depends("RDEPENDS", layername, f, best, args.filenames, ignore_layers)
690 580
691 # The RRECOMMENDS 581 # The RRECOMMENDS
692 all_rrecs = self.bbhandler.cooker_data.runrecs[f].values() 582 all_rrecs = self.bbhandler.cooker_data.runrecs[f].values()
@@ -706,7 +596,7 @@ The .bbappend file can impact the dependency.
706 best = bb.providers.filterProvidersRunTime(all_p, rrec, 596 best = bb.providers.filterProvidersRunTime(all_p, rrec,
707 self.bbhandler.config_data, 597 self.bbhandler.config_data,
708 self.bbhandler.cooker_data)[0][0] 598 self.bbhandler.cooker_data)[0][0]
709 self.check_cross_depends("RRECOMMENDS", layername, f, best, options.show_filenames, ignore_layers) 599 self.check_cross_depends("RRECOMMENDS", layername, f, best, args.filenames, ignore_layers)
710 600
711 # The inherit class 601 # The inherit class
712 cls_re = re.compile('classes/') 602 cls_re = re.compile('classes/')
@@ -721,7 +611,7 @@ The .bbappend file can impact the dependency.
721 continue 611 continue
722 inherit_layername = self.get_file_layer(cls) 612 inherit_layername = self.get_file_layer(cls)
723 if inherit_layername != layername and not inherit_layername in ignore_layers: 613 if inherit_layername != layername and not inherit_layername in ignore_layers:
724 if not options.show_filenames: 614 if not args.filenames:
725 f_short = self.remove_layer_prefix(f) 615 f_short = self.remove_layer_prefix(f)
726 cls = self.remove_layer_prefix(cls) 616 cls = self.remove_layer_prefix(cls)
727 else: 617 else:
@@ -741,7 +631,7 @@ The .bbappend file can impact the dependency.
741 if pv_re.search(needed_file) and f in self.bbhandler.cooker_data.pkg_pepvpr: 631 if pv_re.search(needed_file) and f in self.bbhandler.cooker_data.pkg_pepvpr:
742 pv = self.bbhandler.cooker_data.pkg_pepvpr[f][1] 632 pv = self.bbhandler.cooker_data.pkg_pepvpr[f][1]
743 needed_file = re.sub(r"\${PV}", pv, needed_file) 633 needed_file = re.sub(r"\${PV}", pv, needed_file)
744 self.print_cross_files(bbpath, keyword, layername, f, needed_file, options.show_filenames, ignore_layers) 634 self.print_cross_files(bbpath, keyword, layername, f, needed_file, args.filenames, ignore_layers)
745 line = fnfile.readline() 635 line = fnfile.readline()
746 fnfile.close() 636 fnfile.close()
747 637
@@ -768,7 +658,7 @@ The .bbappend file can impact the dependency.
768 bbclass=".bbclass" 658 bbclass=".bbclass"
769 # Find a 'require/include xxxx' 659 # Find a 'require/include xxxx'
770 if m: 660 if m:
771 self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, options.show_filenames, ignore_layers) 661 self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, args.filenames, ignore_layers)
772 line = ffile.readline() 662 line = ffile.readline()
773 ffile.close() 663 ffile.close()
774 664
@@ -808,5 +698,74 @@ The .bbappend file can impact the dependency.
808 698
809 logger.plain("%s %s %s" % (f, keyword, best_realfn)) 699 logger.plain("%s %s %s" % (f, keyword, best_realfn))
810 700
811if __name__ == '__main__': 701
812 sys.exit(main(sys.argv[1:]) or 0) 702def main():
703
704 cmds = Commands()
705
706 def add_command(cmdname, function, *args, **kwargs):
707 # Convert docstring for function to help (one-liner shown in main --help) and description (shown in subcommand --help)
708 docsplit = function.__doc__.splitlines()
709 help = docsplit[0]
710 if len(docsplit) > 1:
711 desc = '\n'.join(docsplit[1:])
712 else:
713 desc = help
714 subparser = subparsers.add_parser(cmdname, *args, help=help, description=desc, formatter_class=argparse.RawTextHelpFormatter, **kwargs)
715 subparser.set_defaults(func=function)
716 return subparser
717
718 parser = argparse.ArgumentParser(description="BitBake layers utility",
719 epilog="Use %(prog)s <subcommand> --help to get help on a specific command")
720 parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true')
721 parser.add_argument('-q', '--quiet', help='Print only errors', action='store_true')
722 subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>')
723
724 parser_show_layers = add_command('show-layers', cmds.do_show_layers)
725
726 parser_add_layer = add_command('add-layer', cmds.do_add_layer)
727 parser_add_layer.add_argument('layerdir', help='Layer directory to add')
728
729 parser_remove_layer = add_command('remove-layer', cmds.do_remove_layer)
730 parser_remove_layer.add_argument('layerdir', help='Layer directory to remove (wildcards allowed, enclose in quotes to avoid shell expansion)')
731 parser_remove_layer.set_defaults(func=cmds.do_remove_layer)
732
733 parser_show_overlayed = add_command('show-overlayed', cmds.do_show_overlayed)
734 parser_show_overlayed.add_argument('-f', '--filenames', help='instead of the default formatting, list filenames of higher priority recipes with the ones they overlay indented underneath', action='store_true')
735 parser_show_overlayed.add_argument('-s', '--same-version', help='only list overlayed recipes where the version is the same', action='store_true')
736
737 parser_show_recipes = add_command('show-recipes', cmds.do_show_recipes)
738 parser_show_recipes.add_argument('-f', '--filenames', help='instead of the default formatting, list filenames of higher priority recipes with the ones they overlay indented underneath', action='store_true')
739 parser_show_recipes.add_argument('-m', '--multiple', help='only list where multiple recipes (in the same layer or different layers) exist for the same recipe name', action='store_true')
740 parser_show_recipes.add_argument('pnspec', nargs='?', help='optional recipe name specification (wildcards allowed, enclose in quotes to avoid shell expansion)')
741
742 parser_show_appends = add_command('show-appends', cmds.do_show_appends)
743
744 parser_flatten = add_command('flatten', cmds.do_flatten)
745 parser_flatten.add_argument('layer', nargs='*', help='Optional layer(s) to flatten (otherwise all are flattened)')
746 parser_flatten.add_argument('outputdir', help='Output directory')
747
748 parser_show_cross_depends = add_command('show-cross-depends', cmds.do_show_cross_depends)
749 parser_show_cross_depends.add_argument('-f', '--filenames', help='show full file path', action='store_true')
750 parser_show_cross_depends.add_argument('-i', '--ignore', help='ignore dependencies on items in the specified layer(s) (split multiple layer names with commas, no spaces)', metavar='LAYERNAME')
751
752 args = parser.parse_args()
753
754 if args.debug:
755 logger.setLevel(logging.DEBUG)
756 elif args.quiet:
757 logger.setLevel(logging.ERROR)
758
759 ret = args.func(args)
760
761 return ret
762
763
764if __name__ == "__main__":
765 try:
766 ret = main()
767 except Exception:
768 ret = 1
769 import traceback
770 traceback.print_exc(5)
771 sys.exit(ret)