This repository has been archived on 2021-03-01. You can view files and clone it, but cannot push or open issues or pull requests.
kaneton/environment/critical.py

427 lines
11 KiB
Python

#
# ---------- header -----------------------------------------------------------
#
# project kaneton
#
# license kaneton
#
# file /home/mycure/kaneton/environment/critical.py
#
# created julien quintard [fri dec 15 13:43:03 2006]
# updated julien quintard [fri dec 17 20:00:58 2010]
#
#
# ---------- imports ----------------------------------------------------------
#
import os
import sys
import re
#
# ---------- globals ----------------------------------------------------------
#
g_directories = None
g_contents = None
g_assignments = []
g_variables = {}
#
# ---------- functions --------------------------------------------------------
#
#
# error()
#
# this function displays an error and quit.
#
def error(message):
sys.stderr.write("[!] " + message)
sys.exit(42)
#
# warning()
#
# this function simply displays an error.
#
def warning(msg):
sys.stderr.write("[!] " + msg)
#
# load()
#
# this function takes an arbitray number of directories where pattern
# files could be located and load them in a single python string.
#
def load(directories, pattern):
content = ""
directory = None
includes = None
include = None
handle = None
files = None
line = None
file = None
cwd = None
for directory in directories:
if not os.path.isdir(directory):
continue
files = os.listdir(directory);
for file in files:
if not os.path.isfile(directory + "/" + file):
continue
if not re.match(pattern, file):
continue
try:
handle = open(directory + "/" + file, "r")
except IOError:
error("unable to open the file " + directory + "/" + file + ".\n")
for line in handle.readlines():
content += line
content += "\n"
includes = re.findall("(" \
"^" \
"include" \
"[ \t]*" \
"(.*)" \
"\n" \
")", content, re.MULTILINE);
for include in includes:
content = content.replace(include[0],
load([os.path.dirname(directory +
"/" +
include[1])],
"^" +
os.path.basename(directory +
"/" +
include[1]) +
"$"))
handle.close()
return content
#
# comments()
#
# this function removes the comments from the file
#
def comments():
global g_contents
comments = None
c = None
comments = re.findall("^#.*$", g_contents, re.MULTILINE);
for c in comments:
g_contents = g_contents.replace(c, "", 1)
#
# locate()
#
# this function tries to locate the variable of the given array and
# return the corresponding tuple.
#
def locate(array, variable):
var = None
for var in array:
if variable == var[0]:
return var
return None
#
# extract()
#
# this function extracts the variables assignments from the environment
# configuration files previously loaded.
#
def extract():
global g_assignments
assignments = None
assignment = None
already = None
new = None
assignments = re.findall("^" \
"[ \t]*" \
"([a-zA-Z0-9_]+)" \
"[ \t]*" \
"(\+?=)" \
"[ \t]*" \
"((?:(?:\\\\\n)|[^\n])*)" \
"\n", g_contents, re.MULTILINE);
for assignment in assignments:
# look for a previous registered assignment.
already = locate(g_assignments, assignment[0])
if already:
# if it is an assignment, just override the previous declaration.
if assignment[1] == "=":
new = (assignment[0], assignment[2])
# if it is a concatenation, override the previous one with a
# concatenation of the two values.
elif assignment[1] == "+=":
new = (assignment[0], already[1] + " " + assignment[2])
else:
error("unknown assignment token '" + assignment[1] + "' for the "
"variable '" + assignment[0] + "'.\n")
# remove and insert the new tuple.
g_assignments.remove(already)
g_assignments.append(new)
else:
if assignment[1] == "=":
# simple insert the tuple.
new = (assignment[0], assignment[2])
g_assignments.append(new)
elif assignment[1] == "+=":
error("appending to the undefined variable '" + assignment[0] +
"' is not allowed.\n")
else:
error("unknown assignment token '" + assignment[1] + "' for the "
"variable '" + assignment[0] + "'.\n")
#
# expand()
#
# this function tries to expand the given variable.
#
def expand(name, stack):
variables = None
position = None
tuple = None
value = None
var = None
# try to get the variable's value from the already expanded variables.
try:
value = g_variables[name]
return
except:
# check if the variable was declared somewhere.
tuple = locate(g_assignments, name)
if not tuple:
warning("the kaneton environment variable " + name +
" is not defined\n")
value = ""
else:
value = tuple[1]
# check recursion assignments.
try:
position = stack.index(name)
except:
pass
if position != None:
error("the kaneton environment variable " + name +
" recursively references itself.\n")
# locate, expand and replace the kaneton variables.
variables = re.findall("\$\{([^}]+)\}", value)
if variables:
for var in variables:
expand(var, stack + [name])
for var in variables:
value = value.replace("${" + var + "}", g_variables[var])
# locate, expand and replace the shell variables.
variables = re.findall("\$\(([^}]+)\)", value)
if variables:
for var in variables:
if os.getenv(var) == None:
warning("shell user variable " + var + " is not defined\n")
value = value.replace("$(" + var + ")", "")
else:
value = value.replace("$(" + var + ")", os.getenv(var))
# finally register the new variable with its expanded value.
g_variables[name] = value
#
# resolve()
#
# this function resolves the variable assignments.
def resolve():
for assignment in g_assignments:
expand(assignment[0], [])
#
# generate()
#
# this function generates the kaneton development environment files.
#
def generate(mfile, mcontent, pfile, pcontent):
mhandle = None
phandle = None
line = None
var = None
# open the make environment file.
try:
mhandle = open(mfile, "w")
except IOError:
error("unable to open the file " + mfile + ".\n")
# open the python environment file.
try:
phandle = open(pfile, "w")
except IOError:
error("unable to open the file " + pfile + ".\n")
# inject the kaneton environment configuration for the make and python
# environment.
for var in g_variables:
mhandle.write(var + " := " + g_variables[var] + "\n")
phandle.write(var + " = " + "\"" + g_variables[var] + "\"" + "\n")
# append the make environment files to the make environment file.
mhandle.write(mcontent)
# append the python environment files to the python environment file.
phandle.write(pcontent)
# close the files.
phandle.close()
mhandle.close()
#
# main()
#
# this function builds a kaneton development environment.
#
def main():
global g_directories
global g_contents
architecture = None
source_dir = None
platform = None
contents = None
machine = None
python = None
host = None
user = None
# get the shell environment variables.
user = os.getenv("KANETON_USER")
host = os.getenv("KANETON_HOST")
python = os.getenv("KANETON_PYTHON")
platform = os.getenv("KANETON_PLATFORM")
architecture = os.getenv("KANETON_ARCHITECTURE")
# check the presence of the shell environment variable.
if not (user != None and
os.path.isdir("profile/user/" + user)):
error("the shell environment variable KANETON_USER is not set " + \
"or is incorrect.\n")
if not (python != None and
os.path.isfile(python)):
error("the shell environment variable KANETON_PYTHON is not set " + \
"or is incorrect.\n")
if not (platform != None and
os.path.isdir("profile/kaneton/machine/platform/" + platform)):
error("the shell environment variable KANETON_PLATFORM is not " + \
"set or is incorrect.\n")
if not (architecture != None and
os.path.isdir("profile/kaneton/machine/architecture/" + architecture)):
error("the shell environment variable KANETON_ARCHITECTURE is " + \
"not set or is incorrect.\n")
if not (host != None and
os.path.isdir("profile/host/" + host + "." + architecture)):
error("the shell environment variable KANETON_HOST or " + \
"KANETON_ARCHITECTURE is not set or is incorrect.\n")
# set the configuration directories based on the user variables.
g_directories = ("profile/",
"profile/host/",
"profile/host/" + host + "." + architecture + "/",
"profile/boot/",
"profile/boot/" + platform + "." + architecture + "/",
"profile/kaneton/",
"profile/kaneton/core/",
"profile/kaneton/machine/",
"profile/kaneton/machine/platform/",
"profile/kaneton/machine/platform/" + platform + "/",
"profile/kaneton/machine/architecture/",
"profile/kaneton/machine/architecture/" + \
architecture + "/",
"profile/kaneton/machine/glue/",
"profile/kaneton/machine/glue/" + platform + "." + \
architecture + "/",
"profile/kaneton/library/",
"profile/kaneton/modules/",
"profile/user/",
"profile/user/" + user + "/")
# first, set a virtual kaneton variable containing the location of
# the kaneton source directory.
# this directory is expected to be relatively located at: ../
# since this script should have been launched in the environment/
# directory
cwd = os.getcwd()
os.chdir("..")
source_dir = os.getcwd()
os.chdir(cwd)
# load the content of the configuration files *.conf.
g_contents = "_SOURCE_DIR_ = " + source_dir + "\n"
g_contents += load(g_directories, "^.*\.conf$")
# removes the comments
comments()
# extract the assignments from the files.
extract()
# resolve the variables in assignments.
resolve()
# generate the development environment files.
generate("env.mk", load(g_directories, "^.*\.mk$"),
"env.py", load(g_directories, "^.*\.py$"))
#
# ---------- entry point ------------------------------------------------------
#
main()