367 lines
13 KiB
Python
367 lines
13 KiB
Python
|
# -*- 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
|