110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
#!/usr/bin/env python2.7
|
|
# -*- coding: utf-8 -*-
|
|
"""SafeEnvironment implementation for use of exec"""
|
|
|
|
import os
|
|
import cStringIO
|
|
|
|
import PythonDefaults
|
|
import PythonFile
|
|
|
|
class SafeEnvironment(dict):
|
|
"""Environnement isolé dans lequel on exécute un script"""
|
|
|
|
def __init__(self, additionnal=None, parent=None):
|
|
# Création de l'environment initial
|
|
super(self.__class__, self).__init__({
|
|
# Écrit: variable keysep tostring(value)
|
|
"defvar": self.defvar,
|
|
# La convertion en chaîne de charactère
|
|
"tostring": self.tostring,
|
|
# Définition des convertions
|
|
"conv": {
|
|
bool: {
|
|
True: "yes",
|
|
False: "no",
|
|
},
|
|
list: lambda l: ", ".join([
|
|
str(x)
|
|
for x in l
|
|
]),
|
|
tuple: lambda l: ", ".join([
|
|
str(x)
|
|
for x in l
|
|
]),
|
|
},
|
|
# Fonction de base pour imprimer quelque chose
|
|
"out": self.out,
|
|
# Le séparateur pour la forme: variable keysep valeur
|
|
"keysep": "=",
|
|
# Le charactère de commentaire
|
|
"comment_start": "#",
|
|
# Du mapping de certaines fonctions
|
|
"include": self.include,
|
|
# Du mapping de certaines fonctions
|
|
"dump": self.dump,
|
|
# Infos standard pour le fichier (écrasable localement)
|
|
"info": {
|
|
'owner': PythonDefaults.DEFAULT_USER,
|
|
'group': PythonDefaults.DEFAULT_GROUP,
|
|
'mode': PythonDefaults.DEFAULT_ACLS,
|
|
}
|
|
})
|
|
|
|
if additionnal is None:
|
|
additionnal = {}
|
|
super(self.__class__, self).update(additionnal)
|
|
|
|
# On crée le flux dans lequel le fichier de config sera généré
|
|
self.stream = cStringIO.StringIO()
|
|
|
|
# Le Pythonfile parent est référencé ici
|
|
self.parent = parent
|
|
|
|
# Les trucs inclus
|
|
self.included = []
|
|
|
|
def __setitem__(self, variable, value):
|
|
"""Lorsqu'on définit une variable, si elle est listée dans la variable
|
|
exports, on l'incorpore dans le fichier produit"""
|
|
super(self.__class__, self).__setitem__(variable, value)
|
|
|
|
def defvar(self, variable, value):
|
|
"""Quand on fait un export, on utilise defvar pour incorporer la variable
|
|
et sa valeur dans le fichier produit"""
|
|
# On écrit mavariable = toto, en appliquant une éventuelle conversion à toto
|
|
self.out("%s%s%s\n" % (variable, self['keysep'], self.tostring(value)))
|
|
|
|
def out(self, string):
|
|
"""C'est le print local. Sauf qu'on écrit dans self.stream. C'est pas
|
|
indispensable, car l'évaluation du fichier se fait déjà à sys.stdout
|
|
pointant vers ledit stream."""
|
|
self.stream.write(string)
|
|
|
|
def tostring(self, value):
|
|
"""On convertit un objet python dans un format "string" sympa.
|
|
En vrai c'est horrible et il faudrait virer ce genre de kludge."""
|
|
convertor = self["conv"].get(type(value))
|
|
if convertor:
|
|
if type(convertor) == dict:
|
|
return convertor[value]
|
|
else:
|
|
return convertor(value)
|
|
else:
|
|
return str(value)
|
|
|
|
def dump(self, incfile):
|
|
"""On exécute le fichier python dans l'environnement courant
|
|
|
|
incfile est le nom du fichier, sans le .py"""
|
|
filename = os.path.join(self.parent.parent.include, "%s.py" % (incfile,))
|
|
python_file = PythonFile.PythonFile(filename, self.parent.parent)
|
|
python_file.run(environment=self)
|
|
|
|
def include(self, incfile):
|
|
"""Pareil qu'au dessus, mais on ne le fait que si ça n'a pas
|
|
été fait"""
|
|
if incfile in self.included:
|
|
return
|
|
self.included.append(incfile)
|
|
self.dump(incfile)
|