nutools/pyulib/migrate/wo.py

367 lines
13 KiB
Python
Raw Normal View History

2013-08-27 15:14:44 +04:00
# -*- 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