# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 """Fonctions utilitaires pour gérer des projets WebObjects """ try: True, False except NameError: True, False = 1, 0 import os, sys, string, re, types from os import path from base import basename, dirname, matches_name from config import ShConfigFile, PListFile ################################################## # gestion des frameworks systèmes default_frameworks_for_woapp = ['JavaFoundation.framework', 'JavaEOControl.framework', 'JavaEOAccess.framework', 'JavaWebObjects.framework', 'JavaWOExtensions.framework', 'JavaXML.framework', 'JavaJDBCAdaptor.framework', ] default_frameworks_for_jcapp = ['JavaEOApplication.framework', 'JavaEODistribution.framework', 'JavaEOInterface.framework', 'JavaEOInterfaceSwing.framework', ] system_frameworks = default_frameworks_for_woapp + default_frameworks_for_jcapp + \ ['JavaDirectToWeb.framework', 'JavaDTWGeneration.framework', 'JavaEOGeneration.framework', 'JavaEOProject.framework', 'JavaEORuleSystem.framework', 'JavaJNDIAdaptor.framework', 'JavaOpenEJBActivation.framework', 'JavaOpenEJB.framework', 'JavaOpenORB.framework', 'JavaOpenTM.framework', 'JavaPlot.framework', 'JavaWebServicesClient.framework', 'JavaWebServicesGeneration.framework', 'JavaWebServicesSupport.framework', 'JavaWOJSPServlet.framework', 'JavaWOSMIL.framework', ] def is_system_framework(fp): """retourner True si fp est un chemin vers un framework système """ return basename(fp) in system_frameworks def is_default_framework_for_woapp(fp): return is_system_framework(fp) and basename(fp) in default_frameworks_for_woapp def is_default_framework_for_jcapp(fp): return is_system_framework(fp) and basename(fp) in default_frameworks_for_jcapp ################################################## # gestion des exceptions class WOError(Exception): """exception lancée si une erreur se produit dans l'une des fonctions de ce module """ pass ################################################## # gestion des projets class WOProject: """Classe de base des projets webobjects Cette classe est utilisée comme interface, pour indiquer les méthodes qui existent dans les classes dérivées """ def projname(self): """Retourner le nom du projet. Ce nom est utilisé comme nom de base pour le projet compilé, par exemple projname.woa ou projname.framework """ raise NotImplementedError def projsubtype(self): """Retourner le type de sous-projet: woapp, jcapp, framework """ raise NotImplementedError projtype_map = {'woapp': 'woapplication', 'jcapp': 'woapplication', 'wofrm': 'woframework', } def projtype(self): """Retourner le type de projet: woapplication ou woframework """ return self.projtype_map[self.projsubtype()] def projdir(self): """Retourner le répertoire absolu qui contient le projet """ raise NotImplementedError def projname_and_projtype(self): """retourner le tuple (projname, projtype) """ return self.projname(), self.projtype() class WOJawotools(WOProject, ShConfigFile): """Un projet jawotools """ def __init__(self, dir, raise_exception=True): """Initialiser l'objet avec le répertoire dir """ ShConfigFile.__init__(self) self.load(path.join(dir, 'build.properties'), raise_exception=raise_exception) def PROJECT_NAME(self): try: return self['project_name'] except KeyError: raise WOError, "Propriété project_name non définie dans le projet" def PROJECT_TYPE(self): try: return self['project_type'] except KeyError: raise WOError, "Propriété project_type non définie dans le projet" def projname(self): return self.PROJECT_NAME() def projsubtype(self): type = string.lower(self.PROJECT_TYPE()) if type.startswith("application"): type = type.find("+javaclient") != -1 and "jcapp" or "woapp" elif type.startswith("framework"): type = "wofrm" return type def projdir(self): return self.dirname class WOBuildConf(WOProject, ShConfigFile): """Un projet wobuild.conf """ def __init__(self, dir, raise_exception=True): """Initialiser l'objet avec le répertoire dir """ ShConfigFile.__init__(self) self.load(path.join(dir, 'wobuild.conf'), raise_exception=raise_exception) def NAME(self): try: return self['NAME'] except KeyError: raise WOError, "Propriété NAME non définie dans le projet" def TYPE(self): try: return self['TYPE'] except KeyError: raise WOError, "Propriété TYPE non définie dans le projet" def TAG(self): return self.get('TAG', '') def projname(self): return self.NAME() def projsubtype(self): type = string.lower(self.TYPE()) type = {'app': 'woapp', 'framework': 'wofrm'}.get(type, type) return type def projdir(self): return self.dirname class WOProjectMacOSX(WOProject, PListFile): """Un projet de Project Builder sous Mac OS X """ def __init__(self, dir, raise_exception=True): """Initialiser l'objet avec le répertoire dir """ PListFile.__init__(self) adir = path.abspath(dir) bn = basename(adir) if bn == "project.pbxproj" and matches_name("*.pbproj", basename(dirname(adir))): # on a donné directement le fichier project.pbxproj self.load(dir, raise_exception=raise_exception) self._projdir = dirname(dirname(adir)) elif matches_name("*.pbproj", bn): # on a donné le nom du répertoire .pbproj self.load(path.join(dir, 'project.pbxproj'), raise_exception=raise_exception) self._projdir = dirname(adir) else: # on a donné le nom du répertoire du projet. il faut chercher le # répertoire .pbproj files = os.listdir(dir) projects_filter = lambda file, bp=dir: matches_name('*.pbproj/', file, bp) projects = filter(projects_filter, files) if len(projects) != 1: if raise_exception: if len(projects): raise WOError, "Il y a plusieurs répertoires .pbproj dans %s" % dir else: raise WOError, "Aucun répertoire .pbproj n'a été trouvé dans %s" % dir return projfile = path.join(dir, projects[0], 'project.pbxproj') self.load(projfile, raise_exception=raise_exception) self._projdir = adir self.group_for_oid = {} def is_oid(self, oid): """déterminer si oid est un id d'objet n doit être de longeur 24 et n'être composé que de caractères hexadécimaux """ return re.match(r'[0-9a-fA-F]{24,24}$', oid) is not None def object(self, oid): """retourner un objet si l'oid est valide, ou la valeur inchangée si ce n'est pas un oid valide """ if self.is_oid(oid): return self['objects'][oid] else: return oid def objects(self, oids): """retourner une liste d'objet pour une liste d'oids """ return map(self.object, oids) def path(self, p='', o=None, convert_object=True): """retourner un objet dont on donne le chemin """ if o is None: o = self.items if type(o) is types.StringType: o = self.object(o) if p: ps = string.split(p, '.') count = len(ps) for i in range(count): p = ps[i] last = i == count - 1 # obtenir la clé if type(o) is types.DictType: k = p elif type(o) is types.ListType: k = int(p) else: raise ValueError, "chemin invalide vers une valeur scalaire" # obtenir l'objet o = o[k] # convertir éventuellement les références vers des objets if convert_object or not last: if type(o) is types.ListType: o = self.objects(o) elif type(o) is types.StringType: o = self.object(o) return o def __group_for(self, oid, start_at): children = self.path('children', start_at, convert_object=False) if oid in children: return start_at else: for child in children: group = self.object(child) if group['isa'] in ('PBXGroup', 'PBXVariantGroup'): found = self.__group_for(oid, child) if found is not None: return found return None def group_for(self, oid): """retourner l'oid du groupe associé à l'objet d'id find_oid """ if not self.group_for_oid.has_key(oid): self.group_for_oid[oid] = self.__group_for(oid, self.path('rootObject.mainGroup', convert_object=False)) return self.group_for_oid[oid] def PRODUCT_NAME(self): try: if self.path('rootObject.targets.0.isa') in ('PBXApplicationTarget', 'PBXFrameworkTarget'): return self.path('rootObject.targets.0.buildSettings.PRODUCT_NAME') except KeyError: pass raise WOError, "Impossible de déterminer le nom du produit" def TARGET0_ISA(self): try: return self.path('rootObject.targets.0.isa') except KeyError: pass raise WOError, "Impossible de déterminer le type du target principal" def projname(self): return self.PRODUCT_NAME() projsubtype_map = {'PBXApplicationTarget': 'woapp', 'PBXFrameworkTarget': 'wofrm', } def projsubtype(self): subtype = self.projsubtype_map[self.TARGET0_ISA()] if subtype == 'woapp': # tester si les frameworks pour jcapp sont présents pass return subtype def projdir(self): return self._projdir class WOProjectWindows(WOProject, PListFile): """Un projet de Project Builder sous Windows """ def __init__(self, dir, raise_exception=True): """Initialiser l'objet avec le répertoire dir """ PListFile.__init__(self) adir = path.abspath(dir) if basename(adir) == "PB.project": # on a donné le nom du fichier PB.project self.load(dir, raise_exception=raise_exception) else: # on a donné le nom du répertoire du projet. il faut chercher le # fichier PB.project self.load(path.join(dir, 'PB.project'), raise_exception=raise_exception) def PROJECTNAME(self): return self['PROJECTNAME'] def PROJECTTYPE(self): return self['PROJECTTYPE'] def projname(self): return self.PROJECTNAME() projsubtype_map = {'Application': 'woapp', # apparemment, client lourd java / wo4.5 'EOApplication': 'woapp', # client lourd objective c / wo4.5 'JavaWebObjectsApplication': 'woapp', 'JavaWebObjectsFramework': 'wofrm', } def projsubtype(self): subtype = self.projsubtype_map[self.PROJECTTYPE()] if subtype == 'woapp': # tester si les frameworks pour jcapp sont présents pass return subtype def projdir(self): return self.dirname def wo_projname_and_projtype(ap): """Obtenir le nom du projet WebObjects pour le répertoire absolu ap et le type de projet: app ou framework Si ce répertoire ne contient pas de projet WebObjects ou en contient plusieurs, retourner None. """ # tester si le projet est un projet jawotools proj = WOJawotools(ap, raise_exception=False) if proj.valid: try: return proj.projname_and_projtype() except WOError: pass # tester si le projet est un projet wobuild proj = WOBuildConf(ap, raise_exception=False) if proj.valid: try: return proj.projname_and_projtype() except WOError: pass # tester s'il s'agit d'un projet ProjectBuilder/MacOSX # ce test ne fonctione que s'il n'y a qu'un seul projet dans le répertoire proj = WOProjectMacOSX(ap, raise_exception=False) if proj.valid: try: return proj.projname_and_projtype() except WOError: pass # tester s'il s'agit d'un projet ProjectBuilder/Windows proj = WOProjectWindows(ap, raise_exception=False) if proj.valid: try: return proj.projname_and_projtype() except WOError: pass # sinon, on déclare forfait return None, None