have bb.parse.handle() throw ParseError if the input file is not
[bitbake.git] / lib / bb / shell.py
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 #
5 # Copyright (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>, Vanille Media
6 #
7 # This program is free software; you can redistribute it and/or modify it under
8 # the terms of the GNU General Public License as published by the Free Software
9 # Foundation; version 2 of the License.
10 #
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 # Place, Suite 330, Boston, MA 02111-1307 USA.
18 #
19
20 """
21 BitBake Shell
22
23 General Question to be decided: Make it a full-fledged Python Shell or
24 retain the simple command line interface like it is at the moment?
25
26 TODO:
27     * readline completion (file and provider?)
28     * specify tasks
29     * specify force
30     * command to clean stamps
31     * command to reparse one bbfile
32     * automatic check if reparsing is necessary (inotify?)
33     * bb file wizard
34     * call editor on bb file
35     * clean-and-rebuild bbfile
36 """
37
38 try:
39     set
40 except NameError:
41     from sets import Set as set
42 import sys, os, imp, readline
43 imp.load_source( "bitbake", os.path.dirname( sys.argv[0] )+"/bitbake" )
44 from bb import make, data
45
46 __version__ = 0.1
47 __credits__ = """BitBake Shell Version %2.1f (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
48 Type 'help' for more information, press CTRL-D to exit.""" % __version__
49
50 cmds = {}
51 leave_mainloop = False
52 cooker = None
53 parsed = False
54 # debug = False
55 debug = True
56 history_file = "%s/.bbsh_history" % os.environ.get( "HOME" )
57
58 #============================ start of commands ==================
59
60 def buildCommand( params, cmd = "build" ):
61     """Build a .bb file or a provider"""
62     try:
63         name = params[0]
64     except IndexError:
65         print "Usage: build <bbfile|provider>"
66     else:
67         make.options.cmd = cmd
68         cooker.build_cache = []
69         cooker.build_cache_fail = []
70
71         if name.endswith( ".bb" ):
72             cooker.executeOneBB( os.path.abspath( name ) )
73         else:
74             if not parsed:
75                 print "BBSHELL: D'oh! The .bb files haven't been parsed yet. Next time call 'parse' before building stuff. This time I'll do it for 'ya."
76                 parseCommand( None )
77             cooker.buildPackage( name )
78
79 def cleanCommand( params ):
80     """Clean a .bb file or a provider"""
81     buildCommand( params, "clean" )
82
83 def editCommand( params ):
84     """Call $EDITOR on a .bb file"""
85     try:
86         name = params[0]
87     except IndexError:
88         print "Usage: edit <bbfile>"
89     else:
90         os.system( "%s %s" % ( os.environ.get( "EDITOR" ), name ) )
91
92 def exitShell( params ):
93     """Leave the BitBake Shell"""
94     if debug: print "(setting leave_mainloop to true)"
95     global leave_mainloop
96     leave_mainloop = True
97
98 def parseCommand( params ):
99     """(Re-)parse .bb files and calculate the dependency graph"""
100     cooker.status = cooker.ParsingStatus()
101     ignore = data.getVar("ASSUME_PROVIDED", make.cfg, 1) or ""
102     cooker.status.ignored_dependencies = set( ignore.split() )
103     cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", make.cfg, 1) )
104
105     make.collect_bbfiles( cooker.myProgressCallback )
106     cooker.buildDepgraph()
107     global parsed
108     parsed = True
109     print
110
111 def environmentCommand( params ):
112     """Dump out the outer BitBake environment (see bbread)"""
113     data.emit_env(sys.__stdout__, make.cfg, True)
114
115 def printCommand( params ):
116     """Print the contents of an outer BitBake environment variable"""
117     try:
118         var = params[0]
119     except IndexError:
120         print "Usage: print <variable>"
121     else:
122         value = data.getVar( var, make.cfg, 1 )
123         print value
124
125 def rebuildCommand( params ):
126     """Clean and rebuild a .bb file or a provider"""
127     buildCommand( params, "clean" )
128     buildCommand( params, "build" )
129
130 def setVarCommand( params ):
131     """Set an outer BitBake environment variable"""
132     try:
133         var, value = params
134     except ValueError, IndexError:
135         print "Usage: set <variable> <value>"
136     else:
137         data.setVar( var, value, make.cfg )
138         print "OK"
139
140 #============================ end of commands ==================
141
142 def init():
143     """Register commands and set up readline"""
144     registerCommand( "help", showHelp )
145     registerCommand( "exit", exitShell )
146
147     registerCommand( "build", buildCommand )
148     registerCommand( "clean", cleanCommand )
149     registerCommand( "edit", editCommand )
150     registerCommand( "environment", environmentCommand )
151     registerCommand( "parse", parseCommand )
152     registerCommand( "print", printCommand )
153     registerCommand( "rebuild", rebuildCommand )
154     registerCommand( "set", setVarCommand )
155
156     readline.set_completer( completer )
157     readline.parse_and_bind("tab: complete")
158
159     try:
160         global history_file
161         readline.read_history_file( history_file )
162     except IOError:
163         pass  # It doesn't exist yet.
164
165 def cleanup():
166     if debug: print "(writing command history)"
167     try:
168         global history_file
169         readline.write_history_file( history_file )
170     except:
171         print "BBSHELL: Unable to save command history"
172
173 def completer( *args, **kwargs ):
174     print "completer called", args, kwargs
175     return None
176
177 def showCredits():
178     print __credits__
179
180 def showHelp( *args ):
181     """Show a comprehensive list of commands and their purpose"""
182     print "="*35, "Available Commands", "="*35
183     for cmd, func in cmds.items():
184         print "| %s | %s" % (cmd.ljust(max([len(x) for x in cmds.keys()])), func.__doc__)
185     print "="*88
186
187 def registerCommand( command, function ):
188     cmds[command] = function
189
190 def processCommand( command, params ):
191     if debug: print "(processing command '%s'...)" % command
192     if command in cmds:
193         result = cmds[command]( params )
194     else:
195         print "Error: '%s' command is not a valid command." % command
196         return
197     if debug: print "(result was '%s')" % result
198
199 def main():
200     while not leave_mainloop:
201         try:
202             cmdline = raw_input( "BB>> " )
203             if cmdline:
204                 if ' ' in cmdline:
205                     processCommand( cmdline.split()[0], cmdline.split()[1:] )
206                 else:
207                     processCommand( cmdline, "" )
208         except EOFError:
209             print
210             return
211         except KeyboardInterrupt:
212             print
213
214 def start( aCooker ):
215     global cooker
216     cooker = aCooker
217     showCredits()
218     init()
219     main()
220     cleanup()
221
222 if __name__ == "__main__":
223     print "BBSHELL: Sorry, this program should only be called by BitBake."