"""
The Project object is used to represent a project.xml file. Example usage:
>>> from bkgen.project import Project
>>> fn = '/path/to/Project-Folder/project.xml'
>>> project = Project(fn=fn)
Now all of the methods of the project can be called.
"""
import logging
log = logging.getLogger(__name__)
import os, re, shutil, subprocess, sys, time, traceback
from copy import deepcopy
from glob import glob
from bl.dict import Dict
from bl.file import File
from bl.string import String
from bl.rglob import rglob
from bl.text import Text
from bl.dict import Dict
from bl.zip import ZIP
from bxml.xml import XML, etree
from bxml.builder import Builder
from bkgen import NS, config, mimetypes
from .source import Source
FILENAME = os.path.abspath(__file__)
PATH = os.path.dirname(FILENAME)
PUB = Builder.single(NS.pub)
[docs]class Project(XML, Source):
"""Every project has a project.xml file that holds information about the project.
The root element is pub:project, where ``pub:`` is the Publishing XML namespace
(see `publishingxml.org <http://publishingxml.org>`_).
"""
ROOT_TAG = "{%(pub)s}project" % NS #: The tag for the root element of a project.
OUTPUT_KINDS = Dict(**{'EPUB':'.epub', 'Kindle':'.mobi'}) #: The kinds of outputs that are currently supported.
def __init__(self, **args):
XML.__init__(self, **args)
if self.content_folder is None: self.content_folder = 'content'
if self.image_folder is None: self.image_folder = self.content_folder + '/images'
if self.cover_folder is None: self.cover_folder = 'cover'
if self.output_folder is None: self.output_folder = 'outputs'
if self.interior_folder is None: self.interior_folder = 'interior'
if self.source_folder is None: self.source_folder = 'sources'
def __repr__(self):
return "Project(fn=%r)" % self.fn
@property
def name(self):
return self.root.get('name')
@property
def path(self):
return os.path.dirname(os.path.abspath(self.fn))
@property
def content_path(self):
return os.path.join(self.path, self.content_folder)
@property
def image_path(self):
return os.path.join(self.path, self.image_folder)
@property
def cover_path(self):
return os.path.join(self.path, self.cover_folder)
@property
def output_path(self):
return os.path.join(self.path, self.output_folder)
@property
def interior_path(self):
return os.path.join(self.path, self.interior_folder)
@property
def output_kinds(self):
return self.get('output_kinds') or self.OUTPUT_KINDS
# SOURCE METHODS
[docs] def resources(self):
return self.find(self.root, "pub:resources", namespaces=NS)
[docs] def documents(self):
"""all of pub:document files in the content subfolder."""
from .document import Document
return [Document(fn=fn) for fn in rglob(self.path, 'content/*.xml')]
[docs] def images(self):
"""all of the image files in the content subfolder."""
from bf.image import Image
images = [Image(fn=fn)
for fn
in rglob(os.path.join(self.path, self.content_folder), '*.*')
if os.path.splitext(fn)[-1].lower() in
['.jpg', '.jpeg', '.tiff', '.tif', '.png', '.pdf', '.bmp']
]
return images
[docs] def stylesheet(self):
"""the master .css for this project is the resource class="stylesheet"."""
from .css import CSS
csshref = self.find(self.root, "pub:resources/pub:resource[@class='stylesheet']/@href", namespaces=NS)
if csshref is not None:
cssfn = os.path.join(self.path, csshref)
return CSS(fn=cssfn)
# CLASSMETHODS
[docs] @classmethod
def create(Class, parent_path, title, name=None, **project_params):
"""create a new project.
parent_path = the filesystem path to the parent folder that this project is in
title = the title for the project
name = the name of the project, which becomes its folder name and URL slug
project_params = parameters passed to the Project.__init__()
Returns the Project XML object.
"""
name = name or String(title).nameify()
if not(re.match(r"^[\w\-\_\.]+$", name or '', flags=re.U)):
raise ValueError('Please provide a project name containing letters, numbers, hyphens, '
+ 'underscores, and periods -- no whitespace or special characters.')
if not os.path.exists(parent_path):
os.makedirs(parent_path)
# raise ValueError("Before creating the project, first create the parent folder, %s" % parent_path)
project_path = os.path.join(parent_path, name)
if not os.path.exists(project_path):
os.makedirs(project_path)
else:
log.info("Project folder already exists: %s" % project_path)
project_fn = os.path.join(project_path, 'project.xml')
if os.path.exists(project_fn):
log.info("Project file already exists, not overwriting: %s" % project_fn)
project = Class(fn=project_fn, **project_params)
else:
project = Class(fn=os.path.join(PATH, 'templates', 'project.xml'), **project_params)
project.fn = os.path.join(project_path,'project.xml')
project.root.set('name', name)
project.find(project.root, "opf:metadata/dc:title", namespaces=NS).text = title
# make sure there is a base set of project folders
for folder in [project.get(k) for k in project.keys() if '_folder' in k and project.get(k) is not None]:
path = os.path.join(project_path, folder)
if not os.path.exists(path): os.makedirs(path)
# make sure there is a global content stylesheet for this project
stylesheet_elem = project.find(project.root,
"pub:resources/pub:resource[@class='stylesheet']", namespaces=NS)
if stylesheet_elem is not None:
stylesheet_fn = os.path.abspath(os.path.join(project.path, stylesheet_elem.get('href')))
if not os.path.exists(stylesheet_fn):
stylesheet_elem.getparent().remove(stylesheet_elem)
stylesheet_elem = None
if stylesheet_elem is None:
stylesheet_fn = os.path.join(project.path, 'project.css')
stylesheet_href = os.path.relpath(stylesheet_fn, project.path)
project.add_resource(stylesheet_href, 'stylesheet')
if not os.path.exists(stylesheet_fn):
log.debug("stylesheet does not exist, creating")
from bl.text import Text
stylesheet = Text(fn=os.path.join(PATH, 'templates', 'project.css'))
stylesheet.fn = stylesheet_fn
stylesheet.write()
log.debug("project stylesheet = %r" % stylesheet_fn)
project.write()
return project
[docs] def add_resource(self, href, resource_class, kind=None):
"""add the given resource to the project file, if it isn't already present"""
resources = self.resources()
resource = self.find(resources, "/pub:resource[@href='%s' and @class='%s']" % (href, resource_class), namespaces=NS)
if resource is None:
resource = PUB.resource({'href':href, 'class':resource_class}); resource.tail='\n\t\t'
if kind is not None: resource.set('kind', kind)
resources.append(resource)
else:
log.warn("resource with that href already exists: %r" % resource.attrib)
return resource
[docs] def import_source_file(self, fn, **args):
"""import the source fn.
fn = the filesystem path to the file (such as a temporary file location)
args = arguments that will be passed to Project.import_source()
"""
content_type = mimetypes.guess_type(fn)[0]
ext = os.path.splitext(fn)[-1].lower()
result = Dict()
log.info("%r.import_source_file(%r, **%r)" % (self, fn, args))
# .DOCX files
if (content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
or ext == '.docx'):
# write the content data to a temporary folder
from .docx import DOCX
self.import_source(DOCX(fn=fn), **args)
# .EPUB files
elif (content_type=='application/epub+zip'
or ext == '.epub'):
from .epub import EPUB
self.import_source(EPUB(fn=fn), **args)
# .IDML files
elif (content_type=='application/vnd.adobe.indesign-idml-package'
or ext == '.idml'):
from .idml import IDML
self.import_source(IDML(fn=fn), **args)
# .ICML files
elif (content_type=='application/xml'
and ext == '.icml'):
from .icml import ICML
self.import_source(ICML(fn=fn), **args)
# Images
elif (content_type in ['image/jpeg', 'image/png', 'image/bmp', 'image/tiff', 'application/pdf']
or ext in ['.jpg', '.jpeg', '.png', '.bmp', '.tif', '.tiff', '.pdf']):
project.import_image(fn)
# not a matching file type
else:
result.message = 'Sorry, not a supported file type: %r (%r)' % (ext, content_type)
result.status = 'error'
log.error(result.message)
if result.status is None:
result.status = 'success'
result.message = 'import succeeded.'
return result
[docs] def import_source(self, source, documents=True, images=True, stylesheet=True, metadata=False, **params):
"""import a source into the project.
source = a Source object that contains the content source
documents = whether to import documents from the source
images = whether to import images from the source
stylesheet = whether to import a stylesheet from the source
metadata = whether to import metadata from the source
**params = passed to the Source.documents(**params) method
"""
# move / copy the source into the "canonical" source file location for this project.
source_new_fn = os.path.join(self.path, self.source_folder, self.make_basename(fn=source.fn))
if source_new_fn != source.fn:
# copy it if it's not inside the project folder
if self.path not in os.path.commonprefix([self.fn, source.fn]):
shutil.copy(source.fn, source_new_fn)
source.fn = source_new_fn
# import the documents, metadata, images, and stylesheet from this source
if documents==True: self.import_documents(source.documents(output_path=self.content_path, **params))
if metadata==True: self.import_metadata(source.metadata())
if images==True: self.import_images(source.images())
if stylesheet==True:
ss = source.stylesheet()
if ss is not None:
ss.fn = os.path.join(self.path, self.content_folder, self.make_basename(fn=source.fn, ext='.css'))
ss.write()
self.write()
[docs] def import_documents(self, documents):
"""import the given document collection. This includes
(1) storing the document in the project.content_folder
(2) adding sections of the document to the spine, if not present
"""
if documents is None: return
spine_elem = self.find(self.root, "pub:spine", namespaces=NS)
spine_hrefs = [
spineitem.get('href')
for spineitem in self.xpath(spine_elem, "pub:spineitem", namespaces=NS)
]
for doc in documents:
# save the document, overwriting any existing document in that location
doc.fn = os.path.join(self.path, self.content_folder, self.make_basename(fn=doc.fn))
doc.write()
# update the project spine element: append anything that is new.
sections = doc.root.xpath("html:body/html:section[@id]", namespaces=NS)
for section in sections:
section_href = os.path.relpath(doc.fn, self.path) + '#' + section.get('id')
if section_href not in spine_hrefs:
spineitem = PUB.spineitem(href=section_href); spineitem.tail = '\n\t\t'
for attrib in ['title', 'epub:type']:
if section.get(attrib) is not None:
spineitem.set(attrib, section.get(attrib))
spine_elem.append(spineitem)
[docs] def import_images(self, images):
if images is None: return
for image in images:
self.import_image(image.fn)
[docs] def import_image(self, fn, **params):
"""import the image from a local file. Process through GraphicsMagick to ensure clean."""
basename = re.sub("(&[\w^;]+;|[\s\&+;'])", "-", os.path.basename(os.path.splitext(fn)[0]+'.jpg'))
outfn = os.path.join(self.path, self.image_folder, basename)
log.debug('image: %s' % os.path.relpath(fn, self.path))
ext = os.path.splitext(fn)[-1].lower()
if ext == '.pdf':
from bf.pdf import PDF
PDF(fn=fn).gswrite(fn=outfn, device='jpeg', res=600)
else:
from bf.image import Image
Image(fn=fn).convert(outfn, format='jpg', quality=90)
# move the image to the Project folder
# and create a resource for it
f = File(fn=outfn)
resource_fn = os.path.join(self.path, self.image_folder, basename)
log.debug("resource = %s" % os.path.relpath(resource_fn, self.path))
f.write(fn=resource_fn)
log.debug(os.path.relpath(resource_fn, self.path))
href = os.path.relpath(resource_fn, self.path)
resource = self.find(self.root, "//pub:resource[@href='%s']" % href, namespaces=NS)
if resource is None:
resource = etree.Element("{%(pub)s}resource" % NS, href=href, **params)
resource.tail = '\n\t'
log.debug("resource.attrib = %r" % resource.attrib)
resources = self.find(self.root, "pub:resources", namespaces=NS)
if 'cover' in resource.get('class'):
if ((params.get('kind') is None or 'digital' in params.get('kind'))
and os.path.splitext(resource_fn)[-1]=='.jpg'):
existing_cover_digital = self.find(self.root,
"//pub:resource[contains(@class,'cover') and (@kind='%s' or not(@kind))]"
% params.get('kind') or 'digital', namespaces=NS)
if existing_cover_digital is not None:
resources.remove(existing_cover_digital)
resources.append(resource)
self.write()
[docs] def get_cover_href(self, kind='digital'):
return self.find(self.root, """
pub:resources/pub:resource[contains(@class, 'cover') and
(not(@kind) or contains(@kind, '%s'))]/@href""" % kind, namespaces=NS)
[docs] def build_outputs(self, kind=None, cleanup=True, before_compile=None):
"""build the project outputs
kind=None: which kind of output to build; if None, build all
"""
log.info("build project outputs: %s" % self.fn)
output_kinds = [k for k in self.OUTPUT_KINDS.keys() if kind is None or k==kind]
results = []
for output_kind in output_kinds:
try:
log.info("output kind=%r" % output_kind)
assert output_kind in self.OUTPUT_KINDS.keys()
if output_kind=='EPUB':
result = self.build_epub(cleanup=cleanup, before_compile=before_compile)
elif output_kind=='Kindle':
result = self.build_mobi(cleanup=cleanup, before_compile=before_compile)
elif output_kind=='Archive':
result = self.build_archive()
except:
msg = (str(String(sys.exc_info()[0].__name__).camelsplit()) + ' ' + str(sys.exc_info()[1])).strip()
result = Dict(kind=output_kind, message=msg, traceback=traceback.format_exc())
log.error(result.msg)
log.debug(result.traceback)
results.append(result)
outputs_elem = self.find(self.root, "pub:outputs", namespaces=NS)
if outputs_elem is not None:
outputs_elem.set('completed', time.strftime("%Y-%m-%dT%H:%M:%S"))
self.write()
return results
[docs] def build_archive(self):
"""create a zip archive of the project folder itself"""
outfn = os.path.join(self.path, self.output_folder, self.name+'.zip')
zipfn = ZIP.zip_path(self.path, fn=outfn, mode='w',
exclude=[os.path.relpath(outfn, self.path)]) # avoid recursive self-inclusion
result = Dict(fn=zipfn)
return result
[docs] def build_epub(self, clean=True, show_nav=False, zip=True, check=True, cleanup=False, before_compile=None, **image_args):
from .epub import EPUB
epub_isbn = self.metadata().identifier(id_patterns=['epub', 'ebook', 'isbn'])
if epub_isbn is not None and epub_isbn.text is not None:
epub_name = epub_isbn.text.replace('-', '')
else:
epub_name = self.name
epub_path = os.path.join(self.path, self.output_folder, epub_name+"_EPUB")
if clean==True and os.path.isdir(epub_path): shutil.rmtree(epub_path)
if not os.path.isdir(epub_path): os.makedirs(epub_path)
resources = self.output_resources(output_path=epub_path, **image_args)
metadata = self.find(self.root, "opf:metadata", namespaces=NS)
cover_src = self.get_cover_href(kind='digital')
spine_items = self.output_spineitems(output_path=epub_path, resources=resources,
ext='.xhtml', **image_args)
result = EPUB().build(epub_path, metadata,
epub_name=epub_name, spine_items=spine_items, cover_src=cover_src,
show_nav=show_nav, before_compile=before_compile, zip=zip, check=check)
if cleanup==True: shutil.rmtree(epub_path)
return result
[docs] def build_mobi(self, clean=True, cleanup=False, before_compile=None, **image_args):
from .mobi import MOBI
mobi_isbn = self.metadata().identifier(id_patterns=['mobi', 'ebook', 'isbn'])
if mobi_isbn is not None:
mobi_name = mobi_isbn.text.replace('-', '')
else:
mobi_name = self.name
mobi_path = os.path.join(self.path, self.output_folder, mobi_name+"_MOBI")
if clean==True and os.path.isdir(mobi_path): shutil.rmtree(mobi_path)
if not os.path.isdir(mobi_path): os.makedirs(mobi_path)
resources = self.output_resources(output_path=mobi_path, **image_args)
metadata = self.root.find("{%(opf)s}metadata" % NS)
cover_src = self.get_cover_href(kind='digital')
spine_items = self.output_spineitems(output_path=mobi_path, resources=resources,
ext='.html', http_equiv_content_type=True, canonicalized=False, **image_args)
result = MOBI().build(mobi_path, metadata,
mobi_name=mobi_name, spine_items=spine_items, cover_src=cover_src, before_compile=before_compile)
if cleanup==True: shutil.rmtree(mobi_path)
return result
[docs] def output_resources(self, output_path=None, **image_args):
log.debug("project.output_resources()")
output_path = output_path or os.path.join(self.path, self.output_folder)
resources = [deepcopy(resource)
for resource
in self.root.xpath("pub:resources/pub:resource[not(@include='False')]", namespaces=NS)]
for resource in resources:
f = File(fn=os.path.abspath(os.path.join(self.path, resource.get('href'))))
if resource.get('class')=='stylesheet':
outfn = self.output_stylesheet(f.fn, output_path)
elif resource.get('class') in ['cover', 'cover-digital', 'image']:
outfn = self.output_image(f.fn, output_path, **image_args)
else: # other resource as-is
outfn = os.path.join(output_path, os.path.relpath(f.fn, os.path.dirname(self.fn)))
f.write(fn=outfn)
resource.set('href', os.path.relpath(outfn, output_path))
log.debug(resource.attrib)
return resources
[docs] def output_stylesheet(self, fn, output_path=None):
log.debug("project.output_stylesheet()")
output_path = output_path or os.path.join(self.path, self.output_folder)
outfn = os.path.join(output_path, os.path.relpath(fn, self.path))
if os.path.splitext(fn)[-1] == '.scss':
from bf.scss import SCSS
outfn = os.path.splitext(outfn)[0]+'.css'
SCSS(fn=fn).render_css().write(fn=outfn)
else:
File(fn=fn).write(fn=outfn)
return outfn
[docs] def output_image(self, fn, output_path=None, outfn=None,
format='jpeg', ext='.jpg', res=300, quality=80, maxwh=2048, maxpixels=4e6):
f = File(fn=fn)
mimetype = f.mimetype() or ''
output_path = output_path or os.path.join(self.path, self.output_folder)
outfn = outfn or os.path.splitext(os.path.join(output_path, f.relpath(dirpath=self.path)))[0] + ext
if not os.path.exists(os.path.dirname(outfn)):
os.makedirs(os.path.dirname(outfn))
if mimetype=='application/pdf' or f.ext().lower() == '.pdf':
from bf.pdf import PDF
res = PDF(fn=fn).gswrite(fn=outfn, device=format, res=res)
elif 'image/' in mimetype:
from bf.image import Image
img_args=Dict(
format=format.upper(),
density="%dx%d" % (res,res),
geometry="%dx%d>" % (maxwh, maxwh))
if format.lower() in ['jpeg', 'jpg']:
img_args.update(quality=quality)
w,h = [int(i) for i in Image(fn=fn).identify(format="%w,%h").split(',')]
if w*h > maxpixels:
img_args.geometry = "%dx%d>" % (maxpixels**.5, maxpixels**.5)
res = Image(fn=fn).convert(outfn, **img_args)
else:
res = None
return outfn
[docs] def output_spineitems(self, output_path=None, ext='.xhtml', resources=None,
http_equiv_content_type=False, canonicalized=False, **image_args):
from bf.image import Image
from .document import Document
log.debug("project.output_spineitems()")
output_path = output_path or os.path.join(self.path, self.output_folder)
if resources is None: resources = self.output_resources(output_path=output_path, **image_args)
spineitems = [deepcopy(spineitem) for spineitem in
self.root.xpath("pub:spine/pub:spineitem[not(@include='False')]", namespaces=NS)]
outfns = []
css_fns = glob(os.path.join(self.path, self.content_folder, '*.css'))
for spineitem in spineitems:
split_href = spineitem.get('href').split('#')
log.debug(split_href)
docfn = os.path.join(self.path, split_href[0])
doc_css_fns = [cfn for cfn in glob(os.path.splitext(docfn)[0]+'.css') if os.path.exists(cfn)]
if len(split_href) > 1:
d = Document.load(fn=docfn, section_id=split_href[1])
else:
d = Document.load(fn=docfn)
outfn = os.path.splitext(os.path.join(output_path, os.path.relpath(d.fn, self.path)))[0] + ext
if 'html' in ext:
# create the output html for this document
h = d.html(fn=outfn, ext=ext, resources=resources,
output_path=output_path, http_equiv_content_type=http_equiv_content_type)
# add the document-specific CSS, if it exists
for doc_css_fn in doc_css_fns:
out_css_fn = os.path.splitext(
os.path.join(output_path, os.path.relpath(doc_css_fn, self.path)))[0]+'.css'
if os.path.exists(doc_css_fn) and not os.path.exists(out_css_fn):
Text(fn=doc_css_fn).write(fn=out_css_fn)
if os.path.exists(out_css_fn):
head = h.find(h.root, "//html:head", namespaces=NS)
href = os.path.relpath(out_css_fn, h.dirpath())
link = etree.Element("{%(html)s}link" % NS, rel="stylesheet", href=href, type="text/css")
head.append(link)
h.write(doctype="<!DOCTYPE html>", canonicalized=canonicalized)
outfns.append(h.fn)
spineitem.set('href', os.path.relpath(h.fn, output_path))
# output any images that are referenced from the document and are locally available
for img in h.root.xpath("//html:img", namespaces=NS):
srcfn = os.path.join(d.path, img.get('src'))
outfn = os.path.join(h.path, img.get('src'))
if os.path.exists(srcfn):
_ = self.output_image(srcfn, outfn=outfn, **image_args)
else:
log.warn("IMAGE NOT FOUND: %s" % srcfn)
if 'html' in ext:
# collect the @ids from the content and fix the hyperlinks
basenames = [os.path.basename(f) for f in outfns]
ids = Dict()
for outfn in outfns:
for elem in XML(fn=outfn).root.xpath("//*[@id]"):
ids[elem.get('id')] = outfn
for outfn in outfns:
log.debug(outfn)
x = XML(fn=outfn)
for e in [
e for e in x.root.xpath("//*[contains(@href, '#')]")
if (e.get('href')[0]=='#'
or e.get('href').split('#')[0] not in basenames)]:
id = e.get('href').split("#")[-1]
if id in ids:
e.set('href', os.path.relpath(ids[id], x.path)+'#'+id)
# images will be jpegs
# for e in x.root.xpath("//html:img[@src]", namespaces=NS):
# e.set('src', os.path.splitext(e.get('src'))[0]+'.jpg')
x.write()
return spineitems
# == COMMAND INTERFACE METHODS ==
[docs]def import_all(project_path):
"""import sources, cover, and metadata into project"""
project = Project(fn=os.path.join(project_path, 'project.xml'), **(config.Project or {}))
basename = os.path.basename(project.path)
log.info("== IMPORT ALL FOR PROJECT: %s ==" % basename)
# make sure the project folders exist
interior_path = os.path.join(project.path, project.interior_folder)
if not os.path.exists(interior_path): os.makedirs(interior_path)
source_path = os.path.join(project.path, project.source_folder)
if not os.path.exists(source_path): os.makedirs(source_path)
cover_path = os.path.join(project.path, project.cover_folder)
if not os.path.exists(cover_path): os.makedirs(cover_path)
# import idml if available
fns = rglob(interior_path, '*.idml') + rglob(source_path, '*.idml')
log.info('-- %d .idml files' % len(fns))
for fn in fns:
project.import_source_file(fn, fns=fns)
# import icml
fns = rglob(interior_path, '*.icml') + rglob(source_path, '*.icml')
log.info('-- %d .icml files' % len(fns))
for fn in fns:
project.import_source_file(fn, fns=fns)
# import docx
fns = rglob(interior_path, '*.docx') + rglob(source_path, '*.docx')
log.info('-- %d .docx files' % len(fns))
for fn in fns:
project.import_source_file(fn, with_metadata=False)
# import metadata.xml
fns = [fn for fn in rglob(project.path, '*metadata.xml')
if '.itmsp' not in fn] # not inside an iTunes Producer package
log.info('-- %d metadata.xml files' % len(fns))
for fn in fns:
project.import_metadata(fn)
# images
fns = [fn for fn in rglob(interior_path+'/Links', "*.*")
if os.path.splitext(fn)[-1].lower() in ['.pdf', '.jpg', '.png', '.tif', '.tiff', '.eps']]
log.info('-- %d image files' % len(fns))
for fn in fns:
project.import_image(fn)
# cover
fns = rglob(cover_path, "*.jpg")
for fn in fns:
project.import_image(fn, **{'class':'cover', 'kind':'digital'})
[docs]def build_project(project_path, format=None):
log.info("== BUILD PROJECT == %s" % os.path.basename(project_path))
project = Project(fn=os.path.join(project_path, 'project.xml'), **(config.Project or {}))
image_args = config.EPUB.images or {}
if format is None or 'epub' in format:
project.build_epub(**image_args)
if format is None or 'mobi' in format:
project.build_mobi(**image_args)
if format=='archive':
project.build_archive()
[docs]def cleanup_project(project_path):
project = Project(fn=os.path.join(project_path, 'project.xml'), **(config.Project or {}))
ebooks_path = os.path.join(path, 'ebooks')
dirs = [d for d in glob(ebooks_path+'/*') if os.path.isdir(d)]
for d in dirs:
log.debug("Removing: %s" % d)
shutil.rmtree(d)
[docs]def zip_project(project_path):
from bl.zip import ZIP
return ZIP.zip_path(project_path)
[docs]def remove_project(project_path):
shutil.rmtree(project_path)
if __name__=='__main__':
from bkgen import config
logging.basicConfig(**config.Logging)
if len(sys.argv) < 2:
log.warn("Usage: python -m bkgen.project command project_path [project_path] ...")
else:
for project_path in sys.argv[2:]:
project_path = os.path.abspath(project_path)
if 'create' in sys.argv[1]:
Project.create(os.path.dirname(project_path), os.path.basename(project_path))
if 'import-all' in sys.argv[1]:
import_all(project_path)
elif 'import' in sys.argv[1]:
project = Project(fn=os.path.join(sys.argv[2], 'project.xml'))
for fn in sys.argv[3:]:
log.info("import %s" % fn)
project.import_source_file(fn)
if 'build' in sys.argv[1]:
if '-epub' in sys.argv[1]: format='epub'
elif '-mobi' in sys.argv[1]: format='mobi'
elif '-archive' in sys.argv[1]: format='archive'
else: format = None
build_project(project_path, format=format)
if 'cleanup' in sys.argv[1]:
cleanup_project(project_path)
if 'zip' in sys.argv[1]:
zip_project(project_path)
if 'remove' in sys.argv[1]:
remove_project(project_path)