# Copyright (c) 2000-2004 LOGILAB S.A. (Paris, FRANCE). # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ utility functions to generate argo uml files """ __revision__ = "$Id: argoutils.py,v 1.10 2005/06/14 09:56:00 syt Exp $" import os from cStringIO import StringIO from logilab.common.configuration import OptionsProviderMixIn from pyreverse.utils import info from pyreverse.__pkginfo__ import version, modname, web #BASE = 'uci.uml.visual' BASE = 'org.argouml.uml.diagram.static_structure.ui' BASE_REL = 'org.argouml.uml.diagram.ui' def open_pgml(name, f_uuid): """return the pgml file header : xml + DOCTYPE declaration + node """ return ''' ''' % ( f_uuid, name) def make_argo(project_name, files): """return the content of the main argo file describing the project files (xmi and pgml) """ stream = StringIO() stream.write(''' %s %s Generated by pyargo (%s) ''' % (modname, version, web, project_name)) for file in files: stream.write(''' ''' % file) stream.write(''' ''') return stream.getvalue() def make_package(f_id, f_uuid): """return a package group""" return _group("FigPackage", f_id, f_uuid) def make_dependency(new_id, spf, dpf): """return a dependency group""" return _group('FigDependency', new_id, None, ''' sourcePortFig="Fig%s.0" destPortFig="Fig%s.0" sourceFigNode="Fig%s" destFigNode="Fig%s"''' % (spf, dpf, spf, dpf), fill=0, base=BASE_REL) def make_class(f_id, f_uuid, enclose=''): """return a class group""" if enclose: enclose = 'enclosingFig="%s"' % enclose return _group('FigClass', f_id, f_uuid, enclose) def make_interface(f_id, f_uuid, enclose=''): """return an interface group""" if enclose: enclose = 'enclosingFig="%s"' % enclose return _group('FigInterface', f_id, f_uuid, enclose) def make_generalization(new_id, spf, dpf): """return a generalization group""" return _group('FigGeneralization', new_id, None, ''' sourcePortFig="Fig%s.0" destPortFig="Fig%s.0" sourceFigNode="Fig%s" destFigNode="Fig%s"''' % (spf, dpf, spf, dpf), fill=1, base=BASE_REL) def make_realization(new_id, spf, dpf): """return a realization group""" return _group('FigRealization', new_id, None, ''' sourcePortFig="Fig%s.0" destPortFig="Fig%s.0" sourceFigNode="Fig%s" destFigNode="Fig%s"''' % (spf, dpf, spf, dpf), fill=0, base=BASE_REL) def make_association(new_id, spf, dpf): """return a association group""" return _group('FigAssociation', new_id, None, ''' sourcePortFig="Fig%s.0" destPortFig="Fig%s.0" sourceFigNode="Fig%s" destFigNode="Fig%s"''' % (spf, dpf, spf, dpf), base=BASE_REL) def _group(descr, id, idref, private='', fill=1, base=BASE): """return a pgml group node""" if fill: fill = ''' fill="1" fillcolor="-1"''' else: fill = '' if idref: idref = ''' href="%s"''' % idref else: idref = '' return ''' %s ''' % (id, base, descr, idref, fill, private) class ArgoWriter(OptionsProviderMixIn): """ Writer that outputs ArgoUML files. """ name = 'argo' options = ( ("zargo", {'action':"store_true", 'dest':"compress", 'default':0, 'short' : 'z', 'help':"compress output (ArgoUML > 0.9). Require to have \ 'zip' in your path or to specify an alternative zip program using the --zipper \ option"}), ("zipper", {'action':"store", 'type':'string', 'dest':"zipper", 'default':'zip', 'help':"compress output using to zip all files. \ Require to have in your path.", 'metavar':""}), ) def write(self, project, xmi, diagrams, uuid_f): """write xmi to file (named after project) """ self._project = project self.f_uuid = uuid_f self._filenames = [] self.write_xmi(xmi) self.write_pgml(diagrams) self.write_argo() if self.config.compress: self.zargo() def write_xmi(self, xmi): """write to a file the XMI UML definition """ p_f_name = self._project.name.replace(' ', '_') info('writing XMI file to %s.xmi' % p_f_name) xmi_file = '%s.xmi' % p_f_name xmi_f = open(xmi_file, 'w+') from xml.dom.ext import PrettyPrint PrettyPrint(xmi, xmi_f) xmi_f.close() self._filenames.append(xmi_file) def write_pgml(self, diagrams): """write necessary pgml files """ for diagram in diagrams: if diagram.TYPE == 'class': self._write_class_diagram(diagram) else: self._write_package_diagram(diagram) def write_argo(self): """write the argo project description to a file it must be called once write_xmi and write_pgml have been called """ p_f_name = self._project.name.replace(' ', '_') info('writing Argo project file to %s.argo' % p_f_name) argo_file = '%s.argo' % p_f_name argo_f = open(argo_file, 'w+') print >> argo_f, make_argo(self._project.name, self._filenames) argo_f.close() self._filenames.append(argo_file) def zargo(self): """zip generated files to a .zargo file""" assert self._filenames zipper = self.config.zipper assert zipper p_f_name = self._project.name.replace(' ', '_') info('zipping all files to %s.zargo' % p_f_name) cmd = '%s %s.zargo' % (zipper, p_f_name) for filename in self._filenames: cmd = '%s %s' % (cmd, filename) os.system(cmd) ## import zipfile ## zip = zipfile.ZipFile('%s.zargo'%p_name, 'w', ## zipfile.ZIP_DEFLATED) ## zip.write(a_file) ## zip.write(x_file) ## for f in files: ## zip.write(f) ## zip.close() def clean(self): """remove all files after making the zip archive """ for filename in self._filenames: os.remove(filename) self._filenames = [] def _write_package_diagram(self, diagram): f = self._open_pgml(diagram.title) self._write_packages(f, diagram) self._write_classes(f, diagram) print >> f, '' def _write_class_diagram(self, diagram): """write to a file a class diagram according to the pgml dtd """ f = self._open_pgml(diagram.title) self._write_classes(f, diagram) print >> f, '' def _open_pgml(self, name): """create file and return corresponding file object """ filename = '%s.pgml' % name.replace(' ', '_') info('creating diagram %s' % filename) f = open(filename, 'w+') print >> f, open_pgml(name, self.f_uuid(self._project.uid)) self._filenames.append(filename) return f def _write_packages(self, f, diagram): """write a package diagram """ for obj in diagram.modules(): node = obj.node print >> f, make_package(obj.fig_id, self.f_uuid(node.uid)) # package dependencies for rel in diagram.relationships.get('depends', ()): print >> f, make_dependency(rel.fig_id, rel.from_object, rel.to_object) def _write_classes(self, f, diagram): """write classes """ for obj in diagram.classes(): try: mod = diagram.get_relationship(obj, 'ownership') enclose = 'Fig%s' % mod.fig_id except KeyError: enclose = '' figid, oid = obj.fig_id, self.f_uuid(obj.node.uid) if obj.shape == 'interface': print >> f, make_interface(figid, oid, enclose) else: print >> f, make_class(figid, oid, enclose) # inheritance link for rel in diagram.relationships.get('specialization', ()): print >> f, make_generalization(rel.fig_id, rel.from_object.fig_id, rel.to_object.fig_id) # implements link for rel in diagram.relationships.get('implements', ()): print >> f, make_realization(rel.fig_id, rel.from_object.fig_id, rel.to_object.fig_id) # associations for rel in diagram.relationships.get('association', ()): print >> f, make_association(rel.fig_id, rel.from_object.fig_id, rel.to_object.fig_id)