blob: f80fe70e90f66da79d1f63b6f8402c1a5f45fd84 [file] [log] [blame]
import bjam
import re
import types
# Decorator the specifies bjam-side prototype for a Python function
def bjam_signature(s):
def wrap(f):
f.bjam_signature = s
return f
return wrap
def metatarget(f):
f.bjam_signature = (["name"], ["sources", "*"], ["requirements", "*"],
["default_build", "*"], ["usage_requirements", "*"])
return f
class cached(object):
def __init__(self, function):
self.function = function
self.cache = {}
def __call__(self, *args):
try:
return self.cache[args]
except KeyError:
v = self.function(*args)
self.cache[args] = v
return v
def __get__(self, instance, type):
return types.MethodType(self, instance, type)
def unquote(s):
if s and s[0] == '"' and s[-1] == '"':
return s[1:-1]
else:
return s
_extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)")
def qualify_jam_action(action_name, context_module):
if action_name.startswith("###"):
# Callable exported from Python. Don't touch
return action_name
elif _extract_jamfile_and_rule.match(action_name):
# Rule is already in indirect format
return action_name
else:
ix = action_name.find('.')
if ix != -1 and action_name[:ix] == context_module:
return context_module + '%' + action_name[ix+1:]
return context_module + '%' + action_name
def set_jam_action(name, *args):
m = _extract_jamfile_and_rule.match(name)
if m:
args = ("set-update-action-in-module", m.group(1), m.group(2)) + args
else:
args = ("set-update-action", name) + args
return bjam.call(*args)
def call_jam_function(name, *args):
m = _extract_jamfile_and_rule.match(name)
if m:
args = ("call-in-module", m.group(1), m.group(2)) + args
return bjam.call(*args)
else:
return bjam.call(*((name,) + args))
__value_id = 0
__python_to_jam = {}
__jam_to_python = {}
def value_to_jam(value, methods=False):
"""Makes a token to refer to a Python value inside Jam language code.
The token is merely a string that can be passed around in Jam code and
eventually passed back. For example, we might want to pass PropertySet
instance to a tag function and it might eventually call back
to virtual_target.add_suffix_and_prefix, passing the same instance.
For values that are classes, we'll also make class methods callable
from Jam.
Note that this is necessary to make a bit more of existing Jamfiles work.
This trick should not be used to much, or else the performance benefits of
Python port will be eaten.
"""
global __value_id
r = __python_to_jam.get(value, None)
if r:
return r
exported_name = '###_' + str(__value_id)
__value_id = __value_id + 1
__python_to_jam[value] = exported_name
__jam_to_python[exported_name] = value
if methods and type(value) == types.InstanceType:
for field_name in dir(value):
field = getattr(value, field_name)
if callable(field) and not field_name.startswith("__"):
bjam.import_rule("", exported_name + "." + field_name, field)
return exported_name
def record_jam_to_value_mapping(jam_value, python_value):
__jam_to_python[jam_value] = python_value
def jam_to_value_maybe(jam_value):
if type(jam_value) == type(""):
return __jam_to_python.get(jam_value, jam_value)
else:
return jam_value
def stem(filename):
i = filename.find('.')
if i != -1:
return filename[0:i]
else:
return filename