runqueue: simplify RunQueueStats.copy
[bitbake.git] / bin / bitbake-layers
1 #!/usr/bin/env python2.6
2
3 import cmd
4 import logging
5 import os.path
6 import sys
7
8 bindir = os.path.dirname(__file__)
9 topdir = os.path.dirname(bindir)
10 sys.path[0:0] = [os.path.join(topdir, 'lib')]
11
12 import bb.cache
13 import bb.cooker
14 import bb.providers
15 from bb.cooker import state
16
17
18 logger = logging.getLogger('BitBake')
19 default_cmd = 'show_appends'
20
21
22 def main(args):
23     logging.basicConfig(format='%(levelname)s: %(message)s')
24     bb.utils.clean_environment()
25
26     cmds = Commands()
27     if args:
28         cmds.onecmd(' '.join(args))
29     else:
30         cmds.onecmd(default_cmd)
31     return cmds.returncode
32
33
34 class Commands(cmd.Cmd):
35     def __init__(self):
36         cmd.Cmd.__init__(self)
37
38         self.returncode = 0
39         self.config = Config(parse_only=True)
40         self.cooker = bb.cooker.BBCooker(self.config,
41                                          self.register_idle_function)
42         self.config_data = self.cooker.configuration.data
43         bb.providers.logger.setLevel(logging.ERROR)
44         self.prepare_cooker()
45
46     def register_idle_function(self, function, data):
47         pass
48
49     def prepare_cooker(self):
50         sys.stderr.write("Parsing recipes..")
51         logger.setLevel(logging.ERROR)
52
53         try:
54             while self.cooker.state in (state.initial, state.parsing):
55                 self.cooker.updateCache()
56         except KeyboardInterrupt:
57             self.cooker.shutdown()
58             self.cooker.updateCache()
59             sys.exit(2)
60
61         logger.setLevel(logging.INFO)
62         sys.stderr.write("done.\n")
63
64         self.cooker_data = self.cooker.status
65         self.cooker_data.appends = self.cooker.appendlist
66
67     def do_show_layers(self, args):
68         logger.info(str(self.config_data.getVar('BBLAYERS', True)))
69
70     def do_show_appends(self, args):
71         if not self.cooker_data.appends:
72             logger.info('No append files found')
73             return
74
75         logger.info('State of append files:')
76
77         for pn in self.cooker_data.pkg_pn:
78             self.show_appends_for_pn(pn)
79
80         self.show_appends_with_no_recipes()
81
82     def show_appends_for_pn(self, pn):
83         filenames = self.cooker_data.pkg_pn[pn]
84
85         best = bb.providers.findBestProvider(pn,
86                                              self.cooker.configuration.data,
87                                              self.cooker_data,
88                                              self.cooker_data.pkg_pn)
89         best_filename = os.path.basename(best[3])
90
91         appended, missing = self.get_appends_for_files(filenames)
92         if appended:
93             for basename, appends in appended:
94                 logger.info('%s:', basename)
95                 for append in appends:
96                     logger.info('  %s', append)
97
98             if best_filename in missing:
99                 logger.warn('%s: missing append for preferred version',
100                             best_filename)
101                 self.returncode |= 1
102
103     def get_appends_for_files(self, filenames):
104         appended, notappended = set(), set()
105         for filename in filenames:
106             _, cls = bb.cache.Cache.virtualfn2realfn(filename)
107             if cls:
108                 continue
109
110             basename = os.path.basename(filename)
111             appends = self.cooker_data.appends.get(basename)
112             if appends:
113                 appended.add((basename, frozenset(appends)))
114             else:
115                 notappended.add(basename)
116         return appended, notappended
117
118     def show_appends_with_no_recipes(self):
119         recipes = set(os.path.basename(f)
120                       for f in self.cooker_data.pkg_fn.iterkeys())
121         appended_recipes = self.cooker_data.appends.iterkeys()
122         appends_without_recipes = [self.cooker_data.appends[recipe]
123                                    for recipe in appended_recipes
124                                    if recipe not in recipes]
125         if appends_without_recipes:
126             appendlines = ('  %s' % append
127                            for appends in appends_without_recipes
128                            for append in appends)
129             logger.warn('No recipes available for:\n%s',
130                         '\n'.join(appendlines))
131             self.returncode |= 4
132
133     def do_EOF(self, line):
134         return True
135
136
137 class Config(object):
138     def __init__(self, **options):
139         self.pkgs_to_build = []
140         self.debug_domains = []
141         self.extra_assume_provided = []
142         self.file = []
143         self.debug = 0
144         self.__dict__.update(options)
145
146     def __getattr__(self, attribute):
147         try:
148             return super(Config, self).__getattribute__(attribute)
149         except AttributeError:
150             return None
151
152
153 if __name__ == '__main__':
154     sys.exit(main(sys.argv[1:]) or 0)