lib/bb/data.py:
[vuplus_bitbake] / lib / bb / make.py
1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 """
4 BitBake 'Make' implementations
5
6 Functions for reading BB files, building a dependency graph and
7 building a set of BB files while walking along the dependency graph.
8
9 Copyright (C) 2003, 2004  Mickey Lauer
10 Copyright (C) 2003, 2004  Phil Blundell
11 Copyright (C) 2003, 2004  Chris Larson
12
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 2 of the License, or (at your option) any later
16 version.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24 Place, Suite 330, Boston, MA 02111-1307 USA. 
25
26 This file is part of the BitBake build tools.
27 """
28
29 from bb import debug, digraph, data, fetch, fatal, error, note, event, parse
30 import copy, bb, re, sys, os, glob, sre_constants
31
32 pkgdata = {}
33 cfg = data.init()
34 cache = None
35 digits = "0123456789"
36 ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
37 mtime_cache = {}
38
39 def get_bbfiles( path = os.getcwd() ):
40     """Get list of default .bb files by reading out the current directory"""
41     contents = os.listdir(path)
42     bbfiles = []
43     for f in contents:
44         (root, ext) = os.path.splitext(f)
45         if ext == ".bb":
46             bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
47     return bbfiles
48
49 def find_bbfiles( path ):
50     """Find all the .bb files in a directory (uses find)"""
51     findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
52     try:
53         finddata = os.popen(findcmd)
54     except OSError:
55         return []
56     return finddata.readlines()
57
58 def deps_clean(d):
59     depstr = data.getVar('__depends', d)
60     if depstr:
61         deps = depstr.split(" ")
62         for dep in deps:
63             (f,old_mtime_s) = dep.split("@")
64             old_mtime = int(old_mtime_s)
65             new_mtime = parse.cached_mtime(f)
66             if (new_mtime > old_mtime):
67                 return False
68     return True
69
70 def load_bbfile( bbfile ):
71     """Load and parse one .bb build file"""
72
73     if not cache in [None, '']:
74         # get the times
75         cache_mtime = data.init_db_mtime(cache, bbfile)
76         file_mtime = parse.cached_mtime(bbfile)
77
78         if file_mtime > cache_mtime:
79             #print " : '%s' dirty. reparsing..." % bbfile
80             pass
81         else:
82             #print " : '%s' clean. loading from cache..." % bbfile
83             cache_data = data.init_db( cache, bbfile, False )
84             if deps_clean(cache_data):
85                 return cache_data, True
86
87     topdir = data.getVar('TOPDIR', cfg)
88     if not topdir:
89         topdir = os.path.abspath(os.getcwd())
90         # set topdir to here
91         data.setVar('TOPDIR', topdir, cfg)
92     bbfile = os.path.abspath(bbfile)
93     bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
94     # expand tmpdir to include this topdir
95     data.setVar('TMPDIR', data.getVar('TMPDIR', cfg, 1) or "", cfg)
96     # set topdir to location of .bb file
97     topdir = bbfile_loc
98     #data.setVar('TOPDIR', topdir, cfg)
99     # go there
100     oldpath = os.path.abspath(os.getcwd())
101     os.chdir(topdir)
102     bb = data.init_db(cache,bbfile, True, cfg)
103     try:
104         parse.handle(bbfile, bb) # read .bb data
105         if not cache in [None, '']:
106             bb.commit(parse.cached_mtime(bbfile)) # write cache
107         os.chdir(oldpath)
108         return bb, False
109     finally:
110         os.chdir(oldpath)
111
112 def collect_bbfiles( progressCallback ):
113     """Collect all available .bb build files"""
114
115     parsed, cached, skipped, masked = 0, 0, 0, 0
116     global cache
117     cache = bb.data.getVar( "CACHE", cfg, 1 )
118     if not cache in [None, '']:
119         print "NOTE: Using cache in '%s'" % cache
120         try:
121             os.stat( cache )
122         except OSError:
123             bb.mkdirhier( cache )
124     else: print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
125     files = (data.getVar( "BBFILES", cfg, 1 ) or "").split()
126     data.setVar("BBFILES", " ".join(files), cfg)
127
128     if not len(files):
129         files = get_bbfiles()
130
131     if not len(files):
132         bb.error("no files to build.")
133
134     newfiles = []
135     for f in files:
136         if os.path.isdir(f):
137             dirfiles = find_bbfiles(f)
138             if dirfiles:
139                 newfiles += dirfiles
140                 continue
141         newfiles += glob.glob(f) or [ f ]
142
143     bbmask = bb.data.getVar('BBMASK', cfg, 1) or ""
144     try:
145         bbmask_compiled = re.compile(bbmask)
146     except sre_constants.error:
147         bb.fatal("BBMASK is not a valid regular expression.")
148
149     for i in xrange( len( newfiles ) ):
150         f = newfiles[i]
151         if bbmask and bbmask_compiled.search(f):
152               bb.debug(1, "bbmake: skipping %s" % f)
153               masked += 1
154               continue
155         progressCallback( i + 1, len( newfiles ), f )
156         debug(1, "bbmake: parsing %s" % f)
157
158         # read a file's metadata
159         try:
160             pkgdata[f], fromCache = load_bbfile(f)
161             if fromCache: cached += 1
162             else: parsed += 1
163             deps = None
164             if pkgdata[f] is not None:
165                 # allow metadata files to add items to BBFILES
166                 #data.update_data(pkgdata[f])
167                 addbbfiles = data.getVar('BBFILES', pkgdata[f]) or None
168                 if addbbfiles:
169                     for aof in addbbfiles.split():
170                         if not files.count(aof):
171                             if not os.path.isabs(aof):
172                                 aof = os.path.join(os.path.dirname(f),aof)
173                             files.append(aof)
174                 for var in pkgdata[f].keys():
175                     if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
176                         event.register(data.getVar(var, pkgdata[f]))
177         except IOError, e:
178             bb.error("opening %s: %s" % (f, e))
179             pass
180         except bb.parse.SkipPackage:
181             skipped += 1
182             pass
183         except KeyboardInterrupt:
184             raise
185         except Exception, e:
186             bb.error("%s while parsing %s" % (e, f))
187     print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ), 
188
189 def explode_version(s):
190     import string
191     r = []
192     alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
193     numeric_regexp = re.compile('^(\d+)(.*)$')
194     while (s != ''):
195         if s[0] in digits:
196             m = numeric_regexp.match(s)
197             r.append(int(m.group(1)))
198             s = m.group(2)
199             continue
200         if s[0] in ascii_letters:
201             m = alpha_regexp.match(s)
202             r.append(m.group(1))
203             s = m.group(2)
204             continue
205         s = s[1:]
206     return r
207
208 def vercmp_part(a, b):
209     va = explode_version(a)
210     vb = explode_version(b)
211     while True:
212         if va == []:
213             ca = None
214         else:
215             ca = va.pop(0)
216         if vb == []:
217             cb = None
218         else:
219             cb = vb.pop(0)
220         if ca == None and cb == None:
221             return 0
222         if ca > cb:
223             return 1
224         if ca < cb:
225             return -1
226
227 def vercmp(ta, tb):
228     (va, ra) = ta
229     (vb, rb) = tb
230
231     r = vercmp_part(va, vb)
232     if (r == 0):
233         r = vercmp_part(ra, rb)
234     return r