count number of parsed, cached, skipped packages and print a statistic line
[bitbake.git] / bin / oe / 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 OpenEmbedded 'Make' implementations
5
6 Functions for reading OE files, building a dependency graph and
7 building a set of OE files while walking along the dependency graph.
8
9 This file is part of the OpenEmbedded (http://openembedded.org) build infrastructure.
10 """
11
12 from oe import debug, digraph, data, fetch, fatal, error, note, event, parse
13 import copy, oe, re, sys, os, glob
14 try:
15     import cPickle as pickle
16 except ImportError:
17     import pickle
18     print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
19
20 pkgdata = {}
21 cfg = {}
22 cache = None
23 digits = "0123456789"
24 ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
25 mtime_cache = {}
26
27 def get_oefiles( path = os.getcwd() ):
28     """Get list of default .oe files by reading out the current directory"""
29     contents = os.listdir(path)
30     oefiles = []
31     for f in contents:
32         (root, ext) = os.path.splitext(f)
33         if ext == ".oe":
34             oefiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
35     return oefiles
36
37 def find_oefiles( path ):
38     """Find all the .oe files in a directory (uses find)"""
39     findcmd = 'find ' + path + ' -name *.oe | grep -v SCCS/'
40     try:
41         finddata = os.popen(findcmd)
42     except OSError:
43         return []
44     return finddata.readlines()
45
46 def deps_clean(d):
47     depstr = data.getVar('__depends', d)
48     if depstr:
49         deps = depstr.split(" ")
50         for dep in deps:
51             (f,old_mtime_s) = dep.split("@")
52             old_mtime = int(old_mtime_s)
53             new_mtime = parse.cached_mtime(f)
54             if (new_mtime > old_mtime):
55                 return False
56     return True
57
58 def load_oefile( oefile ):
59     """Load and parse one .oe build file"""
60
61     if cache is not None:
62         cache_oefile = oefile.replace( '/', '_' )
63
64         try:
65             cache_mtime = os.stat( "%s/%s" % ( cache, cache_oefile ) )[8]
66         except OSError:
67             cache_mtime = 0
68         file_mtime = parse.cached_mtime(oefile)
69
70         if file_mtime > cache_mtime:
71             #print " : '%s' dirty. reparsing..." % oefile
72             pass
73         else:
74             #print " : '%s' clean. loading from cache..." % oefile
75             cache_data = unpickle_oe( cache_oefile )
76             if deps_clean(cache_data):
77                 return cache_data, True
78
79     oepath = data.getVar('OEPATH', cfg)
80     safeoepath = data.getVar('OEPATH', cfg)
81     topdir = data.getVar('TOPDIR', cfg)
82     if not topdir:
83         topdir = os.path.abspath(os.getcwd())
84         # set topdir to here
85         data.setVar('TOPDIR', topdir, cfg)
86     oefile = os.path.abspath(oefile)
87     oefile_loc = os.path.abspath(os.path.dirname(oefile))
88     # expand tmpdir to include this topdir
89     data.setVar('TMPDIR', data.getVar('TMPDIR', cfg, 1) or "", cfg)
90     # add topdir to oepath
91     oepath = "%s:%s" % (topdir, oepath)
92     # set topdir to location of .oe file
93     topdir = oefile_loc
94     #data.setVar('TOPDIR', topdir, cfg)
95     # add that topdir to oepath
96     oepath = "%s:%s" % (topdir, oepath)
97     # go there
98     oldpath = os.path.abspath(os.getcwd())
99     os.chdir(topdir)
100     data.setVar('OEPATH', oepath, cfg)
101     oe = copy.deepcopy(cfg)
102     try:
103         parse.handle(oefile, oe) # read .oe data
104         if cache is not None: pickle_oe( cache_oefile, oe) # write cache
105         os.chdir(oldpath)
106         return oe, False
107     finally:
108         os.chdir(oldpath)
109         data.setVar('OEPATH', safeoepath, cfg)
110
111 def pickle_oe( oefile, oe ):
112     p = pickle.Pickler( file( "%s/%s" % ( cache, oefile ), "wb" ), -1 )
113     p.dump( oe )
114
115 def unpickle_oe( oefile ):
116     p = pickle.Unpickler( file( "%s/%s" % ( cache, oefile ), "rb" ) )
117     oe = p.load()
118     funcstr = data.getVar('__functions__', oe)
119     if funcstr:
120         comp = compile(funcstr, "<pickled>", "exec")
121         exec comp in __builtins__
122     return oe
123
124 def collect_oefiles( progressCallback ):
125     """Collect all available .oe build files"""
126
127     parsed, cached, skipped = 0, 0, 0
128     global cache
129     cache = oe.data.getVar( "CACHE", cfg, 1 )
130     if cache is not None:
131         print "NOTE: Using cache in '%s'" % cache
132         try:
133             os.stat( cache )
134         except OSError:
135             oe.mkdirhier( cache )
136     else: print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
137     files = (data.getVar( "OEFILES", cfg, 1 ) or "").split()
138     data.setVar("OEFILES", " ".join(files), cfg)
139
140     if not len(files):
141         files = get_oefiles()
142
143     if not len(files):
144         oe.error("no files to build.")
145
146     newfiles = []
147     for f in files:
148         if os.path.isdir(f):
149             dirfiles = find_oefiles(f)
150             if dirfiles:
151                 newfiles += dirfiles
152                 continue
153         newfiles += glob.glob(f) or [ f ]
154
155     for i in xrange( len( newfiles ) ):
156         f = newfiles[i]
157         oemask = oe.data.getVar('OEMASK', cfg, 1)
158         if oemask:
159             if re.search(oemask, f):
160                 oe.debug(1, "oemake: skipping %s" % f)
161                 continue
162
163         progressCallback( i + 1, len( newfiles ), f )
164         debug(1, "oemake: parsing %s" % f)
165
166         # read a file's metadata
167         try:
168             pkgdata[f], fromCache = load_oefile(f)
169             if fromCache: cached += 1
170             else: parsed += 1
171             deps = None
172             if pkgdata[f] is not None:
173                 # allow metadata files to add items to OEFILES
174                 #data.update_data(pkgdata[f])
175                 addoefiles = data.getVar('OEFILES', pkgdata[f]) or None
176                 if addoefiles:
177                     for aof in addoefiles.split():
178                         if not files.count(aof):
179                             if not os.path.isabs(aof):
180                                 aof = os.path.join(os.path.dirname(f),aof)
181                             files.append(aof)
182                 for var in pkgdata[f].keys():
183                     if data.getVarFlag(var, "handler", pkgdata[f]) and data.getVar(var, pkgdata[f]):
184                         event.register(data.getVar(var, pkgdata[f]))
185         except IOError, e:
186             oe.error("opening %s: %s" % (f, e))
187             pass
188         except oe.parse.SkipPackage:
189             skipped += 1
190     print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped." % ( cached, parsed, skipped ), 
191
192 def explode_version(s):
193     import string
194     r = []
195     alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
196     numeric_regexp = re.compile('^(\d+)(.*)$')
197     while (s != ''):
198         if s[0] in digits:
199             m = numeric_regexp.match(s)
200             r.append(int(m.group(1)))
201             s = m.group(2)
202             continue
203         if s[0] in ascii_letters:
204             m = alpha_regexp.match(s)
205             r.append(m.group(1))
206             s = m.group(2)
207             continue
208         s = s[1:]
209     return r
210
211 def vercmp_part(a, b):
212     va = explode_version(a)
213     vb = explode_version(b)
214     while True:
215         if va == []:
216             ca = None
217         else:
218             ca = va.pop(0)
219         if vb == []:
220             cb = None
221         else:
222             cb = vb.pop(0)
223         if ca == None and cb == None:
224             return 0
225         if ca > cb:
226             return 1
227         if ca < cb:
228             return -1
229
230 def vercmp(ta, tb):
231     (va, ra) = ta
232     (vb, rb) = tb
233
234     r = vercmp_part(va, vb)
235     if (r == 0):
236         r = vercmp_part(ra, rb)
237     return r