have bb.parse.handle() throw ParseError if the input file is not
[bitbake.git] / lib / bb / parse / ConfHandler.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 """class for handling configuration data files
5
6    Reads a .conf file and obtains its metadata
7
8    Copyright (C) 2003, 2004  Chris Larson
9    Copyright (C) 2003, 2004  Phil Blundell
10    
11    This program is free software; you can redistribute it and/or modify it under
12    the terms of the GNU General Public License as published by the Free Software
13    Foundation; either version 2 of the License, or (at your option) any later
14    version.
15    
16    This program is distributed in the hope that it will be useful, but WITHOUT
17    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18    FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License along with
21    this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22    Place, Suite 330, Boston, MA 02111-1307 USA.""" 
23
24 import re, bb.data, os, sys
25 from bb import debug, fatal
26
27 #__config_regexp__  = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}]+)\s*(?P<colon>:)?(?P<ques>\?)?=\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
28 __config_regexp__  = re.compile( r"(?P<exp>export\s*)?(?P<var>[a-zA-Z0-9\-_+.${}/]+)(\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?\s*((?P<colon>:=)|(?P<ques>\?=)|(?P<append>\+=)|(?P<prepend>=\+)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
29 __include_regexp__ = re.compile( r"include\s+(.+)" )
30
31 def init(data):
32     if not bb.data.getVar('TOPDIR', data):
33         bb.data.setVar('TOPDIR', os.getcwd(), data)
34     if not bb.data.getVar('BBPATH', data):
35         bb.data.setVar('BBPATH', os.path.join(sys.prefix, 'share', 'bitbake'), data)
36
37 def supports(fn, d):
38     return localpath(fn, d)[-5:] == ".conf"
39
40 def localpath(fn, d):
41     if os.path.exists(fn):
42         return fn
43
44     localfn = None
45     try:
46         localfn = bb.fetch.localpath(fn, d)
47     except bb.MalformedUrl:
48         pass
49
50     if not localfn:
51         localfn = fn
52     return localfn
53
54 def obtain(fn, data = bb.data.init()):
55     import sys, bb
56     fn = bb.data.expand(fn, data)
57     localfn = bb.data.expand(localpath(fn, data), data)
58
59     if localfn != fn:
60         dldir = bb.data.getVar('DL_DIR', data, 1)
61         if not dldir:
62             debug(1, "obtain: DL_DIR not defined")
63             return localfn
64         bb.mkdirhier(dldir)
65         try:
66             bb.fetch.init([fn])
67         except bb.fetch.NoMethodError:
68             (type, value, traceback) = sys.exc_info()
69             debug(1, "obtain: no method: %s" % value)
70             return localfn
71
72         try:
73             bb.fetch.go(data)
74         except bb.fetch.MissingParameterError:
75             (type, value, traceback) = sys.exc_info()
76             debug(1, "obtain: missing parameters: %s" % value)
77             return localfn
78         except bb.fetch.FetchError:
79             (type, value, traceback) = sys.exc_info()
80             debug(1, "obtain: failed: %s" % value)
81             return localfn
82     return localfn
83
84
85 def include(oldfn, fn, data = bb.data.init()):
86     if oldfn == fn: # prevent infinate recursion
87         return None
88
89     import bb
90     fn = bb.data.expand(fn, data)
91     oldfn = bb.data.expand(oldfn, data)
92
93     from bb.parse import handle
94     try:
95         ret = handle(fn, data, 1)
96     except IOError:
97         debug(2, "CONF file '%s' not found" % fn)
98
99 def handle(fn, data = bb.data.init(), include = 0):
100     if include:
101         inc_string = "including"
102     else:
103         inc_string = "reading"
104     init(data)
105
106     if include == 0:
107         bb.data.inheritFromOS(data)
108         oldfile = None
109     else:
110         oldfile = bb.data.getVar('FILE', data)
111
112     fn = obtain(fn, data)
113     bbpath = []
114     if not os.path.isabs(fn):
115         f = None
116         vbbpath = bb.data.getVar("BBPATH", data)
117         if vbbpath:
118             bbpath += vbbpath.split(":")
119         for p in bbpath:
120             currname = os.path.join(bb.data.expand(p, data), fn)
121             if os.access(currname, os.R_OK):
122                 f = open(currname, 'r')
123                 abs_fn = currname
124                 debug(1, "CONF %s %s" % (inc_string, currname))
125                 break
126         if f is None:
127             raise IOError("file not found")
128     else:
129         f = open(fn,'r')
130         debug(1, "CONF %s %s" % (inc_string,fn))
131         abs_fn = fn
132
133     if include:
134         bb.parse.mark_dependency(data, abs_fn)
135
136     lineno = 0
137     bb.data.setVar('FILE', fn, data)
138     while 1:
139         lineno = lineno + 1
140         s = f.readline()
141         if not s: break
142         w = s.strip()
143         if not w: continue          # skip empty lines
144         s = s.rstrip()
145         if s[0] == '#': continue    # skip comments
146         while s[-1] == '\\':
147             s2 = f.readline()[:-1].strip()
148             lineno = lineno + 1
149             s = s[:-1] + s2
150         feeder(lineno, s, fn, data)
151
152     if oldfile:
153         bb.data.setVar('FILE', oldfile, data)
154     return data
155
156 def feeder(lineno, s, fn, data = bb.data.init()):
157     m = __config_regexp__.match(s)
158     if m:
159         groupd = m.groupdict()
160         key = groupd["var"]
161         if "exp" in groupd and groupd["exp"] != None:
162             bb.data.setVarFlag(key, "export", 1, data)
163         if "ques" in groupd and groupd["ques"] != None:
164             val = bb.data.getVar(key, data)
165             if val == None:
166                 val = groupd["value"]
167         elif "colon" in groupd and groupd["colon"] != None:
168             val = bb.data.expand(groupd["value"], data)
169         elif "append" in groupd and groupd["append"] != None:
170             val = "%s %s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
171         elif "prepend" in groupd and groupd["prepend"] != None:
172             val = "%s %s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
173         else:
174             val = groupd["value"]
175         if 'flag' in groupd and groupd['flag'] != None:
176 #           bb.note("setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
177             bb.data.setVarFlag(key, groupd['flag'], val, data)
178         else:
179             bb.data.setVar(key, val, data)
180         return
181
182     m = __include_regexp__.match(s)
183     if m:
184         s = bb.data.expand(m.group(1), data)
185 #       debug(2, "CONF %s:%d: including %s" % (fn, lineno, s))
186         include(fn, s, data)
187         return
188
189     raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
190
191 # Add us to the handlers list
192 from bb.parse import handlers
193 handlers.append({'supports': supports, 'handle': handle, 'init': init})
194 del handlers