Dynastie/dynastie/generators/generator.py

277 lines
8.9 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
"""
2014-01-04 13:55:30 +01:00
Copyright 2012-2014 Grégory Soutadé
This file is part of Dynastie.
Dynastie 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 3 of the License, or
(at your option) any later version.
Dynastie 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 Dynastie. If not, see <http://www.gnu.org/licenses/>.
"""
2012-07-18 11:30:54 +02:00
import os
import hashlib
2012-07-18 11:46:31 +02:00
import gzip
import math
import codecs
2012-07-18 11:30:54 +02:00
from xml.dom import *
2012-08-14 21:26:48 +02:00
from xml.dom.minidom import parse
from xml.parsers.expat import *
2012-07-18 11:30:54 +02:00
class StrictUTF8Writer(codecs.StreamWriter):
'''A StreamWriter for utf8'''
encode = codecs.utf_8_encode
value = ''
def __init__(self):
self.value = u''
def write(self, object):
object = object.replace('&lt;', '<')
object = object.replace('&gt;', '>')
object = object.replace('&quot;', '"')
object = object.replace('&apos;', "'")
2012-12-10 19:30:25 +01:00
object = object.replace('&amp;', '&')
if not type(object) == unicode:
2012-12-10 19:30:25 +01:00
self.value = self.value + unicode(object, 'utf-8')
else:
self.value = self.value + object
return self.value
def reset(self):
self.value = u''
def getvalue(self):
return self.value
2012-07-15 18:21:26 +02:00
class DynastieGenerator:
2012-07-18 11:30:54 +02:00
URI = "http://indefero.soutade.fr/p/dynastie"
2013-01-06 18:28:03 +01:00
def __init__(self, hash_posts=None, hash_posts_content=None):
2012-07-18 11:46:31 +02:00
self.report = ''
2012-07-22 10:47:24 +02:00
self.somethingWrote = False
self.hash_posts = hash_posts
2013-01-06 18:28:03 +01:00
self.hash_posts_content = hash_posts_content
2012-07-18 11:46:31 +02:00
2012-07-18 11:30:54 +02:00
def addReport(self, string, color=''):
if string in self.report: return
2014-09-24 20:27:27 +02:00
if color:
2012-07-18 11:30:54 +02:00
self.report = self.report + '<span style="color:' + color + '">'
self.report = self.report + '<b>' + self.__class__.__name__ + '</b> : '
self.report = self.report + string
2014-09-24 20:27:27 +02:00
if color:
2012-07-18 11:30:54 +02:00
self.report = self.report + '</span>'
self.report = self.report + '<br/>\n'
def addWarning(self, string):
self.addReport(string, 'yellow')
def addError(self, string):
self.addReport(string, 'red')
# Virtual
2012-07-15 18:21:26 +02:00
def generate(self, blog, src, output):
return
2012-08-28 09:09:14 +02:00
def computeNbPages(self, nb_post, nb_post_per_page):
res = math.ceil((nb_post*1.0)/(nb_post_per_page*1.0))
return int(res)
def writeIfNotTheSame(self, filename, node):
from dynastie.models import FileOutputCache
writer = StrictUTF8Writer()
node.writexml(writer)
content = writer.getvalue().encode('utf-8')
2012-07-18 11:30:54 +02:00
dst_md5 = hashlib.md5()
dst_md5.update(content)
2012-07-18 11:30:54 +02:00
cache_objs = FileOutputCache.objects.filter(name=filename)
if cache_objs.count() == 0:
cache_obj = None
else:
cache_obj = cache_objs[0]
2014-09-24 20:27:27 +02:00
if cache_obj or os.path.exists(filename):
if not cache_obj:
src_md5 = hashlib.md5()
f = open(filename,'rb')
src_md5.update(f.read())
f.close()
src_md5 = src_md5.hexdigest()
else:
src_md5 = cache_obj.hash
if src_md5 == dst_md5.hexdigest():
if cache_obj is None:
cache_obj = FileOutputCache(name=filename, hash=src_md5)
cache_obj.save()
2012-07-18 11:46:31 +02:00
filename = filename + '.gz'
if not os.path.exists(filename):
f = gzip.open(filename, 'wb')
f.write(content)
f.close()
2012-07-18 11:30:54 +02:00
return
2014-09-24 20:27:27 +02:00
if os.path.exists(filename):
os.unlink(filename)
2012-07-18 11:30:54 +02:00
if cache_obj is None:
cache_obj = FileOutputCache(name=filename, hash=dst_md5.hexdigest())
else:
cache_obj.hash = dst_md5.hexdigest()
self.addReport('Write (and compress) ' + filename)
2012-07-18 11:30:54 +02:00
f = open(filename,'wb')
f.write(content)
f.close()
2012-07-18 11:46:31 +02:00
filename = filename + '.gz'
#self.addReport('Compressing it ' + filename)
2012-07-18 11:46:31 +02:00
f = gzip.open(filename, 'wb')
f.write(content)
f.close()
2012-07-22 10:47:24 +02:00
cache_obj.save()
2012-07-22 10:47:24 +02:00
self.somethingWrote = True
2012-07-18 11:30:54 +02:00
def createLinkElem(self, dom, path, title):
link_elem = dom.createElement('a')
link_elem.setAttribute('href', path)
text_elem = dom.createTextNode(title)
link_elem.appendChild(text_elem)
return link_elem
2013-10-26 09:26:47 +02:00
def cloneSubtree(self, div, subtree):
for node in subtree.childNodes:
div.appendChild(node.cloneNode(True))
def createElement(self, dom, name='', content='', subtree=None):
2012-07-18 11:30:54 +02:00
div = dom.createElement('div')
2014-09-24 20:27:27 +02:00
if name:
2012-07-20 21:54:43 +02:00
div.setAttribute('class', name)
2014-09-24 20:27:27 +02:00
if content:
2012-07-20 21:54:43 +02:00
div.appendChild(dom.createTextNode(content))
2014-09-24 20:27:27 +02:00
if subtree:
2013-10-26 09:26:47 +02:00
self.cloneSubtree(div, subtree)
2012-07-18 11:30:54 +02:00
return div
2012-07-15 18:21:26 +02:00
def createMeta(self, dom, name='', content=''):
div = dom.createElement('meta')
2014-09-24 20:27:27 +02:00
if name:
div.setAttribute('name', name)
2014-09-24 20:27:27 +02:00
if content:
div.setAttribute('content', content)
return div
# Recursively transform <dyn:XXX> elements with the ones in values
2012-07-18 11:30:54 +02:00
def simpleTransform(self, values, dom, elem, root):
for node in root.childNodes:
if node.prefix == 'dyn':
if node.localName in values:
content = values[node.localName]
2014-09-24 20:27:27 +02:00
if isinstance(content, basestring):
new_elem = self.createElement(dom, node.localName, content)
else:
new_elem = self.createElement(dom, node.localName)
new_elem.appendChild(content)
else:
new_elem = node.cloneNode(False)
self.simpleTransform(values, dom, new_elem, node)
2012-07-18 11:30:54 +02:00
else:
2012-07-20 21:54:43 +02:00
new_elem = node.cloneNode(False)
self.simpleTransform(values, dom, new_elem, node)
elem.appendChild(new_elem)
def replaceByText(self, dom, root, node, content):
new_node = dom.createTextNode(content)
root.replaceChild(new_node, node)
2012-08-14 21:26:48 +02:00
2012-08-28 09:09:14 +02:00
def _parse(self, hooks, posts, dom, root):
for node in root.childNodes:
2014-09-24 20:27:27 +02:00
if node.prefix == 'dyn' and node.localName in hooks:
node = hooks[node.localName](posts, dom, root, node)
if node and node.hasChildNodes():
2012-08-28 09:09:14 +02:00
self._parse(hooks, posts, dom, node)
2012-08-14 21:26:48 +02:00
2012-08-28 09:09:14 +02:00
def parse(self, src, hooks, posts, dom, root):
2012-08-14 21:26:48 +02:00
bases = dom.getElementsByTagNameNS(self.URI, 'base')
2014-09-24 20:27:27 +02:00
if not bases:
2012-08-28 09:09:14 +02:00
self._parse(hooks, posts, dom, root)
2012-08-14 21:26:48 +02:00
return root
if len(bases) != 1:
self.addError('More than one base defined')
2012-08-14 21:26:48 +02:00
return root
base = bases[0]
if not base.hasAttribute('file'):
self.addError('No \'file\' attribute defined')
2012-08-14 21:26:48 +02:00
return root
filename = base.getAttribute('file')
if not os.path.exists(src + '/' + filename):
self.addError('Base ' + filename + ' doesn\'t exists')
2012-08-14 21:26:48 +02:00
return root
2014-03-27 18:25:36 +01:00
target_blocks = base.getElementsByTagNameNS(self.URI, 'block')
2014-09-24 20:27:27 +02:00
if not target_blocks:
2014-03-27 18:25:36 +01:00
self.addError('No \'block\' defined in ' + src + '/' + filename)
return root
for target_block in target_blocks:
if not target_block.hasAttribute('name'):
self.addError('Every block must have a name in ' + src + '/' + filename)
return root
2012-08-14 21:26:48 +02:00
dom2 = root
try:
dom2 = parse(src + '/' + filename)
except ExpatError, e:
self.addError('Error parsing ' + src + '/' + filename)
return root
blocks = dom2.getElementsByTagNameNS(self.URI, 'block')
block_found = False
for block in blocks:
if not block.hasAttribute('name'):
2014-03-27 18:25:36 +01:00
self.addError('block has no attribute \'name\' in ' + src + '/' + filename)
2012-08-14 21:26:48 +02:00
return root
blockname = block.getAttribute('name')
2014-03-27 18:25:36 +01:00
for target_block in target_blocks:
if blockname != target_block.getAttribute('name'):
continue
for child in target_block.childNodes:
block.parentNode.appendChild(child.cloneNode(True))
block_found = True
break
2012-08-14 21:26:48 +02:00
block.parentNode.removeChild(block)
if not block_found:
2014-03-27 18:25:36 +01:00
self.addError('Any block found in ' + src + '/' + filename)
2012-08-14 21:26:48 +02:00
return root
root = dom2.firstChild
2012-08-28 09:09:14 +02:00
self.parse(src, hooks, posts, dom2, root)
2012-08-14 21:26:48 +02:00
return root