#!/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)