1
0
mirror of https://git.yoctoproject.org/poky synced 2026-05-30 12:29:55 +00:00

Initial population

git-svn-id: https://svn.o-hand.com/repos/poky@2 311d38ba-8fff-0310-9ca6-ca027cbcb966
This commit is contained in:
Richard Purdie
2005-08-31 10:47:56 +00:00
parent 4b46c1f6e8
commit f54da734eb
56 changed files with 8930 additions and 0 deletions
File diff suppressed because it is too large Load Diff
Binary file not shown.
+395
View File
@@ -0,0 +1,395 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake 'Build' implementation
Core code for function execution and task handling in the
BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
Based on Gentoo's portage.py.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
from bb import debug, data, fetch, fatal, error, note, event, mkdirhier
import bb, os
# data holds flags and function name for a given task
_task_data = data.init()
# graph represents task interdependencies
_task_graph = bb.digraph()
# stack represents execution order, excepting dependencies
_task_stack = []
# events
class FuncFailed(Exception):
"""Executed function failed"""
class EventException(Exception):
"""Exception which is associated with an Event."""
def __init__(self, msg, event):
self.args = msg, event
class TaskBase(event.Event):
"""Base class for task events"""
def __init__(self, t, d ):
self._task = t
event.Event.__init__(self, d)
def getTask(self):
return self._task
def setTask(self, task):
self._task = task
task = property(getTask, setTask, None, "task property")
class TaskStarted(TaskBase):
"""Task execution started"""
class TaskSucceeded(TaskBase):
"""Task execution completed"""
class TaskFailed(TaskBase):
"""Task execution failed"""
class InvalidTask(TaskBase):
"""Invalid Task"""
# functions
def init(data):
global _task_data, _task_graph, _task_stack
_task_data = data.init()
_task_graph = bb.digraph()
_task_stack = []
def exec_func(func, d, dirs = None):
"""Execute an BB 'function'"""
body = data.getVar(func, d)
if not body:
return
if not dirs:
dirs = (data.getVarFlag(func, 'dirs', d) or "").split()
for adir in dirs:
adir = data.expand(adir, d)
mkdirhier(adir)
if len(dirs) > 0:
adir = dirs[-1]
else:
adir = data.getVar('B', d, 1)
adir = data.expand(adir, d)
try:
prevdir = os.getcwd()
except OSError:
prevdir = data.expand('${TOPDIR}', d)
if adir and os.access(adir, os.F_OK):
os.chdir(adir)
if data.getVarFlag(func, "python", d):
exec_func_python(func, d)
else:
exec_func_shell(func, d)
if os.path.exists(prevdir):
os.chdir(prevdir)
def exec_func_python(func, d):
"""Execute a python BB 'function'"""
import re, os
tmp = "def " + func + "():\n%s" % data.getVar(func, d)
comp = compile(tmp + '\n' + func + '()', bb.data.getVar('FILE', d, 1) + ':' + func, "exec")
prevdir = os.getcwd()
g = {} # globals
g['bb'] = bb
g['os'] = os
g['d'] = d
exec comp in g
if os.path.exists(prevdir):
os.chdir(prevdir)
def exec_func_shell(func, d):
"""Execute a shell BB 'function' Returns true if execution was successful.
For this, it creates a bash shell script in the tmp dectory, writes the local
data into it and finally executes. The output of the shell will end in a log file and stdout.
Note on directory behavior. The 'dirs' varflag should contain a list
of the directories you need created prior to execution. The last
item in the list is where we will chdir/cd to.
"""
import sys
deps = data.getVarFlag(func, 'deps', d)
check = data.getVarFlag(func, 'check', d)
if check in globals():
if globals()[check](func, deps):
return
global logfile
t = data.getVar('T', d, 1)
if not t:
return 0
mkdirhier(t)
logfile = "%s/log.%s.%s" % (t, func, str(os.getpid()))
runfile = "%s/run.%s.%s" % (t, func, str(os.getpid()))
f = open(runfile, "w")
f.write("#!/bin/sh -e\n")
if bb.debug_level > 0: f.write("set -x\n")
data.emit_env(f, d)
f.write("cd %s\n" % os.getcwd())
if func: f.write("%s\n" % func)
f.close()
os.chmod(runfile, 0775)
if not func:
error("Function not specified")
raise FuncFailed()
# open logs
si = file('/dev/null', 'r')
try:
if bb.debug_level > 0:
so = os.popen("tee \"%s\"" % logfile, "w")
else:
so = file(logfile, 'w')
except OSError, e:
bb.error("opening log file: %s" % e)
pass
se = so
# dup the existing fds so we dont lose them
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
# replace those fds with our own
os.dup2(si.fileno(), osi[1])
os.dup2(so.fileno(), oso[1])
os.dup2(se.fileno(), ose[1])
# execute function
prevdir = os.getcwd()
if data.getVarFlag(func, "fakeroot", d):
maybe_fakeroot = "PATH=\"%s\" fakeroot " % bb.data.getVar("PATH", d, 1)
else:
maybe_fakeroot = ''
ret = os.system('%ssh -e %s' % (maybe_fakeroot, runfile))
os.chdir(prevdir)
# restore the backups
os.dup2(osi[0], osi[1])
os.dup2(oso[0], oso[1])
os.dup2(ose[0], ose[1])
# close our logs
si.close()
so.close()
se.close()
# close the backup fds
os.close(osi[0])
os.close(oso[0])
os.close(ose[0])
if ret==0:
if bb.debug_level > 0:
os.remove(runfile)
# os.remove(logfile)
return
else:
error("function %s failed" % func)
if data.getVar("BBINCLUDELOGS", d):
error("log data follows (%s)" % logfile)
f = open(logfile, "r")
while True:
l = f.readline()
if l == '':
break
l = l.rstrip()
print '| %s' % l
f.close()
else:
error("see log in %s" % logfile)
raise FuncFailed( logfile )
def exec_task(task, d):
"""Execute an BB 'task'
The primary difference between executing a task versus executing
a function is that a task exists in the task digraph, and therefore
has dependencies amongst other tasks."""
# check if the task is in the graph..
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
task_cache = data.getVar('_task_cache', d)
if not task_cache:
task_cache = []
data.setVar('_task_cache', task_cache, d)
if not task_graph.hasnode(task):
raise EventException("Missing node in task graph", InvalidTask(task, d))
# check whether this task needs executing..
if not data.getVarFlag(task, 'force', d):
if stamp_is_current(task, d):
return 1
# follow digraph path up, then execute our way back down
def execute(graph, item):
if data.getVarFlag(item, 'task', d):
if item in task_cache:
return 1
if task != item:
# deeper than toplevel, exec w/ deps
exec_task(item, d)
return 1
try:
debug(1, "Executing task %s" % item)
old_overrides = data.getVar('OVERRIDES', d, 0)
localdata = data.createCopy(d)
data.setVar('OVERRIDES', 'task_%s:%s' % (item, old_overrides), localdata)
data.update_data(localdata)
event.fire(TaskStarted(item, localdata))
exec_func(item, localdata)
event.fire(TaskSucceeded(item, localdata))
task_cache.append(item)
data.setVar('_task_cache', task_cache, d)
except FuncFailed, reason:
note( "Task failed: %s" % reason )
failedevent = TaskFailed(item, d)
event.fire(failedevent)
raise EventException("Function failed in task: %s" % reason, failedevent)
# execute
task_graph.walkdown(task, execute)
# make stamp, or cause event and raise exception
if not data.getVarFlag(task, 'nostamp', d):
mkstamp(task, d)
def stamp_is_current(task, d, checkdeps = 1):
"""Check status of a given task's stamp. returns 0 if it is not current and needs updating."""
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
stamp = data.getVar('STAMP', d)
if not stamp:
return 0
stampfile = "%s.%s" % (data.expand(stamp, d), task)
if not os.access(stampfile, os.F_OK):
return 0
if checkdeps == 0:
return 1
import stat
tasktime = os.stat(stampfile)[stat.ST_MTIME]
_deps = []
def checkStamp(graph, task):
# check for existance
if data.getVarFlag(task, 'nostamp', d):
return 1
if not stamp_is_current(task, d, 0):
return 0
depfile = "%s.%s" % (data.expand(stamp, d), task)
deptime = os.stat(depfile)[stat.ST_MTIME]
if deptime > tasktime:
return 0
return 1
return task_graph.walkdown(task, checkStamp)
def md5_is_current(task):
"""Check if a md5 file for a given task is current"""
def mkstamp(task, d):
"""Creates/updates a stamp for a given task"""
stamp = data.getVar('STAMP', d)
if not stamp:
return
stamp = "%s.%s" % (data.expand(stamp, d), task)
mkdirhier(os.path.dirname(stamp))
open(stamp, "w+")
def add_task(task, deps, d):
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVarFlag(task, 'task', 1, d)
task_graph.addnode(task, None)
for dep in deps:
if not task_graph.hasnode(dep):
task_graph.addnode(dep, None)
task_graph.addnode(task, dep)
# don't assume holding a reference
data.setVar('_task_graph', task_graph, d)
def remove_task(task, kill, d):
"""Remove an BB 'task'.
If kill is 1, also remove tasks that depend on this task."""
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
if not task_graph.hasnode(task):
return
data.delVarFlag(task, 'task', d)
ref = 1
if kill == 1:
ref = 2
task_graph.delnode(task, ref)
data.setVar('_task_graph', task_graph, d)
def task_exists(task, d):
task_graph = data.getVar('_task_graph', d)
if not task_graph:
task_graph = bb.digraph()
data.setVar('_task_graph', task_graph, d)
return task_graph.hasnode(task)
def get_task_data():
return _task_data
Binary file not shown.
+580
View File
@@ -0,0 +1,580 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake 'Data' implementations
Functions for interacting with the data structure used by the
BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2005 Holger Hans Peter Freyther
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
import sys, os, re, time, types
if sys.argv[0][-5:] == "pydoc":
path = os.path.dirname(os.path.dirname(sys.argv[1]))
else:
path = os.path.dirname(os.path.dirname(sys.argv[0]))
sys.path.append(path)
from bb import note, debug, data_smart
_dict_type = data_smart.DataSmart
_dict_p_type = data_smart.DataSmartPackage
class DataDictFull(dict):
"""
This implements our Package Data Storage Interface.
setDirty is a no op as all items are held in memory
"""
def setDirty(self, bbfile, data):
"""
No-Op we assume data was manipulated as some sort of
reference
"""
if not bbfile in self:
raise Exception("File %s was not in dictionary before" % bbfile)
self[bbfile] = data
class DataDictCache:
"""
Databacked Dictionary implementation
"""
def __init__(self, cache_dir, config):
self.cache_dir = cache_dir
self.files = []
self.dirty = {}
self.config = config
def has_key(self,key):
return key in self.files
def keys(self):
return self.files
def __setitem__(self, key, data):
"""
Add the key to the list of known files and
place the data in the cache?
"""
if key in self.files:
return
self.files.append(key)
def __getitem__(self, key):
if not key in self.files:
return None
# if it was dirty we will
if key in self.dirty:
return self.dirty[key]
# not cached yet
return _dict_p_type(self.cache_dir, key,False,self.config)
def setDirty(self, bbfile, data):
"""
Only already added items can be declared dirty!!!
"""
if not bbfile in self.files:
raise Exception("File %s was not in dictionary before" % bbfile)
self.dirty[bbfile] = data
def init():
return _dict_type()
def init_db(cache,name,clean,parent = None):
return _dict_p_type(cache,name,clean,parent)
def init_db_mtime(cache,cache_bbfile):
return _dict_p_type.mtime(cache,cache_bbfile)
def pkgdata(use_cache, cache, config = None):
"""
Return some sort of dictionary to lookup parsed dictionaires
"""
if use_cache:
return DataDictCache(cache, config)
return DataDictFull()
def createCopy(source):
"""Link the source set to the destination
If one does not find the value in the destination set,
search will go on to the source set to get the value.
Value from source are copy-on-write. i.e. any try to
modify one of them will end up putting the modified value
in the destination set.
"""
return source.createCopy()
def initVar(var, d):
"""Non-destructive var init for data structure"""
d.initVar(var)
def setVar(var, value, d):
"""Set a variable to a given value
Example:
>>> d = init()
>>> setVar('TEST', 'testcontents', d)
>>> print getVar('TEST', d)
testcontents
"""
d.setVar(var,value)
def getVar(var, d, exp = 0):
"""Gets the value of a variable
Example:
>>> d = init()
>>> setVar('TEST', 'testcontents', d)
>>> print getVar('TEST', d)
testcontents
"""
return d.getVar(var,exp)
def delVar(var, d):
"""Removes a variable from the data set
Example:
>>> d = init()
>>> setVar('TEST', 'testcontents', d)
>>> print getVar('TEST', d)
testcontents
>>> delVar('TEST', d)
>>> print getVar('TEST', d)
None
"""
d.delVar(var)
def setVarFlag(var, flag, flagvalue, d):
"""Set a flag for a given variable to a given value
Example:
>>> d = init()
>>> setVarFlag('TEST', 'python', 1, d)
>>> print getVarFlag('TEST', 'python', d)
1
"""
d.setVarFlag(var,flag,flagvalue)
def getVarFlag(var, flag, d):
"""Gets given flag from given var
Example:
>>> d = init()
>>> setVarFlag('TEST', 'python', 1, d)
>>> print getVarFlag('TEST', 'python', d)
1
"""
return d.getVarFlag(var,flag)
def delVarFlag(var, flag, d):
"""Removes a given flag from the variable's flags
Example:
>>> d = init()
>>> setVarFlag('TEST', 'testflag', 1, d)
>>> print getVarFlag('TEST', 'testflag', d)
1
>>> delVarFlag('TEST', 'testflag', d)
>>> print getVarFlag('TEST', 'testflag', d)
None
"""
d.delVarFlag(var,flag)
def setVarFlags(var, flags, d):
"""Set the flags for a given variable
Example:
>>> d = init()
>>> myflags = {}
>>> myflags['test'] = 'blah'
>>> setVarFlags('TEST', myflags, d)
>>> print getVarFlag('TEST', 'test', d)
blah
"""
d.setVarFlags(var,flags)
def getVarFlags(var, d):
"""Gets a variable's flags
Example:
>>> d = init()
>>> setVarFlag('TEST', 'test', 'blah', d)
>>> print getVarFlags('TEST', d)['test']
blah
"""
return d.getVarFlags(var)
def delVarFlags(var, d):
"""Removes a variable's flags
Example:
>>> data = init()
>>> setVarFlag('TEST', 'testflag', 1, data)
>>> print getVarFlag('TEST', 'testflag', data)
1
>>> delVarFlags('TEST', data)
>>> print getVarFlags('TEST', data)
None
"""
d.delVarFlags(var)
def keys(d):
"""Return a list of keys in d
Example:
>>> d = init()
>>> setVar('TEST', 1, d)
>>> setVar('MOO' , 2, d)
>>> setVarFlag('TEST', 'test', 1, d)
>>> keys(d)
['TEST', 'MOO']
"""
return d.keys()
def getData(d):
"""Returns the data object used"""
return d
def setData(newData, d):
"""Sets the data object to the supplied value"""
d = newData
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
__expand_python_regexp__ = re.compile(r"\${@.+?}")
def expand(s, d, varname = None):
"""Variable expansion using the data store.
Example:
Standard expansion:
>>> d = init()
>>> setVar('A', 'sshd', d)
>>> print expand('/usr/bin/${A}', d)
/usr/bin/sshd
Python expansion:
>>> d = init()
>>> print expand('result: ${@37 * 72}', d)
result: 2664
Shell expansion:
>>> d = init()
>>> print expand('${TARGET_MOO}', d)
${TARGET_MOO}
>>> setVar('TARGET_MOO', 'yupp', d)
>>> print expand('${TARGET_MOO}',d)
yupp
>>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
>>> delVar('TARGET_MOO', d)
>>> print expand('${SRC_URI}', d)
http://somebug.${TARGET_MOO}
"""
def var_sub(match):
key = match.group()[2:-1]
if varname and key:
if varname == key:
raise Exception("variable %s references itself!" % varname)
var = getVar(key, d, 1)
if var is not None:
return var
else:
return match.group()
def python_sub(match):
import bb
code = match.group()[3:-1]
locals()['d'] = d
s = eval(code)
if type(s) == types.IntType: s = str(s)
return s
if type(s) is not types.StringType: # sanity check
return s
while s.find('$') != -1:
olds = s
try:
s = __expand_var_regexp__.sub(var_sub, s)
s = __expand_python_regexp__.sub(python_sub, s)
if s == olds: break
if type(s) is not types.StringType: # sanity check
import bb
bb.error('expansion of %s returned non-string %s' % (olds, s))
except KeyboardInterrupt:
raise
except:
note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
raise
return s
def expandKeys(alterdata, readdata = None):
if readdata == None:
readdata = alterdata
for key in keys(alterdata):
ekey = expand(key, readdata)
if key == ekey:
continue
val = getVar(key, alterdata)
if val is None:
continue
# import copy
# setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
setVar(ekey, val, alterdata)
for i in ('_append', '_prepend', '_delete'):
dest = getVarFlag(ekey, i, alterdata) or []
src = getVarFlag(key, i, readdata) or []
dest.extend(src)
setVarFlag(ekey, i, dest, alterdata)
delVar(key, alterdata)
def expandData(alterdata, readdata = None):
"""For each variable in alterdata, expand it, and update the var contents.
Replacements use data from readdata.
Example:
>>> a=init()
>>> b=init()
>>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
>>> setVar("DL_DIR", "/path/to/whatever", b)
>>> expandData(a, b)
>>> print getVar("dlmsg", a)
dl_dir is /path/to/whatever
"""
if readdata == None:
readdata = alterdata
for key in keys(alterdata):
val = getVar(key, alterdata)
if type(val) is not types.StringType:
continue
expanded = expand(val, readdata)
# print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
if val != expanded:
setVar(key, expanded, alterdata)
import os
def inheritFromOS(d):
"""Inherit variables from the environment."""
# fakeroot needs to be able to set these
non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
for s in os.environ.keys():
if not s in non_inherit_vars:
try:
setVar(s, os.environ[s], d)
setVarFlag(s, 'matchesenv', '1', d)
except TypeError:
pass
import sys
def emit_var(var, o=sys.__stdout__, d = init(), all=False):
"""Emit a variable to be sourced by a shell."""
if getVarFlag(var, "python", d):
return 0
try:
if all:
oval = getVar(var, d, 0)
val = getVar(var, d, 1)
except KeyboardInterrupt:
raise
except:
excname = str(sys.exc_info()[0])
if excname == "bb.build.FuncFailed":
raise
o.write('# expansion of %s threw %s\n' % (var, excname))
return 0
if all:
o.write('# %s=%s\n' % (var, oval))
if type(val) is not types.StringType:
return 0
if getVarFlag(var, 'matchesenv', d):
return 0
if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
return 0
val.rstrip()
if not val:
return 0
if getVarFlag(var, "func", d):
# NOTE: should probably check for unbalanced {} within the var
o.write("%s() {\n%s\n}\n" % (var, val))
else:
if getVarFlag(var, "export", d):
o.write('export ')
else:
if not all:
return 0
# if we're going to output this within doublequotes,
# to a shell, we need to escape the quotes in the var
alter = re.sub('"', '\\"', val.strip())
o.write('%s="%s"\n' % (var, alter))
return 1
def emit_env(o=sys.__stdout__, d = init(), all=False):
"""Emits all items in the data store in a format such that it can be sourced by a shell."""
env = keys(d)
for e in env:
if getVarFlag(e, "func", d):
continue
emit_var(e, o, d, all) and o.write('\n')
for e in env:
if not getVarFlag(e, "func", d):
continue
emit_var(e, o, d) and o.write('\n')
def update_data(d):
"""Modifies the environment vars according to local overrides and commands.
Examples:
Appending to a variable:
>>> d = init()
>>> setVar('TEST', 'this is a', d)
>>> setVar('TEST_append', ' test', d)
>>> setVar('TEST_append', ' of the emergency broadcast system.', d)
>>> update_data(d)
>>> print getVar('TEST', d)
this is a test of the emergency broadcast system.
Prepending to a variable:
>>> setVar('TEST', 'virtual/libc', d)
>>> setVar('TEST_prepend', 'virtual/tmake ', d)
>>> setVar('TEST_prepend', 'virtual/patcher ', d)
>>> update_data(d)
>>> print getVar('TEST', d)
virtual/patcher virtual/tmake virtual/libc
Overrides:
>>> setVar('TEST_arm', 'target', d)
>>> setVar('TEST_ramses', 'machine', d)
>>> setVar('TEST_local', 'local', d)
>>> setVar('OVERRIDES', 'arm', d)
>>> setVar('TEST', 'original', d)
>>> update_data(d)
>>> print getVar('TEST', d)
target
>>> setVar('OVERRIDES', 'arm:ramses:local', d)
>>> setVar('TEST', 'original', d)
>>> update_data(d)
>>> print getVar('TEST', d)
local
"""
debug(2, "update_data()")
# can't do delete env[...] while iterating over the dictionary, so remember them
dodel = []
overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
def applyOverrides(var, d):
if not overrides:
debug(1, "OVERRIDES not defined, nothing to do")
return
val = getVar(var, d)
for o in overrides:
if var.endswith("_" + o):
l = len(o)+1
name = var[:-l]
d[name] = d[var]
for s in keys(d):
applyOverrides(s, d)
sval = getVar(s, d) or ""
# Handle line appends:
for (a, o) in getVarFlag(s, '_append', d) or []:
# maybe the OVERRIDE was not yet added so keep the append
if (o and o in overrides) or not o:
delVarFlag(s, '_append', d)
if o:
if not o in overrides:
continue
sval+=a
setVar(s, sval, d)
# Handle line prepends
for (a, o) in getVarFlag(s, '_prepend', d) or []:
# maybe the OVERRIDE was not yet added so keep the append
if (o and o in overrides) or not o:
delVarFlag(s, '_prepend', d)
if o:
if not o in overrides:
continue
sval=a+sval
setVar(s, sval, d)
# Handle line deletions
name = s + "_delete"
nameval = getVar(name, d)
if nameval:
sval = getVar(s, d)
if sval:
new = ''
pattern = nameval.replace('\n','').strip()
for line in sval.split('\n'):
if line.find(pattern) == -1:
new = new + '\n' + line
setVar(s, new, d)
dodel.append(name)
# delete all environment vars no longer needed
for s in dodel:
delVar(s, d)
def inherits_class(klass, d):
val = getVar('__inherit_cache', d) or ""
if os.path.join('classes', '%s.bbclass' % klass) in val.split():
return True
return False
def _test():
"""Start a doctest run on this module"""
import doctest
from bb import data
doctest.testmod(data)
if __name__ == "__main__":
_test()
Binary file not shown.
Binary file not shown.
+351
View File
@@ -0,0 +1,351 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake Smart Dictionary Implementation
Functions for interacting with the data structure used by the
BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2004, 2005 Seb Frankengul
Copyright (C) 2005 Holger Hans Peter Freyther
Copyright (C) 2005 Uli Luckas
Copyright (C) 2005 ROAD GmbH
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
import copy, os, re, sys, time, types
from bb import note, debug, fatal
try:
import cPickle as pickle
except ImportError:
import pickle
print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
__setvar_keyword__ = ["_append","_prepend","_delete"]
__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_delete)(_(?P<add>.*))?')
__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
__expand_python_regexp__ = re.compile(r"\${@.+?}")
class DataSmart:
def __init__(self):
self.dict = {}
def expand(self,s, varname):
def var_sub(match):
key = match.group()[2:-1]
if varname and key:
if varname == key:
raise Exception("variable %s references itself!" % varname)
var = self.getVar(key, 1)
if var is not None:
return var
else:
return match.group()
def python_sub(match):
import bb
code = match.group()[3:-1]
locals()['d'] = self
s = eval(code)
if type(s) == types.IntType: s = str(s)
return s
if type(s) is not types.StringType: # sanity check
return s
while s.find('$') != -1:
olds = s
try:
s = __expand_var_regexp__.sub(var_sub, s)
s = __expand_python_regexp__.sub(python_sub, s)
if s == olds: break
if type(s) is not types.StringType: # sanity check
import bb
bb.error('expansion of %s returned non-string %s' % (olds, s))
except KeyboardInterrupt:
raise
except:
note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
raise
return s
def initVar(self, var):
if not var in self.dict:
self.dict[var] = {}
def pickle_prep(self, cfg):
if "_data" in self.dict:
if self.dict["_data"] == cfg:
self.dict["_data"] = "cfg";
else: # this is an unknown array for the moment
pass
def unpickle_prep(self, cfg):
if "_data" in self.dict:
if self.dict["_data"] == "cfg":
self.dict["_data"] = cfg;
def _findVar(self,var):
_dest = self.dict
while (_dest and var not in _dest):
if not "_data" in _dest:
_dest = None
break
_dest = _dest["_data"]
if _dest and var in _dest:
return _dest[var]
return None
def _copyVar(self,var,name):
local_var = self._findVar(var)
if local_var:
self.dict[name] = copy.copy(local_var)
else:
debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
def _makeShadowCopy(self, var):
if var in self.dict:
return
local_var = self._findVar(var)
if local_var:
self.dict[var] = copy.copy(local_var)
else:
self.initVar(var)
def setVar(self,var,value):
match = __setvar_regexp__.match(var)
if match and match.group("keyword") in __setvar_keyword__:
base = match.group('base')
keyword = match.group("keyword")
override = match.group('add')
l = self.getVarFlag(base, keyword) or []
if override == 'delete':
if l.count([value, None]):
del l[l.index([value, None])]
l.append([value, override])
self.setVarFlag(base, match.group("keyword"), l)
return
if not var in self.dict:
self._makeShadowCopy(var)
if self.getVarFlag(var, 'matchesenv'):
self.delVarFlag(var, 'matchesenv')
self.setVarFlag(var, 'export', 1)
# setting var
self.dict[var]["content"] = value
def getVar(self,var,exp):
value = self.getVarFlag(var,"content")
if exp and value:
return self.expand(value,var)
return value
def delVar(self,var):
self.dict[var] = {}
def setVarFlag(self,var,flag,flagvalue):
if not var in self.dict:
self._makeShadowCopy(var)
self.dict[var][flag] = flagvalue
def getVarFlag(self,var,flag):
local_var = self._findVar(var)
if local_var:
if flag in local_var:
return copy.copy(local_var[flag])
return None
def delVarFlag(self,var,flag):
local_var = self._findVar(var)
if not local_var:
return
if not var in self.dict:
self._makeShadowCopy(var)
if var in self.dict and flag in self.dict[var]:
del self.dict[var][flag]
def setVarFlags(self,var,flags):
if not var in self.dict:
self._makeShadowCopy(var)
for i in flags.keys():
if i == "content":
continue
self.dict[var][i] = flags[i]
def getVarFlags(self,var):
local_var = self._findVar(var)
flags = {}
if local_var:
for i in self.dict[var].keys():
if i == "content":
continue
flags[i] = self.dict[var][i]
if len(flags) == 0:
return None
return flags
def delVarFlags(self,var):
if not var in self.dict:
self._makeShadowCopy(var)
if var in self.dict:
content = None
# try to save the content
if "content" in self.dict[var]:
content = self.dict[var]["content"]
self.dict[var] = {}
self.dict[var]["content"] = content
else:
del self.dict[var]
def createCopy(self):
"""
Create a copy of self by setting _data to self
"""
# we really want this to be a DataSmart...
data = DataSmart()
data.dict["_data"] = self.dict
return data
# Dictionary Methods
def keys(self):
def _keys(d, mykey):
if "_data" in d:
_keys(d["_data"],mykey)
for key in d.keys():
if key != "_data":
mykey[key] = None
keytab = {}
_keys(self.dict,keytab)
return keytab.keys()
def __getitem__(self,item):
start = self.dict
while start:
if item in start:
return start[item]
elif "_data" in start:
start = start["_data"]
else:
start = None
return None
def __setitem__(self,var,data):
self._makeShadowCopy(var)
self.dict[var] = data
class DataSmartPackage(DataSmart):
"""
Persistent Data Storage
"""
def sanitize_filename(bbfile):
return bbfile.replace( '/', '_' )
sanitize_filename = staticmethod(sanitize_filename)
def unpickle(self):
"""
Restore the dict from memory
"""
cache_bbfile = self.sanitize_filename(self.bbfile)
p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
self.dict = p.load()
self.unpickle_prep()
funcstr = self.getVar('__functions__', 0)
if funcstr:
comp = compile(funcstr, "<pickled>", "exec")
exec comp in __builtins__
def linkDataSet(self):
if not self.parent == None:
# assume parent is a DataSmartInstance
self.dict["_data"] = self.parent.dict
def __init__(self,cache,name,clean,parent):
"""
Construct a persistent data instance
"""
#Initialize the dictionary
DataSmart.__init__(self)
self.cache = cache
self.bbfile = os.path.abspath( name )
self.parent = parent
# Either unpickle the data or do copy on write
if clean:
self.linkDataSet()
else:
self.unpickle()
def commit(self, mtime):
"""
Save the package to a permanent storage
"""
self.pickle_prep()
cache_bbfile = self.sanitize_filename(self.bbfile)
p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
p.dump( self.dict )
self.unpickle_prep()
def mtime(cache,bbfile):
cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
try:
return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
except OSError:
return 0
mtime = staticmethod(mtime)
def pickle_prep(self):
"""
If self.dict contains a _data key and it is a configuration
we will remember we had a configuration instance attached
"""
if "_data" in self.dict:
if self.dict["_data"] == self.parent:
dest["_data"] = "cfg"
def unpickle_prep(self):
"""
If we had a configuration instance attached, we will reattach it
"""
if "_data" in self.dict:
if self.dict["_data"] == "cfg":
self.dict["_data"] = self.parent
Binary file not shown.
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake 'Event' implementation
Classes and functions for manipulating 'events' in the
BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
"""
import os, re
import bb.data
class Event:
"""Base class for events"""
type = "Event"
def __init__(self, d = bb.data.init()):
self._data = d
def getData(self):
return self._data
def setData(self, data):
self._data = data
data = property(getData, setData, None, "data property")
NotHandled = 0
Handled = 1
handlers = []
def tmpHandler(event):
"""Default handler for code events"""
return NotHandled
def defaultTmpHandler():
tmp = "def tmpHandler(e):\n\t\"\"\"heh\"\"\"\n\treturn 0"
comp = compile(tmp, "tmpHandler(e)", "exec")
return comp
def fire(event):
"""Fire off an Event"""
for h in handlers:
if type(h).__name__ == "code":
exec(h)
if tmpHandler(event) == Handled:
return Handled
else:
if h(event) == Handled:
return Handled
return NotHandled
def register(handler):
"""Register an Event handler"""
if handler is not None:
# handle string containing python code
if type(handler).__name__ == "str":
return registerCode(handler)
# prevent duplicate registration
if not handler in handlers:
handlers.append(handler)
def registerCode(handlerStr):
"""Register a 'code' Event.
Deprecated interface; call register instead.
Expects to be passed python code as a string, which will
be passed in turn to compile() and then exec(). Note that
the code will be within a function, so should have had
appropriate tabbing put in place."""
tmp = "def tmpHandler(e):\n%s" % handlerStr
comp = compile(tmp, "tmpHandler(e)", "exec")
# prevent duplicate registration
if not comp in handlers:
handlers.append(comp)
def remove(handler):
"""Remove an Event handler"""
for h in handlers:
if type(handler).__name__ == "str":
return removeCode(handler)
if handler is h:
handlers.remove(handler)
def removeCode(handlerStr):
"""Remove a 'code' Event handler
Deprecated interface; call remove instead."""
tmp = "def tmpHandler(e):\n%s" % handlerStr
comp = compile(tmp, "tmpHandler(e)", "exec")
handlers.remove(comp)
def getName(e):
"""Returns the name of a class or class instance"""
if getattr(e, "__name__", None) == None:
return e.__class__.__name__
else:
return e.__name__
class PkgBase(Event):
"""Base class for package events"""
def __init__(self, t, d = {}):
self._pkg = t
Event.__init__(self, d)
def getPkg(self):
return self._pkg
def setPkg(self, pkg):
self._pkg = pkg
pkg = property(getPkg, setPkg, None, "pkg property")
class BuildBase(Event):
"""Base class for bbmake run events"""
def __init__(self, n, p, c):
self._name = n
self._pkgs = p
Event.__init__(self, c)
def getPkgs(self):
return self._pkgs
def setPkgs(self, pkgs):
self._pkgs = pkgs
def getName(self):
return self._name
def setName(self, name):
self._name = name
def getCfg(self):
return self.data
def setCfg(self, cfg):
self.data = cfg
pkgs = property(getPkgs, setPkgs, None, "pkgs property")
name = property(getName, setName, None, "name property")
cfg = property(getCfg, setCfg, None, "cfg property")
class DepBase(PkgBase):
"""Base class for dependency events"""
def __init__(self, t, data, d):
self._dep = d
PkgBase.__init__(self, t, data)
def getDep(self):
return self._dep
def setDep(self, dep):
self._dep = dep
dep = property(getDep, setDep, None, "dep property")
class PkgStarted(PkgBase):
"""Package build started"""
class PkgFailed(PkgBase):
"""Package build failed"""
class PkgSucceeded(PkgBase):
"""Package build completed"""
class BuildStarted(BuildBase):
"""bbmake build run started"""
class BuildCompleted(BuildBase):
"""bbmake build run completed"""
class UnsatisfiedDep(DepBase):
"""Unsatisfied Dependency"""
class RecursiveDep(DepBase):
"""Recursive Dependency"""
class MultipleProviders(PkgBase):
"""Multiple Providers"""
Binary file not shown.
+656
View File
@@ -0,0 +1,656 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake 'Fetch' implementations
Classes for obtaining upstream sources for the
BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
import os, re
import bb
from bb import data
class FetchError(Exception):
"""Exception raised when a download fails"""
class NoMethodError(Exception):
"""Exception raised when there is no method to obtain a supplied url or set of urls"""
class MissingParameterError(Exception):
"""Exception raised when a fetch method is missing a critical parameter in the url"""
class MD5SumError(Exception):
"""Exception raised when a MD5SUM of a file does not match the expected one"""
def uri_replace(uri, uri_find, uri_replace, d):
# bb.note("uri_replace: operating on %s" % uri)
if not uri or not uri_find or not uri_replace:
bb.debug(1, "uri_replace: passed an undefined value, not replacing")
uri_decoded = list(bb.decodeurl(uri))
uri_find_decoded = list(bb.decodeurl(uri_find))
uri_replace_decoded = list(bb.decodeurl(uri_replace))
result_decoded = ['','','','','',{}]
for i in uri_find_decoded:
loc = uri_find_decoded.index(i)
result_decoded[loc] = uri_decoded[loc]
import types
if type(i) == types.StringType:
import re
if (re.match(i, uri_decoded[loc])):
result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
if uri_find_decoded.index(i) == 2:
if d:
localfn = bb.fetch.localpath(uri, d)
if localfn:
result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
# bb.note("uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
else:
# bb.note("uri_replace: no match")
return uri
# else:
# for j in i.keys():
# FIXME: apply replacements against options
return bb.encodeurl(result_decoded)
methods = []
def init(urls = [], d = None):
if d == None:
bb.debug(2,"BUG init called with None as data object!!!")
return
for m in methods:
m.urls = []
for u in urls:
for m in methods:
m.data = d
if m.supports(u, d):
m.urls.append(u)
def go(d):
"""Fetch all urls"""
for m in methods:
if m.urls:
m.go(d)
def localpaths(d):
"""Return a list of the local filenames, assuming successful fetch"""
local = []
for m in methods:
for u in m.urls:
local.append(m.localpath(u, d))
return local
def localpath(url, d):
for m in methods:
if m.supports(url, d):
return m.localpath(url, d)
return url
class Fetch(object):
"""Base class for 'fetch'ing data"""
def __init__(self, urls = []):
self.urls = []
for url in urls:
if self.supports(bb.decodeurl(url), d) is 1:
self.urls.append(url)
def supports(url, d):
"""Check to see if this fetch class supports a given url.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
return 0
supports = staticmethod(supports)
def localpath(url, d):
"""Return the local filename of a given url assuming a successful fetch.
"""
return url
localpath = staticmethod(localpath)
def setUrls(self, urls):
self.__urls = urls
def getUrls(self):
return self.__urls
urls = property(getUrls, setUrls, None, "Urls property")
def setData(self, data):
self.__data = data
def getData(self):
return self.__data
data = property(getData, setData, None, "Data property")
def go(self, urls = []):
"""Fetch urls"""
raise NoMethodError("Missing implementation for url")
class Wget(Fetch):
"""Class to fetch urls via 'wget'"""
def supports(url, d):
"""Check to see if a given url can be fetched using wget.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
return type in ['http','https','ftp']
supports = staticmethod(supports)
def localpath(url, d):
# strip off parameters
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
if "localpath" in parm:
# if user overrides local path, use it.
return parm["localpath"]
url = bb.encodeurl([type, host, path, user, pswd, {}])
return os.path.join(data.getVar("DL_DIR", d), os.path.basename(url))
localpath = staticmethod(localpath)
def go(self, d, urls = []):
"""Fetch urls"""
def md5_sum(basename, data):
"""
Fast and incomplete OVERRIDE implementation for MD5SUM handling
MD5SUM_basename = "SUM" and fallback to MD5SUM_basename
"""
var = "MD5SUM_%s" % basename
return getVar(var, data) or get("MD5SUM",data)
def fetch_uri(uri, basename, dl, md5, parm, d):
if os.path.exists(dl):
# file exists, but we didnt complete it.. trying again..
fetchcmd = data.getVar("RESUMECOMMAND", d, 1)
else:
fetchcmd = data.getVar("FETCHCOMMAND", d, 1)
bb.note("fetch " + uri)
fetchcmd = fetchcmd.replace("${URI}", uri)
fetchcmd = fetchcmd.replace("${FILE}", basename)
bb.debug(2, "executing " + fetchcmd)
ret = os.system(fetchcmd)
if ret != 0:
return False
# check if sourceforge did send us to the mirror page
dl_dir = data.getVar("DL_DIR", d, True)
if not os.path.exists(dl):
os.system("rm %s*" % dl) # FIXME shell quote it
bb.debug(2,"sourceforge.net send us to the mirror on %s" % basename)
return False
# supposedly complete.. write out md5sum
if bb.which(data.getVar('PATH', d), 'md5sum'):
try:
md5pipe = os.popen('md5sum ' + dl)
md5data = (md5pipe.readline().split() or [ "" ])[0]
md5pipe.close()
except OSError:
md5data = ""
md5out = file(md5, 'w')
md5out.write(md5data)
md5out.close()
else:
md5out = file(md5, 'w')
md5out.write("")
md5out.close()
return True
if not urls:
urls = self.urls
localdata = data.createCopy(d)
data.setVar('OVERRIDES', "wget:" + data.getVar('OVERRIDES', localdata), localdata)
data.update_data(localdata)
for uri in urls:
completed = 0
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(uri, localdata))
basename = os.path.basename(path)
dl = self.localpath(uri, d)
dl = data.expand(dl, localdata)
md5 = dl + '.md5'
if os.path.exists(md5):
# complete, nothing to see here..
continue
premirrors = [ i.split() for i in (data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ]
for (find, replace) in premirrors:
newuri = uri_replace(uri, find, replace, d)
if newuri != uri:
if fetch_uri(newuri, basename, dl, md5, parm, localdata):
completed = 1
break
if completed:
continue
if fetch_uri(uri, basename, dl, md5, parm, localdata):
continue
# try mirrors
mirrors = [ i.split() for i in (data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ]
for (find, replace) in mirrors:
newuri = uri_replace(uri, find, replace, d)
if newuri != uri:
if fetch_uri(newuri, basename, dl, md5, parm, localdata):
completed = 1
break
if not completed:
raise FetchError(uri)
del localdata
methods.append(Wget())
class Cvs(Fetch):
"""Class to fetch a module or modules from cvs repositories"""
def supports(url, d):
"""Check to see if a given url can be fetched with cvs.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
return type in ['cvs', 'pserver']
supports = staticmethod(supports)
def localpath(url, d):
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
if "localpath" in parm:
# if user overrides local path, use it.
return parm["localpath"]
if not "module" in parm:
raise MissingParameterError("cvs method needs a 'module' parameter")
else:
module = parm["module"]
if 'tag' in parm:
tag = parm['tag']
else:
tag = ""
if 'date' in parm:
date = parm['date']
else:
if not tag:
date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
else:
date = ""
return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d))
localpath = staticmethod(localpath)
def go(self, d, urls = []):
"""Fetch urls"""
if not urls:
urls = self.urls
localdata = data.createCopy(d)
data.setVar('OVERRIDES', "cvs:%s" % data.getVar('OVERRIDES', localdata), localdata)
data.update_data(localdata)
for loc in urls:
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
if not "module" in parm:
raise MissingParameterError("cvs method needs a 'module' parameter")
else:
module = parm["module"]
dlfile = self.localpath(loc, localdata)
dldir = data.getVar('DL_DIR', localdata, 1)
# if local path contains the cvs
# module, consider the dir above it to be the
# download directory
# pos = dlfile.find(module)
# if pos:
# dldir = dlfile[:pos]
# else:
# dldir = os.path.dirname(dlfile)
# setup cvs options
options = []
if 'tag' in parm:
tag = parm['tag']
else:
tag = ""
if 'date' in parm:
date = parm['date']
else:
if not tag:
date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
else:
date = ""
if "method" in parm:
method = parm["method"]
else:
method = "pserver"
if "localdir" in parm:
localdir = parm["localdir"]
else:
localdir = module
cvs_rsh = None
if method == "ext":
if "rsh" in parm:
cvs_rsh = parm["rsh"]
tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata)
data.setVar('TARFILES', dlfile, localdata)
data.setVar('TARFN', tarfn, localdata)
dl = os.path.join(dldir, tarfn)
if os.access(dl, os.R_OK):
bb.debug(1, "%s already exists, skipping cvs checkout." % tarfn)
continue
pn = data.getVar('PN', d, 1)
cvs_tarball_stash = None
if pn:
cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH_%s' % pn, d, 1)
if cvs_tarball_stash == None:
cvs_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
if cvs_tarball_stash:
fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
uri = cvs_tarball_stash + tarfn
bb.note("fetch " + uri)
fetchcmd = fetchcmd.replace("${URI}", uri)
ret = os.system(fetchcmd)
if ret == 0:
bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
continue
if date:
options.append("-D %s" % date)
if tag:
options.append("-r %s" % tag)
olddir = os.path.abspath(os.getcwd())
os.chdir(data.expand(dldir, localdata))
# setup cvsroot
if method == "dir":
cvsroot = path
else:
cvsroot = ":" + method + ":" + user
if pswd:
cvsroot += ":" + pswd
cvsroot += "@" + host + ":" + path
data.setVar('CVSROOT', cvsroot, localdata)
data.setVar('CVSCOOPTS', " ".join(options), localdata)
data.setVar('CVSMODULE', module, localdata)
cvscmd = data.getVar('FETCHCOMMAND', localdata, 1)
cvsupdatecmd = data.getVar('UPDATECOMMAND', localdata, 1)
if cvs_rsh:
cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd)
cvsupdatecmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvsupdatecmd)
# create module directory
bb.debug(2, "Fetch: checking for module directory")
pkg=data.expand('${PN}', d)
pkgdir=os.path.join(data.expand('${CVSDIR}', localdata), pkg)
moddir=os.path.join(pkgdir,localdir)
if os.access(os.path.join(moddir,'CVS'), os.R_OK):
bb.note("Update " + loc)
# update sources there
os.chdir(moddir)
myret = os.system(cvsupdatecmd)
else:
bb.note("Fetch " + loc)
# check out sources there
bb.mkdirhier(pkgdir)
os.chdir(pkgdir)
bb.debug(1, "Running %s" % cvscmd)
myret = os.system(cvscmd)
if myret != 0:
try:
os.rmdir(moddir)
except OSError:
pass
raise FetchError(module)
os.chdir(moddir)
os.chdir('..')
# tar them up to a defined filename
myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(moddir)))
if myret != 0:
try:
os.unlink(tarfn)
except OSError:
pass
os.chdir(olddir)
del localdata
methods.append(Cvs())
class Bk(Fetch):
def supports(url, d):
"""Check to see if a given url can be fetched via bitkeeper.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
return type in ['bk']
supports = staticmethod(supports)
methods.append(Bk())
class Local(Fetch):
def supports(url, d):
"""Check to see if a given url can be fetched in the local filesystem.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
return type in ['file','patch']
supports = staticmethod(supports)
def localpath(url, d):
"""Return the local filename of a given url assuming a successful fetch.
"""
path = url.split("://")[1]
newpath = path
if path[0] != "/":
filespath = data.getVar('FILESPATH', d, 1)
if filespath:
newpath = bb.which(filespath, path)
if not newpath:
filesdir = data.getVar('FILESDIR', d, 1)
if filesdir:
newpath = os.path.join(filesdir, path)
return newpath
localpath = staticmethod(localpath)
def go(self, urls = []):
"""Fetch urls (no-op for Local method)"""
# no need to fetch local files, we'll deal with them in place.
return 1
methods.append(Local())
class Svn(Fetch):
"""Class to fetch a module or modules from svn repositories"""
def supports(url, d):
"""Check to see if a given url can be fetched with svn.
Expects supplied url in list form, as outputted by bb.decodeurl().
"""
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
return type in ['svn']
supports = staticmethod(supports)
def localpath(url, d):
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
if "localpath" in parm:
# if user overrides local path, use it.
return parm["localpath"]
if not "module" in parm:
raise MissingParameterError("svn method needs a 'module' parameter")
else:
module = parm["module"]
if 'rev' in parm:
revision = parm['rev']
else:
revision = ""
date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
return os.path.join(data.getVar("DL_DIR", d, 1),data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, revision, date), d))
localpath = staticmethod(localpath)
def go(self, d, urls = []):
"""Fetch urls"""
if not urls:
urls = self.urls
localdata = data.createCopy(d)
data.setVar('OVERRIDES', "svn:%s" % data.getVar('OVERRIDES', localdata), localdata)
data.update_data(localdata)
for loc in urls:
(type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, localdata))
if not "module" in parm:
raise MissingParameterError("svn method needs a 'module' parameter")
else:
module = parm["module"]
dlfile = self.localpath(loc, localdata)
dldir = data.getVar('DL_DIR', localdata, 1)
# if local path contains the svn
# module, consider the dir above it to be the
# download directory
# pos = dlfile.find(module)
# if pos:
# dldir = dlfile[:pos]
# else:
# dldir = os.path.dirname(dlfile)
# setup svn options
options = []
if 'rev' in parm:
revision = parm['rev']
else:
revision = ""
date = data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
if "method" in parm:
method = parm["method"]
else:
method = "pserver"
if "proto" in parm:
proto = parm["proto"]
else:
proto = "svn"
svn_rsh = None
if method == "ext":
if "rsh" in parm:
svn_rsh = parm["rsh"]
tarfn = data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, revision, date), localdata)
data.setVar('TARFILES', dlfile, localdata)
data.setVar('TARFN', tarfn, localdata)
dl = os.path.join(dldir, tarfn)
if os.access(dl, os.R_OK):
bb.debug(1, "%s already exists, skipping svn checkout." % tarfn)
continue
svn_tarball_stash = data.getVar('CVS_TARBALL_STASH', d, 1)
if svn_tarball_stash:
fetchcmd = data.getVar("FETCHCOMMAND_wget", d, 1)
uri = svn_tarball_stash + tarfn
bb.note("fetch " + uri)
fetchcmd = fetchcmd.replace("${URI}", uri)
ret = os.system(fetchcmd)
if ret == 0:
bb.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
continue
olddir = os.path.abspath(os.getcwd())
os.chdir(data.expand(dldir, localdata))
# setup svnroot
# svnroot = ":" + method + ":" + user
# if pswd:
# svnroot += ":" + pswd
svnroot = host + path
data.setVar('SVNROOT', svnroot, localdata)
data.setVar('SVNCOOPTS', " ".join(options), localdata)
data.setVar('SVNMODULE', module, localdata)
svncmd = data.getVar('FETCHCOMMAND', localdata, 1)
svncmd = "svn co %s://%s/%s" % (proto, svnroot, module)
if revision:
svncmd = "svn co -r %s %s://%s/%s" % (revision, proto, svnroot, module)
if svn_rsh:
svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
# create temp directory
bb.debug(2, "Fetch: creating temporary directory")
bb.mkdirhier(data.expand('${WORKDIR}', localdata))
data.setVar('TMPBASE', data.expand('${WORKDIR}/oesvn.XXXXXX', localdata), localdata)
tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
tmpfile = tmppipe.readline().strip()
if not tmpfile:
bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
raise FetchError(module)
# check out sources there
os.chdir(tmpfile)
bb.note("Fetch " + loc)
bb.debug(1, "Running %s" % svncmd)
myret = os.system(svncmd)
if myret != 0:
try:
os.rmdir(tmpfile)
except OSError:
pass
raise FetchError(module)
os.chdir(os.path.join(tmpfile, os.path.dirname(module)))
# tar them up to a defined filename
myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module)))
if myret != 0:
try:
os.unlink(tarfn)
except OSError:
pass
# cleanup
os.system('rm -rf %s' % tmpfile)
os.chdir(olddir)
del localdata
methods.append(Svn())
Binary file not shown.
Binary file not shown.
+144
View File
@@ -0,0 +1,144 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (C) 2003, 2004 Chris Larson
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA.
import os, sys
import bb, bb.data
def getfields(line):
fields = {}
fieldmap = ( "pkg", "src", "dest", "type", "mode", "uid", "gid", "major", "minor", "start", "inc", "count" )
for f in xrange(len(fieldmap)):
fields[fieldmap[f]] = None
if not line:
return None
splitline = line.split()
if not len(splitline):
return None
try:
for f in xrange(len(fieldmap)):
if splitline[f] == '-':
continue
fields[fieldmap[f]] = splitline[f]
except IndexError:
pass
return fields
def parse (mfile, d):
manifest = []
while 1:
line = mfile.readline()
if not line:
break
if line.startswith("#"):
continue
fields = getfields(line)
if not fields:
continue
manifest.append(fields)
return manifest
def emit (func, manifest, d):
#str = "%s () {\n" % func
str = ""
for line in manifest:
emittedline = emit_line(func, line, d)
if not emittedline:
continue
str += emittedline + "\n"
# str += "}\n"
return str
def mangle (func, line, d):
import copy
newline = copy.copy(line)
src = bb.data.expand(newline["src"], d)
if src:
if not os.path.isabs(src):
src = "${WORKDIR}/" + src
dest = newline["dest"]
if not dest:
return
if dest.startswith("/"):
dest = dest[1:]
if func is "do_install":
dest = "${D}/" + dest
elif func is "do_populate":
dest = "${WORKDIR}/install/" + newline["pkg"] + "/" + dest
elif func is "do_stage":
varmap = {}
varmap["${bindir}"] = "${STAGING_DIR}/${HOST_SYS}/bin"
varmap["${libdir}"] = "${STAGING_DIR}/${HOST_SYS}/lib"
varmap["${includedir}"] = "${STAGING_DIR}/${HOST_SYS}/include"
varmap["${datadir}"] = "${STAGING_DATADIR}"
matched = 0
for key in varmap.keys():
if dest.startswith(key):
dest = varmap[key] + "/" + dest[len(key):]
matched = 1
if not matched:
newline = None
return
else:
newline = None
return
newline["src"] = src
newline["dest"] = dest
return newline
def emit_line (func, line, d):
import copy
newline = copy.deepcopy(line)
newline = mangle(func, newline, d)
if not newline:
return None
str = ""
type = newline["type"]
mode = newline["mode"]
src = newline["src"]
dest = newline["dest"]
if type is "d":
str = "install -d "
if mode:
str += "-m %s " % mode
str += dest
elif type is "f":
if not src:
return None
if dest.endswith("/"):
str = "install -d "
str += dest + "\n"
str += "install "
else:
str = "install -D "
if mode:
str += "-m %s " % mode
str += src + " " + dest
del newline
return str
Binary file not shown.
Binary file not shown.
Binary file not shown.
+70
View File
@@ -0,0 +1,70 @@
"""
BitBake Parsers
File parsers for the BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2003, 2004 Phil Blundell
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
__all__ = [ 'ParseError', 'SkipPackage', 'cached_mtime', 'mark_dependency',
'supports', 'handle', 'init' ]
handlers = []
class ParseError(Exception):
"""Exception raised when parsing fails"""
class SkipPackage(Exception):
"""Exception raised to skip this package"""
__mtime_cache = {}
def cached_mtime(f):
import os
if not __mtime_cache.has_key(f):
__mtime_cache[f] = os.stat(f)[8]
return __mtime_cache[f]
def mark_dependency(d, f):
import bb, os
if f.startswith('./'):
f = "%s/%s" % (os.getcwd(), f[2:])
deps = (bb.data.getVar('__depends', d) or "").split()
deps.append("%s@%s" % (f, cached_mtime(f)))
bb.data.setVar('__depends', " ".join(deps), d)
def supports(fn, data):
"""Returns true if we have a handler for this file, false otherwise"""
for h in handlers:
if h['supports'](fn, data):
return 1
return 0
def handle(fn, data, include = 0):
"""Call the handler that is appropriate for this file"""
for h in handlers:
if h['supports'](fn, data):
return h['handle'](fn, data, include)
raise ParseError("%s is not a BitBake file" % fn)
def init(fn, data):
for h in handlers:
if h['supports'](fn):
return h['init'](data)
from parse_py import __version__, ConfHandler, BBHandler
Binary file not shown.
@@ -0,0 +1,288 @@
/* bbf.flex
written by Marc Singer
6 January 2005
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
DESCRIPTION
-----------
flex lexer specification for a BitBake input file parser.
Unfortunately, flex doesn't welcome comments within the rule sets.
I say unfortunately because this lexer is unreasonably complex and
comments would make the code much easier to comprehend.
The BitBake grammar is not regular. In order to interpret all
of the available input files, the lexer maintains much state as it
parses. There are places where this lexer will emit tokens that
are invalid. The parser will tend to catch these.
The lexer requires C++ at the moment. The only reason for this has
to do with a very small amount of managed state. Producing a C
lexer should be a reasonably easy task as long as the %reentrant
option is used.
NOTES
-----
o RVALUES. There are three kinds of RVALUES. There are unquoted
values, double quote enclosed strings, and single quote
strings. Quoted strings may contain unescaped quotes (of either
type), *and* any type may span more than one line by using a
continuation '\' at the end of the line. This requires us to
recognize all types of values with a single expression.
Moreover, the only reason to quote a value is to include
trailing or leading whitespace. Whitespace within a value is
preserved, ugh.
o CLASSES. C_ patterns define classes. Classes ought not include
a repitition operator, instead letting the reference to the class
define the repitition count.
C_SS - symbol start
C_SB - symbol body
C_SP - whitespace
*/
%option never-interactive
%option yylineno
%option noyywrap
%option reentrant stack
%{
#include "token.h"
#include "lexer.h"
#include <ctype.h>
extern void *bbparseAlloc(void *(*mallocProc)(size_t));
extern void bbparseFree(void *p, void (*freeProc)(void*));
extern void *bbparseAlloc(void *(*mallocProc)(size_t));
extern void *bbparse(void*, int, token_t, lex_t*);
extern void bbparseTrace(FILE *TraceFILE, char *zTracePrompt);
//static const char* rgbInput;
//static size_t cbInput;
int lineError;
int errorParse;
enum {
errorNone = 0,
errorUnexpectedInput,
errorUnsupportedFeature,
};
#define YY_EXTRA_TYPE lex_t*
/* Read from buffer */
#define YY_INPUT(buf,result,max_size) \
{ yyextra->input(buf, &result, max_size); }
//#define YY_DECL static size_t yylex ()
#define ERROR(e) \
do { lineError = yylineno; errorParse = e; yyterminate (); } while (0)
static const char* fixup_escapes (const char* sz);
%}
C_SP [ \t]
COMMENT #.*\n
OP_ASSIGN "="
OP_IMMEDIATE ":="
OP_PREPEND "=+"
OP_APPEND "+="
OP_COND "?="
B_OPEN "{"
B_CLOSE "}"
K_ADDTASK "addtask"
K_ADDHANDLER "addhandler"
K_AFTER "after"
K_BEFORE "before"
K_DEF "def"
K_INCLUDE "include"
K_INHERIT "inherit"
K_PYTHON "python"
K_FAKEROOT "fakeroot"
K_EXPORT "export"
K_EXPORT_FUNC "EXPORT_FUNCTIONS"
STRING \"([^\n\r]|"\\\n")*\"
SSTRING \'([^\n\r]|"\\\n")*\'
VALUE ([^'" \t\n])|([^'" \t\n]([^\n]|(\\\n))*[^'" \t\n])
C_SS [a-zA-Z_]
C_SB [a-zA-Z0-9_+-.]
REF $\{{C_SS}{C_SB}*\}
SYMBOL {C_SS}{C_SB}*
VARIABLE $?{C_SS}({C_SB}*|{REF})*(\[[a-zA-Z0-9_]*\])?
FILENAME ([a-zA-Z_./]|{REF})(([-+a-zA-Z0-9_./]*)|{REF})*
PROC \({C_SP}*\)
%s S_DEF
%s S_DEF_ARGS
%s S_DEF_BODY
%s S_FUNC
%s S_INCLUDE
%s S_INHERIT
%s S_PROC
%s S_RVALUE
%s S_TASK
%%
{OP_APPEND} { BEGIN S_RVALUE;
yyextra->accept (T_OP_APPEND); }
{OP_PREPEND} { BEGIN S_RVALUE;
yyextra->accept (T_OP_PREPEND); }
{OP_IMMEDIATE} { BEGIN S_RVALUE;
yyextra->accept (T_OP_IMMEDIATE); }
{OP_ASSIGN} { BEGIN S_RVALUE;
yyextra->accept (T_OP_ASSIGN); }
{OP_COND} { BEGIN S_RVALUE;
yyextra->accept (T_OP_COND); }
<S_RVALUE>\\\n{C_SP}* { }
<S_RVALUE>{STRING} { BEGIN INITIAL;
size_t cb = yyleng;
while (cb && isspace (yytext[cb - 1]))
--cb;
yytext[cb - 1] = 0;
yyextra->accept (T_STRING, yytext + 1); }
<S_RVALUE>{SSTRING} { BEGIN INITIAL;
size_t cb = yyleng;
while (cb && isspace (yytext[cb - 1]))
--cb;
yytext[cb - 1] = 0;
yyextra->accept (T_STRING, yytext + 1); }
<S_RVALUE>{VALUE} { ERROR (errorUnexpectedInput); }
<S_RVALUE>{C_SP}*\n+ { BEGIN INITIAL;
yyextra->accept (T_STRING, NULL); }
{K_INCLUDE} { BEGIN S_INCLUDE;
yyextra->accept (T_INCLUDE); }
{K_INHERIT} { BEGIN S_INHERIT;
yyextra->accept (T_INHERIT); }
{K_ADDTASK} { BEGIN S_TASK;
yyextra->accept (T_ADDTASK); }
{K_ADDHANDLER} { yyextra->accept (T_ADDHANDLER); }
{K_EXPORT_FUNC} { BEGIN S_FUNC;
yyextra->accept (T_EXPORT_FUNC); }
<S_TASK>{K_BEFORE} { yyextra->accept (T_BEFORE); }
<S_TASK>{K_AFTER} { yyextra->accept (T_AFTER); }
<INITIAL>{K_EXPORT} { yyextra->accept (T_EXPORT); }
<INITIAL>{K_FAKEROOT} { yyextra->accept (T_FAKEROOT); }
<INITIAL>{K_PYTHON} { yyextra->accept (T_PYTHON); }
{PROC}{C_SP}*{B_OPEN}{C_SP}*\n* { BEGIN S_PROC;
yyextra->accept (T_PROC_OPEN); }
<S_PROC>{B_CLOSE}{C_SP}*\n* { BEGIN INITIAL;
yyextra->accept (T_PROC_CLOSE); }
<S_PROC>([^}][^\n]*)?\n* { yyextra->accept (T_PROC_BODY, yytext); }
{K_DEF} { BEGIN S_DEF; }
<S_DEF>{SYMBOL} { BEGIN S_DEF_ARGS;
yyextra->accept (T_SYMBOL, yytext); }
<S_DEF_ARGS>[^\n:]*: { yyextra->accept (T_DEF_ARGS, yytext); }
<S_DEF_ARGS>{C_SP}*\n { BEGIN S_DEF_BODY; }
<S_DEF_BODY>{C_SP}+[^\n]*\n { yyextra->accept (T_DEF_BODY, yytext); }
<S_DEF_BODY>\n { yyextra->accept (T_DEF_BODY, yytext); }
<S_DEF_BODY>. { BEGIN INITIAL; unput (yytext[0]); }
{COMMENT} { }
<INITIAL>{SYMBOL} { yyextra->accept (T_SYMBOL, yytext); }
<INITIAL>{VARIABLE} { yyextra->accept (T_VARIABLE, yytext); }
<S_TASK>{SYMBOL} { yyextra->accept (T_TSYMBOL, yytext); }
<S_FUNC>{SYMBOL} { yyextra->accept (T_FSYMBOL, yytext); }
<S_INHERIT>{SYMBOL} { yyextra->accept (T_ISYMBOL, yytext); }
<S_INCLUDE>{FILENAME} { BEGIN INITIAL;
yyextra->accept (T_ISYMBOL, yytext); }
<S_TASK>\n { BEGIN INITIAL; }
<S_FUNC>\n { BEGIN INITIAL; }
<S_INHERIT>\n { BEGIN INITIAL; }
[ \t\r\n] /* Insignificant whitespace */
. { ERROR (errorUnexpectedInput); }
/* Check for premature termination */
<<EOF>> { return T_EOF; }
%%
void lex_t::accept (int token, const char* sz)
{
token_t t;
memset (&t, 0, sizeof (t));
t.copyString(sz);
/* tell lemon to parse the token */
parse (parser, token, t, this);
}
int lex_t::line ()const
{
return yyget_lineno (scanner);
}
const char* lex_t::filename ()const
{
return m_fileName;
}
void parse (MappedFile* mf)
{
void* parser = bbparseAlloc (malloc);
yyscan_t scanner;
lex_t lex;
yylex_init (&scanner);
lex.parser = parser;
lex.scanner = scanner;
lex.mf = mf;
lex.rgbInput = mf->m_rgb;
lex.cbInput = mf->m_cb;
lex.parse = bbparse;
yyset_extra (&lex, scanner);
int result = yylex (scanner);
lex.accept (0);
bbparseTrace (NULL, NULL);
if (result != T_EOF)
WARNING ("premature end of file\n");
yylex_destroy (scanner);
bbparseFree (parser, free);
}
@@ -0,0 +1,133 @@
"""
BitBake C Parser Python Code
Copyright (C) 2005 Holger Hans Peter Freyther
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
__version__ = "0xdeadbeef"
class CParser:
"""
The C-based Parser for Bitbake
"""
def __init__(self, data, type):
"""
Constructor
"""
self._data = data
def _syntax_error(self, file, line):
"""
lemon/flex reports an syntax error to us and we will
raise an exception
"""
pass
def _export(self, data):
"""
EXPORT VAR = "MOO"
we will now export VAR
"""
pass
def _assign(self, key, value):
"""
VAR = "MOO"
we will assign moo to VAR
"""
pass
def _assign(self, key, value):
"""
"""
pass
def _append(self, key, value):
"""
VAR += "MOO"
we will append " MOO" to var
"""
pass
def _prepend(self, key, value):
"""
VAR =+ "MOO"
we will prepend "MOO " to var
"""
pass
def _immediate(self, key, value):
"""
VAR := "MOO ${CVSDATE}"
we will assign immediately and expand vars
"""
pass
def _conditional(self, key, value):
"""
"""
pass
def _add_task(self, task, before = None, after = None):
"""
"""
pass
def _include(self, file):
"""
"""
pass
def _inherit(self, file):
"""
"""
pass
def _shell_procedure(self, name, body):
"""
"""
pass
def _python_procedure(self, name, body):
"""
"""
pass
def _fakeroot_procedure(self, name, body):
"""
"""
pass
def _def_procedure(self, a, b, c):
"""
"""
pass
def _export_func(self, name):
"""
"""
pass
def _add_handler(self, handler):
"""
"""
pass
@@ -0,0 +1,161 @@
/* bbp.lemon
written by Marc Singer
6 January 2005
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
DESCRIPTION
-----------
lemon parser specification file for a BitBake input file parser.
Most of the interesting shenanigans are done in the lexer. The
BitBake grammar is not regular. In order to emit tokens that
the parser can properly interpret in LALR fashion, the lexer
manages the interpretation state. This is why there are ISYMBOLs,
SYMBOLS, and TSYMBOLS.
This parser was developed by reading the limited available
documentation for BitBake and by analyzing the available BB files.
There is no assertion of correctness to be made about this parser.
*/
%token_type {token_t}
%name bbparse
%token_prefix T_
%extra_argument {lex_t* lex}
%include {
#include "token.h"
}
%token_destructor { $$.release_this (); }
%syntax_error { printf ("%s:%d: syntax error\n",
lex->filename (), lex->line ()); }
program ::= statements.
statements ::= statements statement.
statements ::= .
variable(r) ::= SYMBOL(s).
{ r.assignString( s.string() );
s.assignString( 0 );
s.release_this(); }
variable(r) ::= VARIABLE(v).
{
r.assignString( v.string() );
v.assignString( 0 );
v.release_this(); }
statement ::= EXPORT variable(s) OP_ASSIGN STRING(v).
{ e_assign( s.string(), v.string() );
e_export( s.string() );
s.release_this(); v.release_this(); }
statement ::= EXPORT variable(s) OP_IMMEDIATE STRING(v).
{ e_immediate (s.string(), v.string() );
e_export( s.string() );
s.release_this(); v.release_this(); }
statement ::= EXPORT variable(s) OP_COND STRING(v).
{ e_cond( s.string(), v.string() );
s.release_this(); v.release_this(); }
statement ::= variable(s) OP_ASSIGN STRING(v).
{ e_assign( s.string(), v.string() );
s.release_this(); v.release_this(); }
statement ::= variable(s) OP_PREPEND STRING(v).
{ e_prepend( s.string(), v.string() );
s.release_this(); v.release_this(); }
statement ::= variable(s) OP_APPEND STRING(v).
{ e_append( s.string() , v.string() );
s.release_this(); v.release_this(); }
statement ::= variable(s) OP_IMMEDIATE STRING(v).
{ e_immediate( s.string(), v.string() );
s.release_this(); v.release_this(); }
statement ::= variable(s) OP_COND STRING(v).
{ e_cond( s.string(), v.string() );
s.release_this(); v.release_this(); }
task ::= TSYMBOL(t) BEFORE TSYMBOL(b) AFTER TSYMBOL(a).
{ e_addtask( t.string(), b.string(), a.string() );
t.release_this(); b.release_this(); a.release_this(); }
task ::= TSYMBOL(t) AFTER TSYMBOL(a) BEFORE TSYMBOL(b).
{ e_addtask( t.string(), b.string(), a.string());
t.release_this(); a.release_this(); b.release_this(); }
task ::= TSYMBOL(t).
{ e_addtask( t.string(), NULL, NULL);
t.release_this();}
task ::= TSYMBOL(t) BEFORE TSYMBOL(b).
{ e_addtask( t.string(), b.string(), NULL);
t.release_this(); b.release_this(); }
task ::= TSYMBOL(t) AFTER TSYMBOL(a).
{ e_addtask( t.string(), NULL, a.string());
t.release_this(); a.release_this(); }
tasks ::= tasks task.
tasks ::= task.
statement ::= ADDTASK tasks.
statement ::= ADDHANDLER SYMBOL(s).
{ e_addhandler( s.string()); s.release_this (); }
func ::= FSYMBOL(f). { e_export_func(f.string()); f.release_this(); }
funcs ::= funcs func.
funcs ::= func.
statement ::= EXPORT_FUNC funcs.
inherit ::= ISYMBOL(i). { e_inherit(i.string() ); i.release_this (); }
inherits ::= inherits inherit.
inherits ::= inherit.
statement ::= INHERIT inherits.
statement ::= INCLUDE ISYMBOL(i).
{ e_include(i.string() ); i.release_this(); }
proc_body(r) ::= proc_body(l) PROC_BODY(b).
{ /* concatenate body lines */
r.assignString( token_t::concatString(l.string(), b.string()) );
l.release_this ();
b.release_this ();
}
proc_body(b) ::= . { b.assignString(0); }
statement ::= variable(p) PROC_OPEN proc_body(b) PROC_CLOSE.
{ e_proc( p.string(), b.string() );
p.release_this(); b.release_this(); }
statement ::= PYTHON SYMBOL(p) PROC_OPEN proc_body(b) PROC_CLOSE.
{ e_proc_python (p.string(), b.string() );
p.release_this(); b.release_this(); }
statement ::= PYTHON PROC_OPEN proc_body(b) PROC_CLOSE.
{ e_proc_python( NULL, b.string());
b.release_this (); }
statement ::= FAKEROOT SYMBOL(p) PROC_OPEN proc_body(b) PROC_CLOSE.
{ e_proc_fakeroot(p.string(), b.string() );
p.release_this (); b.release_this (); }
def_body(r) ::= def_body(l) DEF_BODY(b).
{ /* concatenate body lines */
r.assignString( token_t::concatString(l.string(), b.string());
l.release_this (); b.release_this ();
}
def_body(b) ::= . { b.sz = 0; }
statement ::= SYMBOL(p) DEF_ARGS(a) def_body(b).
{ e_def( p.string(), a.string(), b.string());
p.release_this(); a.release_this(); b.release_this(); }
+41
View File
@@ -0,0 +1,41 @@
/*
Copyright (C) 2005 Holger Hans Peter Freyther
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LEXER_H
#define LEXER_H
struct lex_t {
void *parser;
void *scanner;
void* (*parse)(void*, int, token_t, lex_t*);
void accept(int token, const char* string = 0);
void input(char *buf, int *result, int_max_size);
int line()const;
const char* filename()const;
private:
const char* m_fileName;
};
#endif
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright (C) 2005 Holger Hans Peter Freyther
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef TOKEN_H
#define TOKEN_H
#define PURE_METHOD
struct token_t {
const char* string()const PURE_METHOD;
static char* concatString(const char* l, const char* r);
void assignString(const char* str);
void copyString(const char* str);
void release_this();
private:
char *m_string;
size_t m_stringLen;
};
inline const char* token_t::string()const
{
return m_string;
}
/*
* append str to the current string
*/
inline char* token_t::concatString(const char* l, const char* r)
{
size_t cb = (l ? strlen (l) : 0) + strlen (r) + 1;
r_sz = new char[cb];
*r_sz = 0;
if (l) strcat (r_sz, l);
strcat (r_sz, r);
return r_sz;
}
inline void token_t::assignString(const char* str)
{
m_string = str;
m_stringLen = str ? strlen(str) : 0;
}
inline void token_t::copyString(const char* str)
{
if( str ) {
m_stringLen = strlen(str);
m_string = new char[m_stringLen+1];
strcpy(m_string, str)
}
}
inline void token_t::release_this()
{
delete m_string;
m_string = 0;
}
#endif
+378
View File
@@ -0,0 +1,378 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""class for handling .bb files
Reads a .bb file and obtains its metadata
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2003, 2004 Phil Blundell
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA."""
import re, bb, os, sys
import bb.fetch, bb.build
from bb import debug, data, fetch, fatal
from ConfHandler import include, localpath, obtain, init
from bb.parse import ParseError
__func_start_regexp__ = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
__inherit_regexp__ = re.compile( r"inherit\s+(.+)" )
__export_func_regexp__ = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
__addtask_regexp__ = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
__addhandler_regexp__ = re.compile( r"addhandler\s+(.+)" )
__def_regexp__ = re.compile( r"def\s+(\w+).*:" )
__python_func_regexp__ = re.compile( r"(\s+.*)|(^$)" )
__word__ = re.compile(r"\S+")
__infunc__ = ""
__inpython__ = False
__body__ = []
__bbpath_found__ = 0
__classname__ = ""
classes = [ None, ]
def supports(fn, d):
localfn = localpath(fn, d)
return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
def inherit(files, d):
__inherit_cache = data.getVar('__inherit_cache', d) or ""
fn = ""
lineno = 0
for f in files:
file = data.expand(f, d)
if file[0] != "/" and file[-8:] != ".bbclass":
file = os.path.join('classes', '%s.bbclass' % file)
if not file in __inherit_cache.split():
debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
__inherit_cache += " %s" % file
include(fn, file, d)
data.setVar('__inherit_cache', __inherit_cache, d)
def handle(fn, d, include = 0):
global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
__body__ = []
__bbpath_found__ = 0
__infunc__ = ""
__classname__ = ""
__residue__ = []
if include == 0:
debug(2, "BB " + fn + ": handle(data)")
else:
debug(2, "BB " + fn + ": handle(data, include)")
(root, ext) = os.path.splitext(os.path.basename(fn))
init(d)
if ext == ".bbclass":
__classname__ = root
classes.append(__classname__)
if include != 0:
oldfile = data.getVar('FILE', d)
else:
oldfile = None
fn = obtain(fn, d)
bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
if not os.path.isabs(fn):
f = None
for p in bbpath:
p = data.expand(p, d)
j = os.path.join(p, fn)
if os.access(j, os.R_OK):
abs_fn = j
f = open(j, 'r')
break
if f is None:
raise IOError("file not found")
else:
f = open(fn,'r')
abs_fn = fn
if ext != ".bbclass":
bbpath.insert(0, os.path.dirname(abs_fn))
data.setVar('BBPATH', ":".join(bbpath), d)
if include:
bb.parse.mark_dependency(d, abs_fn)
if ext != ".bbclass":
data.setVar('FILE', fn, d)
i = (data.getVar("INHERIT", d, 1) or "").split()
if not "base" in i and __classname__ != "base":
i[0:0] = ["base"]
inherit(i, d)
lineno = 0
while 1:
lineno = lineno + 1
s = f.readline()
if not s: break
s = s.rstrip()
feeder(lineno, s, fn, d)
if __inpython__:
# add a blank line to close out any python definition
feeder(lineno + 1, "", fn, d)
if ext == ".bbclass":
classes.remove(__classname__)
else:
if include == 0:
data.expandKeys(d)
data.update_data(d)
anonqueue = data.getVar("__anonqueue", d, 1) or []
for anon in anonqueue:
data.setVar("__anonfunc", anon["content"], d)
data.setVarFlags("__anonfunc", anon["flags"], d)
from bb import build
try:
t = data.getVar('T', d)
data.setVar('T', '${TMPDIR}/', d)
build.exec_func("__anonfunc", d)
data.delVar('T', d)
if t:
data.setVar('T', t, d)
except Exception, e:
bb.debug(1, "executing anonymous function: %s" % e)
raise
data.delVar("__anonqueue", d)
data.delVar("__anonfunc", d)
set_additional_vars(fn, d, include)
data.update_data(d)
for var in data.keys(d):
if data.getVarFlag(var, 'handler', d):
bb.event.register(data.getVar(var, d))
continue
if not data.getVarFlag(var, 'task', d):
continue
deps = data.getVarFlag(var, 'deps', d) or []
postdeps = data.getVarFlag(var, 'postdeps', d) or []
bb.build.add_task(var, deps, d)
for p in postdeps:
pdeps = data.getVarFlag(p, 'deps', d) or []
pdeps.append(var)
data.setVarFlag(p, 'deps', pdeps, d)
bb.build.add_task(p, pdeps, d)
bbpath.pop(0)
if oldfile:
bb.data.setVar("FILE", oldfile, d)
return d
def feeder(lineno, s, fn, d):
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__
if __infunc__:
if s == '}':
__body__.append('')
data.setVar(__infunc__, '\n'.join(__body__), d)
data.setVarFlag(__infunc__, "func", 1, d)
if __infunc__ == "__anonymous":
anonqueue = bb.data.getVar("__anonqueue", d) or []
anonitem = {}
anonitem["content"] = bb.data.getVar("__anonymous", d)
anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
anonqueue.append(anonitem)
bb.data.setVar("__anonqueue", anonqueue, d)
bb.data.delVarFlags("__anonymous", d)
bb.data.delVar("__anonymous", d)
__infunc__ = ""
__body__ = []
else:
__body__.append(s)
return
if __inpython__:
m = __python_func_regexp__.match(s)
if m:
__body__.append(s)
return
else:
text = '\n'.join(__body__)
comp = compile(text, "<bb>", "exec")
exec comp in __builtins__
__body__ = []
__inpython__ = False
funcs = data.getVar('__functions__', d) or ""
data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
# fall through
if s == '' or s[0] == '#': return # skip comments and empty lines
if s[-1] == '\\':
__residue__.append(s[:-1])
return
s = "".join(__residue__) + s
__residue__ = []
m = __func_start_regexp__.match(s)
if m:
__infunc__ = m.group("func") or "__anonymous"
key = __infunc__
if data.getVar(key, d):
# clean up old version of this piece of metadata, as its
# flags could cause problems
data.setVarFlag(key, 'python', None, d)
data.setVarFlag(key, 'fakeroot', None, d)
if m.group("py") is not None:
data.setVarFlag(key, "python", "1", d)
else:
data.delVarFlag(key, "python", d)
if m.group("fr") is not None:
data.setVarFlag(key, "fakeroot", "1", d)
else:
data.delVarFlag(key, "fakeroot", d)
return
m = __def_regexp__.match(s)
if m:
__body__.append(s)
__inpython__ = True
return
m = __export_func_regexp__.match(s)
if m:
fns = m.group(1)
n = __word__.findall(fns)
for f in n:
allvars = []
allvars.append(f)
allvars.append(classes[-1] + "_" + f)
vars = [[ allvars[0], allvars[1] ]]
if len(classes) > 1 and classes[-2] is not None:
allvars.append(classes[-2] + "_" + f)
vars = []
vars.append([allvars[2], allvars[1]])
vars.append([allvars[0], allvars[2]])
for (var, calledvar) in vars:
if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
continue
if data.getVar(var, d):
data.setVarFlag(var, 'python', None, d)
data.setVarFlag(var, 'func', None, d)
for flag in [ "func", "python" ]:
if data.getVarFlag(calledvar, flag, d):
data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
for flag in [ "dirs" ]:
if data.getVarFlag(var, flag, d):
data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
if data.getVarFlag(calledvar, "python", d):
data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
else:
data.setVar(var, "\t" + calledvar + "\n", d)
data.setVarFlag(var, 'export_func', '1', d)
return
m = __addtask_regexp__.match(s)
if m:
func = m.group("func")
before = m.group("before")
after = m.group("after")
if func is None:
return
var = "do_" + func
data.setVarFlag(var, "task", 1, d)
if after is not None:
# set up deps for function
data.setVarFlag(var, "deps", after.split(), d)
if before is not None:
# set up things that depend on this func
data.setVarFlag(var, "postdeps", before.split(), d)
return
m = __addhandler_regexp__.match(s)
if m:
fns = m.group(1)
hs = __word__.findall(fns)
for h in hs:
data.setVarFlag(h, "handler", 1, d)
return
m = __inherit_regexp__.match(s)
if m:
files = m.group(1)
n = __word__.findall(files)
inherit(n, d)
return
from bb.parse import ConfHandler
return ConfHandler.feeder(lineno, s, fn, d)
__pkgsplit_cache__={}
def vars_from_file(mypkg, d):
if not mypkg:
return (None, None, None)
if mypkg in __pkgsplit_cache__:
return __pkgsplit_cache__[mypkg]
myfile = os.path.splitext(os.path.basename(mypkg))
parts = myfile[0].split('_')
__pkgsplit_cache__[mypkg] = parts
exp = 3 - len(parts)
tmplist = []
while exp != 0:
exp -= 1
tmplist.append(None)
parts.extend(tmplist)
return parts
def set_additional_vars(file, d, include):
"""Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
debug(2,"BB %s: set_additional_vars" % file)
src_uri = data.getVar('SRC_URI', d)
if not src_uri:
return
src_uri = data.expand(src_uri, d)
a = data.getVar('A', d)
if a:
a = data.expand(a, d).split()
else:
a = []
from bb import fetch
try:
fetch.init(src_uri.split(), d)
except fetch.NoMethodError:
pass
except bb.MalformedUrl,e:
raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
a += fetch.localpaths(d)
del fetch
data.setVar('A', " ".join(a), d)
# Add us to the handlers list
from bb.parse import handlers
handlers.append({'supports': supports, 'handle': handle, 'init': init})
del handlers
Binary file not shown.
@@ -0,0 +1,199 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""class for handling configuration data files
Reads a .conf file and obtains its metadata
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2003, 2004 Phil Blundell
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA."""
import re, bb.data, os, sys
from bb import debug, fatal
from bb.parse import ParseError
#__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)$")
__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)$")
__include_regexp__ = re.compile( r"include\s+(.+)" )
def init(data):
if not bb.data.getVar('TOPDIR', data):
bb.data.setVar('TOPDIR', os.getcwd(), data)
if not bb.data.getVar('BBPATH', data):
bb.data.setVar('BBPATH', os.path.join(sys.prefix, 'share', 'bitbake'), data)
def supports(fn, d):
return localpath(fn, d)[-5:] == ".conf"
def localpath(fn, d):
if os.path.exists(fn):
return fn
localfn = None
try:
localfn = bb.fetch.localpath(fn, d)
except bb.MalformedUrl:
pass
if not localfn:
localfn = fn
return localfn
def obtain(fn, data = bb.data.init()):
import sys, bb
fn = bb.data.expand(fn, data)
localfn = bb.data.expand(localpath(fn, data), data)
if localfn != fn:
dldir = bb.data.getVar('DL_DIR', data, 1)
if not dldir:
debug(1, "obtain: DL_DIR not defined")
return localfn
bb.mkdirhier(dldir)
try:
bb.fetch.init([fn])
except bb.fetch.NoMethodError:
(type, value, traceback) = sys.exc_info()
debug(1, "obtain: no method: %s" % value)
return localfn
try:
bb.fetch.go(data)
except bb.fetch.MissingParameterError:
(type, value, traceback) = sys.exc_info()
debug(1, "obtain: missing parameters: %s" % value)
return localfn
except bb.fetch.FetchError:
(type, value, traceback) = sys.exc_info()
debug(1, "obtain: failed: %s" % value)
return localfn
return localfn
def include(oldfn, fn, data = bb.data.init()):
if oldfn == fn: # prevent infinate recursion
return None
import bb
fn = bb.data.expand(fn, data)
oldfn = bb.data.expand(oldfn, data)
from bb.parse import handle
try:
ret = handle(fn, data, 1)
except IOError:
debug(2, "CONF file '%s' not found" % fn)
def handle(fn, data = bb.data.init(), include = 0):
if include:
inc_string = "including"
else:
inc_string = "reading"
init(data)
if include == 0:
bb.data.inheritFromOS(data)
oldfile = None
else:
oldfile = bb.data.getVar('FILE', data)
fn = obtain(fn, data)
bbpath = []
if not os.path.isabs(fn):
f = None
vbbpath = bb.data.getVar("BBPATH", data)
if vbbpath:
bbpath += vbbpath.split(":")
for p in bbpath:
currname = os.path.join(bb.data.expand(p, data), fn)
if os.access(currname, os.R_OK):
f = open(currname, 'r')
abs_fn = currname
debug(1, "CONF %s %s" % (inc_string, currname))
break
if f is None:
raise IOError("file not found")
else:
f = open(fn,'r')
debug(1, "CONF %s %s" % (inc_string,fn))
abs_fn = fn
if include:
bb.parse.mark_dependency(data, abs_fn)
lineno = 0
bb.data.setVar('FILE', fn, data)
while 1:
lineno = lineno + 1
s = f.readline()
if not s: break
w = s.strip()
if not w: continue # skip empty lines
s = s.rstrip()
if s[0] == '#': continue # skip comments
while s[-1] == '\\':
s2 = f.readline()[:-1].strip()
lineno = lineno + 1
s = s[:-1] + s2
feeder(lineno, s, fn, data)
if oldfile:
bb.data.setVar('FILE', oldfile, data)
return data
def feeder(lineno, s, fn, data = bb.data.init()):
m = __config_regexp__.match(s)
if m:
groupd = m.groupdict()
key = groupd["var"]
if "exp" in groupd and groupd["exp"] != None:
bb.data.setVarFlag(key, "export", 1, data)
if "ques" in groupd and groupd["ques"] != None:
val = bb.data.getVar(key, data)
if val == None:
val = groupd["value"]
elif "colon" in groupd and groupd["colon"] != None:
val = bb.data.expand(groupd["value"], data)
elif "append" in groupd and groupd["append"] != None:
val = "%s %s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
elif "prepend" in groupd and groupd["prepend"] != None:
val = "%s %s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
elif "postdot" in groupd and groupd["postdot"] != None:
val = "%s%s" % ((bb.data.getVar(key, data) or ""), groupd["value"])
elif "predot" in groupd and groupd["predot"] != None:
val = "%s%s" % (groupd["value"], (bb.data.getVar(key, data) or ""))
else:
val = groupd["value"]
if 'flag' in groupd and groupd['flag'] != None:
# bb.note("setVarFlag(%s, %s, %s, data)" % (key, groupd['flag'], val))
bb.data.setVarFlag(key, groupd['flag'], val, data)
else:
bb.data.setVar(key, val, data)
return
m = __include_regexp__.match(s)
if m:
s = bb.data.expand(m.group(1), data)
# debug(2, "CONF %s:%d: including %s" % (fn, lineno, s))
include(fn, s, data)
return
raise ParseError("%s:%d: unparsed line: '%s'" % (fn, lineno, s));
# Add us to the handlers list
from bb.parse import handlers
handlers.append({'supports': supports, 'handle': handle, 'init': init})
del handlers
Binary file not shown.
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake Parsers
File parsers for the BitBake build tools.
Copyright (C) 2003, 2004 Chris Larson
Copyright (C) 2003, 2004 Phil Blundell
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
Based on functions from the base bb module, Copyright 2003 Holger Schurig
"""
__version__ = '1.0'
__all__ = [ 'ConfHandler', 'BBHandler']
import ConfHandler
import BBHandler
Binary file not shown.
+779
View File
@@ -0,0 +1,779 @@
#!/usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
##########################################################################
#
# Copyright (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>, Vanille Media
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA.
#
##########################################################################
"""
BitBake Shell
IDEAS:
* list defined tasks per package
* list classes
* toggle force
* command to reparse just one (or more) bbfile(s)
* automatic check if reparsing is necessary (inotify?)
* frontend for bb file manipulation
* more shell-like features:
- output control, i.e. pipe output into grep, sort, etc.
- job control, i.e. bring running commands into background and foreground
* start parsing in background right after startup
* ncurses interface
PROBLEMS:
* force doesn't always work
* readline completion for commands with more than one parameters
"""
##########################################################################
# Import and setup global variables
##########################################################################
try:
set
except NameError:
from sets import Set as set
import sys, os, imp, readline, socket, httplib, urllib, commands, popen2, copy, shlex, Queue, fnmatch
imp.load_source( "bitbake", os.path.dirname( sys.argv[0] )+"/bitbake" )
from bb import data, parse, build, fatal
__version__ = "0.5.2"
__credits__ = """BitBake Shell Version %s (C) 2005 Michael 'Mickey' Lauer <mickey@Vanille.de>
Type 'help' for more information, press CTRL-D to exit.""" % __version__
cmds = {}
leave_mainloop = False
last_exception = None
cooker = None
parsed = False
initdata = None
debug = os.environ.get( "BBSHELL_DEBUG", "" )
##########################################################################
# Class BitBakeShellCommands
##########################################################################
class BitBakeShellCommands:
"""This class contains the valid commands for the shell"""
def __init__( self, shell ):
"""Register all the commands"""
self._shell = shell
for attr in BitBakeShellCommands.__dict__:
if not attr.startswith( "_" ):
if attr.endswith( "_" ):
command = attr[:-1].lower()
else:
command = attr[:].lower()
method = getattr( BitBakeShellCommands, attr )
debugOut( "registering command '%s'" % command )
# scan number of arguments
usage = getattr( method, "usage", "" )
if usage != "<...>":
numArgs = len( usage.split() )
else:
numArgs = -1
shell.registerCommand( command, method, numArgs, "%s %s" % ( command, usage ), method.__doc__ )
def _checkParsed( self ):
if not parsed:
print "SHELL: This command needs to parse bbfiles..."
self.parse( None )
def _findProvider( self, item ):
self._checkParsed()
preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
if not preferred: preferred = item
try:
lv, lf, pv, pf = cooker.findBestProvider( preferred )
except KeyError:
if item in cooker.status.providers:
pf = cooker.status.providers[item][0]
else:
pf = None
return pf
def alias( self, params ):
"""Register a new name for a command"""
new, old = params
if not old in cmds:
print "ERROR: Command '%s' not known" % old
else:
cmds[new] = cmds[old]
print "OK"
alias.usage = "<alias> <command>"
def buffer( self, params ):
"""Dump specified output buffer"""
index = params[0]
print self._shell.myout.buffer( int( index ) )
buffer.usage = "<index>"
def buffers( self, params ):
"""Show the available output buffers"""
commands = self._shell.myout.bufferedCommands()
if not commands:
print "SHELL: No buffered commands available yet. Start doing something."
else:
print "="*35, "Available Output Buffers", "="*27
for index, cmd in enumerate( commands ):
print "| %s %s" % ( str( index ).ljust( 3 ), cmd )
print "="*88
def build( self, params, cmd = "build" ):
"""Build a providee"""
globexpr = params[0]
self._checkParsed()
names = globfilter( cooker.status.pkg_pn.keys(), globexpr )
if len( names ) == 0: names = [ globexpr ]
print "SHELL: Building %s" % ' '.join( names )
oldcmd = cooker.configuration.cmd
cooker.configuration.cmd = cmd
cooker.build_cache = []
cooker.build_cache_fail = []
for name in names:
try:
cooker.buildProvider( name )
except build.EventException, e:
print "ERROR: Couldn't build '%s'" % name
global last_exception
last_exception = e
break
cooker.configuration.cmd = oldcmd
build.usage = "<providee>"
def clean( self, params ):
"""Clean a providee"""
self.build( params, "clean" )
clean.usage = "<providee>"
def compile( self, params ):
"""Execute 'compile' on a providee"""
self.build( params, "compile" )
compile.usage = "<providee>"
def configure( self, params ):
"""Execute 'configure' on a providee"""
self.build( params, "configure" )
configure.usage = "<providee>"
def edit( self, params ):
"""Call $EDITOR on a providee"""
name = params[0]
bbfile = self._findProvider( name )
if bbfile is not None:
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), bbfile ) )
else:
print "ERROR: Nothing provides '%s'" % name
edit.usage = "<providee>"
def environment( self, params ):
"""Dump out the outer BitBake environment (see bbread)"""
data.emit_env(sys.__stdout__, cooker.configuration.data, True)
def exit_( self, params ):
"""Leave the BitBake Shell"""
debugOut( "setting leave_mainloop to true" )
global leave_mainloop
leave_mainloop = True
def fetch( self, params ):
"""Fetch a providee"""
self.build( params, "fetch" )
fetch.usage = "<providee>"
def fileBuild( self, params, cmd = "build" ):
"""Parse and build a .bb file"""
name = params[0]
bf = completeFilePath( name )
print "SHELL: Calling '%s' on '%s'" % ( cmd, bf )
oldcmd = cooker.configuration.cmd
cooker.configuration.cmd = cmd
cooker.build_cache = []
cooker.build_cache_fail = []
thisdata = copy.deepcopy( initdata )
# Caution: parse.handle modifies thisdata, hence it would
# lead to pollution cooker.configuration.data, which is
# why we use it on a safe copy we obtained from cooker right after
# parsing the initial *.conf files
try:
bbfile_data = parse.handle( bf, thisdata )
except parse.ParseError:
print "ERROR: Unable to open or parse '%s'" % bf
else:
item = data.getVar('PN', bbfile_data, 1)
data.setVar( "_task_cache", [], bbfile_data ) # force
try:
cooker.tryBuildPackage( os.path.abspath( bf ), item, bbfile_data )
except build.EventException, e:
print "ERROR: Couldn't build '%s'" % name
global last_exception
last_exception = e
cooker.configuration.cmd = oldcmd
fileBuild.usage = "<bbfile>"
def fileClean( self, params ):
"""Clean a .bb file"""
self.fileBuild( params, "clean" )
fileClean.usage = "<bbfile>"
def fileEdit( self, params ):
"""Call $EDITOR on a .bb file"""
name = params[0]
os.system( "%s %s" % ( os.environ.get( "EDITOR", "vi" ), completeFilePath( name ) ) )
fileEdit.usage = "<bbfile>"
def fileRebuild( self, params ):
"""Rebuild (clean & build) a .bb file"""
self.fileClean( params )
self.fileBuild( params )
fileRebuild.usage = "<bbfile>"
def force( self, params ):
"""Toggle force task execution flag (see bitbake -f)"""
cooker.configuration.force = not cooker.configuration.force
print "SHELL: Force Flag is now '%s'" % repr( cooker.configuration.force )
def help( self, params ):
"""Show a comprehensive list of commands and their purpose"""
print "="*30, "Available Commands", "="*30
allcmds = cmds.keys()
allcmds.sort()
for cmd in allcmds:
function,numparams,usage,helptext = cmds[cmd]
print "| %s | %s" % (usage.ljust(30), helptext)
print "="*78
def lastError( self, params ):
"""Show the reason or log that was produced by the last BitBake event exception"""
if last_exception is None:
print "SHELL: No Errors yet (Phew)..."
else:
reason, event = last_exception.args
print "SHELL: Reason for the last error: '%s'" % reason
if ':' in reason:
msg, filename = reason.split( ':' )
filename = filename.strip()
print "SHELL: Dumping log file for last error:"
try:
print open( filename ).read()
except IOError:
print "ERROR: Couldn't open '%s'" % filename
def match( self, params ):
"""Dump all files or providers matching a glob expression"""
what, globexpr = params
if what == "files":
self._checkParsed()
for key in globfilter( cooker.pkgdata.keys(), globexpr ): print key
elif what == "providers":
self._checkParsed()
for key in globfilter( cooker.status.pkg_pn.keys(), globexpr ): print key
else:
print "Usage: match %s" % self.print_.usage
match.usage = "<files|providers> <glob>"
def new( self, params ):
"""Create a new .bb file and open the editor"""
dirname, filename = params
packages = '/'.join( data.getVar( "BBFILES", cooker.configuration.data, 1 ).split('/')[:-2] )
fulldirname = "%s/%s" % ( packages, dirname )
if not os.path.exists( fulldirname ):
print "SHELL: Creating '%s'" % fulldirname
os.mkdir( fulldirname )
if os.path.exists( fulldirname ) and os.path.isdir( fulldirname ):
if os.path.exists( "%s/%s" % ( fulldirname, filename ) ):
print "SHELL: ERROR: %s/%s already exists" % ( fulldirname, filename )
return False
print "SHELL: Creating '%s/%s'" % ( fulldirname, filename )
newpackage = open( "%s/%s" % ( fulldirname, filename ), "w" )
print >>newpackage,"""DESCRIPTION = ""
SECTION = ""
AUTHOR = ""
HOMEPAGE = ""
MAINTAINER = ""
LICENSE = "GPL"
PR = "r0"
SRC_URI = ""
#inherit base
#do_configure() {
#
#}
#do_compile() {
#
#}
#do_stage() {
#
#}
#do_install() {
#
#}
"""
newpackage.close()
os.system( "%s %s/%s" % ( os.environ.get( "EDITOR" ), fulldirname, filename ) )
new.usage = "<directory> <filename>"
def pasteBin( self, params ):
"""Send a command + output buffer to http://pastebin.com"""
index = params[0]
contents = self._shell.myout.buffer( int( index ) )
status, error, location = sendToPastebin( contents )
if status == 302:
print "SHELL: Pasted to %s" % location
else:
print "ERROR: %s %s" % ( status, error )
pasteBin.usage = "<index>"
def pasteLog( self, params ):
"""Send the last event exception error log (if there is one) to http://pastebin.com"""
if last_exception is None:
print "SHELL: No Errors yet (Phew)..."
else:
reason, event = last_exception.args
print "SHELL: Reason for the last error: '%s'" % reason
if ':' in reason:
msg, filename = reason.split( ':' )
filename = filename.strip()
print "SHELL: Pasting log file to pastebin..."
status, error, location = sendToPastebin( open( filename ).read() )
if status == 302:
print "SHELL: Pasted to %s" % location
else:
print "ERROR: %s %s" % ( status, error )
def patch( self, params ):
"""Execute 'patch' command on a providee"""
self.build( params, "patch" )
patch.usage = "<providee>"
def parse( self, params ):
"""(Re-)parse .bb files and calculate the dependency graph"""
cooker.status = cooker.ParsingStatus()
ignore = data.getVar("ASSUME_PROVIDED", cooker.configuration.data, 1) or ""
cooker.status.ignored_dependencies = set( ignore.split() )
cooker.handleCollections( data.getVar("BBFILE_COLLECTIONS", cooker.configuration.data, 1) )
cooker.collect_bbfiles( cooker.myProgressCallback )
cooker.buildDepgraph()
global parsed
parsed = True
print
def getvar( self, params ):
"""Dump the contents of an outer BitBake environment variable"""
var = params[0]
value = data.getVar( var, cooker.configuration.data, 1 )
print value
getvar.usage = "<variable>"
def peek( self, params ):
"""Dump contents of variable defined in providee's metadata"""
name, var = params
bbfile = self._findProvider( name )
if bbfile is not None:
value = cooker.pkgdata[bbfile].getVar( var, 1 )
print value
else:
print "ERROR: Nothing provides '%s'" % name
peek.usage = "<providee> <variable>"
def poke( self, params ):
"""Set contents of variable defined in providee's metadata"""
name, var, value = params
bbfile = self._findProvider( name )
d = cooker.pkgdata[bbfile]
if bbfile is not None:
data.setVar( var, value, d )
# mark the change semi persistant
cooker.pkgdata.setDirty(bbfile, d)
print "OK"
else:
print "ERROR: Nothing provides '%s'" % name
poke.usage = "<providee> <variable> <value>"
def print_( self, params ):
"""Dump all files or providers"""
what = params[0]
if what == "files":
self._checkParsed()
for key in cooker.pkgdata.keys(): print key
elif what == "providers":
self._checkParsed()
for key in cooker.status.providers.keys(): print key
else:
print "Usage: print %s" % self.print_.usage
print_.usage = "<files|providers>"
def python( self, params ):
"""Enter the expert mode - an interactive BitBake Python Interpreter"""
sys.ps1 = "EXPERT BB>>> "
sys.ps2 = "EXPERT BB... "
import code
interpreter = code.InteractiveConsole( dict( globals() ) )
interpreter.interact( "SHELL: Expert Mode - BitBake Python %s\nType 'help' for more information, press CTRL-D to switch back to BBSHELL." % sys.version )
def showdata( self, params ):
"""Execute 'showdata' on a providee"""
self.build( params, "showdata" )
showdata.usage = "<providee>"
def setVar( self, params ):
"""Set an outer BitBake environment variable"""
var, value = params
data.setVar( var, value, cooker.configuration.data )
print "OK"
setVar.usage = "<variable> <value>"
def rebuild( self, params ):
"""Clean and rebuild a .bb file or a providee"""
self.build( params, "clean" )
self.build( params, "build" )
rebuild.usage = "<providee>"
def shell( self, params ):
"""Execute a shell command and dump the output"""
if params != "":
print commands.getoutput( " ".join( params ) )
shell.usage = "<...>"
def stage( self, params ):
"""Execute 'stage' on a providee"""
self.build( params, "stage" )
stage.usage = "<providee>"
def status( self, params ):
"""<just for testing>"""
print "-" * 78
print "build cache = '%s'" % cooker.build_cache
print "build cache fail = '%s'" % cooker.build_cache_fail
print "building list = '%s'" % cooker.building_list
print "build path = '%s'" % cooker.build_path
print "consider_msgs_cache = '%s'" % cooker.consider_msgs_cache
print "build stats = '%s'" % cooker.stats
if last_exception is not None: print "last_exception = '%s'" % repr( last_exception.args )
print "memory output contents = '%s'" % self._shell.myout._buffer
def test( self, params ):
"""<just for testing>"""
print "testCommand called with '%s'" % params
def unpack( self, params ):
"""Execute 'unpack' on a providee"""
self.build( params, "unpack" )
unpack.usage = "<providee>"
def which( self, params ):
"""Computes the providers for a given providee"""
item = params[0]
self._checkParsed()
preferred = data.getVar( "PREFERRED_PROVIDER_%s" % item, cooker.configuration.data, 1 )
if not preferred: preferred = item
try:
lv, lf, pv, pf = cooker.findBestProvider( preferred )
except KeyError:
lv, lf, pv, pf = (None,)*4
try:
providers = cooker.status.providers[item]
except KeyError:
print "SHELL: ERROR: Nothing provides", preferred
else:
for provider in providers:
if provider == pf: provider = " (***) %s" % provider
else: provider = " %s" % provider
print provider
which.usage = "<providee>"
##########################################################################
# Common helper functions
##########################################################################
def completeFilePath( bbfile ):
"""Get the complete bbfile path"""
if not cooker.pkgdata: return bbfile
for key in cooker.pkgdata.keys():
if key.endswith( bbfile ):
return key
return bbfile
def sendToPastebin( content ):
"""Send content to http://www.pastebin.com"""
mydata = {}
mydata["parent_pid"] = ""
mydata["format"] = "bash"
mydata["code2"] = content
mydata["paste"] = "Send"
mydata["poster"] = "%s@%s" % ( os.environ.get( "USER", "unknown" ), socket.gethostname() or "unknown" )
params = urllib.urlencode( mydata )
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
conn = httplib.HTTPConnection( "pastebin.com:80" )
conn.request("POST", "/", params, headers )
response = conn.getresponse()
conn.close()
return response.status, response.reason, response.getheader( "location" ) or "unknown"
def completer( text, state ):
"""Return a possible readline completion"""
debugOut( "completer called with text='%s', state='%d'" % ( text, state ) )
if state == 0:
line = readline.get_line_buffer()
if " " in line:
line = line.split()
# we are in second (or more) argument
if line[0] in cmds and hasattr( cmds[line[0]][0], "usage" ): # known command and usage
u = getattr( cmds[line[0]][0], "usage" ).split()[0]
if u == "<variable>":
allmatches = cooker.configuration.data.keys()
elif u == "<bbfile>":
if cooker.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
else: allmatches = [ x.split("/")[-1] for x in cooker.pkgdata.keys() ]
elif u == "<providee>":
if cooker.pkgdata is None: allmatches = [ "(No Matches Available. Parsed yet?)" ]
else: allmatches = cooker.status.providers.iterkeys()
else: allmatches = [ "(No tab completion available for this command)" ]
else: allmatches = [ "(No tab completion available for this command)" ]
else:
# we are in first argument
allmatches = cmds.iterkeys()
completer.matches = [ x for x in allmatches if x[:len(text)] == text ]
#print "completer.matches = '%s'" % completer.matches
if len( completer.matches ) > state:
return completer.matches[state]
else:
return None
def debugOut( text ):
if debug:
sys.stderr.write( "( %s )\n" % text )
def columnize( alist, width = 80 ):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""
return reduce(lambda line, word, width=width: '%s%s%s' %
(line,
' \n'[(len(line[line.rfind('\n')+1:])
+ len(word.split('\n',1)[0]
) >= width)],
word),
alist
)
def globfilter( names, pattern ):
return fnmatch.filter( names, pattern )
##########################################################################
# Class MemoryOutput
##########################################################################
class MemoryOutput:
"""File-like output class buffering the output of the last 10 commands"""
def __init__( self, delegate ):
self.delegate = delegate
self._buffer = []
self.text = []
self._command = None
def startCommand( self, command ):
self._command = command
self.text = []
def endCommand( self ):
if self._command is not None:
if len( self._buffer ) == 10: del self._buffer[0]
self._buffer.append( ( self._command, self.text ) )
def removeLast( self ):
if self._buffer:
del self._buffer[ len( self._buffer ) - 1 ]
self.text = []
self._command = None
def lastBuffer( self ):
if self._buffer:
return self._buffer[ len( self._buffer ) -1 ][1]
def bufferedCommands( self ):
return [ cmd for cmd, output in self._buffer ]
def buffer( self, i ):
if i < len( self._buffer ):
return "BB>> %s\n%s" % ( self._buffer[i][0], "".join( self._buffer[i][1] ) )
else: return "ERROR: Invalid buffer number. Buffer needs to be in (0, %d)" % ( len( self._buffer ) - 1 )
def write( self, text ):
if self._command is not None and text != "BB>> ": self.text.append( text )
if self.delegate is not None: self.delegate.write( text )
def flush( self ):
return self.delegate.flush()
def fileno( self ):
return self.delegate.fileno()
def isatty( self ):
return self.delegate.isatty()
##########################################################################
# Class BitBakeShell
##########################################################################
class BitBakeShell:
def __init__( self ):
"""Register commands and set up readline"""
self.commandQ = Queue.Queue()
self.commands = BitBakeShellCommands( self )
self.myout = MemoryOutput( sys.stdout )
self.historyfilename = os.path.expanduser( "~/.bbsh_history" )
self.startupfilename = os.path.expanduser( "~/.bbsh_startup" )
readline.set_completer( completer )
readline.set_completer_delims( " " )
readline.parse_and_bind("tab: complete")
try:
readline.read_history_file( self.historyfilename )
except IOError:
pass # It doesn't exist yet.
print __credits__
# save initial cooker configuration (will be reused in file*** commands)
global initdata
initdata = copy.deepcopy( cooker.configuration.data )
def cleanup( self ):
"""Write readline history and clean up resources"""
debugOut( "writing command history" )
try:
readline.write_history_file( self.historyfilename )
except:
print "SHELL: Unable to save command history"
def registerCommand( self, command, function, numparams = 0, usage = "", helptext = "" ):
"""Register a command"""
if usage == "": usage = command
if helptext == "": helptext = function.__doc__ or "<not yet documented>"
cmds[command] = ( function, numparams, usage, helptext )
def processCommand( self, command, params ):
"""Process a command. Check number of params and print a usage string, if appropriate"""
debugOut( "processing command '%s'..." % command )
try:
function, numparams, usage, helptext = cmds[command]
except KeyError:
print "SHELL: ERROR: '%s' command is not a valid command." % command
self.myout.removeLast()
else:
if (numparams != -1) and (not len( params ) == numparams):
print "Usage: '%s'" % usage
return
result = function( self.commands, params )
debugOut( "result was '%s'" % result )
def processStartupFile( self ):
"""Read and execute all commands found in $HOME/.bbsh_startup"""
if os.path.exists( self.startupfilename ):
startupfile = open( self.startupfilename, "r" )
for cmdline in startupfile:
debugOut( "processing startup line '%s'" % cmdline )
if not cmdline:
continue
if "|" in cmdline:
print "ERROR: '|' in startup file is not allowed. Ignoring line"
continue
self.commandQ.put( cmdline.strip() )
def main( self ):
"""The main command loop"""
while not leave_mainloop:
try:
if self.commandQ.empty():
sys.stdout = self.myout.delegate
cmdline = raw_input( "BB>> " )
sys.stdout = self.myout
else:
cmdline = self.commandQ.get()
if cmdline:
allCommands = cmdline.split( ';' )
for command in allCommands:
pipecmd = None
#
# special case for expert mode
if command == 'python':
sys.stdout = self.myout.delegate
self.processCommand( command, "" )
sys.stdout = self.myout
else:
self.myout.startCommand( command )
if '|' in command: # disable output
command, pipecmd = command.split( '|' )
delegate = self.myout.delegate
self.myout.delegate = None
tokens = shlex.split( command, True )
self.processCommand( tokens[0], tokens[1:] or "" )
self.myout.endCommand()
if pipecmd is not None: # restore output
self.myout.delegate = delegate
pipe = popen2.Popen4( pipecmd )
pipe.tochild.write( "\n".join( self.myout.lastBuffer() ) )
pipe.tochild.close()
sys.stdout.write( pipe.fromchild.read() )
#
except EOFError:
print
return
except KeyboardInterrupt:
print
##########################################################################
# Start function - called from the BitBake command line utility
##########################################################################
def start( aCooker ):
global cooker
cooker = aCooker
bbshell = BitBakeShell()
bbshell.processStartupFile()
bbshell.main()
bbshell.cleanup()
if __name__ == "__main__":
print "SHELL: Sorry, this program should only be called by BitBake."
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
"""
BitBake Utility Functions
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA.
This file is part of the BitBake build tools.
"""
digits = "0123456789"
ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
import re
def explode_version(s):
r = []
alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
numeric_regexp = re.compile('^(\d+)(.*)$')
while (s != ''):
if s[0] in digits:
m = numeric_regexp.match(s)
r.append(int(m.group(1)))
s = m.group(2)
continue
if s[0] in ascii_letters:
m = alpha_regexp.match(s)
r.append(m.group(1))
s = m.group(2)
continue
s = s[1:]
return r
def vercmp_part(a, b):
va = explode_version(a)
vb = explode_version(b)
while True:
if va == []:
ca = None
else:
ca = va.pop(0)
if vb == []:
cb = None
else:
cb = vb.pop(0)
if ca == None and cb == None:
return 0
if ca > cb:
return 1
if ca < cb:
return -1
def vercmp(ta, tb):
(va, ra) = ta
(vb, rb) = tb
r = vercmp_part(va, vb)
if (r == 0):
r = vercmp_part(ra, rb)
return r
Binary file not shown.