summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorRichard Purdie <richard@openedhand.com>2005-08-31 10:47:56 +0000
committerRichard Purdie <richard@openedhand.com>2005-08-31 10:47:56 +0000
commitf54da734eb7b69e8e34de505bd89a13479e230e0 (patch)
treef796bea6f5683dfe3d591ca5390d12fd78e59c96 /bitbake
parent4b46c1f6e891b1ddd5968536440b888661fade3e (diff)
downloadpoky-f54da734eb7b69e8e34de505bd89a13479e230e0.tar.gz
Initial population
git-svn-id: https://svn.o-hand.com/repos/poky@2 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/AUTHORS5
-rw-r--r--bitbake/ChangeLog35
-rw-r--r--bitbake/MANIFEST27
-rw-r--r--bitbake/TODO18
-rwxr-xr-xbitbake/bin/bbimage154
-rwxr-xr-xbitbake/bin/bitbake927
-rw-r--r--bitbake/bin/bitbakecbin0 -> 27715 bytes
-rwxr-xr-xbitbake/bin/bitdoc529
-rw-r--r--bitbake/classes/base.bbclass79
-rw-r--r--bitbake/conf/bitbake.conf55
-rw-r--r--bitbake/contrib/README1
-rw-r--r--bitbake/contrib/bbdev.sh31
-rw-r--r--bitbake/doc/COPYING.GPL340
-rw-r--r--bitbake/doc/COPYING.MIT17
-rw-r--r--bitbake/doc/manual/Makefile56
-rw-r--r--bitbake/doc/manual/html.css281
-rw-r--r--bitbake/doc/manual/usermanual.xml361
-rw-r--r--bitbake/lib/bb/__init__.py1266
-rw-r--r--bitbake/lib/bb/__init__.pycbin0 -> 29886 bytes
-rw-r--r--bitbake/lib/bb/build.py395
-rw-r--r--bitbake/lib/bb/build.pycbin0 -> 12365 bytes
-rw-r--r--bitbake/lib/bb/data.py580
-rw-r--r--bitbake/lib/bb/data.pycbin0 -> 18362 bytes
-rw-r--r--bitbake/lib/bb/data_dict.pycbin0 -> 6854 bytes
-rw-r--r--bitbake/lib/bb/data_smart.py351
-rw-r--r--bitbake/lib/bb/data_smart.pycbin0 -> 11522 bytes
-rw-r--r--bitbake/lib/bb/event.py210
-rw-r--r--bitbake/lib/bb/event.pycbin0 -> 8226 bytes
-rw-r--r--bitbake/lib/bb/fetch.py656
-rw-r--r--bitbake/lib/bb/fetch.pycbin0 -> 20663 bytes
-rw-r--r--bitbake/lib/bb/make.pycbin0 -> 8013 bytes
-rw-r--r--bitbake/lib/bb/manifest.py144
-rw-r--r--bitbake/lib/bb/manifest.pycbin0 -> 3295 bytes
-rw-r--r--bitbake/lib/bb/parse/BBHandler.pycbin0 -> 10831 bytes
-rw-r--r--bitbake/lib/bb/parse/ConfHandler.pycbin0 -> 6391 bytes
-rw-r--r--bitbake/lib/bb/parse/__init__.py70
-rw-r--r--bitbake/lib/bb/parse/__init__.pycbin0 -> 3254 bytes
-rw-r--r--bitbake/lib/bb/parse/parse_c/bitbakeparser.l288
-rw-r--r--bitbake/lib/bb/parse/parse_c/bitbakeparser.py133
-rw-r--r--bitbake/lib/bb/parse/parse_c/bitbakeparser.y161
-rw-r--r--bitbake/lib/bb/parse/parse_c/lexer.h41
-rw-r--r--bitbake/lib/bb/parse/parse_c/token.h83
-rw-r--r--bitbake/lib/bb/parse/parse_py/BBHandler.py378
-rw-r--r--bitbake/lib/bb/parse/parse_py/BBHandler.pycbin0 -> 10825 bytes
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py199
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.pycbin0 -> 6673 bytes
-rw-r--r--bitbake/lib/bb/parse/parse_py/__init__.py32
-rw-r--r--bitbake/lib/bb/parse/parse_py/__init__.pycbin0 -> 1185 bytes
-rw-r--r--bitbake/lib/bb/shell.py779
-rw-r--r--bitbake/lib/bb/shell.pycbin0 -> 27748 bytes
-rw-r--r--bitbake/lib/bb/utils.py71
-rw-r--r--bitbake/lib/bb/utils.pycbin0 -> 2313 bytes
-rwxr-xr-xbitbake/setup.py69
53 files changed, 8822 insertions, 0 deletions
diff --git a/bitbake/AUTHORS b/bitbake/AUTHORS
new file mode 100644
index 0000000000..4129e4c523
--- /dev/null
+++ b/bitbake/AUTHORS
@@ -0,0 +1,5 @@
1Holger Freyther <zecke@handhelds.org>
2Chris Larson <kergoth@handhelds.org>
3Mickey Lauer <mickey@Vanille.de>
4Holger Schurig <holgerschurig@gmx.de>
5Phil Blundell <pb@handhelds.org>
diff --git a/bitbake/ChangeLog b/bitbake/ChangeLog
new file mode 100644
index 0000000000..db503ffb1a
--- /dev/null
+++ b/bitbake/ChangeLog
@@ -0,0 +1,35 @@
1Changes in BitBake 1.3.2:
2 - reintegration of make.py into BitBake
3 - bbread is gone, use bitbake -e
4 - lots of shell updates and bugfixes
5 - Introduction of the .= and =. operator
6 - Sort variables, keys and groups in bitdoc
7 - Fix regression in the handling of BBCOLLECTIONS
8 - Update the bitbake usermanual
9
10Changes in BitBake 1.3.0:
11 - add bitbake interactive shell (bitbake -i)
12 - refactor bitbake utility in OO style
13 - kill default arguments in methods in the bb.data module
14 - kill default arguments in methods in the bb.fetch module
15 - the http/https/ftp fetcher will fail if the to be
16 downloaded file was not found in DL_DIR (this is needed
17 to avoid unpacking the sourceforge mirror page)
18 - Switch to a cow like data instance for persistent and non
19 persisting mode (called data_smart.py)
20 - Changed the callback of bb.make.collect_bbfiles to carry
21 additional parameters
22 - Drastically reduced the amount of needed RAM by not holding
23 each data instance in memory when using a cache/persistent
24 storage
25
26Changes in BitBake 1.2.1:
27 The 1.2.1 release is meant as a intermediate release to lay the
28 ground for more radical changes. The most notable changes are:
29
30 - Do not hardcode {}, use bb.data.init() instead if you want to
31 get a instance of a data class
32 - bb.data.init() is a factory and the old bb.data methods are delegates
33 - Do not use deepcopy use bb.data.createCopy() instead.
34 - Removed default arguments in bb.fetch
35
diff --git a/bitbake/MANIFEST b/bitbake/MANIFEST
new file mode 100644
index 0000000000..71e3605a47
--- /dev/null
+++ b/bitbake/MANIFEST
@@ -0,0 +1,27 @@
1AUTHORS
2ChangeLog
3MANIFEST
4setup.py
5bin/bbimage
6bin/bitbake
7lib/bb/__init__.py
8lib/bb/build.py
9lib/bb/data.py
10lib/bb/data_smart.py
11lib/bb/event.py
12lib/bb/fetch.py
13lib/bb/manifest.py
14lib/bb/parse/__init__.py
15lib/bb/parse/parse_py/BBHandler.py
16lib/bb/parse/parse_py/ConfHandler.py
17lib/bb/parse/parse_py/__init__.py
18lib/bb/shell.py
19lib/bb/utils.py
20doc/COPYING.GPL
21doc/COPYING.MIT
22doc/manual/html.css
23doc/manual/Makefile
24doc/manual/usermanual.xml
25contrib/bbdev.sh
26conf/bitbake.conf
27classes/base.bbclass
diff --git a/bitbake/TODO b/bitbake/TODO
new file mode 100644
index 0000000000..511fae4a25
--- /dev/null
+++ b/bitbake/TODO
@@ -0,0 +1,18 @@
1On popular request by popular people a list of tasks to-do:
2
3 -Kill insecure usage of os.system either by properly escaping
4 the strings or a faster replacement not involving /bin/sh
5 -Introduce a -p option to automatically hotshot/profile the
6 run
7 -Cache dependencies separately and invalidate them when any file
8 changed.
9 -...
10
11
12DONE:
13· -On generating the inter package deps do not parse each file multiply
14· times.
15 -We build the lists while parsing the data now
16· (WAS: Do not generate the world dependency tree, only when someone
17· requests it.
18
diff --git a/bitbake/bin/bbimage b/bitbake/bin/bbimage
new file mode 100755
index 0000000000..df6caa28ed
--- /dev/null
+++ b/bitbake/bin/bbimage
@@ -0,0 +1,154 @@
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) 2003 Chris Larson
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; either version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along with
17# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18# Place, Suite 330, Boston, MA 02111-1307 USA.
19
20import sys, os
21sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
22import bb
23from bb import *
24
25__version__ = 1.0
26type = "jffs2"
27cfg_bb = data.init()
28cfg_oespawn = data.init()
29
30
31def usage():
32 print "Usage: bbimage [options ...]"
33 print "Creates an image for a target device from a root filesystem,"
34 print "obeying configuration parameters from the BitBake"
35 print "configuration files, thereby easing handling of deviceisms."
36 print ""
37 print " %s\t\t%s" % ("-r [arg], --root [arg]", "root directory (default=${IMAGE_ROOTFS})")
38 print " %s\t\t%s" % ("-t [arg], --type [arg]", "image type (jffs2[default], cramfs)")
39 print " %s\t\t%s" % ("-n [arg], --name [arg]", "image name (override IMAGE_NAME variable)")
40 print " %s\t\t%s" % ("-v, --version", "output version information and exit")
41 sys.exit(0)
42
43def version():
44 print "BitBake Build Tool Core version %s" % bb.__version__
45 print "BBImage version %s" % __version__
46
47def emit_bb(d, base_d = {}):
48 for v in d.keys():
49 if d[v] != base_d[v]:
50 data.emit_var(v, d)
51
52def getopthash(l):
53 h = {}
54 for (opt, val) in l:
55 h[opt] = val
56 return h
57
58import getopt
59try:
60 (opts, args) = getopt.getopt(sys.argv[1:], 'vr:t:e:n:', [ 'version', 'root=', 'type=', 'bbfile=', 'name=' ])
61except getopt.GetoptError:
62 usage()
63
64# handle opts
65opthash = getopthash(opts)
66
67if '--version' in opthash or '-v' in opthash:
68 version()
69 sys.exit(0)
70
71try:
72 cfg_bb = parse.handle(os.path.join('conf', 'bitbake.conf'), cfg_bb)
73except IOError:
74 fatal("Unable to open bitbake.conf")
75
76# sanity check
77if cfg_bb is None:
78 fatal("Unable to open/parse %s" % os.path.join('conf', 'bitbake.conf'))
79 usage(1)
80
81rootfs = None
82extra_files = []
83
84if '--root' in opthash:
85 rootfs = opthash['--root']
86if '-r' in opthash:
87 rootfs = opthash['-r']
88
89if '--type' in opthash:
90 type = opthash['--type']
91if '-t' in opthash:
92 type = opthash['-t']
93
94if '--bbfile' in opthash:
95 extra_files.append(opthash['--bbfile'])
96if '-e' in opthash:
97 extra_files.append(opthash['-e'])
98
99for f in extra_files:
100 try:
101 cfg_bb = parse.handle(f, cfg_bb)
102 except IOError:
103 print "unable to open %s" % f
104
105if not rootfs:
106 rootfs = data.getVar('IMAGE_ROOTFS', cfg_bb, 1)
107
108if not rootfs:
109 bb.fatal("IMAGE_ROOTFS not defined")
110
111data.setVar('IMAGE_ROOTFS', rootfs, cfg_bb)
112
113from copy import copy, deepcopy
114localdata = data.createCopy(cfg_bb)
115
116overrides = data.getVar('OVERRIDES', localdata)
117if not overrides:
118 bb.fatal("OVERRIDES not defined.")
119data.setVar('OVERRIDES', '%s:%s' % (overrides, type), localdata)
120data.update_data(localdata)
121data.setVar('OVERRIDES', overrides, localdata)
122
123if '-n' in opthash:
124 data.setVar('IMAGE_NAME', opthash['-n'], localdata)
125if '--name' in opthash:
126 data.setVar('IMAGE_NAME', opthash['--name'], localdata)
127
128topdir = data.getVar('TOPDIR', localdata, 1) or os.getcwd()
129
130cmd = data.getVar('IMAGE_CMD', localdata, 1)
131if not cmd:
132 bb.fatal("IMAGE_CMD not defined")
133
134outdir = data.getVar('DEPLOY_DIR_IMAGE', localdata, 1)
135if not outdir:
136 bb.fatal('DEPLOY_DIR_IMAGE not defined')
137mkdirhier(outdir)
138
139#depends = data.getVar('IMAGE_DEPENDS', localdata, 1) or ""
140#if depends:
141# bb.note("Spawning bbmake to satisfy dependencies: %s" % depends)
142# ret = os.system('bbmake %s' % depends)
143# if ret != 0:
144# bb.error("executing bbmake to satisfy dependencies")
145
146bb.note("Executing %s" % cmd)
147data.setVar('image_cmd', cmd, localdata)
148data.setVarFlag('image_cmd', 'func', 1, localdata)
149try:
150 bb.build.exec_func('image_cmd', localdata)
151except bb.build.FuncFailed:
152 sys.exit(1)
153#ret = os.system(cmd)
154#sys.exit(ret)
diff --git a/bitbake/bin/bitbake b/bitbake/bin/bitbake
new file mode 100755
index 0000000000..d327a69ab8
--- /dev/null
+++ b/bitbake/bin/bitbake
@@ -0,0 +1,927 @@
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) 2003, 2004 Chris Larson
6# Copyright (C) 2003, 2004 Phil Blundell
7# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
8# Copyright (C) 2005 Holger Hans Peter Freyther
9# Copyright (C) 2005 ROAD GmbH
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
24import sys, os, getopt, glob, copy, os.path, re, time
25sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
26import bb
27from bb import utils, data, parse, debug, event, fatal
28from sets import Set
29import itertools, optparse
30
31parsespin = itertools.cycle( r'|/-\\' )
32bbdebug = 0
33
34__version__ = "1.3.2"
35
36#============================================================================#
37# BBParsingStatus
38#============================================================================#
39class BBParsingStatus:
40 """
41 The initial idea for this status class is to use the data when it is
42 already loaded instead of loading it from various place over and over
43 again.
44 """
45
46 def __init__(self):
47 self.cache_dirty = False
48 self.providers = {}
49 self.bbfile_priority = {}
50 self.bbfile_config_priorities = []
51 self.ignored_depedencies = None
52 self.possible_world = []
53 self.world_target = Set()
54 self.pkg_pn = {}
55 self.pkg_fn = {}
56 self.pkg_pvpr = {}
57 self.pkg_dp = {}
58 self.pn_provides = {}
59 self.all_depends = Set()
60
61 def handle_bb_data(self, file_name, bb_data, cached):
62 """
63 We will fill the dictionaries with the stuff we
64 need for building the tree more fast
65 """
66 if bb_data == None:
67 return
68
69 if not cached:
70 self.cache_dirty = True
71
72 pn = bb.data.getVar('PN', bb_data, True)
73 pv = bb.data.getVar('PV', bb_data, True)
74 pr = bb.data.getVar('PR', bb_data, True)
75 dp = int(bb.data.getVar('DEFAULT_PREFERENCE', bb_data, True) or "0")
76 provides = Set([pn] + (bb.data.getVar("PROVIDES", bb_data, 1) or "").split())
77 depends = (bb.data.getVar("DEPENDS", bb_data, True) or "").split()
78
79
80 # build PackageName to FileName lookup table
81 if pn not in self.pkg_pn:
82 self.pkg_pn[pn] = []
83 self.pkg_pn[pn].append(file_name)
84
85 # build FileName to PackageName lookup table
86 self.pkg_fn[file_name] = pn
87 self.pkg_pvpr[file_name] = (pv,pr)
88 self.pkg_dp[file_name] = dp
89
90 # Build forward and reverse provider hashes
91 # Forward: virtual -> [filenames]
92 # Reverse: PN -> [virtuals]
93 if pn not in self.pn_provides:
94 self.pn_provides[pn] = Set()
95 self.pn_provides[pn] |= provides
96
97 for provide in provides:
98 if provide not in self.providers:
99 self.providers[provide] = []
100 self.providers[provide].append(file_name)
101
102 for dep in depends:
103 self.all_depends.add(dep)
104
105 # Collect files we may need for possible world-dep
106 # calculations
107 if not bb.data.getVar('BROKEN', bb_data, True) and not bb.data.getVar('EXCLUDE_FROM_WORLD', bb_data, True):
108 self.possible_world.append(file_name)
109
110
111#============================================================================#
112# BBStatistics
113#============================================================================#
114class BBStatistics:
115 """
116 Manage build statistics for one run
117 """
118 def __init__(self ):
119 self.attempt = 0
120 self.success = 0
121 self.fail = 0
122 self.deps = 0
123
124 def show( self ):
125 print "Build statistics:"
126 print " Attempted builds: %d" % self.attempt
127 if self.fail:
128 print " Failed builds: %d" % self.fail
129 if self.deps:
130 print " Dependencies not satisfied: %d" % self.deps
131 if self.fail or self.deps: return 1
132 else: return 0
133
134
135#============================================================================#
136# BBOptions
137#============================================================================#
138class BBConfiguration( object ):
139 """
140 Manages build options and configurations for one run
141 """
142 def __init__( self, options ):
143 for key, val in options.__dict__.items():
144 setattr( self, key, val )
145 self.data = data.init()
146
147#============================================================================#
148# BBCooker
149#============================================================================#
150class BBCooker:
151 """
152 Manages one bitbake build run
153 """
154
155 ParsingStatus = BBParsingStatus # make it visible from the shell
156 Statistics = BBStatistics # make it visible from the shell
157
158 def __init__( self ):
159 self.build_cache_fail = []
160 self.build_cache = []
161 self.building_list = []
162 self.build_path = []
163 self.consider_msgs_cache = []
164 self.preferred = {}
165 self.stats = BBStatistics()
166 self.status = None
167
168 self.pkgdata = None
169 self.cache = None
170
171 def tryBuildPackage( self, fn, item, the_data ):
172 """Build one package"""
173 bb.event.fire(bb.event.PkgStarted(item, the_data))
174 try:
175 self.stats.attempt += 1
176 if self.configuration.force:
177 bb.data.setVarFlag('do_%s' % self.configuration.cmd, 'force', 1, the_data)
178 if not self.configuration.dry_run:
179 bb.build.exec_task('do_%s' % self.configuration.cmd, the_data)
180 bb.event.fire(bb.event.PkgSucceeded(item, the_data))
181 self.build_cache.append(fn)
182 return True
183 except bb.build.FuncFailed:
184 self.stats.fail += 1
185 bb.error("task stack execution failed")
186 bb.event.fire(bb.event.PkgFailed(item, the_data))
187 self.build_cache_fail.append(fn)
188 raise
189 except bb.build.EventException, e:
190 self.stats.fail += 1
191 event = e.args[1]
192 bb.error("%s event exception, aborting" % bb.event.getName(event))
193 bb.event.fire(bb.event.PkgFailed(item, the_data))
194 self.build_cache_fail.append(fn)
195 raise
196
197 def tryBuild( self, fn, virtual ):
198 """Build a provider and its dependencies"""
199 if fn in self.building_list:
200 bb.error("%s depends on itself (eventually)" % fn)
201 bb.error("upwards chain is: %s" % (" -> ".join(self.build_path)))
202 return False
203
204 the_data = self.pkgdata[fn]
205 item = self.status.pkg_fn[fn]
206
207 self.building_list.append(fn)
208
209 pathstr = "%s (%s)" % (item, virtual)
210 self.build_path.append(pathstr)
211
212 depends_list = (bb.data.getVar('DEPENDS', the_data, 1) or "").split()
213 if self.configuration.verbose:
214 bb.note("current path: %s" % (" -> ".join(self.build_path)))
215 bb.note("dependencies for %s are: %s" % (item, " ".join(depends_list)))
216
217 try:
218 failed = False
219
220 depcmd = self.configuration.cmd
221 bbdepcmd = bb.data.getVarFlag('do_%s' % self.configuration.cmd, 'bbdepcmd', the_data)
222 if bbdepcmd is not None:
223 if bbdepcmd == "":
224 depcmd = None
225 else:
226 depcmd = bbdepcmd
227
228 if depcmd:
229 oldcmd = self.configuration.cmd
230 self.configuration.cmd = depcmd
231
232 for dependency in depends_list:
233 if dependency in self.status.ignored_dependencies:
234 continue
235 if not depcmd:
236 continue
237 if self.buildProvider( dependency ) == 0:
238 bb.error("dependency %s (for %s) not satisfied" % (dependency,item))
239 failed = True
240 if self.configuration.abort:
241 break
242
243 if depcmd:
244 self.configuration.cmd = oldcmd
245
246 if failed:
247 self.stats.deps += 1
248 return False
249
250 if bb.build.stamp_is_current('do_%s' % self.configuration.cmd, the_data):
251 self.build_cache.append(fn)
252 return True
253
254 return self.tryBuildPackage( fn, item, the_data )
255
256 finally:
257 self.building_list.remove(fn)
258 self.build_path.remove(pathstr)
259
260 def findBestProvider( self, pn, pkg_pn = None):
261 """
262 If there is a PREFERRED_VERSION, find the highest-priority bbfile
263 providing that version. If not, find the latest version provided by
264 an bbfile in the highest-priority set.
265 """
266 if not pkg_pn:
267 pkg_pn = self.status.pkg_pn
268
269 files = pkg_pn[pn]
270 priorities = {}
271 for f in files:
272 priority = self.status.bbfile_priority[f]
273 if priority not in priorities:
274 priorities[priority] = []
275 priorities[priority].append(f)
276 p_list = priorities.keys()
277 p_list.sort(lambda a, b: a - b)
278 tmp_pn = []
279 for p in p_list:
280 tmp_pn = [priorities[p]] + tmp_pn
281
282 preferred_file = None
283
284 preferred_v = bb.data.getVar('PREFERRED_VERSION_%s' % pn, self.configuration.data, 1)
285 if preferred_v:
286 m = re.match('(.*)_(.*)', preferred_v)
287 if m:
288 preferred_v = m.group(1)
289 preferred_r = m.group(2)
290 else:
291 preferred_r = None
292
293 for file_set in tmp_pn:
294 for f in file_set:
295 pv,pr = self.status.pkg_pvpr[f]
296 if preferred_v == pv and (preferred_r == pr or preferred_r == None):
297 preferred_file = f
298 preferred_ver = (pv, pr)
299 break
300 if preferred_file:
301 break;
302 if preferred_r:
303 pv_str = '%s-%s' % (preferred_v, preferred_r)
304 else:
305 pv_str = preferred_v
306 if preferred_file is None:
307 bb.note("preferred version %s of %s not available" % (pv_str, pn))
308 else:
309 bb.debug(1, "selecting %s as PREFERRED_VERSION %s of package %s" % (preferred_file, pv_str, pn))
310
311 # get highest priority file set
312 files = tmp_pn[0]
313 latest = None
314 latest_p = 0
315 latest_f = None
316 for file_name in files:
317 pv,pr = self.status.pkg_pvpr[file_name]
318 dp = self.status.pkg_dp[file_name]
319
320 if (latest is None) or ((latest_p == dp) and (utils.vercmp(latest, (pv, pr)) < 0)) or (dp > latest_p):
321 latest = (pv, pr)
322 latest_f = file_name
323 latest_p = dp
324 if preferred_file is None:
325 preferred_file = latest_f
326 preferred_ver = latest
327
328 return (latest,latest_f,preferred_ver, preferred_file)
329
330 def showVersions( self ):
331 pkg_pn = self.status.pkg_pn
332 preferred_versions = {}
333 latest_versions = {}
334
335 # Sort by priority
336 for pn in pkg_pn.keys():
337 (last_ver,last_file,pref_ver,pref_file) = self.findBestProvider(pn)
338 preferred_versions[pn] = (pref_ver, pref_file)
339 latest_versions[pn] = (last_ver, last_file)
340
341 pkg_list = pkg_pn.keys()
342 pkg_list.sort()
343
344 for p in pkg_list:
345 pref = preferred_versions[p]
346 latest = latest_versions[p]
347
348 if pref != latest:
349 prefstr = pref[0][0] + "-" + pref[0][1]
350 else:
351 prefstr = ""
352
353 print "%-30s %20s %20s" % (p, latest[0][0] + "-" + latest[0][1],
354 prefstr)
355
356 def showEnvironment( self ):
357 """Show the outer or per-package environment"""
358 if self.configuration.buildfile:
359 try:
360 self.configuration.data, fromCache = self.load_bbfile( self.configuration.buildfile )
361 except IOError, e:
362 fatal("Unable to read %s: %s" % ( self.configuration.buildfile, e ))
363 except Exception, e:
364 fatal("%s" % e)
365 # emit variables and shell functions
366 try:
367 data.update_data( self.configuration.data )
368 data.emit_env(sys.__stdout__, self.configuration.data, True)
369 except Exception, e:
370 fatal("%s" % e)
371 # emit the metadata which isnt valid shell
372 for e in self.configuration.data.keys():
373 if data.getVarFlag( e, 'python', self.configuration.data ):
374 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, data.getVar(e, self.configuration.data, 1)))
375
376 def buildProvider( self, item ):
377 fn = None
378
379 discriminated = False
380
381 if item not in self.status.providers:
382 bb.error("Nothing provides %s" % item)
383 return 0
384
385 all_p = self.status.providers[item]
386
387 for p in all_p:
388 if p in self.build_cache:
389 bb.debug(1, "already built %s in this run\n" % p)
390 return 1
391
392 eligible = []
393 preferred_versions = {}
394
395 # Collate providers by PN
396 pkg_pn = {}
397 for p in all_p:
398 pn = self.status.pkg_fn[p]
399 if pn not in pkg_pn:
400 pkg_pn[pn] = []
401 pkg_pn[pn].append(p)
402
403 bb.debug(1, "providers for %s are: %s" % (item, pkg_pn.keys()))
404
405 for pn in pkg_pn.keys():
406 preferred_versions[pn] = self.findBestProvider(pn, pkg_pn)[2:4]
407 eligible.append(preferred_versions[pn][1])
408
409 for p in eligible:
410 if p in self.build_cache_fail:
411 bb.debug(1, "rejecting already-failed %s" % p)
412 eligible.remove(p)
413
414 if len(eligible) == 0:
415 bb.error("no eligible providers for %s" % item)
416 return 0
417
418 # look to see if one of them is already staged, or marked as preferred.
419 # if so, bump it to the head of the queue
420 for p in all_p:
421 the_data = self.pkgdata[p]
422 pn = bb.data.getVar('PN', the_data, 1)
423 pv = bb.data.getVar('PV', the_data, 1)
424 pr = bb.data.getVar('PR', the_data, 1)
425 tmpdir = bb.data.getVar('TMPDIR', the_data, 1)
426 stamp = '%s/stamps/%s-%s-%s.do_populate_staging' % (tmpdir, pn, pv, pr)
427 if os.path.exists(stamp):
428 (newvers, fn) = preferred_versions[pn]
429 if not fn in eligible:
430 # package was made ineligible by already-failed check
431 continue
432 oldver = "%s-%s" % (pv, pr)
433 newver = '-'.join(newvers)
434 if (newver != oldver):
435 extra_chat = "; upgrading from %s to %s" % (oldver, newver)
436 else:
437 extra_chat = ""
438 if self.configuration.verbose:
439 bb.note("selecting already-staged %s to satisfy %s%s" % (pn, item, extra_chat))
440 eligible.remove(fn)
441 eligible = [fn] + eligible
442 discriminated = True
443 break
444
445 prefervar = bb.data.getVar('PREFERRED_PROVIDER_%s' % item, self.configuration.data, 1)
446 if prefervar:
447 self.preferred[item] = prefervar
448
449 if item in self.preferred:
450 for p in eligible:
451 pn = self.status.pkg_fn[p]
452 if self.preferred[item] == pn:
453 if self.configuration.verbose:
454 bb.note("selecting %s to satisfy %s due to PREFERRED_PROVIDERS" % (pn, item))
455 eligible.remove(p)
456 eligible = [p] + eligible
457 discriminated = True
458 break
459
460 if len(eligible) > 1 and discriminated == False:
461 if item not in self.consider_msgs_cache:
462 providers_list = []
463 for fn in eligible:
464 providers_list.append(self.status.pkg_fn[fn])
465 bb.note("multiple providers are available (%s);" % ", ".join(providers_list))
466 bb.note("consider defining PREFERRED_PROVIDER_%s" % item)
467 self.consider_msgs_cache.append(item)
468
469
470 # run through the list until we find one that we can build
471 for fn in eligible:
472 bb.debug(2, "selecting %s to satisfy %s" % (fn, item))
473 if self.tryBuild(fn, item):
474 return 1
475
476 bb.note("no buildable providers for %s" % item)
477 return 0
478
479 def buildDepgraph( self ):
480 all_depends = self.status.all_depends
481 pn_provides = self.status.pn_provides
482
483 def calc_bbfile_priority(filename):
484 for (regex, pri) in self.status.bbfile_config_priorities:
485 if regex.match(filename):
486 return pri
487 return 0
488
489 # Handle PREFERRED_PROVIDERS
490 for p in (bb.data.getVar('PREFERRED_PROVIDERS', self.configuration.data, 1) or "").split():
491 (providee, provider) = p.split(':')
492 if providee in self.preferred and self.preferred[providee] != provider:
493 bb.error("conflicting preferences for %s: both %s and %s specified" % (providee, provider, self.preferred[providee]))
494 self.preferred[providee] = provider
495
496 # Calculate priorities for each file
497 for p in self.pkgdata.keys():
498 self.status.bbfile_priority[p] = calc_bbfile_priority(p)
499
500 # Build package list for "bitbake world"
501 bb.debug(1, "collating packages for \"world\"")
502 for f in self.status.possible_world:
503 terminal = True
504 pn = self.status.pkg_fn[f]
505
506 for p in pn_provides[pn]:
507 if p.startswith('virtual/'):
508 bb.debug(2, "skipping %s due to %s provider starting with virtual/" % (f, p))
509 terminal = False
510 break
511 for pf in self.status.providers[p]:
512 if self.status.pkg_fn[pf] != pn:
513 bb.debug(2, "skipping %s due to both us and %s providing %s" % (f, pf, p))
514 terminal = False
515 break
516 if terminal:
517 self.status.world_target.add(pn)
518
519 # drop reference count now
520 self.status.possible_world = None
521 self.status.all_depends = None
522
523 def myProgressCallback( self, x, y, f, file_data, from_cache ):
524 # feed the status with new input
525 self.status.handle_bb_data(f, file_data, from_cache)
526
527 if bbdebug > 0:
528 return
529 if os.isatty(sys.stdout.fileno()):
530 sys.stdout.write("\rNOTE: Handling BitBake files: %s (%04d/%04d) [%2d %%]" % ( parsespin.next(), x, y, x*100/y ) )
531 sys.stdout.flush()
532 else:
533 if x == 1:
534 sys.stdout.write("Parsing .bb files, please wait...")
535 sys.stdout.flush()
536 if x == y:
537 sys.stdout.write("done.")
538 sys.stdout.flush()
539
540 def interactiveMode( self ):
541 """Drop off into a shell"""
542 try:
543 from bb import shell
544 except ImportError, details:
545 bb.fatal("Sorry, shell not available (%s)" % details )
546 else:
547 bb.data.update_data( self.configuration.data )
548 shell.start( self )
549 sys.exit( 0 )
550
551 def parseConfigurationFile( self, afile ):
552 try:
553 self.configuration.data = bb.parse.handle( afile, self.configuration.data )
554 except IOError:
555 bb.fatal( "Unable to open %s" % afile )
556 except bb.parse.ParseError, details:
557 bb.fatal( "Unable to parse %s (%s)" % (afile, details) )
558
559 def handleCollections( self, collections ):
560 """Handle collections"""
561 if collections:
562 collection_list = collections.split()
563 for c in collection_list:
564 regex = bb.data.getVar("BBFILE_PATTERN_%s" % c, self.configuration.data, 1)
565 if regex == None:
566 bb.error("BBFILE_PATTERN_%s not defined" % c)
567 continue
568 priority = bb.data.getVar("BBFILE_PRIORITY_%s" % c, self.configuration.data, 1)
569 if priority == None:
570 bb.error("BBFILE_PRIORITY_%s not defined" % c)
571 continue
572 try:
573 cre = re.compile(regex)
574 except re.error:
575 bb.error("BBFILE_PATTERN_%s \"%s\" is not a valid regular expression" % (c, regex))
576 continue
577 try:
578 pri = int(priority)
579 self.status.bbfile_config_priorities.append((cre, pri))
580 except ValueError:
581 bb.error("invalid value for BBFILE_PRIORITY_%s: \"%s\"" % (c, priority))
582
583
584 def cook( self, configuration, args ):
585 self.configuration = configuration
586
587 if not self.configuration.cmd:
588 self.configuration.cmd = "build"
589
590 if self.configuration.debug:
591 bb.debug_level = self.configuration.debug
592
593 self.configuration.data = bb.data.init()
594
595 for f in self.configuration.file:
596 self.parseConfigurationFile( f )
597
598 self.parseConfigurationFile( os.path.join( "conf", "bitbake.conf" ) )
599
600 if self.configuration.show_environment:
601 self.showEnvironment()
602 sys.exit( 0 )
603
604 # inject custom variables
605 if not bb.data.getVar("BUILDNAME", self.configuration.data):
606 bb.data.setVar("BUILDNAME", os.popen('date +%Y%m%d%H%M').readline().strip(), self.configuration.data)
607 bb.data.setVar("BUILDSTART", time.strftime('%m/%d/%Y %H:%M:%S',time.gmtime()),self.configuration.data)
608
609 buildname = bb.data.getVar("BUILDNAME", self.configuration.data)
610
611 if self.configuration.interactive:
612 self.interactiveMode()
613
614 if self.configuration.buildfile is not None:
615 bf = os.path.abspath( self.configuration.buildfile )
616 try:
617 bbfile_data = bb.parse.handle(bf, self.configuration.data)
618 except IOError:
619 bb.fatal("Unable to open %s" % bf)
620
621 item = bb.data.getVar('PN', bbfile_data, 1)
622 try:
623 self.tryBuildPackage( bf, item, bbfile_data )
624 except bb.build.EventException:
625 bb.error( "Build of '%s' failed" % item )
626
627 sys.exit( self.stats.show() )
628
629 # initialise the parsing status now we know we will need deps
630 self.status = BBParsingStatus()
631
632 ignore = bb.data.getVar("ASSUME_PROVIDED", self.configuration.data, 1) or ""
633 self.status.ignored_dependencies = Set( ignore.split() )
634
635 self.handleCollections( bb.data.getVar("BBFILE_COLLECTIONS", self.configuration.data, 1) )
636
637 pkgs_to_build = None
638 if args:
639 if not pkgs_to_build:
640 pkgs_to_build = []
641 pkgs_to_build.extend(args)
642 if not pkgs_to_build:
643 bbpkgs = bb.data.getVar('BBPKGS', self.configuration.data, 1)
644 if bbpkgs:
645 pkgs_to_build = bbpkgs.split()
646 if not pkgs_to_build and not self.configuration.show_versions \
647 and not self.configuration.interactive \
648 and not self.configuration.show_environment:
649 print "Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help'"
650 print "for usage information."
651 sys.exit(0)
652
653 # Import Psyco if available and not disabled
654 if not self.configuration.disable_psyco:
655 try:
656 import psyco
657 except ImportError:
658 if bbdebug == 0:
659 bb.note("Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.")
660 else:
661 psyco.bind( self.collect_bbfiles )
662 else:
663 bb.note("You have disabled Psyco. This decreases performance.")
664
665 try:
666 bb.debug(1, "collecting .bb files")
667 self.collect_bbfiles( self.myProgressCallback )
668 bb.debug(1, "parsing complete")
669 if bbdebug == 0:
670 print
671 if self.configuration.parse_only:
672 print "Requested parsing .bb files only. Exiting."
673 return
674
675 bb.data.update_data( self.configuration.data )
676 self.buildDepgraph()
677
678 if self.configuration.show_versions:
679 self.showVersions()
680 sys.exit( 0 )
681 if 'world' in pkgs_to_build:
682 pkgs_to_build.remove('world')
683 for t in self.status.world_target:
684 pkgs_to_build.append(t)
685
686 bb.event.fire(bb.event.BuildStarted(buildname, pkgs_to_build, self.configuration.data))
687
688 for k in pkgs_to_build:
689 failed = False
690 try:
691 if self.buildProvider( k ) == 0:
692 # already diagnosed
693 failed = True
694 except bb.build.EventException:
695 bb.error("Build of " + k + " failed")
696 failed = True
697
698 if failed:
699 if self.configuration.abort:
700 sys.exit(1)
701
702 bb.event.fire(bb.event.BuildCompleted(buildname, pkgs_to_build, self.configuration.data))
703
704 sys.exit( self.stats.show() )
705
706 except KeyboardInterrupt:
707 print "\nNOTE: KeyboardInterrupt - Build not completed."
708 sys.exit(1)
709
710 def get_bbfiles( self, path = os.getcwd() ):
711 """Get list of default .bb files by reading out the current directory"""
712 contents = os.listdir(path)
713 bbfiles = []
714 for f in contents:
715 (root, ext) = os.path.splitext(f)
716 if ext == ".bb":
717 bbfiles.append(os.path.abspath(os.path.join(os.getcwd(),f)))
718 return bbfiles
719
720 def find_bbfiles( self, path ):
721 """Find all the .bb files in a directory (uses find)"""
722 findcmd = 'find ' + path + ' -name *.bb | grep -v SCCS/'
723 try:
724 finddata = os.popen(findcmd)
725 except OSError:
726 return []
727 return finddata.readlines()
728
729 def deps_clean(self, d):
730 depstr = data.getVar('__depends', d)
731 if depstr:
732 deps = depstr.split(" ")
733 for dep in deps:
734 (f,old_mtime_s) = dep.split("@")
735 old_mtime = int(old_mtime_s)
736 new_mtime = parse.cached_mtime(f)
737 if (new_mtime > old_mtime):
738 return False
739 return True
740
741 def load_bbfile( self, bbfile ):
742 """Load and parse one .bb build file"""
743
744 if not self.cache in [None, '']:
745 # get the times
746 cache_mtime = data.init_db_mtime(self.cache, bbfile)
747 file_mtime = parse.cached_mtime(bbfile)
748
749 if file_mtime > cache_mtime:
750 #print " : '%s' dirty. reparsing..." % bbfile
751 pass
752 else:
753 #print " : '%s' clean. loading from cache..." % bbfile
754 cache_data = data.init_db( self.cache, bbfile, False )
755 if self.deps_clean(cache_data):
756 return cache_data, True
757
758 topdir = data.getVar('TOPDIR', self.configuration.data)
759 if not topdir:
760 topdir = os.path.abspath(os.getcwd())
761 # set topdir to here
762 data.setVar('TOPDIR', topdir, self.configuration)
763 bbfile = os.path.abspath(bbfile)
764 bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
765 # expand tmpdir to include this topdir
766 data.setVar('TMPDIR', data.getVar('TMPDIR', self.configuration.data, 1) or "", self.configuration.data)
767 # set topdir to location of .bb file
768 topdir = bbfile_loc
769 #data.setVar('TOPDIR', topdir, cfg)
770 # go there
771 oldpath = os.path.abspath(os.getcwd())
772 os.chdir(topdir)
773 bb = data.init_db(self.cache,bbfile, True, self.configuration.data)
774 try:
775 parse.handle(bbfile, bb) # read .bb data
776 if not self.cache in [None, '']:
777 bb.commit(parse.cached_mtime(bbfile)) # write cache
778 os.chdir(oldpath)
779 return bb, False
780 finally:
781 os.chdir(oldpath)
782
783 def collect_bbfiles( self, progressCallback ):
784 """Collect all available .bb build files"""
785 self.cb = progressCallback
786 parsed, cached, skipped, masked = 0, 0, 0, 0
787 self.cache = bb.data.getVar( "CACHE", self.configuration.data, 1 )
788 self.pkgdata = data.pkgdata( not self.cache in [None, ''], self.cache, self.configuration.data )
789
790 if not self.cache in [None, '']:
791 if self.cb is not None:
792 print "NOTE: Using cache in '%s'" % self.cache
793 try:
794 os.stat( self.cache )
795 except OSError:
796 bb.mkdirhier( self.cache )
797 else:
798 if self.cb is not None:
799 print "NOTE: Not using a cache. Set CACHE = <directory> to enable."
800 files = (data.getVar( "BBFILES", self.configuration.data, 1 ) or "").split()
801 data.setVar("BBFILES", " ".join(files), self.configuration.data)
802
803 if not len(files):
804 files = self.get_bbfiles()
805
806 if not len(files):
807 bb.error("no files to build.")
808
809 newfiles = []
810 for f in files:
811 if os.path.isdir(f):
812 dirfiles = self.find_bbfiles(f)
813 if dirfiles:
814 newfiles += dirfiles
815 continue
816 newfiles += glob.glob(f) or [ f ]
817
818 bbmask = bb.data.getVar('BBMASK', self.configuration.data, 1) or ""
819 try:
820 bbmask_compiled = re.compile(bbmask)
821 except sre_constants.error:
822 bb.fatal("BBMASK is not a valid regular expression.")
823
824 for i in xrange( len( newfiles ) ):
825 f = newfiles[i]
826 if bbmask and bbmask_compiled.search(f):
827 bb.debug(1, "bbmake: skipping %s" % f)
828 masked += 1
829 continue
830 debug(1, "bbmake: parsing %s" % f)
831
832 # read a file's metadata
833 try:
834 bb_data, fromCache = self.load_bbfile(f)
835 if fromCache: cached += 1
836 else: parsed += 1
837 deps = None
838 if bb_data is not None:
839 # allow metadata files to add items to BBFILES
840 #data.update_data(self.pkgdata[f])
841 addbbfiles = data.getVar('BBFILES', bb_data) or None
842 if addbbfiles:
843 for aof in addbbfiles.split():
844 if not files.count(aof):
845 if not os.path.isabs(aof):
846 aof = os.path.join(os.path.dirname(f),aof)
847 files.append(aof)
848 for var in bb_data.keys():
849 if data.getVarFlag(var, "handler", bb_data) and data.getVar(var, bb_data):
850 event.register(data.getVar(var, bb_data))
851 self.pkgdata[f] = bb_data
852
853 # now inform the caller
854 if self.cb is not None:
855 self.cb( i + 1, len( newfiles ), f, bb_data, fromCache )
856
857 except IOError, e:
858 bb.error("opening %s: %s" % (f, e))
859 pass
860 except bb.parse.SkipPackage:
861 skipped += 1
862 pass
863 except KeyboardInterrupt:
864 raise
865 except Exception, e:
866 bb.error("%s while parsing %s" % (e, f))
867
868 if self.cb is not None:
869 print "\rNOTE: Parsing finished. %d cached, %d parsed, %d skipped, %d masked." % ( cached, parsed, skipped, masked ),
870
871#============================================================================#
872# main
873#============================================================================#
874
875if __name__ == "__main__":
876
877 parser = optparse.OptionParser( version = "BitBake Build Tool Core version %s, %%prog version %s" % ( bb.__version__, __version__ ),
878 usage = """%prog [options] [package ...]
879
880Executes the specified task (default is 'build') for a given set of BitBake files.
881It expects that BBFILES is defined, which is a space seperated list of files to
882be executed. BBFILES does support wildcards.
883Default BBFILES are the .bb files in the current directory.""" )
884
885 parser.add_option( "-b", "--buildfile", help = "execute the task against this .bb file, rather than a package from BBFILES.",
886 action = "store", dest = "buildfile", default = None )
887
888 parser.add_option( "-k", "--continue", help = "continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same.",
889 action = "store_false", dest = "abort", default = True )
890
891 parser.add_option( "-f", "--force", help = "force run of specified cmd, regardless of stamp status",
892 action = "store_true", dest = "force", default = False )
893
894 parser.add_option( "-i", "--interactive", help = "drop into the interactive mode.",
895 action = "store_true", dest = "interactive", default = False )
896
897 parser.add_option( "-c", "--cmd", help = "Specify task to execute. Note that this only executes the specified task for the providee and the packages it depends on, i.e. 'compile' does not implicitly call stage for the dependencies (IOW: use only if you know what you are doing)",
898 action = "store", dest = "cmd", default = "build" )
899
900 parser.add_option( "-r", "--read", help = "read the specified file before bitbake.conf",
901 action = "append", dest = "file", default = [] )
902
903 parser.add_option( "-v", "--verbose", help = "output more chit-chat to the terminal",
904 action = "store_true", dest = "verbose", default = False )
905
906 parser.add_option( "-D", "--debug", help = "Increase the debug level",
907 action = "count", dest="debug", default = 0)
908
909 parser.add_option( "-n", "--dry-run", help = "don't execute, just go through the motions",
910 action = "store_true", dest = "dry_run", default = False )
911
912 parser.add_option( "-p", "--parse-only", help = "quit after parsing the BB files (developers only)",
913 action = "store_true", dest = "parse_only", default = False )
914
915 parser.add_option( "-d", "--disable-psyco", help = "disable using the psyco just-in-time compiler (not recommended)",
916 action = "store_true", dest = "disable_psyco", default = False )
917
918 parser.add_option( "-s", "--show-versions", help = "show current and preferred versions of all packages",
919 action = "store_true", dest = "show_versions", default = False )
920
921 parser.add_option( "-e", "--environment", help = "show the global or per-package environment (this is what used to be bbread)",
922 action = "store_true", dest = "show_environment", default = False )
923
924 options, args = parser.parse_args( sys.argv )
925
926 cooker = BBCooker()
927 cooker.cook( BBConfiguration( options ), args[1:] )
diff --git a/bitbake/bin/bitbakec b/bitbake/bin/bitbakec
new file mode 100644
index 0000000000..dc2e0a9fa9
--- /dev/null
+++ b/bitbake/bin/bitbakec
Binary files differ
diff --git a/bitbake/bin/bitdoc b/bitbake/bin/bitdoc
new file mode 100755
index 0000000000..64d32945ba
--- /dev/null
+++ b/bitbake/bin/bitdoc
@@ -0,0 +1,529 @@
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 Holger Hans Peter Freyther
6#
7#
8# Permission is hereby granted, free of charge, to any person obtaining a copy
9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in all
16# copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
24# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25#
26#
27
28import optparse, os, sys
29
30# bitbake
31sys.path.append(os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
32import bb
33from bb import make
34from string import split, join
35
36__version__ = "0.0.2"
37
38class HTMLFormatter:
39 """
40 Simple class to help to generate some sort of HTML files. It is
41 quite inferior solution compared to docbook, gtkdoc, doxygen but it
42 should work for now.
43 We've a global introduction site (index.html) and then one site for
44 the list of keys (alphabetical sorted) and one for the list of groups,
45 one site for each key with links to the relations and groups.
46
47 index.html
48 keys.html
49 groups.html
50 groupNAME.html
51 keyNAME.html
52 """
53
54 def replace(self, text, *pairs):
55 """
56 From pydoc... almost identical at least
57 """
58 while pairs:
59 (a,b) = pairs[0]
60 text = join(split(text, a), b)
61 pairs = pairs[1:]
62 return text
63 def escape(self, text):
64 """
65 Escape string to be conform HTML
66 """
67 return self.replace(text,
68 ('&', '&amp;'),
69 ('<', '&lt;' ),
70 ('>', '&gt;' ) )
71 def createNavigator(self):
72 """
73 Create the navgiator
74 """
75 return """<table class="navigation" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2">
76<tr valign="middle">
77<td><a accesskey="g" href="index.html">Home</a></td>
78<td><a accesskey="n" href="groups.html">Groups</a></td>
79<td><a accesskey="u" href="keys.html">Keys</a></td>
80</tr></table>
81"""
82
83 def relatedKeys(self, item):
84 """
85 Create HTML to link to foreign keys
86 """
87
88 if len(item.related()) == 0:
89 return ""
90
91 txt = "<p><b>See also:</b><br>"
92 for it in item.related():
93 txt += """<a href="key%s.html">%s</a>, """ % (it, it)
94
95 return txt
96
97 def groups(self,item):
98 """
99 Create HTML to link to related groups
100 """
101
102 if len(item.groups()) == 0:
103 return ""
104
105
106 txt = "<p><b>Seel also:</b><br>"
107 for group in item.groups():
108 txt += """<a href="group%s.html">%s</a>, """ % (group,group)
109
110 return txt
111
112
113 def createKeySite(self,item):
114 """
115 Create a site for a key. It contains the header/navigator, a heading,
116 the description, links to related keys and to the groups.
117 """
118
119 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
120<html><head><title>Key %s</title></head>
121<link rel="stylesheet" href="style.css" type="text/css">
122<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
123%s
124<h2><span class="refentrytitle">%s</span></h2>
125
126<div class="refsynopsisdiv">
127<h2>Synopsis</h2>
128<pre class="synopsis">
129%s
130</pre>
131</div>
132
133<div class="refsynopsisdiv">
134<h2>Related Keys</h2>
135<pre class="synopsis">
136%s
137</pre>
138</div>
139
140<div class="refsynopsisdiv">
141<h2>Groups</h2>
142<pre class="synopsis">
143%s
144</pre>
145</div>
146
147
148</body>
149""" % (item.name(), self.createNavigator(), item.name(),
150 self.escape(item.description()), self.relatedKeys(item), self.groups(item))
151
152 def createGroupsSite(self, doc):
153 """
154 Create the Group Overview site
155 """
156
157 groups = ""
158 sorted_groups = doc.groups()
159 sorted_groups.sort()
160 for group in sorted_groups:
161 groups += """<a href="group%s.html">%s</a><br>""" % (group, group)
162
163 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
164<html><head><title>Group overview</title></head>
165<link rel="stylesheet" href="style.css" type="text/css">
166<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
167%s
168<h2>Available Groups</h2>
169%s
170</body>
171""" % (self.createNavigator(), groups)
172
173 def createIndex(self):
174 """
175 Create the index file
176 """
177
178 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
179<html><head><title>Bitbake Documentation</title></head>
180<link rel="stylesheet" href="style.css" type="text/css">
181<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
182%s
183<h2>Documentation Entrance</h2>
184<a href="groups.html">All available groups</a><br>
185<a href="keys.html">All available keys</a><br>
186</body>
187""" % self.createNavigator()
188
189 def createKeysSite(self, doc):
190 """
191 Create Overview of all avilable keys
192 """
193 keys = ""
194 sorted_keys = doc.doc_keys()
195 sorted_keys.sort()
196 for key in sorted_keys:
197 keys += """<a href="key%s.html">%s</a><br>""" % (key, key)
198
199 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
200<html><head><title>Key overview</title></head>
201<link rel="stylesheet" href="style.css" type="text/css">
202<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
203%s
204<h2>Available Keys</h2>
205%s
206</body>
207""" % (self.createNavigator(), keys)
208
209 def createGroupSite(self,gr, items):
210 """
211 Create a site for a group:
212 Group the name of the group, items contain the name of the keys
213 inside this group
214 """
215 groups = ""
216 for group in items:
217 groups += """<a href="key%s.html">%s</a><br>""" % (group.name(), group.name())
218
219 return """<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
220<html><head><title>Group %s</title></head>
221<link rel="stylesheet" href="style.css" type="text/css">
222<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
223%s
224<div class="refsynopsisdiv">
225<h2>Keys in Group %s</h2>
226<pre class="synopsis">
227%s
228</pre>
229</div>
230</body>
231""" % (gr, self.createNavigator(), gr, groups)
232
233
234
235 def createCSS(self):
236 """
237 Create the CSS file
238 """
239 return """.synopsis, .classsynopsis
240{
241 background: #eeeeee;
242 border: solid 1px #aaaaaa;
243 padding: 0.5em;
244}
245.programlisting
246{
247 background: #eeeeff;
248 border: solid 1px #aaaaff;
249 padding: 0.5em;
250}
251.variablelist
252{
253 padding: 4px;
254 margin-left: 3em;
255}
256.variablelist td:first-child
257{
258 vertical-align: top;
259}
260table.navigation
261{
262 background: #ffeeee;
263 border: solid 1px #ffaaaa;
264 margin-top: 0.5em;
265 margin-bottom: 0.5em;
266}
267.navigation a
268{
269 color: #770000;
270}
271.navigation a:visited
272{
273 color: #550000;
274}
275.navigation .title
276{
277 font-size: 200%;
278}
279div.refnamediv
280{
281 margin-top: 2em;
282}
283div.gallery-float
284{
285 float: left;
286 padding: 10px;
287}
288div.gallery-float img
289{
290 border-style: none;
291}
292div.gallery-spacer
293{
294 clear: both;
295}
296a
297{
298 text-decoration: none;
299}
300a:hover
301{
302 text-decoration: underline;
303 color: #FF0000;
304}
305"""
306
307
308
309class DocumentationItem:
310 """
311 A class to hold information about a configuration
312 item. It contains the key name, description, a list of related names,
313 and the group this item is contained in.
314 """
315
316 def __init__(self):
317 self._groups = []
318 self._related = []
319 self._name = ""
320 self._desc = ""
321
322 def groups(self):
323 return self._groups
324
325 def name(self):
326 return self._name
327
328 def description(self):
329 return self._desc
330
331 def related(self):
332 return self._related
333
334 def setName(self, name):
335 self._name = name
336
337 def setDescription(self, desc):
338 self._desc = desc
339
340 def addGroup(self, group):
341 self._groups.append(group)
342
343 def addRelation(self,relation):
344 self._related.append(relation)
345
346 def sort(self):
347 self._related.sort()
348 self._groups.sort()
349
350
351class Documentation:
352 """
353 Holds the documentation... with mappings from key to items...
354 """
355
356 def __init__(self):
357 self.__keys = {}
358 self.__groups = {}
359
360 def insert_doc_item(self, item):
361 """
362 Insert the Doc Item into the internal list
363 of representation
364 """
365 item.sort()
366 self.__keys[item.name()] = item
367
368 for group in item.groups():
369 if not group in self.__groups:
370 self.__groups[group] = []
371 self.__groups[group].append(item)
372 self.__groups[group].sort()
373
374
375 def doc_item(self, key):
376 """
377 Return the DocumentationInstance describing the key
378 """
379 try:
380 return self.__keys[key]
381 except KeyError:
382 return None
383
384 def doc_keys(self):
385 """
386 Return the documented KEYS (names)
387 """
388 return self.__keys.keys()
389
390 def groups(self):
391 """
392 Return the names of available groups
393 """
394 return self.__groups.keys()
395
396 def group_content(self,group_name):
397 """
398 Return a list of keys/names that are in a specefic
399 group or the empty list
400 """
401 try:
402 return self.__groups[group_name]
403 except KeyError:
404 return []
405
406
407def parse_cmdline(args):
408 """
409 Parse the CMD line and return the result as a n-tuple
410 """
411
412 parser = optparse.OptionParser( version = "Bitbake Documentation Tool Core version %s, %%prog version %s" % (bb.__version__,__version__))
413 usage = """%prog [options]
414
415Create a set of html pages (documentation) for a bitbake.conf....
416"""
417
418 # Add the needed options
419 parser.add_option( "-c", "--config", help = "Use the specified configuration file as source",
420 action = "store", dest = "config", default = os.path.join("conf", "documentation.conf") )
421
422 parser.add_option( "-o", "--output", help = "Output directory for html files",
423 action = "store", dest = "output", default = "html/" )
424
425 parser.add_option( "-D", "--debug", help = "Increase the debug level",
426 action = "count", dest = "debug", default = 0 )
427
428 parser.add_option( "-v","--verbose", help = "output more chit-char to the terminal",
429 action = "store_true", dest = "verbose", default = False )
430
431 options, args = parser.parse_args( sys.argv )
432
433 if options.debug:
434 bb.debug_level = options.debug
435
436 return options.config, options.output
437
438def main():
439 """
440 The main Method
441 """
442
443 (config_file,output_dir) = parse_cmdline( sys.argv )
444
445 # right to let us load the file now
446 try:
447 documentation = bb.parse.handle( config_file, bb.data.init() )
448 except IOError:
449 bb.fatal( "Unable to open %s" % config_file )
450 except bb.parse.ParseError:
451 bb.fatal( "Unable to parse %s" % config_file )
452
453
454 # Assuming we've the file loaded now, we will initialize the 'tree'
455 doc = Documentation()
456
457 # defined states
458 state_begin = 0
459 state_see = 1
460 state_group = 2
461
462 for key in bb.data.keys(documentation):
463 data = bb.data.getVarFlag(key, "doc", documentation)
464 if not data:
465 continue
466
467 # The Documentation now starts
468 doc_ins = DocumentationItem()
469 doc_ins.setName(key)
470
471
472 tokens = data.split(' ')
473 state = state_begin
474 string= ""
475 for token in tokens:
476 token = token.strip(',')
477
478 if not state == state_see and token == "@see":
479 state = state_see
480 continue
481 elif not state == state_group and token == "@group":
482 state = state_group
483 continue
484
485 if state == state_begin:
486 string += " %s" % token
487 elif state == state_see:
488 doc_ins.addRelation(token)
489 elif state == state_group:
490 doc_ins.addGroup(token)
491
492 # set the description
493 doc_ins.setDescription(string)
494 doc.insert_doc_item(doc_ins)
495
496 # let us create the HTML now
497 bb.mkdirhier(output_dir)
498 os.chdir(output_dir)
499
500 # Let us create the sites now. We do it in the following order
501 # Start with the index.html. It will point to sites explaining all
502 # keys and groups
503 html_slave = HTMLFormatter()
504
505 f = file('style.css', 'w')
506 print >> f, html_slave.createCSS()
507
508 f = file('index.html', 'w')
509 print >> f, html_slave.createIndex()
510
511 f = file('groups.html', 'w')
512 print >> f, html_slave.createGroupsSite(doc)
513
514 f = file('keys.html', 'w')
515 print >> f, html_slave.createKeysSite(doc)
516
517 # now for each group create the site
518 for group in doc.groups():
519 f = file('group%s.html' % group, 'w')
520 print >> f, html_slave.createGroupSite(group, doc.group_content(group))
521
522 # now for the keys
523 for key in doc.doc_keys():
524 f = file('key%s.html' % doc.doc_item(key).name(), 'w')
525 print >> f, html_slave.createKeySite(doc.doc_item(key))
526
527
528if __name__ == "__main__":
529 main()
diff --git a/bitbake/classes/base.bbclass b/bitbake/classes/base.bbclass
new file mode 100644
index 0000000000..1d75964f57
--- /dev/null
+++ b/bitbake/classes/base.bbclass
@@ -0,0 +1,79 @@
1# Copyright (C) 2003 Chris Larson
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the "Software"),
5# to deal in the Software without restriction, including without limitation
6# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7# and/or sell copies of the Software, and to permit persons to whom the
8# Software is furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included
11# in all copies or substantial portions of the Software.
12#
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
17# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19# OTHER DEALINGS IN THE SOFTWARE.
20
21die() {
22 bbfatal "$*"
23}
24
25bbnote() {
26 echo "NOTE:" "$*"
27}
28
29bbwarn() {
30 echo "WARNING:" "$*"
31}
32
33bbfatal() {
34 echo "FATAL:" "$*"
35 exit 1
36}
37
38bbdebug() {
39 test $# -ge 2 || {
40 echo "Usage: bbdebug level \"message\""
41 exit 1
42 }
43
44 test ${@bb.debug_level} -ge $1 && {
45 shift
46 echo "DEBUG:" $*
47 }
48}
49
50addtask showdata
51do_showdata[nostamp] = "1"
52python do_showdata() {
53 import sys
54 # emit variables and shell functions
55 bb.data.emit_env(sys.__stdout__, d, True)
56 # emit the metadata which isnt valid shell
57 for e in bb.data.keys(d):
58 if bb.data.getVarFlag(e, 'python', d):
59 sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, 1)))
60}
61
62addtask listtasks
63do_listtasks[nostamp] = "1"
64python do_listtasks() {
65 import sys
66 for e in bb.data.keys(d):
67 if bb.data.getVarFlag(e, 'task', d):
68 sys.__stdout__.write("%s\n" % e)
69}
70
71addtask build
72do_build[dirs] = "${TOPDIR}"
73do_build[nostamp] = "1"
74python base_do_build () {
75 bb.note("The included, default BB base.bbclass does not define a useful default task.")
76 bb.note("Try running the 'listtasks' task against a .bb to see what tasks are defined.")
77}
78
79EXPORT_FUNCTIONS do_clean do_mrproper do_build
diff --git a/bitbake/conf/bitbake.conf b/bitbake/conf/bitbake.conf
new file mode 100644
index 0000000000..fd216a3261
--- /dev/null
+++ b/bitbake/conf/bitbake.conf
@@ -0,0 +1,55 @@
1# Copyright (C) 2003 Chris Larson
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the "Software"),
5# to deal in the Software without restriction, including without limitation
6# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7# and/or sell copies of the Software, and to permit persons to whom the
8# Software is furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included
11# in all copies or substantial portions of the Software.
12#
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
17# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19# OTHER DEALINGS IN THE SOFTWARE.
20
21B = "${S}"
22CVSDIR = "${DL_DIR}/cvs"
23DEPENDS = ""
24DEPLOY_DIR = "${TMPDIR}/deploy"
25DEPLOY_DIR_IMAGE = "${DEPLOY_DIR}/images"
26DL_DIR = "${TMPDIR}/downloads"
27FETCHCOMMAND = ""
28FETCHCOMMAND_cvs = "/usr/bin/env cvs -d${CVSROOT} co ${CVSCOOPTS} ${CVSMODULE}"
29FETCHCOMMAND_svn = "/usr/bin/env svn co http://${SVNROOT} ${SVNCOOPTS} ${SVNMODULE}"
30FETCHCOMMAND_wget = "/usr/bin/env wget -t 5 --passive-ftp -P ${DL_DIR} ${URI}"
31FILESDIR = "${@bb.which(bb.data.getVar('FILESPATH', d, 1), '.')}"
32FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
33FILE_DIRNAME = "${@os.path.dirname(bb.data.getVar('FILE', d))}"
34IMAGE_CMD = "_NO_DEFINED_IMAGE_TYPES_"
35IMAGE_ROOTFS = "${TMPDIR}/rootfs"
36MKTEMPCMD = "mktemp -q ${TMPBASE}"
37MKTEMPDIRCMD = "mktemp -d -q ${TMPBASE}"
38OVERRIDES = "local:${MACHINE}:${TARGET_OS}:${TARGET_ARCH}"
39P = "${PN}-${PV}"
40PF = "${PN}-${PV}-${PR}"
41PN = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[0] or 'defaultpkgname'}"
42PR = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[2] or 'r0'}"
43PROVIDES = ""
44PV = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[1] or '1.0'}"
45RESUMECOMMAND = ""
46RESUMECOMMAND_wget = "/usr/bin/env wget -c -t 5 --passive-ftp -P ${DL_DIR} ${URI}"
47S = "${WORKDIR}/${P}"
48SRC_URI = "file://${FILE}"
49STAMP = "${TMPDIR}/stamps/${PF}"
50T = "${WORKDIR}/temp"
51TARGET_ARCH = "${BUILD_ARCH}"
52TMPDIR = "${TOPDIR}/tmp"
53UPDATECOMMAND = ""
54UPDATECOMMAND_cvs = "/usr/bin/env cvs update ${CVSCOOPTS}"
55WORKDIR = "${TMPDIR}/work/${PF}"
diff --git a/bitbake/contrib/README b/bitbake/contrib/README
new file mode 100644
index 0000000000..25e5156619
--- /dev/null
+++ b/bitbake/contrib/README
@@ -0,0 +1 @@
This directory is for additional contributed files which may be useful.
diff --git a/bitbake/contrib/bbdev.sh b/bitbake/contrib/bbdev.sh
new file mode 100644
index 0000000000..33a78531e1
--- /dev/null
+++ b/bitbake/contrib/bbdev.sh
@@ -0,0 +1,31 @@
1# This is a shell function to be sourced into your shell or placed in your .profile,
2# which makes setting things up for BitBake a bit easier.
3#
4# The author disclaims copyright to the contents of this file and places it in the
5# public domain.
6
7bbdev () {
8 local BBDIR PKGDIR BUILDDIR
9 if test x"$1" = "x--help"; then echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"; return 1; fi
10 if test x"$1" = x; then BBDIR=`pwd`; else BBDIR=$1; fi
11 if test x"$2" = x; then PKGDIR=`pwd`; else PKGDIR=$2; fi
12 if test x"$3" = x; then BUILDDIR=`pwd`; else BUILDDIR=$3; fi
13
14 BBDIR=`readlink -f $BBDIR`
15 PKGDIR=`readlink -f $PKGDIR`
16 BUILDDIR=`readlink -f $BUILDDIR`
17 if ! (test -d $BBDIR && test -d $PKGDIR && test -d $BUILDDIR); then
18 echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"
19 return 1
20 fi
21
22 PATH=$BBDIR/bin:$PATH
23 BBPATH=$BBDIR
24 if test x"$BBDIR" != x"$PKGDIR"; then
25 BBPATH=$PKGDIR:$BBPATH
26 fi
27 if test x"$PKGDIR" != x"$BUILDDIR"; then
28 BBPATH=$BUILDDIR:$BBPATH
29 fi
30 export BBPATH
31}
diff --git a/bitbake/doc/COPYING.GPL b/bitbake/doc/COPYING.GPL
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/bitbake/doc/COPYING.GPL
@@ -0,0 +1,340 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Library General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License
307 along with this program; if not, write to the Free Software
308 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
309
310
311Also add information on how to contact you by electronic and paper mail.
312
313If the program is interactive, make it output a short notice like this
314when it starts in an interactive mode:
315
316 Gnomovision version 69, Copyright (C) year name of author
317 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318 This is free software, and you are welcome to redistribute it
319 under certain conditions; type `show c' for details.
320
321The hypothetical commands `show w' and `show c' should show the appropriate
322parts of the General Public License. Of course, the commands you use may
323be called something other than `show w' and `show c'; they could even be
324mouse-clicks or menu items--whatever suits your program.
325
326You should also get your employer (if you work as a programmer) or your
327school, if any, to sign a "copyright disclaimer" for the program, if
328necessary. Here is a sample; alter the names:
329
330 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331 `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
333 <signature of Ty Coon>, 1 April 1989
334 Ty Coon, President of Vice
335
336This General Public License does not permit incorporating your program into
337proprietary programs. If your program is a subroutine library, you may
338consider it more useful to permit linking proprietary applications with the
339library. If this is what you want to do, use the GNU Library General
340Public License instead of this License.
diff --git a/bitbake/doc/COPYING.MIT b/bitbake/doc/COPYING.MIT
new file mode 100644
index 0000000000..7e7d57413d
--- /dev/null
+++ b/bitbake/doc/COPYING.MIT
@@ -0,0 +1,17 @@
1Permission is hereby granted, free of charge, to any person obtaining a copy
2of this software and associated documentation files (the "Software"), to deal
3in the Software without restriction, including without limitation the rights
4to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5copies of the Software, and to permit persons to whom the Software is
6furnished to do so, subject to the following conditions:
7
8The above copyright notice and this permission notice shall be included in all
9copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
14SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
17THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/bitbake/doc/manual/Makefile b/bitbake/doc/manual/Makefile
new file mode 100644
index 0000000000..a43c025455
--- /dev/null
+++ b/bitbake/doc/manual/Makefile
@@ -0,0 +1,56 @@
1topdir = .
2manual = $(topdir)/usermanual.xml
3# types = pdf txt rtf ps xhtml html man tex texi dvi
4# types = pdf txt
5types = $(xmltotypes) $(htmltypes)
6xmltotypes = pdf txt
7htmltypes = html xhtml
8htmlxsl = $(if $(filter $@,$(foreach type,$(htmltypes),$(type)-nochunks)),http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl,http://docbook.sourceforge.net/release/xsl/current/$@/chunk.xsl)
9htmlcssfile = docbook.css
10htmlcss = $(topdir)/html.css
11# htmlcssfile =
12# htmlcss =
13cleanfiles = $(foreach i,$(types),$(topdir)/$(i))
14
15ifdef DEBUG
16define command
17 $(1)
18endef
19else
20define command
21 @echo $(2) $(3) $(4)
22 @$(1) >/dev/null
23endef
24endif
25
26all: $(types)
27
28lint: $(manual) FORCE
29 $(call command,xmllint --xinclude --postvalid --noout $(manual),XMLLINT $(manual))
30
31$(types) $(foreach type,$(htmltypes),$(type)-nochunks): lint FORCE
32
33$(foreach type,$(htmltypes),$(type)-nochunks): $(if $(htmlcss),$(htmlcss)) $(manual)
34 @mkdir -p $@
35ifdef htmlcss
36 $(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
37endif
38 $(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual) > $@/index.$(patsubst %-nochunks,%,$@),XSLTPROC $@ $(manual))
39
40$(htmltypes): $(if $(htmlcss),$(htmlcss)) $(manual)
41 @mkdir -p $@
42ifdef htmlcss
43 $(call command,install -m 0644 $(htmlcss) $@/$(htmlcssfile),CP $(htmlcss) $@/$(htmlcssfile))
44endif
45 $(call command,xsltproc --stringparam base.dir $@/ $(if $(htmlcssfile),--stringparam html.stylesheet $(htmlcssfile)) $(htmlxsl) $(manual),XSLTPROC $@ $(manual))
46
47$(xmltotypes): $(manual)
48 $(call command,xmlto --extensions -o $(topdir)/$@ $@ $(manual),XMLTO $@ $(manual))
49
50clean:
51 rm -rf $(cleanfiles)
52
53$(foreach i,$(types) $(foreach type,$(htmltypes),$(type)-nochunks),clean-$(i)):
54 rm -rf $(patsubst clean-%,%,$@)
55
56FORCE:
diff --git a/bitbake/doc/manual/html.css b/bitbake/doc/manual/html.css
new file mode 100644
index 0000000000..6eedfd3189
--- /dev/null
+++ b/bitbake/doc/manual/html.css
@@ -0,0 +1,281 @@
1/* Feuille de style DocBook du projet Traduc.org */
2/* DocBook CSS stylesheet of the Traduc.org project */
3
4/* (c) Jean-Philippe Guérard - 14 août 2004 */
5/* (c) Jean-Philippe Guérard - 14 August 2004 */
6
7/* Cette feuille de style est libre, vous pouvez la */
8/* redistribuer et la modifier selon les termes de la Licence */
9/* Art Libre. Vous trouverez un exemplaire de cette Licence sur */
10/* http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
11
12/* This work of art is free, you can redistribute it and/or */
13/* modify it according to terms of the Free Art license. You */
14/* will find a specimen of this license on the Copyleft */
15/* Attitude web site: http://artlibre.org as well as on other */
16/* sites. */
17/* Please note that the French version of this licence as shown */
18/* on http://tigreraye.org/Petit-guide-du-traducteur.html#licence-art-libre */
19/* is only official licence of this document. The English */
20/* is only provided to help you understand this licence. */
21
22/* La dernière version de cette feuille de style est toujours */
23/* disponible sur : http://tigreraye.org/style.css */
24/* Elle est également disponible sur : */
25/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
26
27/* The latest version of this stylesheet is available from: */
28/* http://tigreraye.org/style.css */
29/* It is also available on: */
30/* http://www.traduc.org/docs/HOWTO/lecture/style.css */
31
32/* N'hésitez pas à envoyer vos commentaires et corrections à */
33/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
34
35/* Please send feedback and bug reports to */
36/* Jean-Philippe Guérard <jean-philippe.guerard@tigreraye.org> */
37
38/* $Id: style.css,v 1.14 2004/09/10 20:12:09 fevrier Exp fevrier $ */
39
40/* Présentation générale du document */
41/* Overall document presentation */
42
43body {
44 /*
45 font-family: Apolline, "URW Palladio L", Garamond, jGaramond,
46 "Bitstream Cyberbit", "Palatino Linotype", serif;
47 */
48 margin: 7%;
49 background-color: white;
50}
51
52/* Taille du texte */
53/* Text size */
54
55* { font-size: 100%; }
56
57/* Gestion des textes mis en relief imbriqués */
58/* Embedded emphasis */
59
60em { font-style: italic; }
61em em { font-style: normal; }
62em em em { font-style: italic; }
63
64/* Titres */
65/* Titles */
66
67h1 { font-size: 200%; font-weight: 900; }
68h2 { font-size: 160%; font-weight: 900; }
69h3 { font-size: 130%; font-weight: bold; }
70h4 { font-size: 115%; font-weight: bold; }
71h5 { font-size: 108%; font-weight: bold; }
72h6 { font-weight: bold; }
73
74/* Nom de famille en petites majuscules (uniquement en français) */
75/* Last names in small caps (for French only) */
76
77*[class~="surname"]:lang(fr) { font-variant: small-caps; }
78
79/* Blocs de citation */
80/* Quotation blocs */
81
82div[class~="blockquote"] {
83 border: solid 2px #AAA;
84 padding: 5px;
85 margin: 5px;
86}
87
88div[class~="blockquote"] > table {
89 border: none;
90}
91
92/* Blocs litéraux : fond gris clair */
93/* Literal blocs: light gray background */
94
95*[class~="literallayout"] {
96 background: #f0f0f0;
97 padding: 5px;
98 margin: 5px;
99}
100
101/* Programmes et captures texte : fond bleu clair */
102/* Listing and text screen snapshots: light blue background */
103
104*[class~="programlisting"], *[class~="screen"] {
105 background: #f0f0ff;
106 padding: 5px;
107 margin: 5px;
108}
109
110/* Les textes à remplacer sont surlignés en vert pâle */
111/* Replaceable text in highlighted in pale green */
112
113*[class~="replaceable"] {
114 background-color: #98fb98;
115 font-style: normal; }
116
117/* Tables : fonds gris clair & bords simples */
118/* Tables: light gray background and solid borders */
119
120*[class~="table"] *[class~="title"] { width:100%; border: 0px; }
121
122table {
123 border: 1px solid #aaa;
124 border-collapse: collapse;
125 padding: 2px;
126 margin: 5px;
127}
128
129/* Listes simples en style table */
130/* Simples lists in table presentation */
131
132table[class~="simplelist"] {
133 background-color: #F0F0F0;
134 margin: 5px;
135 border: solid 1px #AAA;
136}
137
138table[class~="simplelist"] td {
139 border: solid 1px #AAA;
140}
141
142/* Les tables */
143/* Tables */
144
145*[class~="table"] table {
146 background-color: #F0F0F0;
147 border: solid 1px #AAA;
148}
149*[class~="informaltable"] table { background-color: #F0F0F0; }
150
151th,td {
152 vertical-align: baseline;
153 text-align: left;
154 padding: 0.1em 0.3em;
155 empty-cells: show;
156}
157
158/* Alignement des colonnes */
159/* Colunms alignment */
160
161td[align=center] , th[align=center] { text-align: center; }
162td[align=right] , th[align=right] { text-align: right; }
163td[align=left] , th[align=left] { text-align: left; }
164td[align=justify] , th[align=justify] { text-align: justify; }
165
166/* Pas de marge autour des images */
167/* No inside margins for images */
168
169img { border: 0; }
170
171/* Les liens ne sont pas soulignés */
172/* No underlines for links */
173
174:link , :visited , :active { text-decoration: none; }
175
176/* Prudence : cadre jaune et fond jaune clair */
177/* Caution: yellow border and light yellow background */
178
179*[class~="caution"] {
180 border: solid 2px yellow;
181 background-color: #ffffe0;
182 padding: 1em 6px 1em ;
183 margin: 5px;
184}
185
186*[class~="caution"] th {
187 vertical-align: middle
188}
189
190*[class~="caution"] table {
191 background-color: #ffffe0;
192 border: none;
193}
194
195/* Note importante : cadre jaune et fond jaune clair */
196/* Important: yellow border and light yellow background */
197
198*[class~="important"] {
199 border: solid 2px yellow;
200 background-color: #ffffe0;
201 padding: 1em 6px 1em;
202 margin: 5px;
203}
204
205*[class~="important"] th {
206 vertical-align: middle
207}
208
209*[class~="important"] table {
210 background-color: #ffffe0;
211 border: none;
212}
213
214/* Mise en évidence : texte légèrement plus grand */
215/* Highlights: slightly larger texts */
216
217*[class~="highlights"] {
218 font-size: 110%;
219}
220
221/* Note : cadre bleu et fond bleu clair */
222/* Notes: blue border and light blue background */
223
224*[class~="note"] {
225 border: solid 2px #7099C5;
226 background-color: #f0f0ff;
227 padding: 1em 6px 1em ;
228 margin: 5px;
229}
230
231*[class~="note"] th {
232 vertical-align: middle
233}
234
235*[class~="note"] table {
236 background-color: #f0f0ff;
237 border: none;
238}
239
240/* Astuce : cadre vert et fond vert clair */
241/* Tip: green border and light green background */
242
243*[class~="tip"] {
244 border: solid 2px #00ff00;
245 background-color: #f0ffff;
246 padding: 1em 6px 1em ;
247 margin: 5px;
248}
249
250*[class~="tip"] th {
251 vertical-align: middle;
252}
253
254*[class~="tip"] table {
255 background-color: #f0ffff;
256 border: none;
257}
258
259/* Avertissement : cadre rouge et fond rouge clair */
260/* Warning: red border and light red background */
261
262*[class~="warning"] {
263 border: solid 2px #ff0000;
264 background-color: #fff0f0;
265 padding: 1em 6px 1em ;
266 margin: 5px;
267}
268
269*[class~="warning"] th {
270 vertical-align: middle;
271}
272
273
274*[class~="warning"] table {
275 background-color: #fff0f0;
276 border: none;
277}
278
279/* Fin */
280/* The End */
281
diff --git a/bitbake/doc/manual/usermanual.xml b/bitbake/doc/manual/usermanual.xml
new file mode 100644
index 0000000000..b96863c031
--- /dev/null
+++ b/bitbake/doc/manual/usermanual.xml
@@ -0,0 +1,361 @@
1<?xml version="1.0"?>
2<!--
3 ex:ts=4:sw=4:sts=4:et
4 -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5-->
6<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
7 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
8<book>
9 <bookinfo>
10 <title>BitBake User Manual</title>
11 <authorgroup>
12 <corpauthor>BitBake Team</corpauthor>
13 </authorgroup>
14 <copyright>
15 <year>2004, 2005</year>
16 <holder>Chris Larson</holder>
17 <holder>Phil Blundell</holder>
18 </copyright>
19 <legalnotice>
20 <para>This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit <ulink url="http://creativecommons.org/licenses/by/2.0/">http://creativecommons.org/licenses/by/2.0/</ulink> or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.</para>
21 </legalnotice>
22 </bookinfo>
23 <chapter>
24 <title>Introduction</title>
25 <section>
26 <title>Overview</title>
27 <para>BitBake is, at its simplest, a tool for executing
28tasks and managing metadata. As such, its similarities to GNU make and other
29build tools are readily apparent. It was inspired by Portage, the package management system used by the Gentoo Linux distribution. BitBake is the basis of the <ulink url="http://www.openembedded.org/">OpenEmbedded</ulink> project, which is being used to build and maintain a number of embedded Linux distributions, including OpenZaurus and Familiar.</para>
30 </section>
31 <section>
32 <title>Background and Goals</title>
33 <para>Prior to BitBake, no other build tool adequately met
34the needs of an aspiring embedded Linux distribution. All of the
35buildsystems used by traditional desktop Linux distributions lacked
36important functionality, and none of the ad-hoc
37<emphasis>buildroot</emphasis> systems, prevalent in the
38embedded space, were scalable or maintainable.</para>
39
40 <para>Some important goals for BitBake were:
41 <itemizedlist>
42 <listitem><para>Handle crosscompilation.</para></listitem>
43 <listitem><para>Handle interpackage dependencies (build time on target architecture, build time on native architecture, and runtime).</para></listitem>
44 <listitem><para>Support running any number of tasks within a given package, including, but not limited to, fetching upstream sources, unpacking them, patching them, configuring them, et cetera.</para></listitem>
45 <listitem><para>Must be linux distribution agnostic (both build and target).</para></listitem>
46 <listitem><para>Must be architecture agnostic</para></listitem>
47 <listitem><para>Must support multiple build and target operating systems (including cygwin, the BSDs, etc).</para></listitem>
48 <listitem><para>Must be able to be self contained, rather than tightly integrated into the build machine's root filesystem.</para></listitem>
49 <listitem><para>There must be a way to handle conditional metadata (on target architecture, operating system, distribution, machine).</para></listitem>
50 <listitem><para>It must be easy for the person using the tools to supply their own local metadata and packages to operate against.</para></listitem>
51 <listitem><para>Must make it easy to collaborate
52between multiple projects using BitBake for their
53builds.</para></listitem>
54 <listitem><para>Should provide an inheritance mechanism to
55share common metadata between many packages.</para></listitem>
56 <listitem><para>Et cetera...</para></listitem>
57 </itemizedlist>
58 </para>
59 <para>BitBake satisfies all these and many more. Flexibility and power have always been the priorities. It is highly extensible, supporting embedded Python code and execution of any arbitrary tasks.</para>
60 </section>
61 </chapter>
62 <chapter>
63 <title>Metadata</title>
64 <section>
65 <title>Description</title>
66 <itemizedlist>
67 <para>BitBake metadata can be classified into 3 major areas:</para>
68 <listitem>
69 <para>Configuration Files</para>
70 </listitem>
71 <listitem>
72 <para>.bb Files</para>
73 </listitem>
74 <listitem>
75 <para>Classes</para>
76 </listitem>
77 </itemizedlist>
78 <para>What follows are a large number of examples of BitBake metadata. Any syntax which isn't supported in any of the aforementioned areas will be documented as such.</para>
79 <section>
80 <title>Basic variable setting</title>
81 <para><screen><varname>VARIABLE</varname> = "value"</screen></para>
82 <para>In this example, <varname>VARIABLE</varname> is <literal>value</literal>.</para>
83 </section>
84 <section>
85 <title>Variable expansion</title>
86 <para>BitBake supports variables referencing one another's contents using a syntax which is similar to shell scripting</para>
87 <para><screen><varname>A</varname> = "aval"
88<varname>B</varname> = "pre${A}post"</screen></para>
89 <para>This results in <varname>A</varname> containing <literal>aval</literal> and <varname>B</varname> containing <literal>preavalpost</literal>.</para>
90 </section>
91 <section>
92 <title>Immediate variable expansion (:=)</title>
93 <para>:= results in a variable's contents being expanded immediately, rather than when the variable is actually used.</para>
94 <para><screen><varname>T</varname> = "123"
95<varname>A</varname> := "${B} ${A} test ${T}"
96<varname>T</varname> = "456"
97<varname>B</varname> = "${T} bval"
98
99<varname>C</varname> = "cval"
100<varname>C</varname> := "${C}append"</screen></para>
101 <para>In that example, <varname>A</varname> would contain <literal> test 123</literal>, <varname>B</varname> would contain <literal>456 bval</literal>, and <varname>C</varname> would be <literal>cvalappend</literal>.</para>
102 </section>
103 <section>
104 <title>Appending (+=) and prepending (=+)</title>
105 <para><screen><varname>B</varname> = "bval"
106<varname>B</varname> += "additionaldata"
107<varname>C</varname> = "cval"
108<varname>C</varname> =+ "test"</screen></para>
109 <para>In this example, <varname>B</varname> is now <literal>bval additionaldata</literal> and <varname>C</varname> is <literal>test cval</literal>.</para>
110 </section>
111 <section>
112 <title>Appending (.=) and prepending (=.) without spaces</title>
113 <para><screen><varname>B</varname> = "bval"
114<varname>B</varname> += "additionaldata"
115<varname>C</varname> = "cval"
116<varname>C</varname> =+ "test"</screen></para>
117 <para>In this example, <varname>B</varname> is now <literal>bvaladditionaldata</literal> and <varname>C</varname> is <literal>testcval</literal>. In contrast to the above Appending and Prepending operators no additional space
118will be introduced.</para>
119 </section>
120 <section>
121 <title>Conditional metadata set</title>
122 <para>OVERRIDES is a <quote>:</quote> seperated variable containing each item you want to satisfy conditions. So, if you have a variable which is conditional on <quote>arm</quote>, and <quote>arm</quote> is in OVERRIDES, then the <quote>arm</quote> specific version of the variable is used rather than the non-conditional version. Example:</para>
123 <para><screen><varname>OVERRIDES</varname> = "architecture:os:machine"
124<varname>TEST</varname> = "defaultvalue"
125<varname>TEST_os</varname> = "osspecificvalue"
126<varname>TEST_condnotinoverrides</varname> = "othercondvalue"</screen></para>
127 <para>In this example, <varname>TEST</varname> would be <literal>osspecificvalue</literal>, due to the condition <quote>os</quote> being in <varname>OVERRIDES</varname>.</para>
128 </section>
129 <section>
130 <title>Conditional appending</title>
131 <para>BitBake also supports appending and prepending to variables based on whether something is in OVERRIDES. Example:</para>
132 <para><screen><varname>DEPENDS</varname> = "glibc ncurses"
133<varname>OVERRIDES</varname> = "machine:local"
134<varname>DEPENDS_append_machine</varname> = " libmad"</screen></para>
135 <para>In this example, <varname>DEPENDS</varname> is set to <literal>glibc ncurses libmad</literal>.</para>
136 </section>
137 <section>
138 <title>Inclusion</title>
139 <para>Next, there is the <literal>include</literal> directive, which causes BitBake to parse in whatever file you specify, and insert it at that location, which is not unlike <command>make</command>. However, if the path specified on the <literal>include</literal> line is a relative path, BitBake will locate the first one it can find within <envar>BBPATH</envar>.</para>
140 </section>
141 <section>
142 <title>Python variable expansion</title>
143 <para><screen><varname>DATE</varname> = "${@time.strftime('%Y%m%d',time.gmtime())}"</screen></para>
144 <para>This would result in the <varname>DATE</varname> variable containing today's date.</para>
145 </section>
146 <section>
147 <title>Defining executable metadata</title>
148 <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
149 <para><screen>do_mytask () {
150 echo "Hello, world!"
151}</screen></para>
152 <para>This is essentially identical to setting a variable, except that this variable happens to be executable shell code.</para>
153 <para><screen>python do_printdate () {
154 import time
155 print time.strftime('%Y%m%d', time.gmtime())
156}</screen></para>
157 <para>This is the similar to the previous, but flags it as python so that BitBake knows it is python code.</para>
158 </section>
159 <section>
160 <title>Defining python functions into the global python namespace</title>
161 <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
162 <para><screen>def get_depends(bb, d):
163 if bb.data.getVar('SOMECONDITION', d, True):
164 return "dependencywithcond"
165 else:
166 return "dependency"
167
168<varname>SOMECONDITION</varname> = "1"
169<varname>DEPENDS</varname> = "${@get_depends(bb, d)}"</screen></para>
170 <para>This would result in <varname>DEPENDS</varname> containing <literal>dependencywithcond</literal>.</para>
171 </section>
172 <section>
173 <title>Inheritance</title>
174 <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
175 <para>The <literal>inherit</literal> directive is a means of specifying what classes of functionality your .bb requires. It is a rudamentary form of inheritence. For example, you can easily abstract out the tasks involved in building a package that uses autoconf and automake, and put that into a bbclass for your packages to make use of. A given bbclass is located by searching for classes/filename.oeclass in <envar>BBPATH</envar>, where filename is what you inherited.</para>
176 </section>
177 <section>
178 <title>Tasks</title>
179 <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
180 <para>In BitBake, each step that needs to be run for a given .bb is known as a task. There is a command <literal>addtask</literal> to add new tasks (must be a defined python executable metadata and must start with <quote>do_</quote>) and describe intertask dependencies.</para>
181 <para><screen>python do_printdate () {
182 import time
183 print time.strftime('%Y%m%d', time.gmtime())
184}
185
186addtask printdate before do_build</screen></para>
187 <para>This defines the necessary python function and adds it as a task which is now a dependency of do_build (the default task). If anyone executes the do_build task, that will result in do_printdate being run first.</para>
188 </section>
189 <section>
190 <title>Events</title>
191 <para><emphasis>NOTE:</emphasis> This is only supported in .bb and .bbclass files.</para>
192 <para>BitBake also implements a means of registering event handlers. Events are triggered at certain points during operation, such as, the beginning of operation against a given .bb, the start of a given task, task failure, task success, et cetera. The intent was to make it easy to do things like email notifications on build failure.</para>
193 <para><screen>addhandler myclass_eventhandler
194python myclass_eventhandler() {
195 from bb.event import NotHandled, getName
196 from bb import data
197
198 print "The name of the Event is %s" % getName(e)
199 print "The file we run for is %s" % data.getVar('FILE', e.data, True)
200
201 return NotHandled
202</screen></para><para>
203This event handler gets called every time an event is triggered. A global variable <varname>e</varname> is defined. <varname>e</varname>.data contains an instance of bb.data. With the getName(<varname>e</varname>)
204method one can get the name of the triggered event.</para><para>The above event handler prints the name
205of the event and the content of the <varname>FILE</varname> variable.</para>
206 </section>
207 </section>
208 <section>
209 <title>Parsing</title>
210 <section>
211 <title>Configuration Files</title>
212 <para>The first of the classifications of metadata in BitBake is configuration metadata. This metadata is global, and therefore affects <emphasis>all</emphasis> packages and tasks which are executed. Currently, BitBake has hardcoded knowledge of a single configuration file. It expects to find 'conf/bitbake.conf' somewhere in the user specified <envar>BBPATH</envar>. That configuration file generally has include directives to pull in any other metadata (generally files specific to architecture, machine, <emphasis>local</emphasis> and so on.</para>
213 <para>Only variable definitions and include directives are allowed in .conf files.</para>
214 </section>
215 <section>
216 <title>Classes</title>
217 <para>BitBake classes are our rudamentary inheritence mechanism. As briefly mentioned in the metadata introduction, they're parsed when an <literal>inherit</literal> directive is encountered, and they are located in classes/ relative to the dirs in <envar>BBPATH</envar>.</para>
218 </section>
219 <section>
220 <title>.bb Files</title>
221 <para>A BitBake (.bb) file is a logical unit of tasks to be executed. Normally this is a package to be built. Inter-.bb dependencies are obeyed. The files themselves are located via the <varname>BBFILES</varname> variable, which is set to a space seperated list of .bb files, and does handle wildcards.</para>
222 </section>
223 </section>
224 </chapter>
225 <chapter>
226 <title>Commands</title>
227 <section>
228 <title>bbread</title>
229 <para>bbread is a command for displaying BitBake metadata. When run with no arguments, it has the core parse 'conf/bitbake.conf', as located in BBPATH, and displays that. If you supply a file on the commandline, such as a .bb, then it parses that afterwards, using the aforementioned configuration metadata.</para>
230 <para><emphasis>NOTE: the stand a lone bbread command was removed. Instead of bbread use bitbake -e.
231 </emphasis></para>
232 </section>
233 <section>
234 <title>bitbake</title>
235 <section>
236 <title>Introduction</title>
237 <para>bitbake is the primary command in the system. It facilitates executing tasks in a single .bb file, or executing a given task on a set of multiple .bb files, accounting for interdependencies amongst them.</para>
238 </section>
239 <section>
240 <title>Usage and Syntax</title>
241 <para>
242 <screen><prompt>$ </prompt>bitbake --help
243usage: bitbake [options] [package ...]
244
245Executes the specified task (default is 'build') for a given set of BitBake files.
246It expects that BBFILES is defined, which is a space seperated list of files to
247be executed. BBFILES does support wildcards.
248Default BBFILES are the .bb files in the current directory.
249
250options:
251 --version show program's version number and exit
252 -h, --help show this help message and exit
253 -b BUILDFILE, --buildfile=BUILDFILE
254 execute the task against this .bb file, rather than a
255 package from BBFILES.
256 -k, --continue continue as much as possible after an error. While the
257 target that failed, and those that depend on it,
258 cannot be remade, the other dependencies of these
259 targets can be processed all the same.
260 -f, --force force run of specified cmd, regardless of stamp status
261 -i, --interactive drop into the interactive mode.
262 -c CMD, --cmd=CMD Specify task to execute. Note that this only executes
263 the specified task for the providee and the packages
264 it depends on, i.e. 'compile' does not implicitly call
265 stage for the dependencies (IOW: use only if you know
266 what you are doing)
267 -r FILE, --read=FILE read the specified file before bitbake.conf
268 -v, --verbose output more chit-chat to the terminal
269 -D, --debug Increase the debug level
270 -n, --dry-run don't execute, just go through the motions
271 -p, --parse-only quit after parsing the BB files (developers only)
272 -d, --disable-psyco disable using the psyco just-in-time compiler (not
273 recommended)
274 -s, --show-versions show current and preferred versions of all packages
275 -e, --environment show the global or per-package environment (this is
276 what used to be bbread)
277
278</screen>
279 </para>
280 <para>
281 <example>
282 <title>Executing a task against a single .bb</title>
283 <para>Executing tasks for a single file is relatively simple. You specify the file in question, and bitbake parses it and executes the specified task (or <quote>build</quote> by default). It obeys intertask dependencies when doing so.</para>
284 <para><quote>clean</quote> task:</para>
285 <para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb -c clean</screen></para>
286 <para><quote>build</quote> task:</para>
287 <para><screen><prompt>$ </prompt>bitbake -b blah_1.0.bb</screen></para>
288 </example>
289 </para>
290 <para>
291 <example>
292 <title>Executing tasks against a set of .bb files</title>
293 <para>There are a number of additional complexities introduced when one wants to manage multiple .bb files. Clearly there needs to be a way to tell bitbake what files are available, and of those, which we want to execute at this time. There also needs to be a way for each .bb to express its dependencies, both for build time and runtime. There must be a way for the user to express their preferences when multiple .bb's provide the same functionality, or when there are multiple versions of a .bb.</para>
294 <para>The next section, Metadata, outlines how one goes about specifying such things.</para>
295 <para>Note that the bitbake command, when not using --buildfile, accepts a <varname>PROVIDER</varname>, not a filename or anything else. By default, a .bb generally PROVIDES its packagename, packagename-version, and packagename-version-revision.</para>
296 <screen><prompt>$ </prompt>bitbake blah</screen>
297 <screen><prompt>$ </prompt>bitbake blah-1.0</screen>
298 <screen><prompt>$ </prompt>bitbake blah-1.0-r0</screen>
299 <screen><prompt>$ </prompt>bitbake -c clean blah</screen>
300 <screen><prompt>$ </prompt>bitbake virtual/whatever</screen>
301 <screen><prompt>$ </prompt>bitbake -c clean virtual/whatever</screen>
302 </example>
303 </para>
304 </section>
305 <section>
306 <title>Metadata</title>
307 <para>As you may have seen in the usage information, or in the information about .bb files, the BBFILES variable is how the bitbake tool locates its files. This variable is a space seperated list of files that are available, and supports wildcards.
308 <example>
309 <title>Setting BBFILES</title>
310 <programlisting><varname>BBFILES</varname> = "/path/to/bbfiles/*.bb"</programlisting>
311 </example></para>
312 <para>With regard to dependencies, it expects the .bb to define a <varname>DEPENDS</varname> variable, which contains a space seperated list of <quote>package names</quote>, which themselves are the <varname>PN</varname> variable. The <varname>PN</varname> variable is, in general, by default, set to a component of the .bb filename.</para>
313 <example>
314 <title>Depending on another .bb</title>
315 <para>a.bb:
316 <screen>PN = "package-a"
317 DEPENDS += "package-b"</screen>
318 </para>
319 <para>b.bb:
320 <screen>PN = "package-b"</screen>
321 </para>
322 </example>
323 <example>
324 <title>Using PROVIDES</title>
325 <para>This example shows the usage of the PROVIDES variable, which allows a given .bb to specify what functionality it provides.</para>
326 <para>package1.bb:
327 <screen>PROVIDES += "virtual/package"</screen>
328 </para>
329 <para>package2.bb:
330 <screen>DEPENDS += "virtual/package"</screen>
331 </para>
332 <para>package3.bb:
333 <screen>PROVIDES += "virtual/package"</screen>
334 </para>
335 <para>As you can see, here there are two different .bb's that provide the same functionality (virtual/package). Clearly, there needs to be a way for the person running bitbake to control which of those providers gets used. There is, indeed, such a way.</para>
336 <para>The following would go into a .conf file, to select package1:
337 <screen>PREFERRED_PROVIDER_virtual/package = "package1"</screen>
338 </para>
339 </example>
340 <example>
341 <title>Specifying version preference</title>
342 <para>When there are multiple <quote>versions</quote> of a given package, bitbake defaults to selecting the most recent version, unless otherwise specified. If the .bb in question has a <varname>DEFAULT_PREFERENCE</varname> set lower than the other .bb's (default is 0), then it will not be selected. This allows the person or persons maintaining the repository of .bb files to specify their preferences for the default selected version. In addition, the user can specify their preferences with regard to version.</para>
343 <para>If the first .bb is named <filename>a_1.1.bb</filename>, then the <varname>PN</varname> variable will be set to <quote>a</quote>, and the <varname>PV</varname> variable will be set to 1.1.</para>
344 <para>If we then have an <filename>a_1.2.bb</filename>, bitbake will choose 1.2 by default. However, if we define the following variable in a .conf that bitbake parses, we can change that.
345 <screen>PREFERRED_VERSION_a = "1.1"</screen>
346 </para>
347 </example>
348 <example>
349 <title>Using <quote>bbfile collections</quote></title>
350 <para>bbfile collections exist to allow the user to have multiple repositories of bbfiles that contain the same exact package. For example, one could easily use them to make one's own local copy of an upstream repository, but with custom modifications that one does not want upstream. Usage:</para>
351 <screen>BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
352BBFILE_COLLECTIONS = "upstream local"
353BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
354BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
355BBFILE_PRIORITY_upstream = "5"
356BBFILE_PRIORITY_local = "10"</screen>
357 </example>
358 </section>
359 </section>
360 </chapter>
361</book>
diff --git a/bitbake/lib/bb/__init__.py b/bitbake/lib/bb/__init__.py
new file mode 100644
index 0000000000..00b0e8b57f
--- /dev/null
+++ b/bitbake/lib/bb/__init__.py
@@ -0,0 +1,1266 @@
1#!/usr/bin/python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4"""
5BitBake Build System Python Library
6
7Copyright (C) 2003 Holger Schurig
8Copyright (C) 2003, 2004 Chris Larson
9
10Based on Gentoo's portage.py.
11
12This program is free software; you can redistribute it and/or modify it under
13the terms of the GNU General Public License as published by the Free Software
14Foundation; either version 2 of the License, or (at your option) any later
15version.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23Place, Suite 330, Boston, MA 02111-1307 USA.
24"""
25
26__version__ = "1.3.2"
27
28__all__ = [
29
30 "debug",
31 "note",
32 "error",
33 "fatal",
34
35 "mkdirhier",
36 "movefile",
37
38 "tokenize",
39 "evaluate",
40 "flatten",
41 "relparse",
42 "ververify",
43 "isjustname",
44 "isspecific",
45 "pkgsplit",
46 "catpkgsplit",
47 "vercmp",
48 "pkgcmp",
49 "dep_parenreduce",
50 "dep_opconvert",
51 "digraph",
52
53# fetch
54 "decodeurl",
55 "encodeurl",
56
57# modules
58 "parse",
59 "data",
60 "event",
61 "build",
62 "fetch",
63 "manifest"
64 ]
65
66whitespace = '\t\n\x0b\x0c\r '
67lowercase = 'abcdefghijklmnopqrstuvwxyz'
68
69import sys, os, types, re, string
70
71#projectdir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
72projectdir = os.getcwd()
73
74debug_level = 0
75
76if "BBDEBUG" in os.environ:
77 level = int(os.environ["BBDEBUG"])
78 if level:
79 debug_level = level
80 else:
81 debug_level = 0
82
83class VarExpandError(Exception):
84 pass
85
86class MalformedUrl(Exception):
87 """Exception raised when encountering an invalid url"""
88
89
90#######################################################################
91#######################################################################
92#
93# SECTION: Debug
94#
95# PURPOSE: little functions to make yourself known
96#
97#######################################################################
98#######################################################################
99
100debug_prepend = ''
101
102
103def debug(lvl, *args):
104 if debug_level >= lvl:
105 print debug_prepend + 'DEBUG:', ''.join(args)
106
107def note(*args):
108 print debug_prepend + 'NOTE:', ''.join(args)
109
110def error(*args):
111 print debug_prepend + 'ERROR:', ''.join(args)
112
113def fatal(*args):
114 print debug_prepend + 'ERROR:', ''.join(args)
115 sys.exit(1)
116
117
118#######################################################################
119#######################################################################
120#
121# SECTION: File
122#
123# PURPOSE: Basic file and directory tree related functions
124#
125#######################################################################
126#######################################################################
127
128def mkdirhier(dir):
129 """Create a directory like 'mkdir -p', but does not complain if
130 directory already exists like os.makedirs
131 """
132
133 debug(3, "mkdirhier(%s)" % dir)
134 try:
135 os.makedirs(dir)
136 debug(2, "created " + dir)
137 except OSError, e:
138 if e.errno != 17: raise e
139
140
141#######################################################################
142
143import stat
144
145def movefile(src,dest,newmtime=None,sstat=None):
146 """Moves a file from src to dest, preserving all permissions and
147 attributes; mtime will be preserved even when moving across
148 filesystems. Returns true on success and false on failure. Move is
149 atomic.
150 """
151
152 #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")"
153 try:
154 if not sstat:
155 sstat=os.lstat(src)
156 except Exception, e:
157 print "!!! Stating source file failed... movefile()"
158 print "!!!",e
159 return None
160
161 destexists=1
162 try:
163 dstat=os.lstat(dest)
164 except:
165 dstat=os.lstat(os.path.dirname(dest))
166 destexists=0
167
168 if destexists:
169 if stat.S_ISLNK(dstat[stat.ST_MODE]):
170 try:
171 os.unlink(dest)
172 destexists=0
173 except Exception, e:
174 pass
175
176 if stat.S_ISLNK(sstat[stat.ST_MODE]):
177 try:
178 target=os.readlink(src)
179 if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
180 os.unlink(dest)
181 os.symlink(target,dest)
182# os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
183 os.unlink(src)
184 return os.lstat(dest)
185 except Exception, e:
186 print "!!! failed to properly create symlink:"
187 print "!!!",dest,"->",target
188 print "!!!",e
189 return None
190
191 renamefailed=1
192 if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]:
193 try:
194 ret=os.rename(src,dest)
195 renamefailed=0
196 except Exception, e:
197 import errno
198 if e[0]!=errno.EXDEV:
199 # Some random error.
200 print "!!! Failed to move",src,"to",dest
201 print "!!!",e
202 return None
203 # Invalid cross-device-link 'bind' mounted or actually Cross-Device
204
205 if renamefailed:
206 didcopy=0
207 if stat.S_ISREG(sstat[stat.ST_MODE]):
208 try: # For safety copy then move it over.
209 shutil.copyfile(src,dest+"#new")
210 os.rename(dest+"#new",dest)
211 didcopy=1
212 except Exception, e:
213 print '!!! copy',src,'->',dest,'failed.'
214 print "!!!",e
215 return None
216 else:
217 #we don't yet handle special, so we need to fall back to /bin/mv
218 a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'")
219 if a[0]!=0:
220 print "!!! Failed to move special file:"
221 print "!!! '"+src+"' to '"+dest+"'"
222 print "!!!",a
223 return None # failure
224 try:
225 if didcopy:
226 missingos.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
227 os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
228 os.unlink(src)
229 except Exception, e:
230 print "!!! Failed to chown/chmod/unlink in movefile()"
231 print "!!!",dest
232 print "!!!",e
233 return None
234
235 if newmtime:
236 os.utime(dest,(newmtime,newmtime))
237 else:
238 os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
239 newmtime=sstat[stat.ST_MTIME]
240 return newmtime
241
242
243
244#######################################################################
245#######################################################################
246#
247# SECTION: Download
248#
249# PURPOSE: Download via HTTP, FTP, CVS, BITKEEPER, handling of MD5-signatures
250# and mirrors
251#
252#######################################################################
253#######################################################################
254
255def decodeurl(url):
256 """Decodes an URL into the tokens (scheme, network location, path,
257 user, password, parameters).
258
259 >>> decodeurl("http://www.google.com/index.html")
260 ('http', 'www.google.com', '/index.html', '', '', {})
261
262 CVS url with username, host and cvsroot. The cvs module to check out is in the
263 parameters:
264
265 >>> decodeurl("cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg")
266 ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'})
267
268 Dito, but this time the username has a password part. And we also request a special tag
269 to check out.
270
271 >>> decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81")
272 ('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
273 """
274
275 m = re.compile('(?P<type>[^:]*)://((?P<user>.+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
276 if not m:
277 raise MalformedUrl(url)
278
279 type = m.group('type')
280 location = m.group('location')
281 if not location:
282 raise MalformedUrl(url)
283 user = m.group('user')
284 parm = m.group('parm')
285 m = re.compile('(?P<host>[^/;]+)(?P<path>/[^;]+)').match(location)
286 if m:
287 host = m.group('host')
288 path = m.group('path')
289 else:
290 host = ""
291 path = location
292 if user:
293 m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
294 if m:
295 user = m.group('user')
296 pswd = m.group('pswd')
297 else:
298 user = ''
299 pswd = ''
300
301 p = {}
302 if parm:
303 for s in parm.split(';'):
304 s1,s2 = s.split('=')
305 p[s1] = s2
306
307 return (type, host, path, user, pswd, p)
308
309#######################################################################
310
311def encodeurl(decoded):
312 """Encodes a URL from tokens (scheme, network location, path,
313 user, password, parameters).
314
315 >>> encodeurl(['http', 'www.google.com', '/index.html', '', '', {}])
316 'http://www.google.com/index.html'
317
318 CVS with username, host and cvsroot. The cvs module to check out is in the
319 parameters:
320
321 >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', '', {'module': 'familiar/dist/ipkg'}])
322 'cvs://anoncvs@cvs.handhelds.org/cvs;module=familiar/dist/ipkg'
323
324 Dito, but this time the username has a password part. And we also request a special tag
325 to check out.
326
327 >>> encodeurl(['cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'}])
328 'cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;tag=V0-99-81;module=familiar/dist/ipkg'
329 """
330
331 (type, host, path, user, pswd, p) = decoded
332
333 if not type or not path:
334 fatal("invalid or missing parameters for url encoding")
335 url = '%s://' % type
336 if user:
337 url += "%s" % user
338 if pswd:
339 url += ":%s" % pswd
340 url += "@"
341 if host:
342 url += "%s" % host
343 url += "%s" % path
344 if p:
345 for parm in p.keys():
346 url += ";%s=%s" % (parm, p[parm])
347
348 return url
349
350#######################################################################
351
352def which(path, item, direction = 0):
353 """Useful function for locating a file in a PATH"""
354 found = ""
355 for p in (path or "").split(':'):
356 if os.path.exists(os.path.join(p, item)):
357 found = os.path.join(p, item)
358 if direction == 0:
359 break
360 return found
361
362#######################################################################
363
364
365
366
367#######################################################################
368#######################################################################
369#
370# SECTION: Dependency
371#
372# PURPOSE: Compare build & run dependencies
373#
374#######################################################################
375#######################################################################
376
377def tokenize(mystring):
378 """Breaks a string like 'foo? (bar) oni? (blah (blah))' into (possibly embedded) lists:
379
380 >>> tokenize("x")
381 ['x']
382 >>> tokenize("x y")
383 ['x', 'y']
384 >>> tokenize("(x y)")
385 [['x', 'y']]
386 >>> tokenize("(x y) b c")
387 [['x', 'y'], 'b', 'c']
388 >>> tokenize("foo? (bar) oni? (blah (blah))")
389 ['foo?', ['bar'], 'oni?', ['blah', ['blah']]]
390 >>> tokenize("sys-apps/linux-headers nls? (sys-devel/gettext)")
391 ['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']]
392 """
393
394 newtokens = []
395 curlist = newtokens
396 prevlists = []
397 level = 0
398 accum = ""
399 for x in mystring:
400 if x=="(":
401 if accum:
402 curlist.append(accum)
403 accum=""
404 prevlists.append(curlist)
405 curlist=[]
406 level=level+1
407 elif x==")":
408 if accum:
409 curlist.append(accum)
410 accum=""
411 if level==0:
412 print "!!! tokenizer: Unmatched left parenthesis in:\n'"+mystring+"'"
413 return None
414 newlist=curlist
415 curlist=prevlists.pop()
416 curlist.append(newlist)
417 level=level-1
418 elif x in whitespace:
419 if accum:
420 curlist.append(accum)
421 accum=""
422 else:
423 accum=accum+x
424 if accum:
425 curlist.append(accum)
426 if (level!=0):
427 print "!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+mystring+"'"
428 return None
429 return newtokens
430
431
432#######################################################################
433
434def evaluate(tokens,mydefines,allon=0):
435 """Removes tokens based on whether conditional definitions exist or not.
436 Recognizes !
437
438 >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {})
439 ['sys-apps/linux-headers']
440
441 Negate the flag:
442
443 >>> evaluate(['sys-apps/linux-headers', '!nls?', ['sys-devel/gettext']], {})
444 ['sys-apps/linux-headers', ['sys-devel/gettext']]
445
446 Define 'nls':
447
448 >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {"nls":1})
449 ['sys-apps/linux-headers', ['sys-devel/gettext']]
450
451 Turn allon on:
452
453 >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}, True)
454 ['sys-apps/linux-headers', ['sys-devel/gettext']]
455 """
456
457 if tokens == None:
458 return None
459 mytokens = tokens + [] # this copies the list
460 pos = 0
461 while pos < len(mytokens):
462 if type(mytokens[pos]) == types.ListType:
463 evaluate(mytokens[pos], mydefines)
464 if not len(mytokens[pos]):
465 del mytokens[pos]
466 continue
467 elif mytokens[pos][-1] == "?":
468 cur = mytokens[pos][:-1]
469 del mytokens[pos]
470 if allon:
471 if cur[0] == "!":
472 del mytokens[pos]
473 else:
474 if cur[0] == "!":
475 if (cur[1:] in mydefines) and (pos < len(mytokens)):
476 del mytokens[pos]
477 continue
478 elif (cur not in mydefines) and (pos < len(mytokens)):
479 del mytokens[pos]
480 continue
481 pos = pos + 1
482 return mytokens
483
484
485#######################################################################
486
487def flatten(mytokens):
488 """Converts nested arrays into a flat arrays:
489
490 >>> flatten([1,[2,3]])
491 [1, 2, 3]
492 >>> flatten(['sys-apps/linux-headers', ['sys-devel/gettext']])
493 ['sys-apps/linux-headers', 'sys-devel/gettext']
494 """
495
496 newlist=[]
497 for x in mytokens:
498 if type(x)==types.ListType:
499 newlist.extend(flatten(x))
500 else:
501 newlist.append(x)
502 return newlist
503
504
505#######################################################################
506
507_package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered
508_package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list
509
510def relparse(myver):
511 """Parses the last elements of a version number into a triplet, that can
512 later be compared:
513
514 >>> relparse('1.2_pre3')
515 [1.2, -2, 3.0]
516 >>> relparse('1.2b')
517 [1.2, 98, 0]
518 >>> relparse('1.2')
519 [1.2, 0, 0]
520 """
521
522 number = 0
523 p1 = 0
524 p2 = 0
525 mynewver = myver.split('_')
526 if len(mynewver)==2:
527 # an _package_weights_
528 number = float(mynewver[0])
529 match = 0
530 for x in _package_ends_:
531 elen = len(x)
532 if mynewver[1][:elen] == x:
533 match = 1
534 p1 = _package_weights_[x]
535 try:
536 p2 = float(mynewver[1][elen:])
537 except:
538 p2 = 0
539 break
540 if not match:
541 # normal number or number with letter at end
542 divider = len(myver)-1
543 if myver[divider:] not in "1234567890":
544 # letter at end
545 p1 = ord(myver[divider:])
546 number = float(myver[0:divider])
547 else:
548 number = float(myver)
549 else:
550 # normal number or number with letter at end
551 divider = len(myver)-1
552 if myver[divider:] not in "1234567890":
553 #letter at end
554 p1 = ord(myver[divider:])
555 number = float(myver[0:divider])
556 else:
557 number = float(myver)
558 return [number,p1,p2]
559
560
561#######################################################################
562
563__ververify_cache__ = {}
564
565def ververify(myorigval,silent=1):
566 """Returns 1 if given a valid version string, els 0. Valid versions are in the format
567
568 <v1>.<v2>...<vx>[a-z,_{_package_weights_}[vy]]
569
570 >>> ververify('2.4.20')
571 1
572 >>> ververify('2.4..20') # two dots
573 0
574 >>> ververify('2.x.20') # 'x' is not numeric
575 0
576 >>> ververify('2.4.20a')
577 1
578 >>> ververify('2.4.20cvs') # only one trailing letter
579 0
580 >>> ververify('1a')
581 1
582 >>> ververify('test_a') # no version at all
583 0
584 >>> ververify('2.4.20_beta1')
585 1
586 >>> ververify('2.4.20_beta')
587 1
588 >>> ververify('2.4.20_wrongext') # _wrongext is no valid trailer
589 0
590 """
591
592 # Lookup the cache first
593 try:
594 return __ververify_cache__[myorigval]
595 except KeyError:
596 pass
597
598 if len(myorigval) == 0:
599 if not silent:
600 error("package version is empty")
601 __ververify_cache__[myorigval] = 0
602 return 0
603 myval = myorigval.split('.')
604 if len(myval)==0:
605 if not silent:
606 error("package name has empty version string")
607 __ververify_cache__[myorigval] = 0
608 return 0
609 # all but the last version must be a numeric
610 for x in myval[:-1]:
611 if not len(x):
612 if not silent:
613 error("package version has two points in a row")
614 __ververify_cache__[myorigval] = 0
615 return 0
616 try:
617 foo = int(x)
618 except:
619 if not silent:
620 error("package version contains non-numeric '"+x+"'")
621 __ververify_cache__[myorigval] = 0
622 return 0
623 if not len(myval[-1]):
624 if not silent:
625 error("package version has trailing dot")
626 __ververify_cache__[myorigval] = 0
627 return 0
628 try:
629 foo = int(myval[-1])
630 __ververify_cache__[myorigval] = 1
631 return 1
632 except:
633 pass
634
635 # ok, our last component is not a plain number or blank, let's continue
636 if myval[-1][-1] in lowercase:
637 try:
638 foo = int(myval[-1][:-1])
639 return 1
640 __ververify_cache__[myorigval] = 1
641 # 1a, 2.0b, etc.
642 except:
643 pass
644 # ok, maybe we have a 1_alpha or 1_beta2; let's see
645 ep=string.split(myval[-1],"_")
646 if len(ep)!= 2:
647 if not silent:
648 error("package version has more than one letter at then end")
649 __ververify_cache__[myorigval] = 0
650 return 0
651 try:
652 foo = string.atoi(ep[0])
653 except:
654 # this needs to be numeric, i.e. the "1" in "1_alpha"
655 if not silent:
656 error("package version must have numeric part before the '_'")
657 __ververify_cache__[myorigval] = 0
658 return 0
659
660 for mye in _package_ends_:
661 if ep[1][0:len(mye)] == mye:
662 if len(mye) == len(ep[1]):
663 # no trailing numeric is ok
664 __ververify_cache__[myorigval] = 1
665 return 1
666 else:
667 try:
668 foo = string.atoi(ep[1][len(mye):])
669 __ververify_cache__[myorigval] = 1
670 return 1
671 except:
672 # if no _package_weights_ work, *then* we return 0
673 pass
674 if not silent:
675 error("package version extension after '_' is invalid")
676 __ververify_cache__[myorigval] = 0
677 return 0
678
679
680def isjustname(mypkg):
681 myparts = string.split(mypkg,'-')
682 for x in myparts:
683 if ververify(x):
684 return 0
685 return 1
686
687
688_isspecific_cache_={}
689
690def isspecific(mypkg):
691 "now supports packages with no category"
692 try:
693 return __isspecific_cache__[mypkg]
694 except:
695 pass
696
697 mysplit = string.split(mypkg,"/")
698 if not isjustname(mysplit[-1]):
699 __isspecific_cache__[mypkg] = 1
700 return 1
701 __isspecific_cache__[mypkg] = 0
702 return 0
703
704
705#######################################################################
706
707__pkgsplit_cache__={}
708
709def pkgsplit(mypkg, silent=1):
710
711 """This function can be used as a package verification function. If
712 it is a valid name, pkgsplit will return a list containing:
713 [pkgname, pkgversion(norev), pkgrev ].
714
715 >>> pkgsplit('')
716 >>> pkgsplit('x')
717 >>> pkgsplit('x-')
718 >>> pkgsplit('-1')
719 >>> pkgsplit('glibc-1.2-8.9-r7')
720 >>> pkgsplit('glibc-2.2.5-r7')
721 ['glibc', '2.2.5', 'r7']
722 >>> pkgsplit('foo-1.2-1')
723 >>> pkgsplit('Mesa-3.0')
724 ['Mesa', '3.0', 'r0']
725 """
726
727 try:
728 return __pkgsplit_cache__[mypkg]
729 except KeyError:
730 pass
731
732 myparts = string.split(mypkg,'-')
733 if len(myparts) < 2:
734 if not silent:
735 error("package name without name or version part")
736 __pkgsplit_cache__[mypkg] = None
737 return None
738 for x in myparts:
739 if len(x) == 0:
740 if not silent:
741 error("package name with empty name or version part")
742 __pkgsplit_cache__[mypkg] = None
743 return None
744 # verify rev
745 revok = 0
746 myrev = myparts[-1]
747 ververify(myrev, silent)
748 if len(myrev) and myrev[0] == "r":
749 try:
750 string.atoi(myrev[1:])
751 revok = 1
752 except:
753 pass
754 if revok:
755 if ververify(myparts[-2]):
756 if len(myparts) == 2:
757 __pkgsplit_cache__[mypkg] = None
758 return None
759 else:
760 for x in myparts[:-2]:
761 if ververify(x):
762 __pkgsplit_cache__[mypkg]=None
763 return None
764 # names can't have versiony looking parts
765 myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]]
766 __pkgsplit_cache__[mypkg]=myval
767 return myval
768 else:
769 __pkgsplit_cache__[mypkg] = None
770 return None
771
772 elif ververify(myparts[-1],silent):
773 if len(myparts)==1:
774 if not silent:
775 print "!!! Name error in",mypkg+": missing name part."
776 __pkgsplit_cache__[mypkg]=None
777 return None
778 else:
779 for x in myparts[:-1]:
780 if ververify(x):
781 if not silent: error("package name has multiple version parts")
782 __pkgsplit_cache__[mypkg] = None
783 return None
784 myval = [string.join(myparts[:-1],"-"), myparts[-1],"r0"]
785 __pkgsplit_cache__[mypkg] = myval
786 return myval
787 else:
788 __pkgsplit_cache__[mypkg] = None
789 return None
790
791
792#######################################################################
793
794__catpkgsplit_cache__ = {}
795
796def catpkgsplit(mydata,silent=1):
797 """returns [cat, pkgname, version, rev ]
798
799 >>> catpkgsplit('sys-libs/glibc-1.2-r7')
800 ['sys-libs', 'glibc', '1.2', 'r7']
801 >>> catpkgsplit('glibc-1.2-r7')
802 [None, 'glibc', '1.2', 'r7']
803 """
804
805 try:
806 return __catpkgsplit_cache__[mydata]
807 except KeyError:
808 pass
809
810 cat = os.path.basename(os.path.dirname(mydata))
811 mydata = os.path.join(cat, os.path.basename(mydata))
812 if mydata[-3:] == '.bb':
813 mydata = mydata[:-3]
814
815 mysplit = mydata.split("/")
816 p_split = None
817 splitlen = len(mysplit)
818 if splitlen == 1:
819 retval = [None]
820 p_split = pkgsplit(mydata,silent)
821 else:
822 retval = [mysplit[splitlen - 2]]
823 p_split = pkgsplit(mysplit[splitlen - 1],silent)
824 if not p_split:
825 __catpkgsplit_cache__[mydata] = None
826 return None
827 retval.extend(p_split)
828 __catpkgsplit_cache__[mydata] = retval
829 return retval
830
831
832#######################################################################
833
834__vercmp_cache__ = {}
835
836def vercmp(val1,val2):
837 """This takes two version strings and returns an integer to tell you whether
838 the versions are the same, val1>val2 or val2>val1.
839
840 >>> vercmp('1', '2')
841 -1.0
842 >>> vercmp('2', '1')
843 1.0
844 >>> vercmp('1', '1.0')
845 0
846 >>> vercmp('1', '1.1')
847 -1.0
848 >>> vercmp('1.1', '1_p2')
849 1.0
850 """
851
852 # quick short-circuit
853 if val1 == val2:
854 return 0
855 valkey = val1+" "+val2
856
857 # cache lookup
858 try:
859 return __vercmp_cache__[valkey]
860 try:
861 return - __vercmp_cache__[val2+" "+val1]
862 except KeyError:
863 pass
864 except KeyError:
865 pass
866
867 # consider 1_p2 vc 1.1
868 # after expansion will become (1_p2,0) vc (1,1)
869 # then 1_p2 is compared with 1 before 0 is compared with 1
870 # to solve the bug we need to convert it to (1,0_p2)
871 # by splitting _prepart part and adding it back _after_expansion
872
873 val1_prepart = val2_prepart = ''
874 if val1.count('_'):
875 val1, val1_prepart = val1.split('_', 1)
876 if val2.count('_'):
877 val2, val2_prepart = val2.split('_', 1)
878
879 # replace '-' by '.'
880 # FIXME: Is it needed? can val1/2 contain '-'?
881
882 val1 = string.split(val1,'-')
883 if len(val1) == 2:
884 val1[0] = val1[0] +"."+ val1[1]
885 val2 = string.split(val2,'-')
886 if len(val2) == 2:
887 val2[0] = val2[0] +"."+ val2[1]
888
889 val1 = string.split(val1[0],'.')
890 val2 = string.split(val2[0],'.')
891
892 # add back decimal point so that .03 does not become "3" !
893 for x in range(1,len(val1)):
894 if val1[x][0] == '0' :
895 val1[x] = '.' + val1[x]
896 for x in range(1,len(val2)):
897 if val2[x][0] == '0' :
898 val2[x] = '.' + val2[x]
899
900 # extend varion numbers
901 if len(val2) < len(val1):
902 val2.extend(["0"]*(len(val1)-len(val2)))
903 elif len(val1) < len(val2):
904 val1.extend(["0"]*(len(val2)-len(val1)))
905
906 # add back _prepart tails
907 if val1_prepart:
908 val1[-1] += '_' + val1_prepart
909 if val2_prepart:
910 val2[-1] += '_' + val2_prepart
911 # The above code will extend version numbers out so they
912 # have the same number of digits.
913 for x in range(0,len(val1)):
914 cmp1 = relparse(val1[x])
915 cmp2 = relparse(val2[x])
916 for y in range(0,3):
917 myret = cmp1[y] - cmp2[y]
918 if myret != 0:
919 __vercmp_cache__[valkey] = myret
920 return myret
921 __vercmp_cache__[valkey] = 0
922 return 0
923
924
925#######################################################################
926
927def pkgcmp(pkg1,pkg2):
928 """ Compares two packages, which should have been split via
929 pkgsplit(). if the return value val is less than zero, then pkg2 is
930 newer than pkg1, zero if equal and positive if older.
931
932 >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r7'])
933 0
934 >>> pkgcmp(['glibc', '2.2.5', 'r4'], ['glibc', '2.2.5', 'r7'])
935 -1
936 >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r2'])
937 1
938 """
939
940 mycmp = vercmp(pkg1[1],pkg2[1])
941 if mycmp > 0:
942 return 1
943 if mycmp < 0:
944 return -1
945 r1=string.atoi(pkg1[2][1:])
946 r2=string.atoi(pkg2[2][1:])
947 if r1 > r2:
948 return 1
949 if r2 > r1:
950 return -1
951 return 0
952
953
954#######################################################################
955
956def dep_parenreduce(mysplit, mypos=0):
957 """Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists:
958
959 >>> dep_parenreduce([''])
960 ['']
961 >>> dep_parenreduce(['1', '2', '3'])
962 ['1', '2', '3']
963 >>> dep_parenreduce(['1', '(', '2', '3', ')', '4'])
964 ['1', ['2', '3'], '4']
965 """
966
967 while mypos < len(mysplit):
968 if mysplit[mypos] == "(":
969 firstpos = mypos
970 mypos = mypos + 1
971 while mypos < len(mysplit):
972 if mysplit[mypos] == ")":
973 mysplit[firstpos:mypos+1] = [mysplit[firstpos+1:mypos]]
974 mypos = firstpos
975 break
976 elif mysplit[mypos] == "(":
977 # recurse
978 mysplit = dep_parenreduce(mysplit,mypos)
979 mypos = mypos + 1
980 mypos = mypos + 1
981 return mysplit
982
983
984def dep_opconvert(mysplit, myuse):
985 "Does dependency operator conversion"
986
987 mypos = 0
988 newsplit = []
989 while mypos < len(mysplit):
990 if type(mysplit[mypos]) == types.ListType:
991 newsplit.append(dep_opconvert(mysplit[mypos],myuse))
992 mypos += 1
993 elif mysplit[mypos] == ")":
994 # mismatched paren, error
995 return None
996 elif mysplit[mypos]=="||":
997 if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType):
998 # || must be followed by paren'd list
999 return None
1000 try:
1001 mynew = dep_opconvert(mysplit[mypos+1],myuse)
1002 except Exception, e:
1003 error("unable to satisfy OR dependancy: " + string.join(mysplit," || "))
1004 raise e
1005 mynew[0:0] = ["||"]
1006 newsplit.append(mynew)
1007 mypos += 2
1008 elif mysplit[mypos][-1] == "?":
1009 # use clause, i.e "gnome? ( foo bar )"
1010 # this is a quick and dirty hack so that repoman can enable all USE vars:
1011 if (len(myuse) == 1) and (myuse[0] == "*"):
1012 # enable it even if it's ! (for repoman) but kill it if it's
1013 # an arch variable that isn't for this arch. XXX Sparc64?
1014 if (mysplit[mypos][:-1] not in settings.usemask) or \
1015 (mysplit[mypos][:-1]==settings["ARCH"]):
1016 enabled=1
1017 else:
1018 enabled=0
1019 else:
1020 if mysplit[mypos][0] == "!":
1021 myusevar = mysplit[mypos][1:-1]
1022 enabled = not myusevar in myuse
1023 #if myusevar in myuse:
1024 # enabled = 0
1025 #else:
1026 # enabled = 1
1027 else:
1028 myusevar=mysplit[mypos][:-1]
1029 enabled = myusevar in myuse
1030 #if myusevar in myuse:
1031 # enabled=1
1032 #else:
1033 # enabled=0
1034 if (mypos +2 < len(mysplit)) and (mysplit[mypos+2] == ":"):
1035 # colon mode
1036 if enabled:
1037 # choose the first option
1038 if type(mysplit[mypos+1]) == types.ListType:
1039 newsplit.append(dep_opconvert(mysplit[mypos+1],myuse))
1040 else:
1041 newsplit.append(mysplit[mypos+1])
1042 else:
1043 # choose the alternate option
1044 if type(mysplit[mypos+1]) == types.ListType:
1045 newsplit.append(dep_opconvert(mysplit[mypos+3],myuse))
1046 else:
1047 newsplit.append(mysplit[mypos+3])
1048 mypos += 4
1049 else:
1050 # normal use mode
1051 if enabled:
1052 if type(mysplit[mypos+1]) == types.ListType:
1053 newsplit.append(dep_opconvert(mysplit[mypos+1],myuse))
1054 else:
1055 newsplit.append(mysplit[mypos+1])
1056 # otherwise, continue
1057 mypos += 2
1058 else:
1059 # normal item
1060 newsplit.append(mysplit[mypos])
1061 mypos += 1
1062 return newsplit
1063
1064class digraph:
1065 """beautiful directed graph object"""
1066
1067 def __init__(self):
1068 self.dict={}
1069 #okeys = keys, in order they were added (to optimize firstzero() ordering)
1070 self.okeys=[]
1071 self.__callback_cache=[]
1072
1073 def __str__(self):
1074 str = ""
1075 for key in self.okeys:
1076 str += "%s:\t%s\n" % (key, self.dict[key][1])
1077 return str
1078
1079 def addnode(self,mykey,myparent):
1080 if not mykey in self.dict:
1081 self.okeys.append(mykey)
1082 if myparent==None:
1083 self.dict[mykey]=[0,[]]
1084 else:
1085 self.dict[mykey]=[0,[myparent]]
1086 self.dict[myparent][0]=self.dict[myparent][0]+1
1087 return
1088 if myparent and (not myparent in self.dict[mykey][1]):
1089 self.dict[mykey][1].append(myparent)
1090 self.dict[myparent][0]=self.dict[myparent][0]+1
1091
1092 def delnode(self,mykey, ref = 1):
1093 """Delete a node
1094
1095 If ref is 1, remove references to this node from other nodes.
1096 If ref is 2, remove nodes that reference this node."""
1097 if not mykey in self.dict:
1098 return
1099 for x in self.dict[mykey][1]:
1100 self.dict[x][0]=self.dict[x][0]-1
1101 del self.dict[mykey]
1102 while 1:
1103 try:
1104 self.okeys.remove(mykey)
1105 except ValueError:
1106 break
1107 if ref:
1108 __kill = []
1109 for k in self.okeys:
1110 if mykey in self.dict[k][1]:
1111 if ref == 1 or ref == 2:
1112 self.dict[k][1].remove(mykey)
1113 if ref == 2:
1114 __kill.append(k)
1115 for l in __kill:
1116 self.delnode(l, ref)
1117
1118 def allnodes(self):
1119 "returns all nodes in the dictionary"
1120 return self.dict.keys()
1121
1122 def firstzero(self):
1123 "returns first node with zero references, or NULL if no such node exists"
1124 for x in self.okeys:
1125 if self.dict[x][0]==0:
1126 return x
1127 return None
1128
1129 def firstnonzero(self):
1130 "returns first node with nonzero references, or NULL if no such node exists"
1131 for x in self.okeys:
1132 if self.dict[x][0]!=0:
1133 return x
1134 return None
1135
1136
1137 def allzeros(self):
1138 "returns all nodes with zero references, or NULL if no such node exists"
1139 zerolist = []
1140 for x in self.dict.keys():
1141 if self.dict[x][0]==0:
1142 zerolist.append(x)
1143 return zerolist
1144
1145 def hasallzeros(self):
1146 "returns 0/1, Are all nodes zeros? 1 : 0"
1147 zerolist = []
1148 for x in self.dict.keys():
1149 if self.dict[x][0]!=0:
1150 return 0
1151 return 1
1152
1153 def empty(self):
1154 if len(self.dict)==0:
1155 return 1
1156 return 0
1157
1158 def hasnode(self,mynode):
1159 return mynode in self.dict
1160
1161 def getparents(self, item):
1162 if not self.hasnode(item):
1163 return []
1164 return self.dict[item][1]
1165
1166 def getchildren(self, item):
1167 if not self.hasnode(item):
1168 return []
1169 children = [i for i in self.okeys if item in self.getparents(i)]
1170 return children
1171
1172 def walkdown(self, item, callback, debug = None, usecache = False):
1173 if not self.hasnode(item):
1174 return 0
1175
1176 if usecache:
1177 if self.__callback_cache.count(item):
1178 if debug:
1179 print "hit cache for item: %s" % item
1180 return 1
1181
1182 parents = self.getparents(item)
1183 children = self.getchildren(item)
1184 for p in parents:
1185 if p in children:
1186# print "%s is both parent and child of %s" % (p, item)
1187 if usecache:
1188 self.__callback_cache.append(p)
1189 ret = callback(self, p)
1190 if ret == 0:
1191 return 0
1192 continue
1193 if item == p:
1194 print "eek, i'm my own parent!"
1195 return 0
1196 if debug:
1197 print "item: %s, p: %s" % (item, p)
1198 ret = self.walkdown(p, callback, debug, usecache)
1199 if ret == 0:
1200 return 0
1201 if usecache:
1202 self.__callback_cache.append(item)
1203 return callback(self, item)
1204
1205 def walkup(self, item, callback):
1206 if not self.hasnode(item):
1207 return 0
1208
1209 parents = self.getparents(item)
1210 children = self.getchildren(item)
1211 for c in children:
1212 if c in parents:
1213 ret = callback(self, item)
1214 if ret == 0:
1215 return 0
1216 continue
1217 if item == c:
1218 print "eek, i'm my own child!"
1219 return 0
1220 ret = self.walkup(c, callback)
1221 if ret == 0:
1222 return 0
1223 return callback(self, item)
1224
1225 def copy(self):
1226 mygraph=digraph()
1227 for x in self.dict.keys():
1228 mygraph.dict[x]=self.dict[x][:]
1229 mygraph.okeys=self.okeys[:]
1230 return mygraph
1231
1232#######################################################################
1233#######################################################################
1234#
1235# SECTION: Config
1236#
1237# PURPOSE: Reading and handling of system/target-specific/local configuration
1238# reading of package configuration
1239#
1240#######################################################################
1241#######################################################################
1242
1243def reader(cfgfile, feeder):
1244 """Generic configuration file reader that opens a file, reads the lines,
1245 handles continuation lines, comments, empty lines and feed all read lines
1246 into the function feeder(lineno, line).
1247 """
1248
1249 f = open(cfgfile,'r')
1250 lineno = 0
1251 while 1:
1252 lineno = lineno + 1
1253 s = f.readline()
1254 if not s: break
1255 w = s.strip()
1256 if not w: continue # skip empty lines
1257 s = s.rstrip()
1258 if s[0] == '#': continue # skip comments
1259 while s[-1] == '\\':
1260 s2 = f.readline()[:-1].strip()
1261 s = s[:-1] + s2
1262 feeder(lineno, s)
1263
1264if __name__ == "__main__":
1265 import doctest, bb
1266 doctest.testmod(bb)
diff --git a/bitbake/lib/bb/__init__.pyc b/bitbake/lib/bb/__init__.pyc
new file mode 100644
index 0000000000..e8331843e8
--- /dev/null
+++ b/bitbake/lib/bb/__init__.pyc
Binary files differ
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py
new file mode 100644
index 0000000000..599b45d9d3
--- /dev/null
+++ b/bitbake/lib/bb/build.py
@@ -0,0 +1,395 @@
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"""
5BitBake 'Build' implementation
6
7Core code for function execution and task handling in the
8BitBake build tools.
9
10Copyright (C) 2003, 2004 Chris Larson
11
12Based on Gentoo's portage.py.
13
14This program is free software; you can redistribute it and/or modify it under
15the terms of the GNU General Public License as published by the Free Software
16Foundation; either version 2 of the License, or (at your option) any later
17version.
18
19This program is distributed in the hope that it will be useful, but WITHOUT
20ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License along with
24
25Based on functions from the base bb module, Copyright 2003 Holger Schurig
26"""
27
28from bb import debug, data, fetch, fatal, error, note, event, mkdirhier
29import bb, os
30
31# data holds flags and function name for a given task
32_task_data = data.init()
33
34# graph represents task interdependencies
35_task_graph = bb.digraph()
36
37# stack represents execution order, excepting dependencies
38_task_stack = []
39
40# events
41class FuncFailed(Exception):
42 """Executed function failed"""
43
44class EventException(Exception):
45 """Exception which is associated with an Event."""
46
47 def __init__(self, msg, event):
48 self.args = msg, event
49
50class TaskBase(event.Event):
51 """Base class for task events"""
52
53 def __init__(self, t, d ):
54 self._task = t
55 event.Event.__init__(self, d)
56
57 def getTask(self):
58 return self._task
59
60 def setTask(self, task):
61 self._task = task
62
63 task = property(getTask, setTask, None, "task property")
64
65class TaskStarted(TaskBase):
66 """Task execution started"""
67
68class TaskSucceeded(TaskBase):
69 """Task execution completed"""
70
71class TaskFailed(TaskBase):
72 """Task execution failed"""
73
74class InvalidTask(TaskBase):
75 """Invalid Task"""
76
77# functions
78
79def init(data):
80 global _task_data, _task_graph, _task_stack
81 _task_data = data.init()
82 _task_graph = bb.digraph()
83 _task_stack = []
84
85
86def exec_func(func, d, dirs = None):
87 """Execute an BB 'function'"""
88
89 body = data.getVar(func, d)
90 if not body:
91 return
92
93 if not dirs:
94 dirs = (data.getVarFlag(func, 'dirs', d) or "").split()
95 for adir in dirs:
96 adir = data.expand(adir, d)
97 mkdirhier(adir)
98
99 if len(dirs) > 0:
100 adir = dirs[-1]
101 else:
102 adir = data.getVar('B', d, 1)
103
104 adir = data.expand(adir, d)
105
106 try:
107 prevdir = os.getcwd()
108 except OSError:
109 prevdir = data.expand('${TOPDIR}', d)
110 if adir and os.access(adir, os.F_OK):
111 os.chdir(adir)
112
113 if data.getVarFlag(func, "python", d):
114 exec_func_python(func, d)
115 else:
116 exec_func_shell(func, d)
117
118 if os.path.exists(prevdir):
119 os.chdir(prevdir)
120
121def exec_func_python(func, d):
122 """Execute a python BB 'function'"""
123 import re, os
124
125 tmp = "def " + func + "():\n%s" % data.getVar(func, d)
126 comp = compile(tmp + '\n' + func + '()', bb.data.getVar('FILE', d, 1) + ':' + func, "exec")
127 prevdir = os.getcwd()
128 g = {} # globals
129 g['bb'] = bb
130 g['os'] = os
131 g['d'] = d
132 exec comp in g
133 if os.path.exists(prevdir):
134 os.chdir(prevdir)
135
136def exec_func_shell(func, d):
137 """Execute a shell BB 'function' Returns true if execution was successful.
138
139 For this, it creates a bash shell script in the tmp dectory, writes the local
140 data into it and finally executes. The output of the shell will end in a log file and stdout.
141
142 Note on directory behavior. The 'dirs' varflag should contain a list
143 of the directories you need created prior to execution. The last
144 item in the list is where we will chdir/cd to.
145 """
146 import sys
147
148 deps = data.getVarFlag(func, 'deps', d)
149 check = data.getVarFlag(func, 'check', d)
150 if check in globals():
151 if globals()[check](func, deps):
152 return
153
154 global logfile
155 t = data.getVar('T', d, 1)
156 if not t:
157 return 0
158 mkdirhier(t)
159 logfile = "%s/log.%s.%s" % (t, func, str(os.getpid()))
160 runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
161
162 f = open(runfile, "w")
163 f.write("#!/bin/sh -e\n")
164 if bb.debug_level > 0: f.write("set -x\n")
165 data.emit_env(f, d)
166
167 f.write("cd %s\n" % os.getcwd())
168 if func: f.write("%s\n" % func)
169 f.close()
170 os.chmod(runfile, 0775)
171 if not func:
172 error("Function not specified")
173 raise FuncFailed()
174
175 # open logs
176 si = file('/dev/null', 'r')
177 try:
178 if bb.debug_level > 0:
179 so = os.popen("tee \"%s\"" % logfile, "w")
180 else:
181 so = file(logfile, 'w')
182 except OSError, e:
183 bb.error("opening log file: %s" % e)
184 pass
185
186 se = so
187
188 # dup the existing fds so we dont lose them
189 osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
190 oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
191 ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
192
193 # replace those fds with our own
194 os.dup2(si.fileno(), osi[1])
195 os.dup2(so.fileno(), oso[1])
196 os.dup2(se.fileno(), ose[1])
197
198 # execute function
199 prevdir = os.getcwd()
200 if data.getVarFlag(func, "fakeroot", d):
201 maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1)
202 else:
203 maybe_fakeroot = ''
204 ret = os.system('%ssh -e %s' % (maybe_fakeroot, runfile))
205 os.chdir(prevdir)
206
207 # restore the backups
208 os.dup2(osi[0], osi[1])
209 os.dup2(oso[0], oso[1])
210 os.dup2(ose[0], ose[1])
211
212 # close our logs
213 si.close()
214 so.close()
215 se.close()
216
217 # close the backup fds
218 os.close(osi[0])
219 os.close(oso[0])
220 os.close(ose[0])
221
222 if ret==0:
223 if bb.debug_level > 0:
224 os.remove(runfile)
225# os.remove(logfile)
226 return
227 else:
228 error("function %s failed" % func)
229 if data.getVar("BBINCLUDELOGS", d):
230 error("log data follows (%s)" % logfile)
231 f = open(logfile, "r")
232 while True:
233 l = f.readline()
234 if l == '':
235 break
236 l = l.rstrip()
237 print '| %s' % l
238 f.close()
239 else:
240 error("see log in %s" % logfile)
241 raise FuncFailed( logfile )
242
243
244def exec_task(task, d):
245 """Execute an BB 'task'
246
247 The primary difference between executing a task versus executing
248 a function is that a task exists in the task digraph, and therefore
249 has dependencies amongst other tasks."""
250
251 # check if the task is in the graph..
252 task_graph = data.getVar('_task_graph', d)
253 if not task_graph:
254 task_graph = bb.digraph()
255 data.setVar('_task_graph', task_graph, d)
256 task_cache = data.getVar('_task_cache', d)
257 if not task_cache:
258 task_cache = []
259 data.setVar('_task_cache', task_cache, d)
260 if not task_graph.hasnode(task):
261 raise EventException("Missing node in task graph", InvalidTask(task, d))
262
263 # check whether this task needs executing..
264 if not data.getVarFlag(task, 'force', d):
265 if stamp_is_current(task, d):
266 return 1
267
268 # follow digraph path up, then execute our way back down
269 def execute(graph, item):
270 if data.getVarFlag(item, 'task', d):
271 if item in task_cache:
272 return 1
273
274 if task != item:
275 # deeper than toplevel, exec w/ deps
276 exec_task(item, d)
277 return 1
278
279 try:
280 debug(1, "Executing task %s" % item)
281 old_overrides = data.getVar('OVERRIDES', d, 0)
282 localdata = data.createCopy(d)
283 data.setVar('OVERRIDES', 'task_%s:%s' % (item, old_overrides), localdata)
284 data.update_data(localdata)
285 event.fire(TaskStarted(item, localdata))
286 exec_func(item, localdata)
287 event.fire(TaskSucceeded(item, localdata))
288 task_cache.append(item)
289 data.setVar('_task_cache', task_cache, d)
290 except FuncFailed, reason:
291 note( "Task failed: %s" % reason )
292 failedevent = TaskFailed(item, d)
293 event.fire(failedevent)
294 raise EventException("Function failed in task: %s" % reason, failedevent)
295
296 # execute
297 task_graph.walkdown(task, execute)
298
299 # make stamp, or cause event and raise exception
300 if not data.getVarFlag(task, 'nostamp', d):
301 mkstamp(task, d)
302
303
304def stamp_is_current(task, d, checkdeps = 1):
305 """Check status of a given task's stamp. returns 0 if it is not current and needs updating."""
306 task_graph = data.getVar('_task_graph', d)
307 if not task_graph:
308 task_graph = bb.digraph()
309 data.setVar('_task_graph', task_graph, d)
310 stamp = data.getVar('STAMP', d)
311 if not stamp:
312 return 0
313 stampfile = "%s.%s" % (data.expand(stamp, d), task)
314 if not os.access(stampfile, os.F_OK):
315 return 0
316
317 if checkdeps == 0:
318 return 1
319
320 import stat
321 tasktime = os.stat(stampfile)[stat.ST_MTIME]
322
323 _deps = []
324 def checkStamp(graph, task):
325 # check for existance
326 if data.getVarFlag(task, 'nostamp', d):
327 return 1
328
329 if not stamp_is_current(task, d, 0):
330 return 0
331
332 depfile = "%s.%s" % (data.expand(stamp, d), task)
333 deptime = os.stat(depfile)[stat.ST_MTIME]
334 if deptime > tasktime:
335 return 0
336 return 1
337
338 return task_graph.walkdown(task, checkStamp)
339
340
341def md5_is_current(task):
342 """Check if a md5 file for a given task is current"""
343
344
345def mkstamp(task, d):
346 """Creates/updates a stamp for a given task"""
347 stamp = data.getVar('STAMP', d)
348 if not stamp:
349 return
350 stamp = "%s.%s" % (data.expand(stamp, d), task)
351 mkdirhier(os.path.dirname(stamp))
352 open(stamp, "w+")
353
354
355def add_task(task, deps, d):
356 task_graph = data.getVar('_task_graph', d)
357 if not task_graph:
358 task_graph = bb.digraph()
359 data.setVarFlag(task, 'task', 1, d)
360 task_graph.addnode(task, None)
361 for dep in deps:
362 if not task_graph.hasnode(dep):
363 task_graph.addnode(dep, None)
364 task_graph.addnode(task, dep)
365 # don't assume holding a reference
366 data.setVar('_task_graph', task_graph, d)
367
368
369def remove_task(task, kill, d):
370 """Remove an BB 'task'.
371
372 If kill is 1, also remove tasks that depend on this task."""
373
374 task_graph = data.getVar('_task_graph', d)
375 if not task_graph:
376 task_graph = bb.digraph()
377 if not task_graph.hasnode(task):
378 return
379
380 data.delVarFlag(task, 'task', d)
381 ref = 1
382 if kill == 1:
383 ref = 2
384 task_graph.delnode(task, ref)
385 data.setVar('_task_graph', task_graph, d)
386
387def task_exists(task, d):
388 task_graph = data.getVar('_task_graph', d)
389 if not task_graph:
390 task_graph = bb.digraph()
391 data.setVar('_task_graph', task_graph, d)
392 return task_graph.hasnode(task)
393
394def get_task_data():
395 return _task_data
diff --git a/bitbake/lib/bb/build.pyc b/bitbake/lib/bb/build.pyc
new file mode 100644
index 0000000000..556a68dc9b
--- /dev/null
+++ b/bitbake/lib/bb/build.pyc
Binary files differ
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
new file mode 100644
index 0000000000..b7d707a920
--- /dev/null
+++ b/bitbake/lib/bb/data.py
@@ -0,0 +1,580 @@
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"""
5BitBake 'Data' implementations
6
7Functions for interacting with the data structure used by the
8BitBake build tools.
9
10Copyright (C) 2003, 2004 Chris Larson
11Copyright (C) 2005 Holger Hans Peter Freyther
12
13This program is free software; you can redistribute it and/or modify it under
14the terms of the GNU General Public License as published by the Free Software
15Foundation; either version 2 of the License, or (at your option) any later
16version.
17
18This program is distributed in the hope that it will be useful, but WITHOUT
19ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24Place, Suite 330, Boston, MA 02111-1307 USA.
25
26Based on functions from the base bb module, Copyright 2003 Holger Schurig
27"""
28
29import sys, os, re, time, types
30if sys.argv[0][-5:] == "pydoc":
31 path = os.path.dirname(os.path.dirname(sys.argv[1]))
32else:
33 path = os.path.dirname(os.path.dirname(sys.argv[0]))
34sys.path.append(path)
35
36from bb import note, debug, data_smart
37
38_dict_type = data_smart.DataSmart
39_dict_p_type = data_smart.DataSmartPackage
40
41class DataDictFull(dict):
42 """
43 This implements our Package Data Storage Interface.
44 setDirty is a no op as all items are held in memory
45 """
46 def setDirty(self, bbfile, data):
47 """
48 No-Op we assume data was manipulated as some sort of
49 reference
50 """
51 if not bbfile in self:
52 raise Exception("File %s was not in dictionary before" % bbfile)
53
54 self[bbfile] = data
55
56class DataDictCache:
57 """
58 Databacked Dictionary implementation
59 """
60 def __init__(self, cache_dir, config):
61 self.cache_dir = cache_dir
62 self.files = []
63 self.dirty = {}
64 self.config = config
65
66 def has_key(self,key):
67 return key in self.files
68
69 def keys(self):
70 return self.files
71
72 def __setitem__(self, key, data):
73 """
74 Add the key to the list of known files and
75 place the data in the cache?
76 """
77 if key in self.files:
78 return
79
80 self.files.append(key)
81
82 def __getitem__(self, key):
83 if not key in self.files:
84 return None
85
86 # if it was dirty we will
87 if key in self.dirty:
88 return self.dirty[key]
89
90 # not cached yet
91 return _dict_p_type(self.cache_dir, key,False,self.config)
92
93 def setDirty(self, bbfile, data):
94 """
95 Only already added items can be declared dirty!!!
96 """
97
98 if not bbfile in self.files:
99 raise Exception("File %s was not in dictionary before" % bbfile)
100
101 self.dirty[bbfile] = data
102
103
104
105def init():
106 return _dict_type()
107
108def init_db(cache,name,clean,parent = None):
109 return _dict_p_type(cache,name,clean,parent)
110
111def init_db_mtime(cache,cache_bbfile):
112 return _dict_p_type.mtime(cache,cache_bbfile)
113
114def pkgdata(use_cache, cache, config = None):
115 """
116 Return some sort of dictionary to lookup parsed dictionaires
117 """
118 if use_cache:
119 return DataDictCache(cache, config)
120 return DataDictFull()
121
122def createCopy(source):
123 """Link the source set to the destination
124 If one does not find the value in the destination set,
125 search will go on to the source set to get the value.
126 Value from source are copy-on-write. i.e. any try to
127 modify one of them will end up putting the modified value
128 in the destination set.
129 """
130 return source.createCopy()
131
132def initVar(var, d):
133 """Non-destructive var init for data structure"""
134 d.initVar(var)
135
136
137def setVar(var, value, d):
138 """Set a variable to a given value
139
140 Example:
141 >>> d = init()
142 >>> setVar('TEST', 'testcontents', d)
143 >>> print getVar('TEST', d)
144 testcontents
145 """
146 d.setVar(var,value)
147
148
149def getVar(var, d, exp = 0):
150 """Gets the value of a variable
151
152 Example:
153 >>> d = init()
154 >>> setVar('TEST', 'testcontents', d)
155 >>> print getVar('TEST', d)
156 testcontents
157 """
158 return d.getVar(var,exp)
159
160def delVar(var, d):
161 """Removes a variable from the data set
162
163 Example:
164 >>> d = init()
165 >>> setVar('TEST', 'testcontents', d)
166 >>> print getVar('TEST', d)
167 testcontents
168 >>> delVar('TEST', d)
169 >>> print getVar('TEST', d)
170 None
171 """
172 d.delVar(var)
173
174def setVarFlag(var, flag, flagvalue, d):
175 """Set a flag for a given variable to a given value
176
177 Example:
178 >>> d = init()
179 >>> setVarFlag('TEST', 'python', 1, d)
180 >>> print getVarFlag('TEST', 'python', d)
181 1
182 """
183 d.setVarFlag(var,flag,flagvalue)
184
185def getVarFlag(var, flag, d):
186 """Gets given flag from given var
187
188 Example:
189 >>> d = init()
190 >>> setVarFlag('TEST', 'python', 1, d)
191 >>> print getVarFlag('TEST', 'python', d)
192 1
193 """
194 return d.getVarFlag(var,flag)
195
196def delVarFlag(var, flag, d):
197 """Removes a given flag from the variable's flags
198
199 Example:
200 >>> d = init()
201 >>> setVarFlag('TEST', 'testflag', 1, d)
202 >>> print getVarFlag('TEST', 'testflag', d)
203 1
204 >>> delVarFlag('TEST', 'testflag', d)
205 >>> print getVarFlag('TEST', 'testflag', d)
206 None
207
208 """
209 d.delVarFlag(var,flag)
210
211def setVarFlags(var, flags, d):
212 """Set the flags for a given variable
213
214 Example:
215 >>> d = init()
216 >>> myflags = {}
217 >>> myflags['test'] = 'blah'
218 >>> setVarFlags('TEST', myflags, d)
219 >>> print getVarFlag('TEST', 'test', d)
220 blah
221 """
222 d.setVarFlags(var,flags)
223
224def getVarFlags(var, d):
225 """Gets a variable's flags
226
227 Example:
228 >>> d = init()
229 >>> setVarFlag('TEST', 'test', 'blah', d)
230 >>> print getVarFlags('TEST', d)['test']
231 blah
232 """
233 return d.getVarFlags(var)
234
235def delVarFlags(var, d):
236 """Removes a variable's flags
237
238 Example:
239 >>> data = init()
240 >>> setVarFlag('TEST', 'testflag', 1, data)
241 >>> print getVarFlag('TEST', 'testflag', data)
242 1
243 >>> delVarFlags('TEST', data)
244 >>> print getVarFlags('TEST', data)
245 None
246
247 """
248 d.delVarFlags(var)
249
250def keys(d):
251 """Return a list of keys in d
252
253 Example:
254 >>> d = init()
255 >>> setVar('TEST', 1, d)
256 >>> setVar('MOO' , 2, d)
257 >>> setVarFlag('TEST', 'test', 1, d)
258 >>> keys(d)
259 ['TEST', 'MOO']
260 """
261 return d.keys()
262
263def getData(d):
264 """Returns the data object used"""
265 return d
266
267def setData(newData, d):
268 """Sets the data object to the supplied value"""
269 d = newData
270
271__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
272__expand_python_regexp__ = re.compile(r"\${@.+?}")
273
274def expand(s, d, varname = None):
275 """Variable expansion using the data store.
276
277 Example:
278 Standard expansion:
279 >>> d = init()
280 >>> setVar('A', 'sshd', d)
281 >>> print expand('/usr/bin/${A}', d)
282 /usr/bin/sshd
283
284 Python expansion:
285 >>> d = init()
286 >>> print expand('result: ${@37 * 72}', d)
287 result: 2664
288
289 Shell expansion:
290 >>> d = init()
291 >>> print expand('${TARGET_MOO}', d)
292 ${TARGET_MOO}
293 >>> setVar('TARGET_MOO', 'yupp', d)
294 >>> print expand('${TARGET_MOO}',d)
295 yupp
296 >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
297 >>> delVar('TARGET_MOO', d)
298 >>> print expand('${SRC_URI}', d)
299 http://somebug.${TARGET_MOO}
300 """
301 def var_sub(match):
302 key = match.group()[2:-1]
303 if varname and key:
304 if varname == key:
305 raise Exception("variable %s references itself!" % varname)
306 var = getVar(key, d, 1)
307 if var is not None:
308 return var
309 else:
310 return match.group()
311
312 def python_sub(match):
313 import bb
314 code = match.group()[3:-1]
315 locals()['d'] = d
316 s = eval(code)
317 if type(s) == types.IntType: s = str(s)
318 return s
319
320 if type(s) is not types.StringType: # sanity check
321 return s
322
323 while s.find('$') != -1:
324 olds = s
325 try:
326 s = __expand_var_regexp__.sub(var_sub, s)
327 s = __expand_python_regexp__.sub(python_sub, s)
328 if s == olds: break
329 if type(s) is not types.StringType: # sanity check
330 import bb
331 bb.error('expansion of %s returned non-string %s' % (olds, s))
332 except KeyboardInterrupt:
333 raise
334 except:
335 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
336 raise
337 return s
338
339def expandKeys(alterdata, readdata = None):
340 if readdata == None:
341 readdata = alterdata
342
343 for key in keys(alterdata):
344 ekey = expand(key, readdata)
345 if key == ekey:
346 continue
347 val = getVar(key, alterdata)
348 if val is None:
349 continue
350# import copy
351# setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
352 setVar(ekey, val, alterdata)
353
354 for i in ('_append', '_prepend', '_delete'):
355 dest = getVarFlag(ekey, i, alterdata) or []
356 src = getVarFlag(key, i, readdata) or []
357 dest.extend(src)
358 setVarFlag(ekey, i, dest, alterdata)
359
360 delVar(key, alterdata)
361
362def expandData(alterdata, readdata = None):
363 """For each variable in alterdata, expand it, and update the var contents.
364 Replacements use data from readdata.
365
366 Example:
367 >>> a=init()
368 >>> b=init()
369 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
370 >>> setVar("DL_DIR", "/path/to/whatever", b)
371 >>> expandData(a, b)
372 >>> print getVar("dlmsg", a)
373 dl_dir is /path/to/whatever
374 """
375 if readdata == None:
376 readdata = alterdata
377
378 for key in keys(alterdata):
379 val = getVar(key, alterdata)
380 if type(val) is not types.StringType:
381 continue
382 expanded = expand(val, readdata)
383# print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
384 if val != expanded:
385 setVar(key, expanded, alterdata)
386
387import os
388
389def inheritFromOS(d):
390 """Inherit variables from the environment."""
391# fakeroot needs to be able to set these
392 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
393 for s in os.environ.keys():
394 if not s in non_inherit_vars:
395 try:
396 setVar(s, os.environ[s], d)
397 setVarFlag(s, 'matchesenv', '1', d)
398 except TypeError:
399 pass
400
401import sys
402
403def emit_var(var, o=sys.__stdout__, d = init(), all=False):
404 """Emit a variable to be sourced by a shell."""
405 if getVarFlag(var, "python", d):
406 return 0
407
408 try:
409 if all:
410 oval = getVar(var, d, 0)
411 val = getVar(var, d, 1)
412 except KeyboardInterrupt:
413 raise
414 except:
415 excname = str(sys.exc_info()[0])
416 if excname == "bb.build.FuncFailed":
417 raise
418 o.write('# expansion of %s threw %s\n' % (var, excname))
419 return 0
420
421 if all:
422 o.write('# %s=%s\n' % (var, oval))
423
424 if type(val) is not types.StringType:
425 return 0
426
427 if getVarFlag(var, 'matchesenv', d):
428 return 0
429
430 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
431 return 0
432
433 val.rstrip()
434 if not val:
435 return 0
436
437 if getVarFlag(var, "func", d):
438# NOTE: should probably check for unbalanced {} within the var
439 o.write("%s() {\n%s\n}\n" % (var, val))
440 else:
441 if getVarFlag(var, "export", d):
442 o.write('export ')
443 else:
444 if not all:
445 return 0
446# if we're going to output this within doublequotes,
447# to a shell, we need to escape the quotes in the var
448 alter = re.sub('"', '\\"', val.strip())
449 o.write('%s="%s"\n' % (var, alter))
450 return 1
451
452
453def emit_env(o=sys.__stdout__, d = init(), all=False):
454 """Emits all items in the data store in a format such that it can be sourced by a shell."""
455
456 env = keys(d)
457
458 for e in env:
459 if getVarFlag(e, "func", d):
460 continue
461 emit_var(e, o, d, all) and o.write('\n')
462
463 for e in env:
464 if not getVarFlag(e, "func", d):
465 continue
466 emit_var(e, o, d) and o.write('\n')
467
468def update_data(d):
469 """Modifies the environment vars according to local overrides and commands.
470 Examples:
471 Appending to a variable:
472 >>> d = init()
473 >>> setVar('TEST', 'this is a', d)
474 >>> setVar('TEST_append', ' test', d)
475 >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
476 >>> update_data(d)
477 >>> print getVar('TEST', d)
478 this is a test of the emergency broadcast system.
479
480 Prepending to a variable:
481 >>> setVar('TEST', 'virtual/libc', d)
482 >>> setVar('TEST_prepend', 'virtual/tmake ', d)
483 >>> setVar('TEST_prepend', 'virtual/patcher ', d)
484 >>> update_data(d)
485 >>> print getVar('TEST', d)
486 virtual/patcher virtual/tmake virtual/libc
487
488 Overrides:
489 >>> setVar('TEST_arm', 'target', d)
490 >>> setVar('TEST_ramses', 'machine', d)
491 >>> setVar('TEST_local', 'local', d)
492 >>> setVar('OVERRIDES', 'arm', d)
493
494 >>> setVar('TEST', 'original', d)
495 >>> update_data(d)
496 >>> print getVar('TEST', d)
497 target
498
499 >>> setVar('OVERRIDES', 'arm:ramses:local', d)
500 >>> setVar('TEST', 'original', d)
501 >>> update_data(d)
502 >>> print getVar('TEST', d)
503 local
504 """
505
506 debug(2, "update_data()")
507
508# can't do delete env[...] while iterating over the dictionary, so remember them
509 dodel = []
510 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
511
512 def applyOverrides(var, d):
513 if not overrides:
514 debug(1, "OVERRIDES not defined, nothing to do")
515 return
516 val = getVar(var, d)
517 for o in overrides:
518 if var.endswith("_" + o):
519 l = len(o)+1
520 name = var[:-l]
521 d[name] = d[var]
522
523 for s in keys(d):
524 applyOverrides(s, d)
525 sval = getVar(s, d) or ""
526
527# Handle line appends:
528 for (a, o) in getVarFlag(s, '_append', d) or []:
529 # maybe the OVERRIDE was not yet added so keep the append
530 if (o and o in overrides) or not o:
531 delVarFlag(s, '_append', d)
532 if o:
533 if not o in overrides:
534 continue
535 sval+=a
536 setVar(s, sval, d)
537
538# Handle line prepends
539 for (a, o) in getVarFlag(s, '_prepend', d) or []:
540 # maybe the OVERRIDE was not yet added so keep the append
541 if (o and o in overrides) or not o:
542 delVarFlag(s, '_prepend', d)
543 if o:
544 if not o in overrides:
545 continue
546 sval=a+sval
547 setVar(s, sval, d)
548
549# Handle line deletions
550 name = s + "_delete"
551 nameval = getVar(name, d)
552 if nameval:
553 sval = getVar(s, d)
554 if sval:
555 new = ''
556 pattern = nameval.replace('\n','').strip()
557 for line in sval.split('\n'):
558 if line.find(pattern) == -1:
559 new = new + '\n' + line
560 setVar(s, new, d)
561 dodel.append(name)
562
563# delete all environment vars no longer needed
564 for s in dodel:
565 delVar(s, d)
566
567def inherits_class(klass, d):
568 val = getVar('__inherit_cache', d) or ""
569 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
570 return True
571 return False
572
573def _test():
574 """Start a doctest run on this module"""
575 import doctest
576 from bb import data
577 doctest.testmod(data)
578
579if __name__ == "__main__":
580 _test()
diff --git a/bitbake/lib/bb/data.pyc b/bitbake/lib/bb/data.pyc
new file mode 100644
index 0000000000..4b729e021f
--- /dev/null
+++ b/bitbake/lib/bb/data.pyc
Binary files differ
diff --git a/bitbake/lib/bb/data_dict.pyc b/bitbake/lib/bb/data_dict.pyc
new file mode 100644
index 0000000000..16c6ea141e
--- /dev/null
+++ b/bitbake/lib/bb/data_dict.pyc
Binary files differ
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
new file mode 100644
index 0000000000..741790502f
--- /dev/null
+++ b/bitbake/lib/bb/data_smart.py
@@ -0,0 +1,351 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake Smart Dictionary Implementation
5
6Functions for interacting with the data structure used by the
7BitBake build tools.
8
9Copyright (C) 2003, 2004 Chris Larson
10Copyright (C) 2004, 2005 Seb Frankengul
11Copyright (C) 2005 Holger Hans Peter Freyther
12Copyright (C) 2005 Uli Luckas
13Copyright (C) 2005 ROAD GmbH
14
15This program is free software; you can redistribute it and/or modify it under
16the terms of the GNU General Public License as published by the Free Software
17Foundation; either version 2 of the License, or (at your option) any later
18version.
19
20This program is distributed in the hope that it will be useful, but WITHOUT
21ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License along with
25this program; if not, write to the Free Software Foundation, Inc., 59 Temple
26Place, Suite 330, Boston, MA 02111-1307 USA.
27
28Based on functions from the base bb module, Copyright 2003 Holger Schurig
29"""
30
31import copy, os, re, sys, time, types
32from bb import note, debug, fatal
33
34try:
35 import cPickle as pickle
36except ImportError:
37 import pickle
38 print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
39
40
41__setvar_keyword__ = ["_append","_prepend","_delete"]
42__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_delete)(_(?P<add>.*))?')
43__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
44__expand_python_regexp__ = re.compile(r"\${@.+?}")
45
46
47class DataSmart:
48 def __init__(self):
49 self.dict = {}
50
51 def expand(self,s, varname):
52 def var_sub(match):
53 key = match.group()[2:-1]
54 if varname and key:
55 if varname == key:
56 raise Exception("variable %s references itself!" % varname)
57 var = self.getVar(key, 1)
58 if var is not None:
59 return var
60 else:
61 return match.group()
62
63 def python_sub(match):
64 import bb
65 code = match.group()[3:-1]
66 locals()['d'] = self
67 s = eval(code)
68 if type(s) == types.IntType: s = str(s)
69 return s
70
71 if type(s) is not types.StringType: # sanity check
72 return s
73
74 while s.find('$') != -1:
75 olds = s
76 try:
77 s = __expand_var_regexp__.sub(var_sub, s)
78 s = __expand_python_regexp__.sub(python_sub, s)
79 if s == olds: break
80 if type(s) is not types.StringType: # sanity check
81 import bb
82 bb.error('expansion of %s returned non-string %s' % (olds, s))
83 except KeyboardInterrupt:
84 raise
85 except:
86 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
87 raise
88 return s
89
90 def initVar(self, var):
91 if not var in self.dict:
92 self.dict[var] = {}
93
94 def pickle_prep(self, cfg):
95 if "_data" in self.dict:
96 if self.dict["_data"] == cfg:
97 self.dict["_data"] = "cfg";
98 else: # this is an unknown array for the moment
99 pass
100
101 def unpickle_prep(self, cfg):
102 if "_data" in self.dict:
103 if self.dict["_data"] == "cfg":
104 self.dict["_data"] = cfg;
105
106 def _findVar(self,var):
107 _dest = self.dict
108
109 while (_dest and var not in _dest):
110 if not "_data" in _dest:
111 _dest = None
112 break
113 _dest = _dest["_data"]
114
115 if _dest and var in _dest:
116 return _dest[var]
117 return None
118
119 def _copyVar(self,var,name):
120 local_var = self._findVar(var)
121 if local_var:
122 self.dict[name] = copy.copy(local_var)
123 else:
124 debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
125
126
127 def _makeShadowCopy(self, var):
128 if var in self.dict:
129 return
130
131 local_var = self._findVar(var)
132
133 if local_var:
134 self.dict[var] = copy.copy(local_var)
135 else:
136 self.initVar(var)
137
138 def setVar(self,var,value):
139 match = __setvar_regexp__.match(var)
140 if match and match.group("keyword") in __setvar_keyword__:
141 base = match.group('base')
142 keyword = match.group("keyword")
143 override = match.group('add')
144 l = self.getVarFlag(base, keyword) or []
145 if override == 'delete':
146 if l.count([value, None]):
147 del l[l.index([value, None])]
148 l.append([value, override])
149 self.setVarFlag(base, match.group("keyword"), l)
150 return
151
152 if not var in self.dict:
153 self._makeShadowCopy(var)
154 if self.getVarFlag(var, 'matchesenv'):
155 self.delVarFlag(var, 'matchesenv')
156 self.setVarFlag(var, 'export', 1)
157
158 # setting var
159 self.dict[var]["content"] = value
160
161 def getVar(self,var,exp):
162 value = self.getVarFlag(var,"content")
163
164 if exp and value:
165 return self.expand(value,var)
166 return value
167
168 def delVar(self,var):
169 self.dict[var] = {}
170
171 def setVarFlag(self,var,flag,flagvalue):
172 if not var in self.dict:
173 self._makeShadowCopy(var)
174 self.dict[var][flag] = flagvalue
175
176 def getVarFlag(self,var,flag):
177 local_var = self._findVar(var)
178 if local_var:
179 if flag in local_var:
180 return copy.copy(local_var[flag])
181 return None
182
183 def delVarFlag(self,var,flag):
184 local_var = self._findVar(var)
185 if not local_var:
186 return
187 if not var in self.dict:
188 self._makeShadowCopy(var)
189
190 if var in self.dict and flag in self.dict[var]:
191 del self.dict[var][flag]
192
193 def setVarFlags(self,var,flags):
194 if not var in self.dict:
195 self._makeShadowCopy(var)
196
197 for i in flags.keys():
198 if i == "content":
199 continue
200 self.dict[var][i] = flags[i]
201
202 def getVarFlags(self,var):
203 local_var = self._findVar(var)
204 flags = {}
205
206 if local_var:
207 for i in self.dict[var].keys():
208 if i == "content":
209 continue
210 flags[i] = self.dict[var][i]
211
212 if len(flags) == 0:
213 return None
214 return flags
215
216
217 def delVarFlags(self,var):
218 if not var in self.dict:
219 self._makeShadowCopy(var)
220
221 if var in self.dict:
222 content = None
223
224 # try to save the content
225 if "content" in self.dict[var]:
226 content = self.dict[var]["content"]
227 self.dict[var] = {}
228 self.dict[var]["content"] = content
229 else:
230 del self.dict[var]
231
232
233 def createCopy(self):
234 """
235 Create a copy of self by setting _data to self
236 """
237 # we really want this to be a DataSmart...
238 data = DataSmart()
239 data.dict["_data"] = self.dict
240
241 return data
242
243 # Dictionary Methods
244 def keys(self):
245 def _keys(d, mykey):
246 if "_data" in d:
247 _keys(d["_data"],mykey)
248
249 for key in d.keys():
250 if key != "_data":
251 mykey[key] = None
252 keytab = {}
253 _keys(self.dict,keytab)
254 return keytab.keys()
255
256 def __getitem__(self,item):
257 start = self.dict
258 while start:
259 if item in start:
260 return start[item]
261 elif "_data" in start:
262 start = start["_data"]
263 else:
264 start = None
265 return None
266
267 def __setitem__(self,var,data):
268 self._makeShadowCopy(var)
269 self.dict[var] = data
270
271
272class DataSmartPackage(DataSmart):
273 """
274 Persistent Data Storage
275 """
276 def sanitize_filename(bbfile):
277 return bbfile.replace( '/', '_' )
278 sanitize_filename = staticmethod(sanitize_filename)
279
280 def unpickle(self):
281 """
282 Restore the dict from memory
283 """
284 cache_bbfile = self.sanitize_filename(self.bbfile)
285 p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
286 self.dict = p.load()
287 self.unpickle_prep()
288 funcstr = self.getVar('__functions__', 0)
289 if funcstr:
290 comp = compile(funcstr, "<pickled>", "exec")
291 exec comp in __builtins__
292
293 def linkDataSet(self):
294 if not self.parent == None:
295 # assume parent is a DataSmartInstance
296 self.dict["_data"] = self.parent.dict
297
298
299 def __init__(self,cache,name,clean,parent):
300 """
301 Construct a persistent data instance
302 """
303 #Initialize the dictionary
304 DataSmart.__init__(self)
305
306 self.cache = cache
307 self.bbfile = os.path.abspath( name )
308 self.parent = parent
309
310 # Either unpickle the data or do copy on write
311 if clean:
312 self.linkDataSet()
313 else:
314 self.unpickle()
315
316 def commit(self, mtime):
317 """
318 Save the package to a permanent storage
319 """
320 self.pickle_prep()
321
322 cache_bbfile = self.sanitize_filename(self.bbfile)
323 p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
324 p.dump( self.dict )
325
326 self.unpickle_prep()
327
328 def mtime(cache,bbfile):
329 cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
330 try:
331 return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
332 except OSError:
333 return 0
334 mtime = staticmethod(mtime)
335
336 def pickle_prep(self):
337 """
338 If self.dict contains a _data key and it is a configuration
339 we will remember we had a configuration instance attached
340 """
341 if "_data" in self.dict:
342 if self.dict["_data"] == self.parent:
343 dest["_data"] = "cfg"
344
345 def unpickle_prep(self):
346 """
347 If we had a configuration instance attached, we will reattach it
348 """
349 if "_data" in self.dict:
350 if self.dict["_data"] == "cfg":
351 self.dict["_data"] = self.parent
diff --git a/bitbake/lib/bb/data_smart.pyc b/bitbake/lib/bb/data_smart.pyc
new file mode 100644
index 0000000000..0f6996a301
--- /dev/null
+++ b/bitbake/lib/bb/data_smart.pyc
Binary files differ
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py
new file mode 100644
index 0000000000..c4e88fa35d
--- /dev/null
+++ b/bitbake/lib/bb/event.py
@@ -0,0 +1,210 @@
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"""
5BitBake 'Event' implementation
6
7Classes and functions for manipulating 'events' in the
8BitBake build tools.
9
10Copyright (C) 2003, 2004 Chris Larson
11
12This program is free software; you can redistribute it and/or modify it under
13the terms of the GNU General Public License as published by the Free Software
14Foundation; either version 2 of the License, or (at your option) any later
15version.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23Place, Suite 330, Boston, MA 02111-1307 USA.
24"""
25
26import os, re
27import bb.data
28
29class Event:
30 """Base class for events"""
31 type = "Event"
32
33 def __init__(self, d = bb.data.init()):
34 self._data = d
35
36 def getData(self):
37 return self._data
38
39 def setData(self, data):
40 self._data = data
41
42 data = property(getData, setData, None, "data property")
43
44NotHandled = 0
45Handled = 1
46handlers = []
47
48def tmpHandler(event):
49 """Default handler for code events"""
50 return NotHandled
51
52def defaultTmpHandler():
53 tmp = "def tmpHandler(e):\n\t\"\"\"heh\"\"\"\n\treturn 0"
54 comp = compile(tmp, "tmpHandler(e)", "exec")
55 return comp
56
57def fire(event):
58 """Fire off an Event"""
59 for h in handlers:
60 if type(h).__name__ == "code":
61 exec(h)
62 if tmpHandler(event) == Handled:
63 return Handled
64 else:
65 if h(event) == Handled:
66 return Handled
67 return NotHandled
68
69def register(handler):
70 """Register an Event handler"""
71 if handler is not None:
72# handle string containing python code
73 if type(handler).__name__ == "str":
74 return registerCode(handler)
75# prevent duplicate registration
76 if not handler in handlers:
77 handlers.append(handler)
78
79def registerCode(handlerStr):
80 """Register a 'code' Event.
81 Deprecated interface; call register instead.
82
83 Expects to be passed python code as a string, which will
84 be passed in turn to compile() and then exec(). Note that
85 the code will be within a function, so should have had
86 appropriate tabbing put in place."""
87 tmp = "def tmpHandler(e):\n%s" % handlerStr
88 comp = compile(tmp, "tmpHandler(e)", "exec")
89# prevent duplicate registration
90 if not comp in handlers:
91 handlers.append(comp)
92
93def remove(handler):
94 """Remove an Event handler"""
95 for h in handlers:
96 if type(handler).__name__ == "str":
97 return removeCode(handler)
98
99 if handler is h:
100 handlers.remove(handler)
101
102def removeCode(handlerStr):
103 """Remove a 'code' Event handler
104 Deprecated interface; call remove instead."""
105 tmp = "def tmpHandler(e):\n%s" % handlerStr
106 comp = compile(tmp, "tmpHandler(e)", "exec")
107 handlers.remove(comp)
108
109def getName(e):
110 """Returns the name of a class or class instance"""
111 if getattr(e, "__name__", None) == None:
112 return e.__class__.__name__
113 else:
114 return e.__name__
115
116
117class PkgBase(Event):
118 """Base class for package events"""
119
120 def __init__(self, t, d = {}):
121 self._pkg = t
122 Event.__init__(self, d)
123
124 def getPkg(self):
125 return self._pkg
126
127 def setPkg(self, pkg):
128 self._pkg = pkg
129
130 pkg = property(getPkg, setPkg, None, "pkg property")
131
132
133class BuildBase(Event):
134 """Base class for bbmake run events"""
135
136 def __init__(self, n, p, c):
137 self._name = n
138 self._pkgs = p
139 Event.__init__(self, c)
140
141 def getPkgs(self):
142 return self._pkgs
143
144 def setPkgs(self, pkgs):
145 self._pkgs = pkgs
146
147 def getName(self):
148 return self._name
149
150 def setName(self, name):
151 self._name = name
152
153 def getCfg(self):
154 return self.data
155
156 def setCfg(self, cfg):
157 self.data = cfg
158
159 pkgs = property(getPkgs, setPkgs, None, "pkgs property")
160 name = property(getName, setName, None, "name property")
161 cfg = property(getCfg, setCfg, None, "cfg property")
162
163
164class DepBase(PkgBase):
165 """Base class for dependency events"""
166
167 def __init__(self, t, data, d):
168 self._dep = d
169 PkgBase.__init__(self, t, data)
170
171 def getDep(self):
172 return self._dep
173
174 def setDep(self, dep):
175 self._dep = dep
176
177 dep = property(getDep, setDep, None, "dep property")
178
179
180class PkgStarted(PkgBase):
181 """Package build started"""
182
183
184class PkgFailed(PkgBase):
185 """Package build failed"""
186
187
188class PkgSucceeded(PkgBase):
189 """Package build completed"""
190
191
192class BuildStarted(BuildBase):
193 """bbmake build run started"""
194
195
196class BuildCompleted(BuildBase):
197 """bbmake build run completed"""
198
199
200class UnsatisfiedDep(DepBase):
201 """Unsatisfied Dependency"""
202
203
204class RecursiveDep(DepBase):
205 """Recursive Dependency"""
206
207
208class MultipleProviders(PkgBase):
209 """Multiple Providers"""
210
diff --git a/bitbake/lib/bb/event.pyc b/bitbake/lib/bb/event.pyc
new file mode 100644
index 0000000000..b6ed391811
--- /dev/null
+++ b/bitbake/lib/bb/event.pyc
Binary files differ
diff --git a/bitbake/lib/bb/fetch.py b/bitbake/lib/bb/fetch.py
new file mode 100644
index 0000000000..982ab51b76
--- /dev/null
+++ b/bitbake/lib/bb/fetch.py
@@ -0,0 +1,656 @@
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"""
5BitBake 'Fetch' implementations
6
7Classes for obtaining upstream sources for the
8BitBake build tools.
9
10Copyright (C) 2003, 2004 Chris Larson
11
12This program is free software; you can redistribute it and/or modify it under
13the terms of the GNU General Public License as published by the Free Software
14Foundation; either version 2 of the License, or (at your option) any later
15version.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23Place, Suite 330, Boston, MA 02111-1307 USA.
24
25Based on functions from the base bb module, Copyright 2003 Holger Schurig
26"""
27
28import os, re
29import bb
30from bb import data
31
32class FetchError(Exception):
33 """Exception raised when a download fails"""
34
35class NoMethodError(Exception):
36 """Exception raised when there is no method to obtain a supplied url or set of urls"""
37
38class MissingParameterError(Exception):
39 """Exception raised when a fetch method is missing a critical parameter in the url"""
40
41class MD5SumError(Exception):
42 """Exception raised when a MD5SUM of a file does not match the expected one"""
43
44def uri_replace(uri, uri_find, uri_replace, d):
45# bb.note("uri_replace: operating on %s" % uri)
46 if not uri or not uri_find or not uri_replace:
47 bb.debug(1, "uri_replace: passed an undefined value, not replacing")
48 uri_decoded = list(bb.decodeurl(uri))
49 uri_find_decoded = list(bb.decodeurl(uri_find))
50 uri_replace_decoded = list(bb.decodeurl(uri_replace))
51 result_decoded = ['','','','','',{}]
52 for i in uri_find_decoded:
53 loc = uri_find_decoded.index(i)
54 result_decoded[loc] = uri_decoded[loc]
55 import types
56 if type(i) == types.StringType:
57 import re
58 if (re.match(i, uri_decoded[loc])):
59 result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
60 if uri_find_decoded.index(i) == 2:
61 if d:
62 localfn = bb.fetch.localpath(uri, d)
63 if localfn:
64 result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
65# bb.note("uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
66 else:
67# bb.note("uri_replace: no match")
68 return uri
69# else:
70# for j in i.keys():
71# FIXME: apply replacements against options
72 return bb.encodeurl(result_decoded)
73
74methods = []
75
76def init(urls = [], d = None):
77 if d == None:
78 bb.debug(2,"BUG init called with None as data object!!!")
79 return
80
81 for m in methods:
82 m.urls = []
83
84 for u in urls:
85 for m in methods:
86 m.data = d
87 if m.supports(u, d):
88 m.urls.append(u)
89
90def go(d):
91 """Fetch all urls"""
92 for m in methods:
93 if m.urls:
94 m.go(d)
95
96def localpaths(d):
97 """Return a list of the local filenames, assuming successful fetch"""
98 local = []
99 for m in methods:
100 for u in m.urls:
101 local.append(m.localpath(u, d))
102 return local
103
104def localpath(url, d):
105 for m in methods:
106 if m.supports(url, d):
107 return m.localpath(url, d)
108 return url
109
110class Fetch(object):
111 """Base class for 'fetch'ing data"""
112
113 def __init__(self, urls = []):
114 self.urls = []
115 for url in urls:
116 if self.supports(bb.decodeurl(url), d) is 1:
117 self.urls.append(url)
118
119 def supports(url, d):
120 """Check to see if this fetch class supports a given url.
121 Expects supplied url in list form, as outputted by bb.decodeurl().
122 """
123 return 0
124 supports = staticmethod(supports)
125
126 def localpath(url, d):
127 """Return the local filename of a given url assuming a successful fetch.
128 """
129 return url
130 localpath = staticmethod(localpath)
131
132 def setUrls(self, urls):
133 self.__urls = urls
134
135 def getUrls(self):
136 return self.__urls
137
138 urls = property(getUrls, setUrls, None, "Urls property")
139
140 def setData(self, data):
141 self.__data = data
142
143 def getData(self):
144 return self.__data
145
146 data = property(getData, setData, None, "Data property")
147
148 def go(self, urls = []):
149 """Fetch urls"""
150 raise NoMethodError("Missing implementation for url")
151
152class Wget(Fetch):
153 """Class to fetch urls via 'wget'"""
154 def supports(url, d):
155 """Check to see if a given url can be fetched using wget.
156 Expects supplied url in list form, as outputted by bb.decodeurl().
157 """
158 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
159 return type in ['http','https','ftp']
160 supports = staticmethod(supports)
161
162 def localpath(url, d):
163# strip off parameters
164 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
165 if "localpath" in parm:
166# if user overrides local path, use it.
167 return parm["localpath"]
168 url = bb.encodeurl([type, host, path, user, pswd, {}])
169
170 return os.path.join(data.getVar("DL_DIR", d), os.path.basename(url))
171 localpath = staticmethod(localpath)
172
173 def go(self, d, urls = []):
174 """Fetch urls"""
175
176 def md5_sum(basename, data):
177 """
178 Fast and incomplete OVERRIDE implementation for MD5SUM handling
179 MD5SUM_basename = "SUM" and fallback to MD5SUM_basename
180 """
181 var = "MD5SUM_%s" % basename
182 return getVar(var, data) or get("MD5SUM",data)
183
184
185 def fetch_uri(uri, basename, dl, md5, parm, d):
186 if os.path.exists(dl):
187# file exists, but we didnt complete it.. trying again..
188 fetchcmd = data.getVar("RESUMECOMMAND", d, 1)
189 else:
190 fetchcmd = data.getVar("FETCHCOMMAND", d, 1)
191
192 bb.note("fetch " + uri)
193 fetchcmd = fetchcmd.replace("${URI}", uri)
194 fetchcmd = fetchcmd.replace("${FILE}", basename)
195 bb.debug(2, "executing " + fetchcmd)
196 ret = os.system(fetchcmd)
197 if ret != 0:
198 return False
199
200 # check if sourceforge did send us to the mirror page
201 dl_dir = data.getVar("DL_DIR", d, True)
202 if not os.path.exists(dl):
203 os.system("rm %s*" % dl) # FIXME shell quote it
204 bb.debug(2,"sourceforge.net send us to the mirror on %s" % basename)
205 return False
206
207# supposedly complete.. write out md5sum
208 if bb.which(data.getVar('PATH', d), 'md5sum'):
209 try:
210 md5pipe = os.popen('md5sum ' + dl)
211 md5data = (md5pipe.readline().split() or [ "" ])[0]
212 md5pipe.close()
213 except OSError:
214 md5data = ""
215 md5out = file(md5, 'w')
216 md5out.write(md5data)
217 md5out.close()
218 else:
219 md5out = file(md5, 'w')
220 md5out.write("")
221 md5out.close()
222 return True
223
224 if not urls:
225 urls = self.urls
226
227 localdata = data.createCopy(d)
228 data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata)
229 data.update_data(localdata)
230
231 for uri in urls:
232 completed = 0
233 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(uri, localdata))
234 basename = os.path.basename(path)
235 dl = self.localpath(uri, d)
236 dl = data.expand(dl, localdata)
237 md5 = dl + '.md5'
238
239 if os.path.exists(md5):
240# complete, nothing to see here..
241 continue
242
243 premirrors = [ i.split() for i in (data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ]
244 for (find, replace) in premirrors:
245 newuri = uri_replace(uri, find, replace, d)
246 if newuri != uri:
247 if fetch_uri(newuri, basename, dl, md5, parm, localdata):
248 completed = 1
249 break
250
251 if completed:
252 continue
253
254 if fetch_uri(uri, basename, dl, md5, parm, localdata):
255 continue
256
257# try mirrors
258 mirrors = [ i.split() for i in (data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ]
259 for (find, replace) in mirrors:
260 newuri = uri_replace(uri, find, replace, d)
261 if newuri != uri:
262 if fetch_uri(newuri, basename, dl, md5, parm, localdata):
263 completed = 1
264 break
265
266 if not completed:
267 raise FetchError(uri)
268
269 del localdata
270
271
272methods.append(Wget())
273
274class Cvs(Fetch):
275 """Class to fetch a module or modules from cvs repositories"""
276 def supports(url, d):
277 """Check to see if a given url can be fetched with cvs.
278 Expects supplied url in list form, as outputted by bb.decodeurl().
279 """
280 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
281 return type in ['cvs', 'pserver']
282 supports = staticmethod(supports)
283
284 def localpath(url, d):
285 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
286 if "localpath" in parm:
287# if user overrides local path, use it.
288 return parm["localpath"]
289
290 if not "module" in parm:
291 raise MissingParameterError("cvs method needs a 'module' parameter")
292 else:
293 module = parm["module"]
294 if 'tag' in parm:
295 tag = parm['tag']
296 else:
297 tag = ""
298 if 'date' in parm:
299 date = parm['date']
300 else:
301 if not tag:
302 date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
303 else:
304 date = ""
305
306 return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d))
307 localpath = staticmethod(localpath)
308
309 def go(self, d, urls = []):
310 """Fetch urls"""
311 if not urls:
312 urls = self.urls
313
314 localdata = data.createCopy(d)
315 data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata)
316 data.update_data(localdata)
317
318 for loc in urls:
319 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
320 if not "module" in parm:
321 raise MissingParameterError("cvs method needs a 'module' parameter")
322 else:
323 module = parm["module"]
324
325 dlfile = self.localpath(loc, localdata)
326 dldir = data.getVar('DL_DIR', localdata, 1)
327# if local path contains the cvs
328# module, consider the dir above it to be the
329# download directory
330# pos = dlfile.find(module)
331# if pos:
332# dldir = dlfile[:pos]
333# else:
334# dldir = os.path.dirname(dlfile)
335
336# setup cvs options
337 options = []
338 if 'tag' in parm:
339 tag = parm['tag']
340 else:
341 tag = ""
342
343 if 'date' in parm:
344 date = parm['date']
345 else:
346 if not tag:
347 date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
348 else:
349 date = ""
350
351 if "method" in parm:
352 method = parm["method"]
353 else:
354 method = "pserver"
355
356 if "localdir" in parm:
357 localdir = parm["localdir"]
358 else:
359 localdir = module
360
361 cvs_rsh = None
362 if method == "ext":
363 if "rsh" in parm:
364 cvs_rsh = parm["rsh"]
365
366 tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata)
367 data.setVar('TARFILES', dlfile, localdata)
368 data.setVar('TARFN', tarfn, localdata)
369
370 dl = os.path.join(dldir, tarfn)
371 if os.access(dl, os.R_OK):
372 bb.debug(1, "%s already exists, skipping cvs checkout." % tarfn)
373 continue
374
375 pn = data.getVar('PN', d, 1)
376 cvs_tarball_stash = None
377 if pn:
378 cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH_%s' % pn, d, 1)
379 if cvs_tarball_stash == None:
380 cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
381 if cvs_tarball_stash:
382 fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
383 uri = cvs_tarball_stash + tarfn
384 bb.note("fetch " + uri)
385 fetchcmd = fetchcmd.replace("${URI}", uri)
386 ret = os.system(fetchcmd)
387 if ret == 0:
388 bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
389 continue
390
391 if date:
392 options.append("-D %s" % date)
393 if tag:
394 options.append("-r %s" % tag)
395
396 olddir = os.path.abspath(os.getcwd())
397 os.chdir(data.expand(dldir, localdata))
398
399# setup cvsroot
400 if method == "dir":
401 cvsroot = path
402 else:
403 cvsroot = ":" + method + ":" + user
404 if pswd:
405 cvsroot += ":" + pswd
406 cvsroot += "@" + host + ":" + path
407
408 data.setVar('CVSROOT', cvsroot, localdata)
409 data.setVar('CVSCOOPTS', " ".join(options), localdata)
410 data.setVar('CVSMODULE', module, localdata)
411 cvscmd = data.getVar('FETCHCOMMAND', localdata, 1)
412 cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, 1)
413
414 if cvs_rsh:
415 cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd)
416 cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
417
418# create module directory
419 bb.debug(2, "Fetch: checking for module directory")
420 pkg=data.expand('${PN}', d)
421 pkgdir=os.path.join(data.expand('${CVSDIR}', localdata), pkg)
422 moddir=os.path.join(pkgdir,localdir)
423 if os.access(os.path.join(moddir,'CVS'), os.R_OK):
424 bb.note("Update " + loc)
425# update sources there
426 os.chdir(moddir)
427 myret = os.system(cvsupdatecmd)
428 else:
429 bb.note("Fetch " + loc)
430# check out sources there
431 bb.mkdirhier(pkgdir)
432 os.chdir(pkgdir)
433 bb.debug(1, "Running %s" % cvscmd)
434 myret = os.system(cvscmd)
435
436 if myret != 0:
437 try:
438 os.rmdir(moddir)
439 except OSError:
440 pass
441 raise FetchError(module)
442
443 os.chdir(moddir)
444 os.chdir('..')
445# tar them up to a defined filename
446 myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(moddir)))
447 if myret != 0:
448 try:
449 os.unlink(tarfn)
450 except OSError:
451 pass
452 os.chdir(olddir)
453 del localdata
454
455methods.append(Cvs())
456
457class Bk(Fetch):
458 def supports(url, d):
459 """Check to see if a given url can be fetched via bitkeeper.
460 Expects supplied url in list form, as outputted by bb.decodeurl().
461 """
462 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
463 return type in ['bk']
464 supports = staticmethod(supports)
465
466methods.append(Bk())
467
468class Local(Fetch):
469 def supports(url, d):
470 """Check to see if a given url can be fetched in the local filesystem.
471 Expects supplied url in list form, as outputted by bb.decodeurl().
472 """
473 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
474 return type in ['file','patch']
475 supports = staticmethod(supports)
476
477 def localpath(url, d):
478 """Return the local filename of a given url assuming a successful fetch.
479 """
480 path = url.split("://")[1]
481 newpath = path
482 if path[0] != "/":
483 filespath = data.getVar('FILESPATH', d, 1)
484 if filespath:
485 newpath = bb.which(filespath, path)
486 if not newpath:
487 filesdir = data.getVar('FILESDIR', d, 1)
488 if filesdir:
489 newpath = os.path.join(filesdir, path)
490 return newpath
491 localpath = staticmethod(localpath)
492
493 def go(self, urls = []):
494 """Fetch urls (no-op for Local method)"""
495# no need to fetch local files, we'll deal with them in place.
496 return 1
497
498methods.append(Local())
499
500class Svn(Fetch):
501 """Class to fetch a module or modules from svn repositories"""
502 def supports(url, d):
503 """Check to see if a given url can be fetched with svn.
504 Expects supplied url in list form, as outputted by bb.decodeurl().
505 """
506 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
507 return type in ['svn']
508 supports = staticmethod(supports)
509
510 def localpath(url, d):
511 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
512 if "localpath" in parm:
513# if user overrides local path, use it.
514 return parm["localpath"]
515
516 if not "module" in parm:
517 raise MissingParameterError("svn method needs a 'module' parameter")
518 else:
519 module = parm["module"]
520 if 'rev' in parm:
521 revision = parm['rev']
522 else:
523 revision = ""
524
525 date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
526
527 return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, revision, date), d))
528 localpath = staticmethod(localpath)
529
530 def go(self, d, urls = []):
531 """Fetch urls"""
532 if not urls:
533 urls = self.urls
534
535 localdata = data.createCopy(d)
536 data.setVar('OVERRIDES', "svn:%s" % data.getVar('OVERRIDES', localdata), localdata)
537 data.update_data(localdata)
538
539 for loc in urls:
540 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
541 if not "module" in parm:
542 raise MissingParameterError("svn method needs a 'module' parameter")
543 else:
544 module = parm["module"]
545
546 dlfile = self.localpath(loc, localdata)
547 dldir = data.getVar('DL_DIR', localdata, 1)
548# if local path contains the svn
549# module, consider the dir above it to be the
550# download directory
551# pos = dlfile.find(module)
552# if pos:
553# dldir = dlfile[:pos]
554# else:
555# dldir = os.path.dirname(dlfile)
556
557# setup svn options
558 options = []
559 if 'rev' in parm:
560 revision = parm['rev']
561 else:
562 revision = ""
563
564 date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
565
566 if "method" in parm:
567 method = parm["method"]
568 else:
569 method = "pserver"
570
571 if "proto" in parm:
572 proto = parm["proto"]
573 else:
574 proto = "svn"
575
576 svn_rsh = None
577 if method == "ext":
578 if "rsh" in parm:
579 svn_rsh = parm["rsh"]
580
581 tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, revision, date), localdata)
582 data.setVar('TARFILES', dlfile, localdata)
583 data.setVar('TARFN', tarfn, localdata)
584
585 dl = os.path.join(dldir, tarfn)
586 if os.access(dl, os.R_OK):
587 bb.debug(1, "%s already exists, skipping svn checkout." % tarfn)
588 continue
589
590 svn_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
591 if svn_tarball_stash:
592 fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
593 uri = svn_tarball_stash + tarfn
594 bb.note("fetch " + uri)
595 fetchcmd = fetchcmd.replace("${URI}", uri)
596 ret = os.system(fetchcmd)
597 if ret == 0:
598 bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
599 continue
600
601 olddir = os.path.abspath(os.getcwd())
602 os.chdir(data.expand(dldir, localdata))
603
604# setup svnroot
605# svnroot = ":" + method + ":" + user
606# if pswd:
607# svnroot += ":" + pswd
608 svnroot = host + path
609
610 data.setVar('SVNROOT', svnroot, localdata)
611 data.setVar('SVNCOOPTS', " ".join(options), localdata)
612 data.setVar('SVNMODULE', module, localdata)
613 svncmd = data.getVar('FETCHCOMMAND', localdata, 1)
614 svncmd = "svn co %s://%s/%s" % (proto, svnroot, module)
615
616 if revision:
617 svncmd = "svn co -r %s %s://%s/%s" % (revision, proto, svnroot, module)
618 if svn_rsh:
619 svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
620
621# create temp directory
622 bb.debug(2, "Fetch: creating temporary directory")
623 bb.mkdirhier(data.expand('${WORKDIR}', localdata))
624 data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvn.XXXXXX', localdata), localdata)
625 tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
626 tmpfile = tmppipe.readline().strip()
627 if not tmpfile:
628 bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
629 raise FetchError(module)
630
631# check out sources there
632 os.chdir(tmpfile)
633 bb.note("Fetch " + loc)
634 bb.debug(1, "Running %s" % svncmd)
635 myret = os.system(svncmd)
636 if myret != 0:
637 try:
638 os.rmdir(tmpfile)
639 except OSError:
640 pass
641 raise FetchError(module)
642
643 os.chdir(os.path.join(tmpfile, os.path.dirname(module)))
644# tar them up to a defined filename
645 myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module)))
646 if myret != 0:
647 try:
648 os.unlink(tarfn)
649 except OSError:
650 pass
651# cleanup
652 os.system('rm -rf %s' % tmpfile)
653 os.chdir(olddir)
654 del localdata
655
656methods.append(Svn())
diff --git a/bitbake/lib/bb/fetch.pyc b/bitbake/lib/bb/fetch.pyc
new file mode 100644
index 0000000000..d2e33835b5
--- /dev/null
+++ b/bitbake/lib/bb/fetch.pyc
Binary files differ
diff --git a/bitbake/lib/bb/make.pyc b/bitbake/lib/bb/make.pyc
new file mode 100644
index 0000000000..f6fabc07a2
--- /dev/null
+++ b/bitbake/lib/bb/make.pyc
Binary files differ
diff --git a/bitbake/lib/bb/manifest.py b/bitbake/lib/bb/manifest.py
new file mode 100644
index 0000000000..30bb454724
--- /dev/null
+++ b/bitbake/lib/bb/manifest.py
@@ -0,0 +1,144 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# Copyright (C) 2003, 2004 Chris Larson
5#
6# This program is free software; you can redistribute it and/or modify it under
7# the terms of the GNU General Public License as published by the Free Software
8# Foundation; either version 2 of the License, or (at your option) any later
9# version.
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
19import os, sys
20import bb, bb.data
21
22def getfields(line):
23 fields = {}
24 fieldmap = ( "pkg", "src", "dest", "type", "mode", "uid", "gid", "major", "minor", "start", "inc", "count" )
25 for f in xrange(len(fieldmap)):
26 fields[fieldmap[f]] = None
27
28 if not line:
29 return None
30
31 splitline = line.split()
32 if not len(splitline):
33 return None
34
35 try:
36 for f in xrange(len(fieldmap)):
37 if splitline[f] == '-':
38 continue
39 fields[fieldmap[f]] = splitline[f]
40 except IndexError:
41 pass
42 return fields
43
44def parse (mfile, d):
45 manifest = []
46 while 1:
47 line = mfile.readline()
48 if not line:
49 break
50 if line.startswith("#"):
51 continue
52 fields = getfields(line)
53 if not fields:
54 continue
55 manifest.append(fields)
56 return manifest
57
58def emit (func, manifest, d):
59#str = "%s () {\n" % func
60 str = ""
61 for line in manifest:
62 emittedline = emit_line(func, line, d)
63 if not emittedline:
64 continue
65 str += emittedline + "\n"
66# str += "}\n"
67 return str
68
69def mangle (func, line, d):
70 import copy
71 newline = copy.copy(line)
72 src = bb.data.expand(newline["src"], d)
73
74 if src:
75 if not os.path.isabs(src):
76 src = "${WORKDIR}/" + src
77
78 dest = newline["dest"]
79 if not dest:
80 return
81
82 if dest.startswith("/"):
83 dest = dest[1:]
84
85 if func is "do_install":
86 dest = "${D}/" + dest
87
88 elif func is "do_populate":
89 dest = "${WORKDIR}/install/" + newline["pkg"] + "/" + dest
90
91 elif func is "do_stage":
92 varmap = {}
93 varmap["${bindir}"] = "${STAGING_DIR}/${HOST_SYS}/bin"
94 varmap["${libdir}"] = "${STAGING_DIR}/${HOST_SYS}/lib"
95 varmap["${includedir}"] = "${STAGING_DIR}/${HOST_SYS}/include"
96 varmap["${datadir}"] = "${STAGING_DATADIR}"
97
98 matched = 0
99 for key in varmap.keys():
100 if dest.startswith(key):
101 dest = varmap[key] + "/" + dest[len(key):]
102 matched = 1
103 if not matched:
104 newline = None
105 return
106 else:
107 newline = None
108 return
109
110 newline["src"] = src
111 newline["dest"] = dest
112 return newline
113
114def emit_line (func, line, d):
115 import copy
116 newline = copy.deepcopy(line)
117 newline = mangle(func, newline, d)
118 if not newline:
119 return None
120
121 str = ""
122 type = newline["type"]
123 mode = newline["mode"]
124 src = newline["src"]
125 dest = newline["dest"]
126 if type is "d":
127 str = "install -d "
128 if mode:
129 str += "-m %s " % mode
130 str += dest
131 elif type is "f":
132 if not src:
133 return None
134 if dest.endswith("/"):
135 str = "install -d "
136 str += dest + "\n"
137 str += "install "
138 else:
139 str = "install -D "
140 if mode:
141 str += "-m %s " % mode
142 str += src + " " + dest
143 del newline
144 return str
diff --git a/bitbake/lib/bb/manifest.pyc b/bitbake/lib/bb/manifest.pyc
new file mode 100644
index 0000000000..02fb18ae4a
--- /dev/null
+++ b/bitbake/lib/bb/manifest.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/BBHandler.pyc b/bitbake/lib/bb/parse/BBHandler.pyc
new file mode 100644
index 0000000000..047a6853a3
--- /dev/null
+++ b/bitbake/lib/bb/parse/BBHandler.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/ConfHandler.pyc b/bitbake/lib/bb/parse/ConfHandler.pyc
new file mode 100644
index 0000000000..620af52942
--- /dev/null
+++ b/bitbake/lib/bb/parse/ConfHandler.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/__init__.py b/bitbake/lib/bb/parse/__init__.py
new file mode 100644
index 0000000000..b8839c09fd
--- /dev/null
+++ b/bitbake/lib/bb/parse/__init__.py
@@ -0,0 +1,70 @@
1"""
2BitBake Parsers
3
4File parsers for the BitBake build tools.
5
6Copyright (C) 2003, 2004 Chris Larson
7Copyright (C) 2003, 2004 Phil Blundell
8
9This program is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free Software
11Foundation; either version 2 of the License, or (at your option) any later
12version.
13
14This program is distributed in the hope that it will be useful, but WITHOUT
15ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License along with
19this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20Place, Suite 330, Boston, MA 02111-1307 USA.
21
22Based on functions from the base bb module, Copyright 2003 Holger Schurig
23"""
24
25__all__ = [ 'ParseError', 'SkipPackage', 'cached_mtime', 'mark_dependency',
26 'supports', 'handle', 'init' ]
27handlers = []
28
29class ParseError(Exception):
30 """Exception raised when parsing fails"""
31
32class SkipPackage(Exception):
33 """Exception raised to skip this package"""
34
35__mtime_cache = {}
36def cached_mtime(f):
37 import os
38 if not __mtime_cache.has_key(f):
39 __mtime_cache[f] = os.stat(f)[8]
40 return __mtime_cache[f]
41
42def mark_dependency(d, f):
43 import bb, os
44 if f.startswith('./'):
45 f = "%s/%s" % (os.getcwd(), f[2:])
46 deps = (bb.data.getVar('__depends', d) or "").split()
47 deps.append("%s@%s" % (f, cached_mtime(f)))
48 bb.data.setVar('__depends', " ".join(deps), d)
49
50def supports(fn, data):
51 """Returns true if we have a handler for this file, false otherwise"""
52 for h in handlers:
53 if h['supports'](fn, data):
54 return 1
55 return 0
56
57def handle(fn, data, include = 0):
58 """Call the handler that is appropriate for this file"""
59 for h in handlers:
60 if h['supports'](fn, data):
61 return h['handle'](fn, data, include)
62 raise ParseError("%s is not a BitBake file" % fn)
63
64def init(fn, data):
65 for h in handlers:
66 if h['supports'](fn):
67 return h['init'](data)
68
69
70from parse_py import __version__, ConfHandler, BBHandler
diff --git a/bitbake/lib/bb/parse/__init__.pyc b/bitbake/lib/bb/parse/__init__.pyc
new file mode 100644
index 0000000000..a2c2d6ae54
--- /dev/null
+++ b/bitbake/lib/bb/parse/__init__.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/parse_c/bitbakeparser.l b/bitbake/lib/bb/parse/parse_c/bitbakeparser.l
new file mode 100644
index 0000000000..ee4ce14839
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_c/bitbakeparser.l
@@ -0,0 +1,288 @@
1/* bbf.flex
2
3 written by Marc Singer
4 6 January 2005
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20
21 DESCRIPTION
22 -----------
23
24 flex lexer specification for a BitBake input file parser.
25
26 Unfortunately, flex doesn't welcome comments within the rule sets.
27 I say unfortunately because this lexer is unreasonably complex and
28 comments would make the code much easier to comprehend.
29
30 The BitBake grammar is not regular. In order to interpret all
31 of the available input files, the lexer maintains much state as it
32 parses. There are places where this lexer will emit tokens that
33 are invalid. The parser will tend to catch these.
34
35 The lexer requires C++ at the moment. The only reason for this has
36 to do with a very small amount of managed state. Producing a C
37 lexer should be a reasonably easy task as long as the %reentrant
38 option is used.
39
40
41 NOTES
42 -----
43
44 o RVALUES. There are three kinds of RVALUES. There are unquoted
45 values, double quote enclosed strings, and single quote
46 strings. Quoted strings may contain unescaped quotes (of either
47 type), *and* any type may span more than one line by using a
48 continuation '\' at the end of the line. This requires us to
49 recognize all types of values with a single expression.
50 Moreover, the only reason to quote a value is to include
51 trailing or leading whitespace. Whitespace within a value is
52 preserved, ugh.
53
54 o CLASSES. C_ patterns define classes. Classes ought not include
55 a repitition operator, instead letting the reference to the class
56 define the repitition count.
57
58 C_SS - symbol start
59 C_SB - symbol body
60 C_SP - whitespace
61
62*/
63
64%option never-interactive
65%option yylineno
66%option noyywrap
67%option reentrant stack
68
69
70%{
71
72#include "token.h"
73#include "lexer.h"
74#include <ctype.h>
75
76extern void *bbparseAlloc(void *(*mallocProc)(size_t));
77extern void bbparseFree(void *p, void (*freeProc)(void*));
78extern void *bbparseAlloc(void *(*mallocProc)(size_t));
79extern void *bbparse(void*, int, token_t, lex_t*);
80extern void bbparseTrace(FILE *TraceFILE, char *zTracePrompt);
81
82//static const char* rgbInput;
83//static size_t cbInput;
84
85
86int lineError;
87int errorParse;
88
89enum {
90 errorNone = 0,
91 errorUnexpectedInput,
92 errorUnsupportedFeature,
93};
94
95#define YY_EXTRA_TYPE lex_t*
96
97 /* Read from buffer */
98#define YY_INPUT(buf,result,max_size) \
99 { yyextra->input(buf, &result, max_size); }
100
101//#define YY_DECL static size_t yylex ()
102
103#define ERROR(e) \
104 do { lineError = yylineno; errorParse = e; yyterminate (); } while (0)
105
106static const char* fixup_escapes (const char* sz);
107
108%}
109
110
111C_SP [ \t]
112COMMENT #.*\n
113OP_ASSIGN "="
114OP_IMMEDIATE ":="
115OP_PREPEND "=+"
116OP_APPEND "+="
117OP_COND "?="
118B_OPEN "{"
119B_CLOSE "}"
120
121K_ADDTASK "addtask"
122K_ADDHANDLER "addhandler"
123K_AFTER "after"
124K_BEFORE "before"
125K_DEF "def"
126K_INCLUDE "include"
127K_INHERIT "inherit"
128K_PYTHON "python"
129K_FAKEROOT "fakeroot"
130K_EXPORT "export"
131K_EXPORT_FUNC "EXPORT_FUNCTIONS"
132
133STRING \"([^\n\r]|"\\\n")*\"
134SSTRING \'([^\n\r]|"\\\n")*\'
135VALUE ([^'" \t\n])|([^'" \t\n]([^\n]|(\\\n))*[^'" \t\n])
136
137C_SS [a-zA-Z_]
138C_SB [a-zA-Z0-9_+-.]
139REF $\{{C_SS}{C_SB}*\}
140SYMBOL {C_SS}{C_SB}*
141VARIABLE $?{C_SS}({C_SB}*|{REF})*(\[[a-zA-Z0-9_]*\])?
142FILENAME ([a-zA-Z_./]|{REF})(([-+a-zA-Z0-9_./]*)|{REF})*
143
144PROC \({C_SP}*\)
145
146%s S_DEF
147%s S_DEF_ARGS
148%s S_DEF_BODY
149%s S_FUNC
150%s S_INCLUDE
151%s S_INHERIT
152%s S_PROC
153%s S_RVALUE
154%s S_TASK
155
156%%
157
158{OP_APPEND} { BEGIN S_RVALUE;
159 yyextra->accept (T_OP_APPEND); }
160{OP_PREPEND} { BEGIN S_RVALUE;
161 yyextra->accept (T_OP_PREPEND); }
162{OP_IMMEDIATE} { BEGIN S_RVALUE;
163 yyextra->accept (T_OP_IMMEDIATE); }
164{OP_ASSIGN} { BEGIN S_RVALUE;
165 yyextra->accept (T_OP_ASSIGN); }
166{OP_COND} { BEGIN S_RVALUE;
167 yyextra->accept (T_OP_COND); }
168
169<S_RVALUE>\\\n{C_SP}* { }
170<S_RVALUE>{STRING} { BEGIN INITIAL;
171 size_t cb = yyleng;
172 while (cb && isspace (yytext[cb - 1]))
173 --cb;
174 yytext[cb - 1] = 0;
175 yyextra->accept (T_STRING, yytext + 1); }
176<S_RVALUE>{SSTRING} { BEGIN INITIAL;
177 size_t cb = yyleng;
178 while (cb && isspace (yytext[cb - 1]))
179 --cb;
180 yytext[cb - 1] = 0;
181 yyextra->accept (T_STRING, yytext + 1); }
182
183<S_RVALUE>{VALUE} { ERROR (errorUnexpectedInput); }
184<S_RVALUE>{C_SP}*\n+ { BEGIN INITIAL;
185 yyextra->accept (T_STRING, NULL); }
186
187{K_INCLUDE} { BEGIN S_INCLUDE;
188 yyextra->accept (T_INCLUDE); }
189{K_INHERIT} { BEGIN S_INHERIT;
190 yyextra->accept (T_INHERIT); }
191{K_ADDTASK} { BEGIN S_TASK;
192 yyextra->accept (T_ADDTASK); }
193{K_ADDHANDLER} { yyextra->accept (T_ADDHANDLER); }
194{K_EXPORT_FUNC} { BEGIN S_FUNC;
195 yyextra->accept (T_EXPORT_FUNC); }
196<S_TASK>{K_BEFORE} { yyextra->accept (T_BEFORE); }
197<S_TASK>{K_AFTER} { yyextra->accept (T_AFTER); }
198<INITIAL>{K_EXPORT} { yyextra->accept (T_EXPORT); }
199
200<INITIAL>{K_FAKEROOT} { yyextra->accept (T_FAKEROOT); }
201<INITIAL>{K_PYTHON} { yyextra->accept (T_PYTHON); }
202{PROC}{C_SP}*{B_OPEN}{C_SP}*\n* { BEGIN S_PROC;
203 yyextra->accept (T_PROC_OPEN); }
204<S_PROC>{B_CLOSE}{C_SP}*\n* { BEGIN INITIAL;
205 yyextra->accept (T_PROC_CLOSE); }
206<S_PROC>([^}][^\n]*)?\n* { yyextra->accept (T_PROC_BODY, yytext); }
207
208{K_DEF} { BEGIN S_DEF; }
209<S_DEF>{SYMBOL} { BEGIN S_DEF_ARGS;
210 yyextra->accept (T_SYMBOL, yytext); }
211<S_DEF_ARGS>[^\n:]*: { yyextra->accept (T_DEF_ARGS, yytext); }
212<S_DEF_ARGS>{C_SP}*\n { BEGIN S_DEF_BODY; }
213<S_DEF_BODY>{C_SP}+[^\n]*\n { yyextra->accept (T_DEF_BODY, yytext); }
214<S_DEF_BODY>\n { yyextra->accept (T_DEF_BODY, yytext); }
215<S_DEF_BODY>. { BEGIN INITIAL; unput (yytext[0]); }
216
217{COMMENT} { }
218
219<INITIAL>{SYMBOL} { yyextra->accept (T_SYMBOL, yytext); }
220<INITIAL>{VARIABLE} { yyextra->accept (T_VARIABLE, yytext); }
221
222<S_TASK>{SYMBOL} { yyextra->accept (T_TSYMBOL, yytext); }
223<S_FUNC>{SYMBOL} { yyextra->accept (T_FSYMBOL, yytext); }
224<S_INHERIT>{SYMBOL} { yyextra->accept (T_ISYMBOL, yytext); }
225<S_INCLUDE>{FILENAME} { BEGIN INITIAL;
226 yyextra->accept (T_ISYMBOL, yytext); }
227
228<S_TASK>\n { BEGIN INITIAL; }
229<S_FUNC>\n { BEGIN INITIAL; }
230<S_INHERIT>\n { BEGIN INITIAL; }
231
232[ \t\r\n] /* Insignificant whitespace */
233
234. { ERROR (errorUnexpectedInput); }
235
236 /* Check for premature termination */
237<<EOF>> { return T_EOF; }
238
239%%
240
241void lex_t::accept (int token, const char* sz)
242{
243 token_t t;
244 memset (&t, 0, sizeof (t));
245 t.copyString(sz);
246
247 /* tell lemon to parse the token */
248 parse (parser, token, t, this);
249}
250
251int lex_t::line ()const
252{
253 return yyget_lineno (scanner);
254}
255
256const char* lex_t::filename ()const
257{
258 return m_fileName;
259}
260
261void parse (MappedFile* mf)
262{
263 void* parser = bbparseAlloc (malloc);
264 yyscan_t scanner;
265 lex_t lex;
266
267 yylex_init (&scanner);
268
269 lex.parser = parser;
270 lex.scanner = scanner;
271 lex.mf = mf;
272 lex.rgbInput = mf->m_rgb;
273 lex.cbInput = mf->m_cb;
274 lex.parse = bbparse;
275 yyset_extra (&lex, scanner);
276
277
278 int result = yylex (scanner);
279
280 lex.accept (0);
281 bbparseTrace (NULL, NULL);
282
283 if (result != T_EOF)
284 WARNING ("premature end of file\n");
285
286 yylex_destroy (scanner);
287 bbparseFree (parser, free);
288}
diff --git a/bitbake/lib/bb/parse/parse_c/bitbakeparser.py b/bitbake/lib/bb/parse/parse_c/bitbakeparser.py
new file mode 100644
index 0000000000..ed7b13eef9
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_c/bitbakeparser.py
@@ -0,0 +1,133 @@
1"""
2
3BitBake C Parser Python Code
4
5Copyright (C) 2005 Holger Hans Peter Freyther
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
20SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24"""
25
26__version__ = "0xdeadbeef"
27
28class CParser:
29 """
30 The C-based Parser for Bitbake
31 """
32 def __init__(self, data, type):
33 """
34 Constructor
35 """
36 self._data = data
37
38 def _syntax_error(self, file, line):
39 """
40 lemon/flex reports an syntax error to us and we will
41 raise an exception
42 """
43 pass
44
45 def _export(self, data):
46 """
47 EXPORT VAR = "MOO"
48 we will now export VAR
49 """
50 pass
51
52 def _assign(self, key, value):
53 """
54 VAR = "MOO"
55 we will assign moo to VAR
56 """
57 pass
58
59 def _assign(self, key, value):
60 """
61 """
62 pass
63
64 def _append(self, key, value):
65 """
66 VAR += "MOO"
67 we will append " MOO" to var
68 """
69 pass
70
71 def _prepend(self, key, value):
72 """
73 VAR =+ "MOO"
74 we will prepend "MOO " to var
75 """
76 pass
77
78 def _immediate(self, key, value):
79 """
80 VAR := "MOO ${CVSDATE}"
81 we will assign immediately and expand vars
82 """
83 pass
84
85 def _conditional(self, key, value):
86 """
87 """
88 pass
89
90 def _add_task(self, task, before = None, after = None):
91 """
92 """
93 pass
94
95 def _include(self, file):
96 """
97 """
98 pass
99
100 def _inherit(self, file):
101 """
102 """
103 pass
104
105 def _shell_procedure(self, name, body):
106 """
107 """
108 pass
109
110 def _python_procedure(self, name, body):
111 """
112 """
113 pass
114
115 def _fakeroot_procedure(self, name, body):
116 """
117 """
118 pass
119
120 def _def_procedure(self, a, b, c):
121 """
122 """
123 pass
124
125 def _export_func(self, name):
126 """
127 """
128 pass
129
130 def _add_handler(self, handler):
131 """
132 """
133 pass
diff --git a/bitbake/lib/bb/parse/parse_c/bitbakeparser.y b/bitbake/lib/bb/parse/parse_c/bitbakeparser.y
new file mode 100644
index 0000000000..4bc81a913a
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_c/bitbakeparser.y
@@ -0,0 +1,161 @@
1/* bbp.lemon
2
3 written by Marc Singer
4 6 January 2005
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20
21 DESCRIPTION
22 -----------
23
24 lemon parser specification file for a BitBake input file parser.
25
26 Most of the interesting shenanigans are done in the lexer. The
27 BitBake grammar is not regular. In order to emit tokens that
28 the parser can properly interpret in LALR fashion, the lexer
29 manages the interpretation state. This is why there are ISYMBOLs,
30 SYMBOLS, and TSYMBOLS.
31
32 This parser was developed by reading the limited available
33 documentation for BitBake and by analyzing the available BB files.
34 There is no assertion of correctness to be made about this parser.
35
36*/
37
38%token_type {token_t}
39%name bbparse
40%token_prefix T_
41%extra_argument {lex_t* lex}
42
43%include {
44#include "token.h"
45}
46
47
48%token_destructor { $$.release_this (); }
49
50%syntax_error { printf ("%s:%d: syntax error\n",
51 lex->filename (), lex->line ()); }
52
53program ::= statements.
54
55statements ::= statements statement.
56statements ::= .
57
58variable(r) ::= SYMBOL(s).
59 { r.assignString( s.string() );
60 s.assignString( 0 );
61 s.release_this(); }
62variable(r) ::= VARIABLE(v).
63 {
64 r.assignString( v.string() );
65 v.assignString( 0 );
66 v.release_this(); }
67
68statement ::= EXPORT variable(s) OP_ASSIGN STRING(v).
69 { e_assign( s.string(), v.string() );
70 e_export( s.string() );
71 s.release_this(); v.release_this(); }
72statement ::= EXPORT variable(s) OP_IMMEDIATE STRING(v).
73 { e_immediate (s.string(), v.string() );
74 e_export( s.string() );
75 s.release_this(); v.release_this(); }
76statement ::= EXPORT variable(s) OP_COND STRING(v).
77 { e_cond( s.string(), v.string() );
78 s.release_this(); v.release_this(); }
79
80statement ::= variable(s) OP_ASSIGN STRING(v).
81 { e_assign( s.string(), v.string() );
82 s.release_this(); v.release_this(); }
83statement ::= variable(s) OP_PREPEND STRING(v).
84 { e_prepend( s.string(), v.string() );
85 s.release_this(); v.release_this(); }
86statement ::= variable(s) OP_APPEND STRING(v).
87 { e_append( s.string() , v.string() );
88 s.release_this(); v.release_this(); }
89statement ::= variable(s) OP_IMMEDIATE STRING(v).
90 { e_immediate( s.string(), v.string() );
91 s.release_this(); v.release_this(); }
92statement ::= variable(s) OP_COND STRING(v).
93 { e_cond( s.string(), v.string() );
94 s.release_this(); v.release_this(); }
95
96task ::= TSYMBOL(t) BEFORE TSYMBOL(b) AFTER TSYMBOL(a).
97 { e_addtask( t.string(), b.string(), a.string() );
98 t.release_this(); b.release_this(); a.release_this(); }
99task ::= TSYMBOL(t) AFTER TSYMBOL(a) BEFORE TSYMBOL(b).
100 { e_addtask( t.string(), b.string(), a.string());
101 t.release_this(); a.release_this(); b.release_this(); }
102task ::= TSYMBOL(t).
103 { e_addtask( t.string(), NULL, NULL);
104 t.release_this();}
105task ::= TSYMBOL(t) BEFORE TSYMBOL(b).
106 { e_addtask( t.string(), b.string(), NULL);
107 t.release_this(); b.release_this(); }
108task ::= TSYMBOL(t) AFTER TSYMBOL(a).
109 { e_addtask( t.string(), NULL, a.string());
110 t.release_this(); a.release_this(); }
111tasks ::= tasks task.
112tasks ::= task.
113statement ::= ADDTASK tasks.
114
115statement ::= ADDHANDLER SYMBOL(s).
116 { e_addhandler( s.string()); s.release_this (); }
117
118func ::= FSYMBOL(f). { e_export_func(f.string()); f.release_this(); }
119funcs ::= funcs func.
120funcs ::= func.
121statement ::= EXPORT_FUNC funcs.
122
123inherit ::= ISYMBOL(i). { e_inherit(i.string() ); i.release_this (); }
124inherits ::= inherits inherit.
125inherits ::= inherit.
126statement ::= INHERIT inherits.
127
128statement ::= INCLUDE ISYMBOL(i).
129 { e_include(i.string() ); i.release_this(); }
130
131proc_body(r) ::= proc_body(l) PROC_BODY(b).
132 { /* concatenate body lines */
133 r.assignString( token_t::concatString(l.string(), b.string()) );
134 l.release_this ();
135 b.release_this ();
136 }
137proc_body(b) ::= . { b.assignString(0); }
138statement ::= variable(p) PROC_OPEN proc_body(b) PROC_CLOSE.
139 { e_proc( p.string(), b.string() );
140 p.release_this(); b.release_this(); }
141statement ::= PYTHON SYMBOL(p) PROC_OPEN proc_body(b) PROC_CLOSE.
142 { e_proc_python (p.string(), b.string() );
143 p.release_this(); b.release_this(); }
144statement ::= PYTHON PROC_OPEN proc_body(b) PROC_CLOSE.
145 { e_proc_python( NULL, b.string());
146 b.release_this (); }
147
148statement ::= FAKEROOT SYMBOL(p) PROC_OPEN proc_body(b) PROC_CLOSE.
149 { e_proc_fakeroot(p.string(), b.string() );
150 p.release_this (); b.release_this (); }
151
152def_body(r) ::= def_body(l) DEF_BODY(b).
153 { /* concatenate body lines */
154 r.assignString( token_t::concatString(l.string(), b.string());
155 l.release_this (); b.release_this ();
156 }
157def_body(b) ::= . { b.sz = 0; }
158statement ::= SYMBOL(p) DEF_ARGS(a) def_body(b).
159 { e_def( p.string(), a.string(), b.string());
160 p.release_this(); a.release_this(); b.release_this(); }
161
diff --git a/bitbake/lib/bb/parse/parse_c/lexer.h b/bitbake/lib/bb/parse/parse_c/lexer.h
new file mode 100644
index 0000000000..1edf72dcf5
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_c/lexer.h
@@ -0,0 +1,41 @@
1/*
2Copyright (C) 2005 Holger Hans Peter Freyther
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
20THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22*/
23
24#ifndef LEXER_H
25#define LEXER_H
26
27struct lex_t {
28 void *parser;
29 void *scanner;
30 void* (*parse)(void*, int, token_t, lex_t*);
31
32 void accept(int token, const char* string = 0);
33 void input(char *buf, int *result, int_max_size);
34 int line()const;
35 const char* filename()const;
36private:
37 const char* m_fileName;
38};
39
40
41#endif
diff --git a/bitbake/lib/bb/parse/parse_c/token.h b/bitbake/lib/bb/parse/parse_c/token.h
new file mode 100644
index 0000000000..2351fda6b5
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_c/token.h
@@ -0,0 +1,83 @@
1/*
2Copyright (C) 2005 Holger Hans Peter Freyther
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
20THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22*/
23
24#ifndef TOKEN_H
25#define TOKEN_H
26
27#define PURE_METHOD
28
29struct token_t {
30 const char* string()const PURE_METHOD;
31
32 static char* concatString(const char* l, const char* r);
33 void assignString(const char* str);
34 void copyString(const char* str);
35
36 void release_this();
37
38private:
39 char *m_string;
40 size_t m_stringLen;
41};
42
43inline const char* token_t::string()const
44{
45 return m_string;
46}
47
48/*
49 * append str to the current string
50 */
51inline char* token_t::concatString(const char* l, const char* r)
52{
53 size_t cb = (l ? strlen (l) : 0) + strlen (r) + 1;
54 r_sz = new char[cb];
55 *r_sz = 0;
56 if (l) strcat (r_sz, l);
57 strcat (r_sz, r);
58
59 return r_sz;
60}
61
62inline void token_t::assignString(const char* str)
63{
64 m_string = str;
65 m_stringLen = str ? strlen(str) : 0;
66}
67
68inline void token_t::copyString(const char* str)
69{
70 if( str ) {
71 m_stringLen = strlen(str);
72 m_string = new char[m_stringLen+1];
73 strcpy(m_string, str)
74 }
75}
76
77inline void token_t::release_this()
78{
79 delete m_string;
80 m_string = 0;
81}
82
83#endif
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.py b/bitbake/lib/bb/parse/parse_py/BBHandler.py
new file mode 100644
index 0000000000..fac3e85b36
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/BBHandler.py
@@ -0,0 +1,378 @@
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 .bb files
5
6 Reads a .bb 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
24import re, bb, os, sys
25import bb.fetch, bb.build
26from bb import debug, data, fetch, fatal
27
28from ConfHandler import include, localpath, obtain, init
29from bb.parse import ParseError
30
31__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
32__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
33__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
34__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
35__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
36__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
37__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
38__word__ = re.compile(r"\S+")
39
40__infunc__ = ""
41__inpython__ = False
42__body__ = []
43__bbpath_found__ = 0
44__classname__ = ""
45classes = [ None, ]
46
47def supports(fn, d):
48 localfn = localpath(fn, d)
49 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
50
51def inherit(files, d):
52 __inherit_cache = data.getVar('__inherit_cache', d) or ""
53 fn = ""
54 lineno = 0
55 for f in files:
56 file = data.expand(f, d)
57 if file[0] != "/" and file[-8:] != ".bbclass":
58 file = os.path.join('classes', '%s.bbclass' % file)
59
60 if not file in __inherit_cache.split():
61 debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
62 __inherit_cache += " %s" % file
63 include(fn, file, d)
64 data.setVar('__inherit_cache', __inherit_cache, d)
65
66
67def handle(fn, d, include = 0):
68 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
69 __body__ = []
70 __bbpath_found__ = 0
71 __infunc__ = ""
72 __classname__ = ""
73 __residue__ = []
74
75 if include == 0:
76 debug(2, "BB " + fn + ": handle(data)")
77 else:
78 debug(2, "BB " + fn + ": handle(data, include)")
79
80 (root, ext) = os.path.splitext(os.path.basename(fn))
81 init(d)
82
83 if ext == ".bbclass":
84 __classname__ = root
85 classes.append(__classname__)
86
87 if include != 0:
88 oldfile = data.getVar('FILE', d)
89 else:
90 oldfile = None
91
92 fn = obtain(fn, d)
93 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
94 if not os.path.isabs(fn):
95 f = None
96 for p in bbpath:
97 p = data.expand(p, d)
98 j = os.path.join(p, fn)
99 if os.access(j, os.R_OK):
100 abs_fn = j
101 f = open(j, 'r')
102 break
103 if f is None:
104 raise IOError("file not found")
105 else:
106 f = open(fn,'r')
107 abs_fn = fn
108
109 if ext != ".bbclass":
110 bbpath.insert(0, os.path.dirname(abs_fn))
111 data.setVar('BBPATH', ":".join(bbpath), d)
112
113 if include:
114 bb.parse.mark_dependency(d, abs_fn)
115
116 if ext != ".bbclass":
117 data.setVar('FILE', fn, d)
118 i = (data.getVar("INHERIT", d, 1) or "").split()
119 if not "base" in i and __classname__ != "base":
120 i[0:0] = ["base"]
121 inherit(i, d)
122
123 lineno = 0
124 while 1:
125 lineno = lineno + 1
126 s = f.readline()
127 if not s: break
128 s = s.rstrip()
129 feeder(lineno, s, fn, d)
130 if __inpython__:
131 # add a blank line to close out any python definition
132 feeder(lineno + 1, "", fn, d)
133 if ext == ".bbclass":
134 classes.remove(__classname__)
135 else:
136 if include == 0:
137 data.expandKeys(d)
138 data.update_data(d)
139 anonqueue = data.getVar("__anonqueue", d, 1) or []
140 for anon in anonqueue:
141 data.setVar("__anonfunc", anon["content"], d)
142 data.setVarFlags("__anonfunc", anon["flags"], d)
143 from bb import build
144 try:
145 t = data.getVar('T', d)
146 data.setVar('T', '${TMPDIR}/', d)
147 build.exec_func("__anonfunc", d)
148 data.delVar('T', d)
149 if t:
150 data.setVar('T', t, d)
151 except Exception, e:
152 bb.debug(1, "executing anonymous function: %s" % e)
153 raise
154 data.delVar("__anonqueue", d)
155 data.delVar("__anonfunc", d)
156 set_additional_vars(fn, d, include)
157 data.update_data(d)
158
159 for var in data.keys(d):
160 if data.getVarFlag(var, 'handler', d):
161 bb.event.register(data.getVar(var, d))
162 continue
163
164 if not data.getVarFlag(var, 'task', d):
165 continue
166
167 deps = data.getVarFlag(var, 'deps', d) or []
168 postdeps = data.getVarFlag(var, 'postdeps', d) or []
169 bb.build.add_task(var, deps, d)
170 for p in postdeps:
171 pdeps = data.getVarFlag(p, 'deps', d) or []
172 pdeps.append(var)
173 data.setVarFlag(p, 'deps', pdeps, d)
174 bb.build.add_task(p, pdeps, d)
175 bbpath.pop(0)
176 if oldfile:
177 bb.data.setVar("FILE", oldfile, d)
178 return d
179
180def feeder(lineno, s, fn, d):
181 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, __bbpath_found__, classes, bb, __residue__
182 if __infunc__:
183 if s == '}':
184 __body__.append('')
185 data.setVar(__infunc__, '\n'.join(__body__), d)
186 data.setVarFlag(__infunc__, "func", 1, d)
187 if __infunc__ == "__anonymous":
188 anonqueue = bb.data.getVar("__anonqueue", d) or []
189 anonitem = {}
190 anonitem["content"] = bb.data.getVar("__anonymous", d)
191 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
192 anonqueue.append(anonitem)
193 bb.data.setVar("__anonqueue", anonqueue, d)
194 bb.data.delVarFlags("__anonymous", d)
195 bb.data.delVar("__anonymous", d)
196 __infunc__ = ""
197 __body__ = []
198 else:
199 __body__.append(s)
200 return
201
202 if __inpython__:
203 m = __python_func_regexp__.match(s)
204 if m:
205 __body__.append(s)
206 return
207 else:
208 text = '\n'.join(__body__)
209 comp = compile(text, "<bb>", "exec")
210 exec comp in __builtins__
211 __body__ = []
212 __inpython__ = False
213 funcs = data.getVar('__functions__', d) or ""
214 data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
215# fall through
216
217 if s == '' or s[0] == '#': return # skip comments and empty lines
218
219 if s[-1] == '\\':
220 __residue__.append(s[:-1])
221 return
222
223 s = "".join(__residue__) + s
224 __residue__ = []
225
226 m = __func_start_regexp__.match(s)
227 if m:
228 __infunc__ = m.group("func") or "__anonymous"
229 key = __infunc__
230 if data.getVar(key, d):
231# clean up old version of this piece of metadata, as its
232# flags could cause problems
233 data.setVarFlag(key, 'python', None, d)
234 data.setVarFlag(key, 'fakeroot', None, d)
235 if m.group("py") is not None:
236 data.setVarFlag(key, "python", "1", d)
237 else:
238 data.delVarFlag(key, "python", d)
239 if m.group("fr") is not None:
240 data.setVarFlag(key, "fakeroot", "1", d)
241 else:
242 data.delVarFlag(key, "fakeroot", d)
243 return
244
245 m = __def_regexp__.match(s)
246 if m:
247 __body__.append(s)
248 __inpython__ = True
249 return
250
251 m = __export_func_regexp__.match(s)
252 if m:
253 fns = m.group(1)
254 n = __word__.findall(fns)
255 for f in n:
256 allvars = []
257 allvars.append(f)
258 allvars.append(classes[-1] + "_" + f)
259
260 vars = [[ allvars[0], allvars[1] ]]
261 if len(classes) > 1 and classes[-2] is not None:
262 allvars.append(classes[-2] + "_" + f)
263 vars = []
264 vars.append([allvars[2], allvars[1]])
265 vars.append([allvars[0], allvars[2]])
266
267 for (var, calledvar) in vars:
268 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
269 continue
270
271 if data.getVar(var, d):
272 data.setVarFlag(var, 'python', None, d)
273 data.setVarFlag(var, 'func', None, d)
274
275 for flag in [ "func", "python" ]:
276 if data.getVarFlag(calledvar, flag, d):
277 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
278 for flag in [ "dirs" ]:
279 if data.getVarFlag(var, flag, d):
280 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
281
282 if data.getVarFlag(calledvar, "python", d):
283 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
284 else:
285 data.setVar(var, "\t" + calledvar + "\n", d)
286 data.setVarFlag(var, 'export_func', '1', d)
287
288 return
289
290 m = __addtask_regexp__.match(s)
291 if m:
292 func = m.group("func")
293 before = m.group("before")
294 after = m.group("after")
295 if func is None:
296 return
297 var = "do_" + func
298
299 data.setVarFlag(var, "task", 1, d)
300
301 if after is not None:
302# set up deps for function
303 data.setVarFlag(var, "deps", after.split(), d)
304 if before is not None:
305# set up things that depend on this func
306 data.setVarFlag(var, "postdeps", before.split(), d)
307 return
308
309 m = __addhandler_regexp__.match(s)
310 if m:
311 fns = m.group(1)
312 hs = __word__.findall(fns)
313 for h in hs:
314 data.setVarFlag(h, "handler", 1, d)
315 return
316
317 m = __inherit_regexp__.match(s)
318 if m:
319
320 files = m.group(1)
321 n = __word__.findall(files)
322 inherit(n, d)
323 return
324
325 from bb.parse import ConfHandler
326 return ConfHandler.feeder(lineno, s, fn, d)
327
328__pkgsplit_cache__={}
329def vars_from_file(mypkg, d):
330 if not mypkg:
331 return (None, None, None)
332 if mypkg in __pkgsplit_cache__:
333 return __pkgsplit_cache__[mypkg]
334
335 myfile = os.path.splitext(os.path.basename(mypkg))
336 parts = myfile[0].split('_')
337 __pkgsplit_cache__[mypkg] = parts
338 exp = 3 - len(parts)
339 tmplist = []
340 while exp != 0:
341 exp -= 1
342 tmplist.append(None)
343 parts.extend(tmplist)
344 return parts
345
346def set_additional_vars(file, d, include):
347 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
348
349 debug(2,"BB %s: set_additional_vars" % file)
350
351 src_uri = data.getVar('SRC_URI', d)
352 if not src_uri:
353 return
354 src_uri = data.expand(src_uri, d)
355
356 a = data.getVar('A', d)
357 if a:
358 a = data.expand(a, d).split()
359 else:
360 a = []
361
362 from bb import fetch
363 try:
364 fetch.init(src_uri.split(), d)
365 except fetch.NoMethodError:
366 pass
367 except bb.MalformedUrl,e:
368 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
369
370 a += fetch.localpaths(d)
371 del fetch
372 data.setVar('A', " ".join(a), d)
373
374
375# Add us to the handlers list
376from bb.parse import handlers
377handlers.append({'supports': supports, 'handle': handle, 'init': init})
378del handlers
diff --git a/bitbake/lib/bb/parse/parse_py/BBHandler.pyc b/bitbake/lib/bb/parse/parse_py/BBHandler.pyc
new file mode 100644
index 0000000000..bfaa4c6004
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/BBHandler.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
new file mode 100644
index 0000000000..41ef96d557
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
@@ -0,0 +1,199 @@
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
24import re, bb.data, os, sys
25from bb import debug, fatal
26from bb.parse import ParseError
27
28#__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)$")
29__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>=\+)|(?P<predot>=\.)|(?P<postdot>\.=)|=)\s*(?P<apo>['\"]?)(?P<value>.*)(?P=apo)$")
30__include_regexp__ = re.compile( r"include\s+(.+)" )
31
32def init(data):
33 if not bb.data.getVar('TOPDIR', data):
34 bb.data.setVar('TOPDIR', os.getcwd(), data)
35 if not bb.data.getVar('BBPATH', data):
36 bb.data.setVar('BBPATH', os.path.join(sys.prefix, 'share', 'bitbake'), data)
37
38def supports(fn, d):
39 return localpath(fn, d)[-5:] == ".conf"
40
41def localpath(fn, d):
42 if os.path.exists(fn):
43 return fn
44
45 localfn = None
46 try:
47 localfn = bb.fetch.localpath(fn, d)
48 except bb.MalformedUrl:
49 pass
50
51 if not localfn:
52 localfn = fn
53 return localfn
54
55def obtain(fn, data = bb.data.init()):
56 import sys, bb
57 fn = bb.data.expand(fn, data)
58 localfn = bb.data.expand(localpath(fn, data), data)
59
60 if localfn != fn:
61 dldir = bb.data.getVar('DL_DIR', data, 1)
62 if not dldir:
63 debug(1, "obtain: DL_DIR not defined")
64 return localfn
65 bb.mkdirhier(dldir)
66 try:
67 bb.fetch.init([fn])
68 except bb.fetch.NoMethodError:
69 (type, value, traceback) = sys.exc_info()
70 debug(1, "obtain: no method: %s" % value)
71 return localfn
72
73 try:
74 bb.fetch.go(data)
75 except bb.fetch.MissingParameterError:
76 (type, value, traceback) = sys.exc_info()
77 debug(1, "obtain: missing parameters: %s" % value)
78 return localfn
79 except bb.fetch.FetchError:
80 (type, value, traceback) = sys.exc_info()
81 debug(1, "obtain: failed: %s" % value)
82 return localfn
83 return localfn
84
85
86def include(oldfn, fn, data = bb.data.init()):
87 if oldfn == fn: # prevent infinate recursion
88 return None
89
90 import bb
91 fn = bb.data.expand(fn, data)
92 oldfn = bb.data.expand(oldfn, data)
93
94 from bb.parse import handle
95 try:
96 ret = handle(fn, data, 1)
97 except IOError:
98 debug(2, "CONF file '%s' not found" % fn)
99
100def handle(fn, data = bb.data.init(), include = 0):
101 if include:
102 inc_string = "including"
103 else:
104 inc_string = "reading"
105 init(data)
106
107 if include == 0:
108 bb.data.inheritFromOS(data)
109 oldfile = None
110 else:
111 oldfile = bb.data.getVar('FILE', data)
112
113 fn = obtain(fn, data)
114 bbpath = []
115 if not os.path.isabs(fn):
116 f = None
117 vbbpath = bb.data.getVar("BBPATH", data)
118 if vbbpath:
119 bbpath += vbbpath.split(":")
120 for p in bbpath:
121 currname = os.path.join(bb.data.expand(p, data), fn)
122 if os.access(currname, os.R_OK):
123 f = open(currname, 'r')
124 abs_fn = currname
125 debug(1, "CONF %s %s" % (inc_string, currname))
126 break
127 if f is None:
128 raise IOError("file not found")
129 else:
130 f = open(fn,'r')
131 debug(1, "CONF %s %s" % (inc_string,fn))
132 abs_fn = fn
133
134 if include:
135 bb.parse.mark_dependency(data, abs_fn)
136
137 lineno = 0
138 bb.data.setVar('FILE', fn, data)
139 while 1:
140 lineno = lineno + 1
141 s = f.readline()
142 if not s: break
143 w = s.strip()
144 if not w: continue # skip empty lines
145 s = s.rstrip()
146 if s[0] == '#': continue # skip comments
147 while s[-1] == '\\':
148 s2 = f.readline()[:-1].strip()
149 lineno = lineno + 1
150 s = s[:-1] + s2
151 feeder(lineno, s, fn, data)
152
153 if oldfile:
154 bb.data.setVar('FILE', oldfile, data)
155 return data
156
157def feeder(lineno, s, fn, data = bb.data.init()):
158 m = __config_regexp__.match(s)
159 if m:
160 groupd = m.groupdict()
161 key = groupd["var"]
162 if "exp" in groupd and groupd["exp"] != None:
163 bb.data.setVarFlag(key, "export", 1, data)
164 if "ques" in groupd and groupd["ques"] != None:
165 val = bb.data.getVar(key, data)
166 if val == None:
167 val = groupd["value"]
168 elif "colon" in groupd and groupd["colon"] != None:
169 val = bb.data.expand(groupd["value"], data)
170 elif "append" in groupd and groupd["append"] != None:
171 val = "%s %s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
172 elif "prepend" in groupd and groupd["prepend"] != None:
173 val = "%s %s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
174 elif "postdot" in groupd and groupd["postdot"] != None:
175 val = "%s%s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
176 elif "predot" in groupd and groupd["predot"] != None:
177 val = "%s%s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
178 else:
179 val = groupd["value"]
180 if 'flag' in groupd and groupd['flag'] != None:
181# bb.note("setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
182 bb.data.setVarFlag(key, groupd['flag'], val, data)
183 else:
184 bb.data.setVar(key, val, data)
185 return
186
187 m = __include_regexp__.match(s)
188 if m:
189 s = bb.data.expand(m.group(1), data)
190# debug(2, "CONF %s:%d: including %s" % (fn, lineno, s))
191 include(fn, s, data)
192 return
193
194 raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
195
196# Add us to the handlers list
197from bb.parse import handlers
198handlers.append({'supports': supports, 'handle': handle, 'init': init})
199del handlers
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.pyc b/bitbake/lib/bb/parse/parse_py/ConfHandler.pyc
new file mode 100644
index 0000000000..e0ec666ed1
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.pyc
Binary files differ
diff --git a/bitbake/lib/bb/parse/parse_py/__init__.py b/bitbake/lib/bb/parse/parse_py/__init__.py
new file mode 100644
index 0000000000..6a2ce4059d
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/__init__.py
@@ -0,0 +1,32 @@
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"""
5BitBake Parsers
6
7File parsers for the BitBake build tools.
8
9Copyright (C) 2003, 2004 Chris Larson
10Copyright (C) 2003, 2004 Phil Blundell
11
12This program is free software; you can redistribute it and/or modify it under
13the terms of the GNU General Public License as published by the Free Software
14Foundation; either version 2 of the License, or (at your option) any later
15version.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23Place, Suite 330, Boston, MA 02111-1307 USA.
24
25Based on functions from the base bb module, Copyright 2003 Holger Schurig
26"""
27__version__ = '1.0'
28
29__all__ = [ 'ConfHandler', 'BBHandler']
30
31import ConfHandler
32import BBHandler
diff --git a/bitbake/lib/bb/parse/parse_py/__init__.pyc b/bitbake/lib/bb/parse/parse_py/__init__.pyc
new file mode 100644
index 0000000000..c081e02727
--- /dev/null
+++ b/bitbake/lib/bb/parse/parse_py/__init__.pyc
Binary files differ
diff --git a/bitbake/lib/bb/shell.py b/bitbake/lib/bb/shell.py
new file mode 100644
index 0000000000..97e61e1169
--- /dev/null
+++ b/bitbake/lib/bb/shell.py
@@ -0,0 +1,779 @@
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#
6# Copyright (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>, Vanille Media
7#
8# This program is free software; you can redistribute it and/or modify it under
9# the terms of the GNU General Public License as published by the Free Software
10# Foundation; version 2 of the License.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along with
17# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18# Place, Suite 330, Boston, MA 02111-1307 USA.
19#
20##########################################################################
21
22"""
23BitBake Shell
24
25IDEAS:
26 * list defined tasks per package
27 * list classes
28 * toggle force
29 * command to reparse just one (or more) bbfile(s)
30 * automatic check if reparsing is necessary (inotify?)
31 * frontend for bb file manipulation
32 * more shell-like features:
33 - output control, i.e. pipe output into grep, sort, etc.
34 - job control, i.e. bring running commands into background and foreground
35 * start parsing in background right after startup
36 * ncurses interface
37
38PROBLEMS:
39 * force doesn't always work
40 * readline completion for commands with more than one parameters
41
42"""
43
44##########################################################################
45# Import and setup global variables
46##########################################################################
47
48try:
49 set
50except NameError:
51 from sets import Set as set
52import sys, os, imp, readline, socket, httplib, urllib, commands, popen2, copy, shlex, Queue, fnmatch
53imp.load_source( "bitbake", os.path.dirname( sys.argv[0] )+"/bitbake" )
54from bb import data, parse, build, fatal
55
56__version__ = "0.5.2"
57__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
58Type 'help' for more information, press CTRL-D to exit.""" % __version__
59
60cmds = {}
61leave_mainloop = False
62last_exception = None
63cooker = None
64parsed = False
65initdata = None
66debug = os.environ.get( "BBSHELL_DEBUG", "" )
67
68##########################################################################
69# Class BitBakeShellCommands
70##########################################################################
71
72class BitBakeShellCommands:
73 """This class contains the valid commands for the shell"""
74
75 def __init__( self, shell ):
76 """Register all the commands"""
77 self._shell = shell
78 for attr in BitBakeShellCommands.__dict__:
79 if not attr.startswith( "_" ):
80 if attr.endswith( "_" ):
81 command = attr[:-1].lower()
82 else:
83 command = attr[:].lower()
84 method = getattr( BitBakeShellCommands, attr )
85 debugOut( "registering command '%s'" % command )
86 # scan number of arguments
87 usage = getattr( method, "usage", "" )
88 if usage != "<...>":
89 numArgs = len( usage.split() )
90 else:
91 numArgs = -1
92 shell.registerCommand( command, method, numArgs, "%s %s" % ( command, usage ), method.__doc__ )
93
94 def _checkParsed( self ):
95 if not parsed:
96 print "SHELL: This command needs to parse bbfiles..."
97 self.parse( None )
98
99 def _findProvider( self, item ):
100 self._checkParsed()
101 preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
102 if not preferred: preferred = item
103 try:
104 lv, lf, pv, pf = cooker.findBestProvider( preferred )
105 except KeyError:
106 if item in cooker.status.providers:
107 pf = cooker.status.providers[item][0]
108 else:
109 pf = None
110 return pf
111
112 def alias( self, params ):
113 """Register a new name for a command"""
114 new, old = params
115 if not old in cmds:
116 print "ERROR: Command '%s' not known" % old
117 else:
118 cmds[new] = cmds[old]
119 print "OK"
120 alias.usage = "<alias> <command>"
121
122 def buffer( self, params ):
123 """Dump specified output buffer"""
124 index = params[0]
125 print self._shell.myout.buffer( int( index ) )
126 buffer.usage = "<index>"
127
128 def buffers( self, params ):
129 """Show the available output buffers"""
130 commands = self._shell.myout.bufferedCommands()
131 if not commands:
132 print "SHELL: No buffered commands available yet. Start doing something."
133 else:
134 print "="*35, "Available Output Buffers", "="*27
135 for index, cmd in enumerate( commands ):
136 print "| %s %s" % ( str( index ).ljust( 3 ), cmd )
137 print "="*88
138
139 def build( self, params, cmd = "build" ):
140 """Build a providee"""
141 globexpr = params[0]
142 self._checkParsed()
143 names = globfilter( cooker.status.pkg_pn.keys(), globexpr )
144 if len( names ) == 0: names = [ globexpr ]
145 print "SHELL: Building %s" % ' '.join( names )
146
147 oldcmd = cooker.configuration.cmd
148 cooker.configuration.cmd = cmd
149 cooker.build_cache = []
150 cooker.build_cache_fail = []
151
152 for name in names:
153 try:
154 cooker.buildProvider( name )
155 except build.EventException, e:
156 print "ERROR: Couldn't build '%s'" % name
157 global last_exception
158 last_exception = e
159 break
160
161 cooker.configuration.cmd = oldcmd
162
163 build.usage = "<providee>"
164
165 def clean( self, params ):
166 """Clean a providee"""
167 self.build( params, "clean" )
168 clean.usage = "<providee>"
169
170 def compile( self, params ):
171 """Execute 'compile' on a providee"""
172 self.build( params, "compile" )
173 compile.usage = "<providee>"
174
175 def configure( self, params ):
176 """Execute 'configure' on a providee"""
177 self.build( params, "configure" )
178 configure.usage = "<providee>"
179
180 def edit( self, params ):
181 """Call $EDITOR on a providee"""
182 name = params[0]
183 bbfile = self._findProvider( name )
184 if bbfile is not None:
185 os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
186 else:
187 print "ERROR: Nothing provides '%s'" % name
188 edit.usage = "<providee>"
189
190 def environment( self, params ):
191 """Dump out the outer BitBake environment (see bbread)"""
192 data.emit_env(sys.__stdout__, cooker.configuration.data, True)
193
194 def exit_( self, params ):
195 """Leave the BitBake Shell"""
196 debugOut( "setting leave_mainloop to true" )
197 global leave_mainloop
198 leave_mainloop = True
199
200 def fetch( self, params ):
201 """Fetch a providee"""
202 self.build( params, "fetch" )
203 fetch.usage = "<providee>"
204
205 def fileBuild( self, params, cmd = "build" ):
206 """Parse and build a .bb file"""
207 name = params[0]
208 bf = completeFilePath( name )
209 print "SHELL: Calling '%s' on '%s'" % ( cmd, bf )
210
211 oldcmd = cooker.configuration.cmd
212 cooker.configuration.cmd = cmd
213 cooker.build_cache = []
214 cooker.build_cache_fail = []
215
216 thisdata = copy.deepcopy( initdata )
217 # Caution: parse.handle modifies thisdata, hence it would
218 # lead to pollution cooker.configuration.data, which is
219 # why we use it on a safe copy we obtained from cooker right after
220 # parsing the initial *.conf files
221 try:
222 bbfile_data = parse.handle( bf, thisdata )
223 except parse.ParseError:
224 print "ERROR: Unable to open or parse '%s'" % bf
225 else:
226 item = data.getVar('PN', bbfile_data, 1)
227 data.setVar( "_task_cache", [], bbfile_data ) # force
228 try:
229 cooker.tryBuildPackage( os.path.abspath( bf ), item, bbfile_data )
230 except build.EventException, e:
231 print "ERROR: Couldn't build '%s'" % name
232 global last_exception
233 last_exception = e
234
235 cooker.configuration.cmd = oldcmd
236 fileBuild.usage = "<bbfile>"
237
238 def fileClean( self, params ):
239 """Clean a .bb file"""
240 self.fileBuild( params, "clean" )
241 fileClean.usage = "<bbfile>"
242
243 def fileEdit( self, params ):
244 """Call $EDITOR on a .bb file"""
245 name = params[0]
246 os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), completeFilePath( name ) ) )
247 fileEdit.usage = "<bbfile>"
248
249 def fileRebuild( self, params ):
250 """Rebuild (clean & build) a .bb file"""
251 self.fileClean( params )
252 self.fileBuild( params )
253 fileRebuild.usage = "<bbfile>"
254
255 def force( self, params ):
256 """Toggle force task execution flag (see bitbake -f)"""
257 cooker.configuration.force = not cooker.configuration.force
258 print "SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force )
259
260 def help( self, params ):
261 """Show a comprehensive list of commands and their purpose"""
262 print "="*30, "Available Commands", "="*30
263 allcmds = cmds.keys()
264 allcmds.sort()
265 for cmd in allcmds:
266 function,numparams,usage,helptext = cmds[cmd]
267 print "| %s | %s" % (usage.ljust(30), helptext)
268 print "="*78
269
270 def lastError( self, params ):
271 """Show the reason or log that was produced by the last BitBake event exception"""
272 if last_exception is None:
273 print "SHELL: No Errors yet (Phew)..."
274 else:
275 reason, event = last_exception.args
276 print "SHELL: Reason for the last error: '%s'" % reason
277 if ':' in reason:
278 msg, filename = reason.split( ':' )
279 filename = filename.strip()
280 print "SHELL: Dumping log file for last error:"
281 try:
282 print open( filename ).read()
283 except IOError:
284 print "ERROR: Couldn't open '%s'" % filename
285
286 def match( self, params ):
287 """Dump all files or providers matching a glob expression"""
288 what, globexpr = params
289 if what == "files":
290 self._checkParsed()
291 for key in globfilter( cooker.pkgdata.keys(), globexpr ): print key
292 elif what == "providers":
293 self._checkParsed()
294 for key in globfilter( cooker.status.pkg_pn.keys(), globexpr ): print key
295 else:
296 print "Usage: match %s" % self.print_.usage
297 match.usage = "<files|providers> <glob>"
298
299 def new( self, params ):
300 """Create a new .bb file and open the editor"""
301 dirname, filename = params
302 packages = '/'.join( data.getVar( "BBFILES", cooker.configuration.data, 1 ).split('/')[:-2] )
303 fulldirname = "%s/%s" % ( packages, dirname )
304
305 if not os.path.exists( fulldirname ):
306 print "SHELL: Creating '%s'" % fulldirname
307 os.mkdir( fulldirname )
308 if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
309 if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
310 print "SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename )
311 return False
312 print "SHELL: Creating '%s/%s'" % ( fulldirname, filename )
313 newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
314 print >>newpackage,"""DESCRIPTION = ""
315SECTION = ""
316AUTHOR = ""
317HOMEPAGE = ""
318MAINTAINER = ""
319LICENSE = "GPL"
320PR = "r0"
321
322SRC_URI = ""
323
324#inherit base
325
326#do_configure() {
327#
328#}
329
330#do_compile() {
331#
332#}
333
334#do_stage() {
335#
336#}
337
338#do_install() {
339#
340#}
341"""
342 newpackage.close()
343 os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
344 new.usage = "<directory> <filename>"
345
346 def pasteBin( self, params ):
347 """Send a command + output buffer to http://pastebin.com"""
348 index = params[0]
349 contents = self._shell.myout.buffer( int( index ) )
350 status, error, location = sendToPastebin( contents )
351 if status == 302:
352 print "SHELL: Pasted to %s" % location
353 else:
354 print "ERROR: %s %s" % ( status, error )
355 pasteBin.usage = "<index>"
356
357 def pasteLog( self, params ):
358 """Send the last event exception error log (if there is one) to http://pastebin.com"""
359 if last_exception is None:
360 print "SHELL: No Errors yet (Phew)..."
361 else:
362 reason, event = last_exception.args
363 print "SHELL: Reason for the last error: '%s'" % reason
364 if ':' in reason:
365 msg, filename = reason.split( ':' )
366 filename = filename.strip()
367 print "SHELL: Pasting log file to pastebin..."
368
369 status, error, location = sendToPastebin( open( filename ).read() )
370
371 if status == 302:
372 print "SHELL: Pasted to %s" % location
373 else:
374 print "ERROR: %s %s" % ( status, error )
375
376 def patch( self, params ):
377 """Execute 'patch' command on a providee"""
378 self.build( params, "patch" )
379 patch.usage = "<providee>"
380
381 def parse( self, params ):
382 """(Re-)parse .bb files and calculate the dependency graph"""
383 cooker.status = cooker.ParsingStatus()
384 ignore = data.getVar("ASSUME_PROVIDED", cooker.configuration.data, 1) or ""
385 cooker.status.ignored_dependencies = set( ignore.split() )
386 cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", cooker.configuration.data, 1) )
387
388 cooker.collect_bbfiles( cooker.myProgressCallback )
389 cooker.buildDepgraph()
390 global parsed
391 parsed = True
392 print
393
394 def getvar( self, params ):
395 """Dump the contents of an outer BitBake environment variable"""
396 var = params[0]
397 value = data.getVar( var, cooker.configuration.data, 1 )
398 print value
399 getvar.usage = "<variable>"
400
401 def peek( self, params ):
402 """Dump contents of variable defined in providee's metadata"""
403 name, var = params
404 bbfile = self._findProvider( name )
405 if bbfile is not None:
406 value = cooker.pkgdata[bbfile].getVar( var, 1 )
407 print value
408 else:
409 print "ERROR: Nothing provides '%s'" % name
410 peek.usage = "<providee> <variable>"
411
412 def poke( self, params ):
413 """Set contents of variable defined in providee's metadata"""
414 name, var, value = params
415 bbfile = self._findProvider( name )
416 d = cooker.pkgdata[bbfile]
417 if bbfile is not None:
418 data.setVar( var, value, d )
419
420 # mark the change semi persistant
421 cooker.pkgdata.setDirty(bbfile, d)
422 print "OK"
423 else:
424 print "ERROR: Nothing provides '%s'" % name
425 poke.usage = "<providee> <variable> <value>"
426
427 def print_( self, params ):
428 """Dump all files or providers"""
429 what = params[0]
430 if what == "files":
431 self._checkParsed()
432 for key in cooker.pkgdata.keys(): print key
433 elif what == "providers":
434 self._checkParsed()
435 for key in cooker.status.providers.keys(): print key
436 else:
437 print "Usage: print %s" % self.print_.usage
438 print_.usage = "<files|providers>"
439
440 def python( self, params ):
441 """Enter the expert mode - an interactive BitBake Python Interpreter"""
442 sys.ps1 = "EXPERT BB>>> "
443 sys.ps2 = "EXPERT BB... "
444 import code
445 interpreter = code.InteractiveConsole( dict( globals() ) )
446 interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version )
447
448 def showdata( self, params ):
449 """Execute 'showdata' on a providee"""
450 self.build( params, "showdata" )
451 showdata.usage = "<providee>"
452
453 def setVar( self, params ):
454 """Set an outer BitBake environment variable"""
455 var, value = params
456 data.setVar( var, value, cooker.configuration.data )
457 print "OK"
458 setVar.usage = "<variable> <value>"
459
460 def rebuild( self, params ):
461 """Clean and rebuild a .bb file or a providee"""
462 self.build( params, "clean" )
463 self.build( params, "build" )
464 rebuild.usage = "<providee>"
465
466 def shell( self, params ):
467 """Execute a shell command and dump the output"""
468 if params != "":
469 print commands.getoutput( " ".join( params ) )
470 shell.usage = "<...>"
471
472 def stage( self, params ):
473 """Execute 'stage' on a providee"""
474 self.build( params, "stage" )
475 stage.usage = "<providee>"
476
477 def status( self, params ):
478 """<just for testing>"""
479 print "-" * 78
480 print "build cache = '%s'" % cooker.build_cache
481 print "build cache fail = '%s'" % cooker.build_cache_fail
482 print "building list = '%s'" % cooker.building_list
483 print "build path = '%s'" % cooker.build_path
484 print "consider_msgs_cache = '%s'" % cooker.consider_msgs_cache
485 print "build stats = '%s'" % cooker.stats
486 if last_exception is not None: print "last_exception = '%s'" % repr( last_exception.args )
487 print "memory output contents = '%s'" % self._shell.myout._buffer
488
489 def test( self, params ):
490 """<just for testing>"""
491 print "testCommand called with '%s'" % params
492
493 def unpack( self, params ):
494 """Execute 'unpack' on a providee"""
495 self.build( params, "unpack" )
496 unpack.usage = "<providee>"
497
498 def which( self, params ):
499 """Computes the providers for a given providee"""
500 item = params[0]
501
502 self._checkParsed()
503
504 preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
505 if not preferred: preferred = item
506
507 try:
508 lv, lf, pv, pf = cooker.findBestProvider( preferred )
509 except KeyError:
510 lv, lf, pv, pf = (None,)*4
511
512 try:
513 providers = cooker.status.providers[item]
514 except KeyError:
515 print "SHELL: ERROR: Nothing provides", preferred
516 else:
517 for provider in providers:
518 if provider == pf: provider = " (***) %s" % provider
519 else: provider = " %s" % provider
520 print provider
521 which.usage = "<providee>"
522
523##########################################################################
524# Common helper functions
525##########################################################################
526
527def completeFilePath( bbfile ):
528 """Get the complete bbfile path"""
529 if not cooker.pkgdata: return bbfile
530 for key in cooker.pkgdata.keys():
531 if key.endswith( bbfile ):
532 return key
533 return bbfile
534
535def sendToPastebin( content ):
536 """Send content to http://www.pastebin.com"""
537 mydata = {}
538 mydata["parent_pid"] = ""
539 mydata["format"] = "bash"
540 mydata["code2"] = content
541 mydata["paste"] = "Send"
542 mydata["poster"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
543 params = urllib.urlencode( mydata )
544 headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
545
546 conn = httplib.HTTPConnection( "pastebin.com:80" )
547 conn.request("POST", "/", params, headers )
548
549 response = conn.getresponse()
550 conn.close()
551
552 return response.status, response.reason, response.getheader( "location" ) or "unknown"
553
554def completer( text, state ):
555 """Return a possible readline completion"""
556 debugOut( "completer called with text='%s', state='%d'" % ( text, state ) )
557
558 if state == 0:
559 line = readline.get_line_buffer()
560 if " " in line:
561 line = line.split()
562 # we are in second (or more) argument
563 if line[0] in cmds and hasattr( cmds[line[0]][0], "usage" ): # known command and usage
564 u = getattr( cmds[line[0]][0], "usage" ).split()[0]
565 if u == "<variable>":
566 allmatches = cooker.configuration.data.keys()
567 elif u == "<bbfile>":
568 if cooker.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
569 else: allmatches = [ x.split("/")[-1] for x in cooker.pkgdata.keys() ]
570 elif u == "<providee>":
571 if cooker.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
572 else: allmatches = cooker.status.providers.iterkeys()
573 else: allmatches = [ "(No tab completion available for this command)" ]
574 else: allmatches = [ "(No tab completion available for this command)" ]
575 else:
576 # we are in first argument
577 allmatches = cmds.iterkeys()
578
579 completer.matches = [ x for x in allmatches if x[:len(text)] == text ]
580 #print "completer.matches = '%s'" % completer.matches
581 if len( completer.matches ) > state:
582 return completer.matches[state]
583 else:
584 return None
585
586def debugOut( text ):
587 if debug:
588 sys.stderr.write( "( %s )\n" % text )
589
590def columnize( alist, width = 80 ):
591 """
592 A word-wrap function that preserves existing line breaks
593 and most spaces in the text. Expects that existing line
594 breaks are posix newlines (\n).
595 """
596 return reduce(lambda line, word, width=width: '%s%s%s' %
597 (line,
598 ' \n'[(len(line[line.rfind('\n')+1:])
599 + len(word.split('\n',1)[0]
600 ) >= width)],
601 word),
602 alist
603 )
604
605def globfilter( names, pattern ):
606 return fnmatch.filter( names, pattern )
607
608##########################################################################
609# Class MemoryOutput
610##########################################################################
611
612class MemoryOutput:
613 """File-like output class buffering the output of the last 10 commands"""
614 def __init__( self, delegate ):
615 self.delegate = delegate
616 self._buffer = []
617 self.text = []
618 self._command = None
619
620 def startCommand( self, command ):
621 self._command = command
622 self.text = []
623 def endCommand( self ):
624 if self._command is not None:
625 if len( self._buffer ) == 10: del self._buffer[0]
626 self._buffer.append( ( self._command, self.text ) )
627 def removeLast( self ):
628 if self._buffer:
629 del self._buffer[ len( self._buffer ) - 1 ]
630 self.text = []
631 self._command = None
632 def lastBuffer( self ):
633 if self._buffer:
634 return self._buffer[ len( self._buffer ) -1 ][1]
635 def bufferedCommands( self ):
636 return [ cmd for cmd, output in self._buffer ]
637 def buffer( self, i ):
638 if i < len( self._buffer ):
639 return "BB>> %s\n%s" % ( self._buffer[i][0], "".join( self._buffer[i][1] ) )
640 else: return "ERROR: Invalid buffer number. Buffer needs to be in (0, %d)" % ( len( self._buffer ) - 1 )
641 def write( self, text ):
642 if self._command is not None and text != "BB>> ": self.text.append( text )
643 if self.delegate is not None: self.delegate.write( text )
644 def flush( self ):
645 return self.delegate.flush()
646 def fileno( self ):
647 return self.delegate.fileno()
648 def isatty( self ):
649 return self.delegate.isatty()
650
651##########################################################################
652# Class BitBakeShell
653##########################################################################
654
655class BitBakeShell:
656
657 def __init__( self ):
658 """Register commands and set up readline"""
659 self.commandQ = Queue.Queue()
660 self.commands = BitBakeShellCommands( self )
661 self.myout = MemoryOutput( sys.stdout )
662 self.historyfilename = os.path.expanduser( "~/.bbsh_history" )
663 self.startupfilename = os.path.expanduser( "~/.bbsh_startup" )
664
665 readline.set_completer( completer )
666 readline.set_completer_delims( " " )
667 readline.parse_and_bind("tab: complete")
668
669 try:
670 readline.read_history_file( self.historyfilename )
671 except IOError:
672 pass # It doesn't exist yet.
673
674 print __credits__
675
676 # save initial cooker configuration (will be reused in file*** commands)
677 global initdata
678 initdata = copy.deepcopy( cooker.configuration.data )
679
680 def cleanup( self ):
681 """Write readline history and clean up resources"""
682 debugOut( "writing command history" )
683 try:
684 readline.write_history_file( self.historyfilename )
685 except:
686 print "SHELL: Unable to save command history"
687
688 def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
689 """Register a command"""
690 if usage == "": usage = command
691 if helptext == "": helptext = function.__doc__ or "<not yet documented>"
692 cmds[command] = ( function, numparams, usage, helptext )
693
694 def processCommand( self, command, params ):
695 """Process a command. Check number of params and print a usage string, if appropriate"""
696 debugOut( "processing command '%s'..." % command )
697 try:
698 function, numparams, usage, helptext = cmds[command]
699 except KeyError:
700 print "SHELL: ERROR: '%s' command is not a valid command." % command
701 self.myout.removeLast()
702 else:
703 if (numparams != -1) and (not len( params ) == numparams):
704 print "Usage: '%s'" % usage
705 return
706
707 result = function( self.commands, params )
708 debugOut( "result was '%s'" % result )
709
710 def processStartupFile( self ):
711 """Read and execute all commands found in $HOME/.bbsh_startup"""
712 if os.path.exists( self.startupfilename ):
713 startupfile = open( self.startupfilename, "r" )
714 for cmdline in startupfile:
715 debugOut( "processing startup line '%s'" % cmdline )
716 if not cmdline:
717 continue
718 if "|" in cmdline:
719 print "ERROR: '|' in startup file is not allowed. Ignoring line"
720 continue
721 self.commandQ.put( cmdline.strip() )
722
723 def main( self ):
724 """The main command loop"""
725 while not leave_mainloop:
726 try:
727 if self.commandQ.empty():
728 sys.stdout = self.myout.delegate
729 cmdline = raw_input( "BB>> " )
730 sys.stdout = self.myout
731 else:
732 cmdline = self.commandQ.get()
733 if cmdline:
734 allCommands = cmdline.split( ';' )
735 for command in allCommands:
736 pipecmd = None
737 #
738 # special case for expert mode
739 if command == 'python':
740 sys.stdout = self.myout.delegate
741 self.processCommand( command, "" )
742 sys.stdout = self.myout
743 else:
744 self.myout.startCommand( command )
745 if '|' in command: # disable output
746 command, pipecmd = command.split( '|' )
747 delegate = self.myout.delegate
748 self.myout.delegate = None
749 tokens = shlex.split( command, True )
750 self.processCommand( tokens[0], tokens[1:] or "" )
751 self.myout.endCommand()
752 if pipecmd is not None: # restore output
753 self.myout.delegate = delegate
754
755 pipe = popen2.Popen4( pipecmd )
756 pipe.tochild.write( "\n".join( self.myout.lastBuffer() ) )
757 pipe.tochild.close()
758 sys.stdout.write( pipe.fromchild.read() )
759 #
760 except EOFError:
761 print
762 return
763 except KeyboardInterrupt:
764 print
765
766##########################################################################
767# Start function - called from the BitBake command line utility
768##########################################################################
769
770def start( aCooker ):
771 global cooker
772 cooker = aCooker
773 bbshell = BitBakeShell()
774 bbshell.processStartupFile()
775 bbshell.main()
776 bbshell.cleanup()
777
778if __name__ == "__main__":
779 print "SHELL: Sorry, this program should only be called by BitBake."
diff --git a/bitbake/lib/bb/shell.pyc b/bitbake/lib/bb/shell.pyc
new file mode 100644
index 0000000000..7f9d267504
--- /dev/null
+++ b/bitbake/lib/bb/shell.pyc
Binary files differ
diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py
new file mode 100644
index 0000000000..ee8713a2d0
--- /dev/null
+++ b/bitbake/lib/bb/utils.py
@@ -0,0 +1,71 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake Utility Functions
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; either version 2 of the License, or (at your option) any later
9version.
10
11This program is distributed in the hope that it will be useful, but WITHOUT
12ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17Place, Suite 330, Boston, MA 02111-1307 USA.
18
19This file is part of the BitBake build tools.
20"""
21
22digits = "0123456789"
23ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
24
25import re
26
27def explode_version(s):
28 r = []
29 alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
30 numeric_regexp = re.compile('^(\d+)(.*)$')
31 while (s != ''):
32 if s[0] in digits:
33 m = numeric_regexp.match(s)
34 r.append(int(m.group(1)))
35 s = m.group(2)
36 continue
37 if s[0] in ascii_letters:
38 m = alpha_regexp.match(s)
39 r.append(m.group(1))
40 s = m.group(2)
41 continue
42 s = s[1:]
43 return r
44
45def vercmp_part(a, b):
46 va = explode_version(a)
47 vb = explode_version(b)
48 while True:
49 if va == []:
50 ca = None
51 else:
52 ca = va.pop(0)
53 if vb == []:
54 cb = None
55 else:
56 cb = vb.pop(0)
57 if ca == None and cb == None:
58 return 0
59 if ca > cb:
60 return 1
61 if ca < cb:
62 return -1
63
64def vercmp(ta, tb):
65 (va, ra) = ta
66 (vb, rb) = tb
67
68 r = vercmp_part(va, vb)
69 if (r == 0):
70 r = vercmp_part(ra, rb)
71 return r
diff --git a/bitbake/lib/bb/utils.pyc b/bitbake/lib/bb/utils.pyc
new file mode 100644
index 0000000000..9f2bc75cbc
--- /dev/null
+++ b/bitbake/lib/bb/utils.pyc
Binary files differ
diff --git a/bitbake/setup.py b/bitbake/setup.py
new file mode 100755
index 0000000000..a94c967d99
--- /dev/null
+++ b/bitbake/setup.py
@@ -0,0 +1,69 @@
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) 2003 Chris Larson
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; either version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along with
17# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18# Place, Suite 330, Boston, MA 02111-1307 USA.
19
20from distutils.core import setup
21import os, sys
22
23# bbdir = os.path.join(sys.prefix, 'share', 'bitbake')
24# docdir = os.path.join(sys.prefix, 'share', 'doc')
25bbdir = os.path.join('bitbake')
26docdir = os.path.join('doc')
27
28def clean_doc(type):
29 origpath = os.path.abspath(os.curdir)
30 os.chdir(os.path.join(origpath, 'doc', 'manual'))
31 make = os.environ.get('MAKE') or 'make'
32 os.system('%s clean-%s' % (make, type))
33
34def generate_doc(type):
35 origpath = os.path.abspath(os.curdir)
36 os.chdir(os.path.join(origpath, 'doc', 'manual'))
37 make = os.environ.get('MAKE') or 'make'
38 ret = os.system('%s %s' % (make, type))
39 if ret != 0:
40 print "ERROR: Unable to generate html documentation."
41 sys.exit(ret)
42 os.chdir(origpath)
43
44if 'bdist' in sys.argv[1:]:
45 generate_doc('html')
46
47sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
48import bb
49import glob
50setup(name='bitbake',
51 version=bb.__version__,
52 license='GPL',
53 url='http://developer.berlios.de/projects/bitbake/',
54 description='BitBake build tool',
55 long_description='BitBake is a simple tool for the execution of tasks. It is derived from Portage, which is the package management system used by the Gentoo Linux distribution. It is most commonly used to build packages, as it can easily use its rudamentary inheritence to abstract common operations, such as fetching sources, unpacking them, patching them, compiling them, and so on. It is the basis of the OpenEmbedded project, which is being used for OpenZaurus, Familiar, and a number of other Linux distributions.',
56 author='Chris Larson',
57 author_email='clarson@elinux.org',
58 packages=['bb', 'bb.parse', 'bb.parse.parse_py'],
59 package_dir={'bb': os.path.join('lib', 'bb')},
60 scripts=[os.path.join('bin', 'bitbake'),
61 os.path.join('bin', 'bbimage')],
62 data_files=[(os.path.join(bbdir, 'conf'), [os.path.join('conf', 'bitbake.conf')]),
63 (os.path.join(bbdir, 'classes'), [os.path.join('classes', 'base.bbclass')]),
64 (os.path.join(docdir, 'bitbake-%s' % bb.__version__, 'html'), glob.glob(os.path.join('doc', 'manual', 'html', '*.html'))),
65 (os.path.join(docdir, 'bitbake-%s' % bb.__version__, 'pdf'), glob.glob(os.path.join('doc', 'manual', 'pdf', '*.pdf'))),],
66 )
67
68if 'bdist' in sys.argv[1:]:
69 clean_doc('html')