123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- #!/usr/bin/env python
- """Custom reST_ directive for plantuml_ integration.
- Adapted from ditaa_rst plugin.
- .. _reST: http://docutils.sourceforge.net/rst.html
- .. _plantuml: http://plantuml.sourceforge.net/
- """
- import os
- import tempfile
- from zlib import adler32
- from subprocess import Popen, PIPE
- from docutils.nodes import image, literal_block
- from docutils.parsers.rst import Directive, directives
- from docutils import utils, nodes
- from pelican import logger, signals
- global_siteurl = ""
- class PlantUML(Directive):
- required_arguments = 0
- optional_arguments = 0
- has_content = True
-
- global global_siteurl
- option_spec = {
- 'class' : directives.class_option,
- 'alt' : directives.unchanged,
- 'format': directives.unchanged,
- }
- def run(self):
- source = self.state_machine.input_lines.source(self.lineno - self.state_machine.input_offset - 1)
- source_dir = os.path.dirname(os.path.abspath(source))
- source_dir = utils.relative_path(None, source_dir)
- path = os.path.abspath(os.path.join('output', 'images'))
- if not os.path.exists(path):
- os.makedirs(path)
- nodes = []
- body = '\n'.join(self.content)
- tf = tempfile.NamedTemporaryFile(delete=True)
- tf.write('@startuml\n')
- tf.write(body.encode('utf8'))
- tf.write('\n@enduml')
- tf.flush()
-
- imgformat = self.options.get('format', 'png')
-
- if imgformat == 'png':
- imgext = ".png"
- outopt = "-tpng"
- elif imgformat == 'svg':
- imgext = ".svg"
- outopt = "-tsvg"
- else:
- logger.error("Bad uml image format: "+imgformat)
- # make a name
- name = tf.name+imgext
- alt = self.options.get('alt', 'uml diagram')
- classes = self.options.pop('class', ['uml'])
- cmdline = ['plantuml', '-o', path, outopt, tf.name ]
- try:
- p = Popen(cmdline, stdout=PIPE, stderr=PIPE)
- out, err = p.communicate()
- except Exception, exc:
- error = self.state_machine.reporter.error(
- 'Failed to run plantuml: %s' % (exc, ),
- literal_block(self.block_text, self.block_text),
- line=self.lineno)
- nodes.append(error)
- else:
- if p.returncode == 0:
- # renaming output image using an hash code, just to not pullate
- # output directory with a growing number of images
- name = os.path.join(path, os.path.basename(name))
- newname = os.path.join(path, "%08x" % (adler32(body) & 0xffffffff))+imgext
-
- try: # for Windows
- os.remove(newname)
- except Exception, exc:
- logger.debug('File '+newname+' does not exist, not deleted')
-
- os.rename(name, newname)
- url = global_siteurl + '/images/' + os.path.basename(newname)
- imgnode = image(uri=url, classes=classes, alt=alt)
- nodes.append(imgnode)
- else:
- error = self.state_machine.reporter.error(
- 'Error in "%s" directive: %s' % (self.name, err),
- literal_block(self.block_text, self.block_text),
- line=self.lineno)
- nodes.append(error)
- return nodes
- def custom_url(generator, metadata):
- global global_siteurl
- global_siteurl = generator.settings['SITEURL']
-
- def register():
- """Plugin registration."""
- signals.article_generator_context.connect(custom_url)
- directives.register_directive('uml', PlantUML)
|