def DocbookEpub(env, target, source=None, *args, **kw):
    """
    A pseudo-Builder, providing a Docbook toolchain for ePub output.
    """
    import zipfile
    import shutil
    
    def build_open_container(target, source, env):
        """Generate the *.epub file from intermediate outputs

        Constructs the epub file according to the Open Container Format. This 
        function could be replaced by a call to the SCons Zip builder if support
        was added for different compression formats for separate source nodes.
        """
        zf = zipfile.ZipFile(str(target[0]), 'w')
        mime_file = open('mimetype', 'w')
        mime_file.write('application/epub+zip')
        mime_file.close()
        zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
        for s in source:
            if os.path.isfile(str(s)):
                head, tail = os.path.split(str(s))
                if not head:
                    continue
                s = head
            for dirpath, dirnames, filenames in os.walk(str(s)):
                for fname in filenames:
                    path = os.path.join(dirpath, fname)
                    if os.path.isfile(path):
                        zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
                            zipfile.ZIP_DEFLATED)
        zf.close()
        
    def add_resources(target, source, env):
        """Add missing resources to the OEBPS directory

        Ensure all the resources in the manifest are present in the OEBPS directory.
        """
        hrefs = []
        content_file = os.path.join(source[0].get_abspath(), 'content.opf')
        if not os.path.isfile(content_file):
            return
        
        hrefs = []
        if has_libxml2:
            nsmap = {'opf' : 'http://www.idpf.org/2007/opf'}
            # Read file and resolve entities
            doc = libxml2.readFile(content_file, None, 0)
            opf = doc.getRootElement()
            # Create xpath context
            xpath_context = doc.xpathNewContext()
            # Register namespaces
            for key, val in nsmap.items():
                xpath_context.xpathRegisterNs(key, val)

            if hasattr(opf, 'xpathEval') and xpath_context:
                # Use the xpath context
                xpath_context.setContextNode(opf)
                items = xpath_context.xpathEval(".//opf:item")
            else:
                items = opf.findall(".//{'http://www.idpf.org/2007/opf'}item")

            for item in items:
                if hasattr(item, 'prop'):
                    hrefs.append(item.prop('href'))
                else:
                    hrefs.append(item.attrib['href'])

            doc.freeDoc()
            xpath_context.xpathFreeContext()            
        elif has_lxml:
            from lxml import etree
            
            opf = etree.parse(content_file)
            # All the opf:item elements are resources
            for item in opf.xpath('//opf:item', 
                    namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):
                hrefs.append(item.attrib['href'])
        
        for href in hrefs:
            # If the resource was not already created by DocBook XSL itself, 
            # copy it into the OEBPS folder
            referenced_file = os.path.join(source[0].get_abspath(), href)
            if not os.path.exists(referenced_file):
                shutil.copy(href, os.path.join(source[0].get_abspath(), href))
        
    # Init list of targets/sources
    target, source = __extend_targets_sources(target, source)
    
    # Init XSL stylesheet
    __init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_EPUB', ['epub','docbook.xsl'])

    # Setup builder
    __builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
    
    # Create targets
    result = []
    if not env.GetOption('clean'):        
        # Ensure that the folders OEBPS and META-INF exist
        __create_output_dir('OEBPS/')
        __create_output_dir('META-INF/')
    dirs = env.Dir(['OEBPS', 'META-INF'])
    
    # Set the fixed base_dir
    kw['base_dir'] = 'OEBPS/'
    tocncx = __builder.__call__(env, 'toc.ncx', source[0], **kw)
    cxml = env.File('META-INF/container.xml')
    env.SideEffect(cxml, tocncx)
    
    env.Depends(tocncx, kw['DOCBOOK_XSL'])
    result.extend(tocncx+[cxml])

    container = env.Command(__ensure_suffix(str(target[0]), '.epub'), 
        tocncx+[cxml], [add_resources, build_open_container])    
    mimetype = env.File('mimetype')
    env.SideEffect(mimetype, container)

    result.extend(container)
    # Add supporting files for cleanup
    env.Clean(tocncx, dirs)

    return result
def DocbookEpub ( env , target , source = None , * args , ** kw ) : import zipfile import shutil def build_open_container ( target , source , env ) : zf = zipfile . ZipFile ( str ( target [ 0 ] ) , 'w' ) mime_file = open ( 'mimetype' , 'w' ) mime_file . write ( 'application/epub+zip' ) mime_file . close ( ) zf . write ( mime_file . name , compress_type = zipfile . ZIP_STORED ) for s in source : if os . path . isfile ( str ( s ) ) : head , tail = os . path . split ( str ( s ) ) if not head : continue s = head for dirpath , dirnames , filenames in os . walk ( str ( s ) ) : for fname in filenames : path = os . path . join ( dirpath , fname ) if os . path . isfile ( path ) : zf . write ( path , os . path . relpath ( path , str ( env . get ( 'ZIPROOT' , '' ) ) ) , zipfile . ZIP_DEFLATED ) zf . close ( ) def add_resources ( target , source , env ) : hrefs = [ ] content_file = os . path . join ( source [ 0 ] . get_abspath ( ) , 'content.opf' ) if not os . path . isfile ( content_file ) : return hrefs = [ ] if has_libxml2 : nsmap = { 'opf' : 'http://www.idpf.org/2007/opf' } doc = libxml2 . readFile ( content_file , None , 0 ) opf = doc . getRootElement ( ) xpath_context = doc . xpathNewContext ( ) for key , val in nsmap . items ( ) : xpath_context . xpathRegisterNs ( key , val ) if hasattr ( opf , 'xpathEval' ) and xpath_context : xpath_context . setContextNode ( opf ) items = xpath_context . xpathEval ( ".//opf:item" ) else : items = opf . findall ( ".//{'http://www.idpf.org/2007/opf'}item" ) for item in items : if hasattr ( item , 'prop' ) : hrefs . append ( item . prop ( 'href' ) ) else : hrefs . append ( item . attrib [ 'href' ] ) doc . freeDoc ( ) xpath_context . xpathFreeContext ( ) elif has_lxml : from lxml import etree opf = etree . parse ( content_file ) for item in opf . xpath ( '//opf:item' , namespaces = { 'opf' : 'http://www.idpf.org/2007/opf' } ) : hrefs . append ( item . attrib [ 'href' ] ) for href in hrefs : referenced_file = os . path . join ( source [ 0 ] . get_abspath ( ) , href ) if not os . path . exists ( referenced_file ) : shutil . copy ( href , os . path . join ( source [ 0 ] . get_abspath ( ) , href ) ) target , source = __extend_targets_sources ( target , source ) __init_xsl_stylesheet ( kw , env , '$DOCBOOK_DEFAULT_XSL_EPUB' , [ 'epub' , 'docbook.xsl' ] ) __builder = __select_builder ( __lxml_builder , __libxml2_builder , __xsltproc_builder ) result = [ ] if not env . GetOption ( 'clean' ) : __create_output_dir ( 'OEBPS/' ) __create_output_dir ( 'META-INF/' ) dirs = env . Dir ( [ 'OEBPS' , 'META-INF' ] ) kw [ 'base_dir' ] = 'OEBPS/' tocncx = __builder . __call__ ( env , 'toc.ncx' , source [ 0 ] , ** kw ) cxml = env . File ( 'META-INF/container.xml' ) env . SideEffect ( cxml , tocncx ) env . Depends ( tocncx , kw [ 'DOCBOOK_XSL' ] ) result . extend ( tocncx + [ cxml ] ) container = env . Command ( __ensure_suffix ( str ( target [ 0 ] ) , '.epub' ) , tocncx + [ cxml ] , [ add_resources , build_open_container ] ) mimetype = env . File ( 'mimetype' ) env . SideEffect ( mimetype , container ) result . extend ( container ) env . Clean ( tocncx , dirs ) return result
A pseudo-Builder, providing a Docbook toolchain for ePub output.