2005-08-31 10:47:56 +00:00
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
2007-01-08 23:53:01 +00:00
"""
class for handling configuration data files
2005-08-31 10:47:56 +00:00
Reads a . conf file and obtains its metadata
2007-01-08 23:53:01 +00:00
"""
# Copyright (C) 2003, 2004 Chris Larson
# Copyright (C) 2003, 2004 Phil Blundell
2010-03-24 23:56:12 +00:00
#
2007-01-08 23:53:01 +00:00
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2005-08-31 10:47:56 +00:00
2011-11-25 14:57:53 +00:00
import re , os
2010-06-10 17:35:31 +00:00
import logging
2010-04-10 00:11:03 +00:00
import bb . utils
2010-06-10 17:35:31 +00:00
from bb . parse import ParseError , resolve_file , ast , logger
2005-08-31 10:47:56 +00:00
2013-02-14 11:28:32 +00:00
__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 < lazyques > \? \? = ) |
( ? P < ques > \? = ) |
( ? P < append > \+ = ) |
( ? P < prepend > = \+ ) |
( ? P < predot > = \. ) |
( ? P < postdot > \. = ) |
=
) \s *
( ? ! ' [^ ' ] * ' [^ ' ] * ' $)
( ? ! \" [^ \" ]* \" [^ \" ]* \" $)
( ? P < apo > [ ' \" ])
( ? P < value > . * )
( ? P = apo )
$
""" , re.X)
2005-08-31 10:47:56 +00:00
__include_regexp__ = re . compile ( r " include \ s+(.+) " )
2006-02-10 10:11:32 +00:00
__require_regexp__ = re . compile ( r " require \ s+(.+) " )
2012-02-29 13:09:15 +00:00
__export_regexp__ = re . compile ( r " export \ s+([a-zA-Z0-9 \ -_+.$ {} /]+)$ " )
2005-08-31 10:47:56 +00:00
def init ( data ) :
2011-11-25 14:57:53 +00:00
topdir = data . getVar ( ' TOPDIR ' )
2010-01-20 18:46:02 +00:00
if not topdir :
2011-11-25 14:57:53 +00:00
data . setVar ( ' TOPDIR ' , os . getcwd ( ) )
2010-01-20 18:46:02 +00:00
2005-08-31 10:47:56 +00:00
def supports ( fn , d ) :
2009-05-17 04:06:14 +00:00
return fn [ - 5 : ] == " .conf "
2005-08-31 10:47:56 +00:00
2012-02-23 17:38:08 +00:00
def include ( oldfn , fn , lineno , data , error_out ) :
2006-02-10 10:11:32 +00:00
"""
2012-02-23 17:38:08 +00:00
error_out : A string indicating the verb ( e . g . " include " , " inherit " ) to be
used in a ParseError that will be raised if the file to be included could
not be included . Specify False to avoid raising an error in this case .
2006-02-10 10:11:32 +00:00
"""
2011-01-03 19:57:24 +00:00
if oldfn == fn : # prevent infinite recursion
2005-08-31 10:47:56 +00:00
return None
import bb
2011-11-25 14:57:53 +00:00
fn = data . expand ( fn )
oldfn = data . expand ( oldfn )
2005-08-31 10:47:56 +00:00
2009-05-11 21:41:17 +00:00
if not os . path . isabs ( fn ) :
dname = os . path . dirname ( oldfn )
2012-03-03 10:41:41 +00:00
bbpath = " %s : %s " % ( dname , data . getVar ( " BBPATH " , True ) )
2013-11-29 23:15:56 +00:00
abs_fn , attempts = bb . utils . which ( bbpath , fn , history = True )
if abs_fn and bb . parse . check_dependency ( data , abs_fn ) :
bb . warn ( " Duplicate inclusion for %s in %s " % ( abs_fn , data . getVar ( ' FILE ' , True ) ) )
for af in attempts :
bb . parse . mark_dependency ( data , af )
2009-05-11 21:41:17 +00:00
if abs_fn :
fn = abs_fn
2013-11-29 23:15:56 +00:00
elif bb . parse . check_dependency ( data , fn ) :
bb . warn ( " Duplicate inclusion for %s in %s " % ( fn , data . getVar ( ' FILE ' , True ) ) )
2009-05-11 21:41:17 +00:00
2005-08-31 10:47:56 +00:00
from bb . parse import handle
try :
2009-05-19 10:10:37 +00:00
ret = handle ( fn , data , True )
2013-08-23 17:06:26 +00:00
except ( IOError , OSError ) :
2006-02-10 10:11:32 +00:00
if error_out :
2012-02-23 17:38:08 +00:00
raise ParseError ( " Could not %(error_out)s file %(fn)s " % vars ( ) , oldfn , lineno )
2010-06-10 17:35:31 +00:00
logger . debug ( 2 , " CONF file ' %s ' not found " , fn )
2013-11-29 23:15:56 +00:00
bb . parse . mark_dependency ( data , fn )
2005-08-31 10:47:56 +00:00
2012-04-13 10:51:17 +00:00
# We have an issue where a UI might want to enforce particular settings such as
# an empty DISTRO variable. If configuration files do something like assigning
# a weak default, it turns out to be very difficult to filter out these changes,
# particularly when the weak default might appear half way though parsing a chain
# of configuration files. We therefore let the UIs hook into configuration file
# parsing. This turns out to be a hard problem to solve any other way.
confFilters = [ ]
2009-05-19 10:10:37 +00:00
def handle ( fn , data , include ) :
2005-08-31 10:47:56 +00:00
init ( data )
if include == 0 :
oldfile = None
else :
2011-11-25 14:57:53 +00:00
oldfile = data . getVar ( ' FILE ' )
2005-08-31 10:47:56 +00:00
2009-05-19 11:59:50 +00:00
abs_fn = resolve_file ( fn , data )
f = open ( abs_fn , ' r ' )
2005-08-31 10:47:56 +00:00
if include :
bb . parse . mark_dependency ( data , abs_fn )
2009-05-19 10:10:37 +00:00
statements = ast . StatementGroup ( )
2005-08-31 10:47:56 +00:00
lineno = 0
2010-04-12 00:03:55 +00:00
while True :
2005-08-31 10:47:56 +00:00
lineno = lineno + 1
s = f . readline ( )
2012-12-14 13:53:32 +00:00
if not s :
break
2005-08-31 10:47:56 +00:00
w = s . strip ( )
2012-12-14 13:53:32 +00:00
# skip empty lines
if not w :
continue
2005-08-31 10:47:56 +00:00
s = s . rstrip ( )
while s [ - 1 ] == ' \\ ' :
2011-07-20 21:51:23 +00:00
s2 = f . readline ( ) . strip ( )
2005-08-31 10:47:56 +00:00
lineno = lineno + 1
2013-01-21 11:00:52 +00:00
if ( not s2 or s2 and s2 [ 0 ] != " # " ) and s [ 0 ] == " # " :
2012-12-14 13:53:32 +00:00
bb . fatal ( " There is a confusing multiline, partially commented expression on line %s of file %s ( %s ). \n Please clarify whether this is all a comment or should be parsed. " % ( lineno , fn , s ) )
2005-08-31 10:47:56 +00:00
s = s [ : - 1 ] + s2
2012-12-14 13:53:32 +00:00
# skip comments
if s [ 0 ] == ' # ' :
continue
2009-05-19 10:10:37 +00:00
feeder ( lineno , s , fn , statements )
2005-08-31 10:47:56 +00:00
2009-05-19 10:10:37 +00:00
# DONE WITH PARSING... time to evaluate
2011-11-25 14:57:53 +00:00
data . setVar ( ' FILE ' , abs_fn )
2009-05-19 10:10:37 +00:00
statements . eval ( data )
2005-08-31 10:47:56 +00:00
if oldfile :
2011-11-25 14:57:53 +00:00
data . setVar ( ' FILE ' , oldfile )
2009-05-19 10:10:37 +00:00
2013-05-09 21:06:45 +00:00
f . close ( )
2012-04-13 10:51:17 +00:00
for f in confFilters :
f ( fn , data )
2005-08-31 10:47:56 +00:00
return data
2009-05-19 10:10:37 +00:00
def feeder ( lineno , s , fn , statements ) :
2005-08-31 10:47:56 +00:00
m = __config_regexp__ . match ( s )
if m :
groupd = m . groupdict ( )
2011-01-04 20:34:08 +00:00
ast . handleData ( statements , fn , lineno , groupd )
2005-08-31 10:47:56 +00:00
return
m = __include_regexp__ . match ( s )
if m :
2011-01-04 20:34:08 +00:00
ast . handleInclude ( statements , fn , lineno , m , False )
2005-08-31 10:47:56 +00:00
return
2006-02-10 10:11:32 +00:00
m = __require_regexp__ . match ( s )
if m :
2011-01-04 20:34:08 +00:00
ast . handleInclude ( statements , fn , lineno , m , True )
2006-02-10 10:11:32 +00:00
return
2007-09-05 07:48:15 +00:00
m = __export_regexp__ . match ( s )
if m :
2011-01-04 20:34:08 +00:00
ast . handleExport ( statements , fn , lineno , m )
2007-09-05 07:48:15 +00:00
return
2012-02-23 17:38:08 +00:00
raise ParseError ( " unparsed line: ' %s ' " % s , fn , lineno ) ;
2005-08-31 10:47:56 +00:00
# Add us to the handlers list
from bb . parse import handlers
handlers . append ( { ' supports ' : supports , ' handle ' : handle , ' init ' : init } )
del handlers