#-*- coding: utf-8 -*-
"""Creates extended API reference by *epydoc*.
"""
from __future__ import absolute_import
from __future__ import print_function
import sys
import os
import time
import shutil
import json
import re
import distutils.cmd
import setupdocx
import setuplibcore
import yapyutils.files.utilities as utilities
import yapyutils.files.finder as finder
import yapyutils.config.capabilities
import yapyutils.releases
__author__ = 'Arno-Can Uestuensoez'
__author_email__ = 'acue_sf2@sourceforge.net'
__license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints"
__copyright__ = "Copyright (C) 2019 Arno-Can Uestuensoez @Ingenieurbuero Arno-Can Uestuensoez"
__uuid__ = "45167c30-3261-4a38-9de4-d7151348ba48"
class SetupdocXBuildApirefError(setupdocx.SetupDocXError):
"""Error on build apiref.
"""
pass
class SetupdocXBuildApirefSetupError(SetupdocXBuildApirefError):
"""Erroneous builder tool setup.
"""
pass
class SetupdocXBuildApirefConfError(SetupdocXBuildApirefError):
"""Erroneous configuration of templates/styles for the builder .
"""
pass
[docs]class BuildApirefX(distutils.cmd.Command):
"""Create API reference."""
description = 'Create API reference.'
user_options = [
('builder=', None, "The builder to be used for the creation of the API reference. "
"See '--help-builder'. "
"Default: 'epydoc'"),
('builder-path=', None, "The directory path of the builder. "
"Default: '<SETUPDOCX-PYTHONPATH>/setupdocx/builder/'"),
('build-dir=', None, "The name of the build directory. "
"Default: 'build/'"),
('build-reldir=', None, "The name of the relative build subdirectory."
" Default: '<builder>/apiref/'"),
('clean', None, "Removes the cached previous build. Default: False"),
('clean-all', None, "Removes the complete build directory before calling the wrapper. "
"Default: '<build-dir>/apiref'."),
('config-path=', None, "The directory path containing the assigned configurations. "
"See '--list-templates-std' and '--list-templates'. "
"Default: 'config/<builder>/:<docsource>/config/<builder>/'. "),
('debug', 'd', "Raises degree of debug traces of current context. Supports repetition. "
"Each raises the command verbosity level of the context by one."),
('docname=', None, "The document output name. "
"Default: attribute of derived class self.name"),
('docsource=', None, "The name of the document source directory. "
"Default: 'docsrc/'"),
('doctemplate=', None, "The design template to be used. A valid entry within '<config-path>/'. "
"Default: 'alabaster'."),
('doctype=', None, "The final document type to create. this requires '--gendoc' for activation."
"See '--list-doctypes'. "
"Default: 'html', "),
('executable=', None, "The executable called by the wrapper. "
"Supports relative and absolute file path names. "
"Default: 'epydoc'"),
('executableopts=', None, "Additional options to be passed to the executable. "
"Default: ''"),
('executableopts-reset', None, "Initialize empty options for the called executable. "
"Default: 'False'"),
('gendoc', 'r', "Create complete API document. The default is to create the 'rst' files only. "
"Default: off"),
('indexsrc=', None, "The source file to be copied as 'index.rst'. "
"Default: 'index.rst'"),
('list-doctypes', None, "List of available types of document formats."),
('list-metatypes', None, "List of available types of meta formats."),
('list-templates-std', None, "List provided configuration templates."),
('list-templates=', None, "Lists the configuration templates with filter parameter, see manuals. "
"Online help is evailable by the parameter 'list-templates=help'. "
"Default: same as '--list-templates-std'"),
('metatype=', None, "The meta document type to create to be added to the document sources. "
"See '--list-metatypes'. "
"Default: 'rst', "),
('name=', None, "The name of the package. "
"Default: attribute of derived class 'self.name'"),
('noexec=', None, "Print the call of the selected level only, do not execute. "
"The value is an integer, decremented by each level until '0', " "which is the level to be printed. "
"The option is different from he global '--dry-run' options, as it "
"has to handle multiple call levels of subprocesses."),
('quiet', 'q', "Quiet the current context, resets verbosity of applied context to '0'. "
"This is the enforced global option, which is the negative option "
"of '--verbose'. "
"Default: off"),
('raw', None, "If present uses the raw document output from the API generation, "
"else copies from configuration template. "
"Default: off"),
('srcdir=', None, "Source directory."),
('set-release=', None, "The release of the package."),
('set-version=', None, "The version of the package. "
"Default: attribute of derived class self.distribution.metadata.version"),
('wrapper=', None, "The wrapper called by the builder. "
"Supports pure file names only. "
"Default: 'call_apiref.sh'"),
('wrapperopts=', None, "Additional options to be passed to the called wrapper. "
"Default: ''"),
('wrapperopts-reset', None, "Drop generated options for the wrapper, does not effect environment. "
"Default: 'False'"),
('verbose', 'v', "Raises verbosity of current context. Supports repetition. "
"Each raises the command verbosity level of the context by one. "
"The value is defined by the global option defined in "
"'Distribution'. "
"Refer to the manuals for the special behaviour when used as "
"either a global option(start 'verbose=1'), "
"or as a command context option(start 'verbose=0'). "
"Default:=1."),
#FIXME:
('verbose-ext=', 'x', "verbose for external tools, integer value, higher values raise the level"),
]
#: The provided capabilities of the builder and it's components.
capabilities = yapyutils.config.capabilities.Capability(
{
"components": {
"default": "epydoc", # adjusted in dependence of the 'doctype'
"epydoc": "epydoc", # extract reference
},
"epydoc": {
"metatypes": [
"html", # html
],
"doctypes": [
"html", # html
]
},
"defaults": { # DEFAULTS: updated by capabilities.json
"builder": "default", # False
"builder_path": None, # search(<conf-dir>, <configdir>, <docsrc>/conf)/call_apiref.sh
"build_dir": "build/", # build/
"build_reldir": "epydoc/apiref/", # epydoc/apiref/
"clean": None, # False
"config_path": None, # <docsource>/conf/
"docname": None, # attribute of derived class, see self.name
"docsource": "docsrc/", # docsrc/
"doctype": None, # html
"indexsrc": "index.rst", # 'index.rst'
"name": None, # attribute of derived class, see self.name
"release": None, #
"srcdir": None, # list/tuple(<name>/,)
"template": "", # default template, default:=alabaster
"version": None, #
}
}
)
[docs] def initialize_options(self):
"""API of 'distutils'.
REMARK: verbose and debug are encapsulated/hidden by distutils.
"""
self.verbose = None
self.debug = None
self.quiet = None
self.build_dir = None
self.build_reldir = None
self.builder = None
self.builder_path = None
self.clean = None
self.clean_all = None
self.config_path = None
self.docname = None
self.docsource = None
self.doctemplate = None
self.doctype = None
self.executable = None
self.executableopts = None
self.executableopts_reset = None
self.gendoc = None
self.indexsrc = None
self.list_doctypes = None
self.list_metatypes = None
self.list_templates = None
self.list_templates_std = None
self.metatype = None
self.name = None
self.noexec = None
self.raw = None
self.set_release = None
self.set_version = None
self.srcdir = None
self.wrapper = None
self.wrapperopts = None
self.wrapperopts_reset = None
def set_builder_data(self, fpname):
"""Initializes the hard-coded static values first, than
reads the configuration file - if present - and superposes
present values.
The configuration file is expected to be located within
the builder directory.
Args:
fpname:
The file or directory path name of the setup.
File path names are treated literally, while
directory names are scanned for::
capabilities.<ext>
ext := (json)
# Current version supports JSON only.
Returns:
Loaded configutation 'capabilities'.
Raises:
SetupdocXBuildApirefSetupError
pass-through
"""
if fpname and os.path.isfile(fpname):
# file path name is provided
if os.path.splitext(fpname)[1] != 'json':
raise SetupdocXBuildApirefSetupError(
"Current version supports JSON only, got: "
+ str(os.path.splitext(fpname))
)
with open(fpname) as data_file: # load data
self.capabilities = json.load(data_file)
elif fpname and os.path.isdir(fpname):
# director path is provided
_f = fpname + os.sep + 'capabilities.json'
if not os.path.isfile(_f):
raise SetupdocXBuildApirefSetupError(
"Missing setup file: "
+ str(_f)
)
with open(_f) as data_file: # load data
self.capabilities.data = json.load(data_file)
else:
raise SetupdocXBuildApirefSetupError(
"Setup of builder requires either a file or a directory: "
+ str(fpname)
)
[docs] def finalize_options(self):
"""API of 'distutils'.
Args:
none
Returns:
none
Raises:
SetupdocXBuildApirefSetupError
SetupdocxBuildApirefError
pass-through
"""
# scan for any context-help request - despite the following prepared more detailed
if not (
self.list_templates and self.list_templates.endswith('help')
):
_help_request = setuplibcore.check_for_context_help(self)
if _help_request:
print(_help_request)
sys.exit(0)
# quick-and-dirty hack to resolve the inconsistency of
# global and local verbose values of distutils
try:
# The context option is actually not set by the framework,
# instead the global option is reset and intialized to
# the number of occurances and passes to the initialization
# of the memeber 'self.verbose'.
# Thus the poll fails, while the value is already set via the framework.
# See code distutils.dist.Distribution.
# Anyhow...keeping it as a reminder.
_v_opts = self.distribution.get_option_dict('build_docx')['verbose'][1]
if _v_opts:
self.verbose += 1
except:
# fallback to the slightly erroneous behavior when the interface
# of distutils changes
pass
# global and local verbose values of distutils
try:
# See verbose for description of the global option quiet.
# See code distutils.dist.Distribution.
_q_opts = self.distribution.get_option_dict('build_docx')['quiet'][1]
if _q_opts:
self.quiet += 1
except:
# fallback to the slightly erroneous behavior when the interface
# of distutils changes
if self.quiet == None:
self.quiet = 0
pass
# debug
if self.debug == None:
self.debug = 0
# raw
if self.raw == None:
self.raw = 0
else:
self.raw = 1
#
# current builder
#
if self.builder == None:
self.builder = 'epydoc'
attr_searchpath=(self.builder, 'apiref',)
#
# user has provided setup directory for builder - so load first new defaults
#
if self.builder_path != None:
if not os.path.isdir(self.builder_path):
raise SetupdocXBuildApirefSetupError('Missing --builder-path=' + str(self.builder_path))
self.builder_path = os.path.normpath(self.builder_path) + os.sep
self.set_builder_data(self.builder_path + self.builder)
else:
self.builder_path = os.path.dirname(__file__) + os.sep + 'builder' + os.sep
self.set_builder_data(self.builder_path + self.builder)
#
# validate consistency of current builder and defaults
#
if self.builder != self.capabilities('builder', 'name'):
raise SetupdocXBuildApirefSetupError(
'Inconsistent builder:\nbuilder: %s\ndefaults: %s\n\nCheck: %s' %(
str(self.builder),
str(self.capabilities('builder', 'name')),
str(self.builder_path + self.builder)
)
)
#
# user provided configuration directory
#
if self.config_path == None:
self.config_path = self.capabilities[self.builder]['defaults']['config_path']
if not self.config_path:
# empty - for whatever reason
self.config_path = 'config' + os.sep + self.builder
self.config_path += os.pathsep + os.path.dirname(__file__) + os.sep + 'config' + os.sep + self.builder
else:
self.config_path = os.path.normpath(self.config_path) + os.sep
if not self.config_path:
raise SetupdocXBuildApirefConfError(
'Missing template path "--config-path=%s"' % (str(self.config_path),))
else:
_oneok = False
_onedirok = False
for f in self.config_path.split(os.pathsep):
if os.path.isdir(f):
_onedirok = True
if self.doctemplate:
fp = f + os.sep + self.doctemplate
else:
fp = f + os.sep
if os.path.isdir(fp):
self.config_path = f
_oneok = True
if not _oneok:
if not _onedirok:
raise SetupdocXBuildApirefConfError(
'Missing configuration template directory, got "--config-path=%s"' %(
str(self.config_path)
)
)
else:
raise SetupdocXBuildApirefConfError(
'\n\nCannot find configuration template:\n'
' template name: %s\n'
' search path: %s\n'
'\n'
'Check options "--list-templates-std / --list-templates"\n' %(
str(self.doctemplate),
str(self.config_path),
)
)
# if self.config_path == None:
# self.config_path = self.capabilities(
# 'defaults', 'config_path',
# searchpath=attr_searchpath
# )
# if self.config_path == None:
# self.config_path = 'config' + os.sep + self.builder
# self.config_path += os.pathsep + os.path.dirname(__file__) + os.sep + 'config' + os.sep + self.builder
#
# elif not self.config_path:
# raise SetupdocXBuildApirefConfError(
# 'Missing --config-path=' + str(self.config_path))
# else:
# if not os.path.isdir(self.config_path):
# raise SetupdocXBuildApirefConfError(
# 'Requires directory, got --config-path=' + str(self.config_path))
#
# set source directory of document
#
if self.docsource == None:
self.docsource = self.capabilities(
'defaults', 'docsource', searchpath=attr_searchpath)
if self.docsource == None:
self.docsource = 'docsrc'
if self.docsource:
# set directory for pre-edited document components
if not os.path.exists(self.docsource):
raise SetupdocXBuildApirefError("missing docsrc:" + str(self.docsource))
else:
# uses raw output of the called builder - default apiref - only
pass # a reminder...
#
# show templates
#
if self.list_templates_std != None:
setupdocx.conf_list(depth=20) # maximum depth of subdirectory scan
sys.exit(0)
#
# show templates with filters
#
if self.list_templates != None:
_kargs = {}
_args = ''
# _sep = kargs.get('separator', 0)
# _sep = re.sub(r'(.*?)[\\\\]{0,1}(?<=[\\\\]);', r'\1;', _sep)
# mask the suboption separator
# for ai in re.split(r'(?<![\\\\]);', self.list_templates):
for ai in re.split(r'(?<![\[]);(?![\]])', self.list_templates):
if ai:
try:
_k, _v = ai.split('=')
if _k == 'baselist':
_v = _v.split(os.pathsep)
_kargs[_k] = _v
except ValueError:
_args += ',' + ai
if _args.endswith(',help'):
_h = """
Supports the keyword arguments of 'setupdocx.conf_list'.
The keyword parameter 'filter' could be replaced by a comma separated
list of arguments to be assembled into a filter rule.
*args=<list-of-OR-parts-python-re-expression>*
Example::
input:
args := 'agogo,alabas.*'
rule:
args-rule := '(agogo|alabas.*)'
*filter=<python-re-expression>*
input:
filter := 'filter=(agogo|alabas.*)'
rule:
args-rule := '(agogo|alabas.*)'
The keyword parameter 'filter' provides for a wider range of rule syntaxes,
while the 'args' list offers simplicity for casual calls.
The call without parameters is the same as the option '--list-templates-std'.
The 'setupdocx.conf_list' parameters provided for the user interface are:
setupdocx.conf_list
===================
"""
# help(setupdocx.conf_list)
print(_h + setupdocx.conf_list.__doc__)
sys.exit(0)
_filters = None
if _args:
_filters = [x for x in _args.split(',') if x]
if len(_filters) > 1:
_filter = '(' + '|'.join(_filters) + ')'
else:
_filter = _filters[0]
if 'filter' in _kargs:
if _filters:
raise SetupdocXBuildApirefError(
"Filters could be provided either by args as a comma separated list "
"of partial 're' rules internallz converted to a single rule, "
"or by the 'filters=' option as a single final Python-regular "
"expression. The resulting rule is compiled by 're.compile()'. "
"Got:\n"
" args: %s\n"
" filters: %s\n" % (
str(_filters),
str(_kargs['filter']),
)
)
# _filter_re = re.compile(_kargs['filter'])
# if not _filters:
# _filter_re = None
#
# show templates
#
if _kargs.get('depth') == None:
setupdocx.conf_list(depth=2, **_kargs) # show a bit more than top-level - for new users
sys.exit(0)
# elif str(_kargs.get('depth')) == '0':
# _kargs.pop('depth')
setupdocx.conf_list(**_kargs)
sys.exit(0)
# #
# # show templates with filters
# #
# if self.list_templates != None:
# _kargs = {}
# _args = ''
#
# # _sep = kargs.get('separator', 0)
# # _sep = re.sub(r'(.*?)[\\\\]{0,1}(?<=[\\\\]);', r'\1;', _sep)
#
# # mask the suboption separator
# # for ai in re.split(r'(?<![\\\\]);', self.list_templates):
# for ai in re.split(r'(?<![\[]);(?![\]])', self.list_templates):
# if ai:
# try:
# _k, _v = ai.split('=')
# if _k == 'baselist':
# _v = _v.split(os.pathsep)
# _kargs[_k] = _v
# except ValueError:
# # sort out some options without value
# if ai == 'all':
# # list empty builder too
# _kargs['all'] = True
#
# # add arguments
# else:
# _args += ',' + ai
#
# if _args.endswith(',help'):
# _h = """
# Supports the keyword arguments of 'setupdocx.conf_list'.
#
# The keyword parameter 'filter' could be replaced by a comma separated
# list of arguments to be assembled into a filter rule.
#
# *args=<list-of-OR-parts-python-re-expression>*
# Example::
#
# input:
# args := 'agogo,alabas.*'
#
# rule:
# args-rule := '(agogo|alabas.*)'
#
# *filter=<python-re-expression>*
#
# input:
# filter := 'filter=(agogo|alabas.*)'
#
# rule:
# args-rule := '(agogo|alabas.*)'
#
# The keyword parameter 'filter' provides for a wider range of rule syntaxes,
# while the 'args' list offers simplicity for casual calls.
#
# The call without parameters is the same as the option '--list-templates-std'.
# The 'setupdocx.conf_list' parameters provided for the user interface are:
#
# setupdocx.conf_list
# ===================
#
# """
# # help(setupdocx.conf_list)
# print(_h + setupdocx.conf_list.__doc__)
# sys.exit(0)
#
# _filters = None
# if _args:
# _filters = [x for x in _args.split(',') if x]
# if len(_filters) > 1:
# _filter = '(' + '|'.join(_filters) + ')'
# else:
# _filter = _filters[0]
#
# if 'filter' in _kargs:
# if _filters:
# raise SetupdocxBuildApirefError(
# "Filters could be provided either by args as a comma separated list "
# "of partial 're' rules internallz converted to a single rule, "
# "or by the 'filters=' option as a single final Python-regular "
# "expression. The resulting rule is compiled by 're.compile()'. "
# "Got:\n"
# " args: %s\n"
# " filters: %s\n" % (
# str(_filters),
# str(_kargs['filter']),
# )
# )
# elif _filters:
# _kargs['filter'] = _filter
#
# # _filter_re = re.compile(_kargs['filter'])
#
# # if not _filters:
# # _filter_re = None
#
# setupdocx.conf_list([self.config_path], **_kargs)
# sys.exit(0)
#
# show doctypes
#
if self.list_doctypes != None:
print(
"Known document types for API only documentation. These are activated by '--gendoc':"
)
print()
_dtypes = list(self.capabilities('doctypes', searchpath=attr_searchpath))[:]
for _dt in _dtypes:
print(" {dtype:<20} --doctype={dtype}".format(dtype=str(_dt)))
print()
print(
"Note: For metaformats refer to '--list-metatypes'."
)
print()
sys.exit(0)
#
# show metatypes
#
if self.list_metatypes != None:
print("Known meta types for documents:")
print()
_mtypes = list(self.capabilities('metatypes', searchpath=attr_searchpath))[:]
for _mt in _mtypes:
print(" {mtype:<20} --metatype={mtype}".format(mtype=str(_mt)))
print()
print(
"Note: For docformats of API only documentation refer to '--list-doctypes'."
)
print()
sys.exit(0)
#
# common top of build directory for output
#
if self.build_dir == None:
self.build_dir = self.capabilities('defaults', 'build_dir', searchpath=attr_searchpath)
if not self.build_dir:
self.build_dir = 'build'
#
# subdirectory of build for output
#
if self.build_reldir == None:
self.build_reldir = self.capabilities('defaults', 'build_reldir', searchpath=attr_searchpath)
if not self.build_reldir:
self.build_reldir = 'epydoc/apiref/'
# the complete path for the assembled document sources to be processed
self.build_doc_path = os.path.normpath(self.build_dir + os.sep + self.build_reldir)
#
# clean-all - removes complete build subdirectory
#
if self.clean_all == None:
# self.clean_all = self.capabilities.data[self.builder]['apiref']['defaults']['clean-all']
self.clean_all = self.capabilities('defaults', 'clean_all', searchpath=attr_searchpath)
if not self.clean_all:
self.clean_all = 0
else:
self.clean_all = 1
else:
self.clean_all = True
#
# clean - removes pre-artifacts
#
if self.clean == None:
self.clean = self.capabilities('defaults', 'clean', searchpath=attr_searchpath)
if not self.clean:
self.clean = 0
else:
self.clean = 1
else:
self.clean = 1
#
# raw output from the executed tool only, e.g. epydoc
#
if self.gendoc == None:
self.gendoc = 0
else:
self.gendoc = 1
#
# name - from metadata
#
if self.name == None:
# self.name = self.distribution.metadata.name
self.name = self.distribution.metadata.name + '-apiref'
#
# document name - default from metadata
#
if self.docname == None:
self.docname = self.capabilities('defaults', 'docname', searchpath=attr_searchpath)
if self.docname == None:
self.docname = self.name
#
# document template to be used
#
if self.doctemplate == None:
self.doctemplate = self.capabilities('defaults', 'template', searchpath=attr_searchpath)
if not self.doctemplate:
# final default
self.doctemplate = '' # default:=alabaster
#
# document type to be created
#
if self.doctype == None:
self.doctype = self.capabilities('defaults', 'doctype', searchpath=attr_searchpath)
if not self.doctype:
# final default
self.doctype = 'html'
# some alias
if self.doctype == 'pdf':
self.doctype = 'latexpdf'
#
# custom index file appropriate to the doctype option,
# in case of e.g. 'builder=epydoc' => 'indexsrc=rst'
#
if self.indexsrc == None:
self.indexsrc = self.capabilities('defaults', 'indexsrc', searchpath=attr_searchpath)
if self.indexsrc == None:
self.indexsrc = ''
#
# directory containing the source code
#
if self.srcdir == None:
self.srcdir = self.capabilities('defaults', 'srcdir', searchpath=attr_searchpath)
if self.srcdir == None:
self.srcdir = self.name
else:
if type(self.srcdir) is (list, tuple,):
self.srcdir = ';'.join(self.srcdir)
#
# do not execute - just display call
# effects top-level only
#
if self.noexec != None:
self.noexec = int(self.noexec)
else:
self.noexec = 0
if self.verbose == None:
self.verbose0 = 0
else:
self.verbose0 = self.verbose
if self.debug == None:
self.debug0 = 0
else:
self.debug0 = self.debug
#
# executable - default is sphinx-apiref
#
if self.executable == None:
self.executable = self.capabilities('defaults', 'executable', searchpath=attr_searchpath)
if self.executable == None:
self.executable = 'sphinx-apiref'
elif self.executable == '':
raise SetupdocXBuildApirefSetupError(
"Requires executable: --executable"
)
#
# executableopts_reset - reset options before adding new options
#
if self.executableopts_reset == None:
self.executableopts_reset = self.capabilities(
'defaults', 'executableopts_reset', searchpath=attr_searchpath)
if not self.executableopts_reset:
self.executableopts_reset = 0
elif self.executableopts_reset:
self.executableopts_reset = 1
#
# executableopts - additional options to be passed to executable
#
if not self.executableopts:
self.executableopts = self.capabilities(
'defaults', 'executableopts', searchpath=attr_searchpath)
if self.executableopts == None:
self.executableopts = ''
#
# wrapper - default is call_apiref.sh
#
if self.wrapper == None:
self.wrapper = self.capabilities(
'defaults', 'wrapper', searchpath=attr_searchpath)
if self.wrapper == None:
self.wrapper = 'call_apiref.sh'
elif self.wrapper == '':
raise SetupdocXBuildApirefSetupError(
"Requires wrapper: --wrapper"
)
#
# wrapperopts - additional options to be passed to wrapper
#
if self.wrapperopts_reset == None:
self.wrapperopts_reset = self.capabilities(
'defaults', 'wrapperopts_reset', searchpath=attr_searchpath)
if not self.wrapperopts_reset:
self.wrapperopts_reset = 0
else:
self.wrapperopts_reset = 1
if self.wrapperopts_reset:
self.wrapperopts = '1'
else:
#
# wrapperopts - additional options to be passed to executable
#
if self.wrapperopts == None:
self.wrapperopts = self.capabilities(
'defaults', 'wrapperopts', searchpath=attr_searchpath)
if self.wrapperopts == None:
self.wrapperopts = ''
#
# set version of document
#
if self.set_version == None:
try:
self.version = self.distribution.metadata.version
except:
sys.stderr.write(
"WARNING: Cannot readout the version, requires either call option '--version', "
"or stored configuration data.\n"
)
else:
self.version = yapyutils.releases.get_version_complete(self.set_version)
#
# set release of document
#
if self.set_release == None:
try:
if self.release == None:
self.release = ''
except:
self.release = self.version
else:
self.release = self.set_release
self.builddate = time.strftime("%Y.%m.%d-%H:%M", time.gmtime())
self.author = self.distribution.metadata.author
self.license = self.distribution.metadata.license
self.description = self.distribution.metadata.description
try:
if self.copyright == None:
self.copyright = "(C)%s %s" % (str(time.strftime("%Y", time.gmtime())), str(self.author))
except:
self.copyright = "(C)%s %s" % (str(time.strftime("%Y", time.gmtime())), str(self.author))
try:
if self.status == None:
self.status = ''
elif not self.status:
self.status = "Unknown"
sys.stdout.write("Status is not set: Unknown\n")
except:
self.status = "Missing"
sys.stdout.write("Status is not defined: Missing\n")
# the complete path for the final document
self.build_out_path = os.path.normpath(self.build_dir + "/doc/" + str(self.docname))
[docs] def run(self):
"""Creates documents.
Calls the defined and activated wrapper scripts.
The call flow could be customized by various
interfaces. ::
I. self.set_environment() # could be superposed by derived class
II. self.call_prologue() # could be superposed by derived class
III. subprocesses:
1. builder_path.sh # could be arbitrary custom call wrapper
2. build_docx.sh # could be arbitrary custom call wrapper
3. build_apiref.sh # could be arbitrary custom call wrapper
IV. self.call_epilogue() # could be superposed by derived class
"""
#
# clean
#
if self.clean_all:
# clean the complete build directory
if self.verbose > 2:
print('shutil.rmtree(%s, True)' % (self.build_dir))
shutil.rmtree(self.build_dir, True)
elif self.clean:
# clean build directory of apiref - build/<builder>/apiref
if self.verbose > 2:
print('shutil.rmtree(%s, True)' % (self.build_doc_path))
shutil.rmtree(self.build_doc_path, True)
# create when missing
if not os.path.exists(self.build_doc_path):
os.makedirs(self.build_doc_path)
elif not os.path.isdir(self.build_doc_path):
raise SetupdocXBuildApirefError(
"File present with target dirname: "
+ str(self.build_doc_path)
)
#
# call string of apiref wrapper for subprocess
#
command_apiref = []
if self.builder_path:
command_apiref.append(self.builder_path + self.builder + os.sep + self.wrapper)
elif self.verbose > 1:
command_apiref.append(self.wrapper)
sys.stdout.write("skip : builder_path\n")
command_apiref.append(self.wrapperopts)
if self.noexec == 1 or self.verbose > 1 or self.debug:
print()
print("build_apiref:Capabilities: ")
print(" capabilities = "
+ str(self.builder_path + self.builder + os.sep + 'capabilities.json'))
print()
print("build_apiref:Scripts: ")
print(" builder_path = " + str(self.builder_path))
print()
print("build_apiref:Calls: ")
print(" " + ' '.join(command_apiref))
print()
print("build_apiref:Configuration path: ")
print(" config_path = " + str(os.path.abspath(self.config_path)))
print()
if self.noexec > 0:
sys.exit(0)
#
# decrement counter for passing to the next level
#
if self.noexec > 0:
self.noexec -= 1
self.call_prologue()
if self.verbose or self.debug:
print("build_apiref:Calling wrapper " + str(' '.join(command_apiref)))
print()
exit_code = os.system(' '.join(command_apiref)) # create apiref
if self.verbose or self.debug:
print()
print("Finished: %s => exit=%s\n\n" % (
str(' '.join(command_apiref)), str(exit_code)))
print()
self.call_epilogue()
def set_environment(self):
"""Sets the specific environment variables for the subprocess.
In addition writes source files of the environment for the
manual command line start.
The defined variables represent the interface to the wrapper calls,
so no modification of the provided environment is permitted. When
additional information is required do not forget to call this method.
"""
#
# set parameter via environ
#
os.environ['DOCX_AUTHOR'] = self.author
os.environ['DOCX_BUILDDIR'] = self.build_dir
os.environ['DOCX_BUILDER'] = self.builder
os.environ['DOCX_BUILDRELDIR'] = self.build_reldir
os.environ['DOCX_CLEAN'] = str(self.clean)
os.environ['DOCX_CONFIGPATH'] = self.config_path
os.environ['DOCX_COPYRIGHT'] = self.copyright
os.environ['DOCX_DEBUG'] = str(self.debug0)
os.environ['DOCX_DOCNAME'] = self.docname
os.environ['DOCX_DOCSRC'] = self.docsource
os.environ['DOCX_DOCTEMPLATE'] = self.doctemplate
os.environ['DOCX_DOCTYPE'] = self.doctype
os.environ['DOCX_EMBED'] = '0'
os.environ['DOCX_EXEC'] = str(self.executable)
os.environ['DOCX_EXECOPTS'] = str(self.executableopts)
os.environ['DOCX_EXECOPTS_RESET'] = str(self.executableopts_reset)
os.environ['DOCX_GENDOC'] = str(self.gendoc)
os.environ['DOCX_INDEXSRC'] = self.indexsrc
os.environ['DOCX_LIB'] = os.path.abspath(os.path.dirname(__file__))
os.environ['DOCX_LICENSE'] = self.license
os.environ['DOCX_MISSION'] = self.description
os.environ['DOCX_NAME'] = self.name
os.environ['DOCX_NOEXEC'] = str(self.noexec)
os.environ['DOCX_QUIET'] = str(self.quiet)
os.environ['DOCX_RAWDOC'] = str(self.raw)
os.environ['DOCX_SRCDIR'] = self.srcdir
os.environ['DOCX_STATUS'] = self.status
os.environ['DOCX_VERBOSE'] = str(self.verbose0)
os.environ['DOCX_WRAPPER'] = str(self.wrapper)
os.environ['DOCX_WRAPPEROPTS'] = str(self.wrapperopts)
os.environ['DOCX_WRAPPEROPTS_RESET'] = str(self.wrapperopts_reset)
os.environ['DOCX_VERSION'] = self.version
if self.set_release:
os.environ['DOCX_RELEASE'] = self.release
else:
os.environ['DOCX_RELEASE'] = self.version
if self.noexec or self.verbose > 1 or self.debug > 0:
print()
print("build_apiref:Call environment parameters:")
print(" DOCX_AUTHOR = " + str(os.environ['DOCX_AUTHOR']))
print(" DOCX_BUILDDIR = " + str(self.build_dir))
print(" DOCX_BUILDER = " + str(self.builder))
print(" DOCX_BUILDRELDIR = " + str(self.build_reldir))
print(" DOCX_CLEAN = " + str(self.clean))
print(" DOCX_CONFIGPATH = " + str(self.config_path))
print(" DOCX_COPYRIGHT = " + str(self.copyright))
print(" DOCX_DEBUG = " + str(self.debug0))
print(" DOCX_DOCNAME = " + str(self.docname))
print(" DOCX_DOCSRC = " + str(self.docsource))
print(" DOCX_DOCTEMPLATE = " + str(self.doctemplate))
print(" DOCX_DOCTYPE = " + str(self.doctype))
print(" DOCX_EMBED = " + str(os.environ['DOCX_EMBED']))
print(" DOCX_EXEC = " + str(self.executable))
print(" DOCX_EXECOPTS = " + str(self.executableopts))
print(" DOCX_EXECOPTS_RESET = " + str(self.executableopts_reset))
print(" DOCX_GENDOC = " + str(self.gendoc))
print(" DOCX_INDEXSRC = " + str(self.indexsrc))
print(" DOCX_LIB = " + str(os.environ['DOCX_LIB']))
print(" DOCX_LICENSE = " + str(os.environ['DOCX_LICENSE']))
print(" DOCX_MISSION = " + str(os.environ['DOCX_MISSION']))
print(" DOCX_NAME = " + str(self.name))
print(" DOCX_NOEXEC = " + str(self.noexec))
print(" DOCX_QUIET = " + str(self.quiet))
print(" DOCX_RAWDOC = " + str(self.raw))
print(" DOCX_RELEASE = " + str(self.release))
print(" DOCX_SRCDIR = " + str(self.srcdir))
print(" DOCX_STATUS = " + str(os.environ['DOCX_STATUS']))
print(" DOCX_VERBOSE = " + str(self.verbose0))
print(" DOCX_VERSION = " + str(self.version))
print(" DOCX_WRAPPER = " + str(self.wrapper))
print(" DOCX_WRAPPEROPTS = " + str(self.wrapperopts))
print(" DOCX_WRAPPEROPTS_RESET = " + str(self.wrapperopts_reset))
print()
def write_environment_setter(self):
"""Writes the environment previously set by 'self.set_environment'
into shell scripts to be optionally sourced when the wrapper is
manually called from the command line.
ATTENTION: 'self.set_environment' must be called before.
"""
try:
os.makedirs(self.build_doc_path)
except:
pass
_fpath = self.build_doc_path + os.sep + 'setenv.sh'
with open(_fpath, 'w') as _f:
_f.writelines(
(
'DOCX_AUTHOR="' + os.environ['DOCX_AUTHOR'] + '"; export DOCX_AUTHOR;' + os.linesep,
'DOCX_BUILDDIR="' + os.environ['DOCX_BUILDDIR'] + '"; export DOCX_BUILDDIR;' + os.linesep,
'DOCX_BUILDER="' + os.environ['DOCX_BUILDER'] + '"; export DOCX_BUILDER;' + os.linesep,
'DOCX_BUILDRELDIR="' + os.environ['DOCX_BUILDRELDIR'] + '"; export DOCX_BUILDRELDIR;' + os.linesep,
'DOCX_CLEAN="' + os.environ['DOCX_CLEAN'] + '"; export DOCX_CLEAN' + os.linesep,
'DOCX_CONFIGPATH="' + os.environ['DOCX_CONFIGPATH'] + '"; export DOCX_CONFIGPATH' + os.linesep,
'DOCX_COPYRIGHT="' + os.environ['DOCX_COPYRIGHT'] + '"; export DOCX_COPYRIGHT;' + os.linesep,
'DOCX_DEBUG="' + os.environ['DOCX_DEBUG'] + '"; export DOCX_DEBUG' + os.linesep,
'DOCX_DOCNAME="' + os.environ['DOCX_DOCNAME'] + '"; export DOCX_DOCNAME' + os.linesep,
'DOCX_DOCSRC="' + os.environ['DOCX_DOCSRC'] + '"; export DOCX_DOCSRC' + os.linesep,
'DOCX_DOCTEMPLATE="' + os.environ['DOCX_DOCTEMPLATE'] + '"; export DOCX_DOCTEMPLATE;' + os.linesep,
'DOCX_DOCTYPE="' + os.environ['DOCX_DOCTYPE'] + '"; export DOCX_DOCTYPE' + os.linesep,
'DOCX_EMBED="' + os.environ['DOCX_EMBED'] + '"; export DOCX_EMBED' + os.linesep,
'DOCX_EXEC="' + os.environ['DOCX_EXEC'] + '"; export DOCX_EXEC' + os.linesep,
'DOCX_EXECOPTS="' + os.environ['DOCX_EXECOPTS'] + '"; export DOCX_EXECOPTS' + os.linesep,
'DOCX_EXECOPTS_RESET="' + os.environ['DOCX_EXECOPTS_RESET'] + '"; export DOCX_EXECOPTS_RESET' + os.linesep,
'DOCX_GENDOC="' + os.environ['DOCX_GENDOC'] + '"; export DOCX_GENDOC' + os.linesep,
'DOCX_INDEXSRC="' + os.environ['DOCX_INDEXSRC'] + '"; export DOCX_INDEXSRC' + os.linesep,
'DOCX_LIB="' + os.environ['DOCX_LIB'] + '"; export DOCX_LIB' + os.linesep,
'DOCX_LICENSE="' + os.environ['DOCX_LICENSE'] + '"; export DOCX_LICENSE;' + os.linesep,
'DOCX_MISSION="' + os.environ['DOCX_MISSION'] + '"; export DOCX_MISSION;' + os.linesep,
'DOCX_NAME="' + os.environ['DOCX_NAME'] + '"; export DOCX_NAME' + os.linesep,
'DOCX_NOEXEC="' + os.environ['DOCX_NOEXEC'] + '"; export DOCX_NOEXEC' + os.linesep,
'DOCX_QUIET="' + os.environ['DOCX_QUIET'] + '"; export DOCX_QUIET' + os.linesep,
'DOCX_RAWDOC="' + os.environ['DOCX_RAWDOC'] + '"; export DOCX_RAWDOC' + os.linesep,
'DOCX_RELEASE="' + os.environ['DOCX_RELEASE'] + '"; export DOCX_RELEASE' + os.linesep,
'DOCX_SRCDIR="' + os.environ['DOCX_SRCDIR'] + '"; export DOCX_SRCDIR' + os.linesep,
'DOCX_STATUS="' + os.environ['DOCX_STATUS'] + '"; export DOCX_STATUS;' + os.linesep,
'DOCX_VERBOSE="' + os.environ['DOCX_VERBOSE'] + '"; export DOCX_VERBOSE' + os.linesep,
'DOCX_VERSION="' + os.environ['DOCX_VERSION'] + '"; export DOCX_VERSION' + os.linesep,
'DOCX_WRAPPER="' + os.environ['DOCX_WRAPPER'] + '"; export DOCX_WRAPPER' + os.linesep,
'DOCX_WRAPPEROPTS="' + os.environ['DOCX_WRAPPEROPTS'] + '"; export DOCX_WRAPPEROPTS' + os.linesep,
'DOCX_WRAPPEROPTS_RESET="' + os.environ['DOCX_WRAPPEROPTS_RESET'] + '"; export DOCX_WRAPPEROPTS_RESET' + os.linesep,
)
)
_fpath = self.build_doc_path + os.sep + 'setenv.bat'
with open(_fpath, 'w') as _f:
_f.writelines(
(
'set DOCX_AUTHOR="' + os.environ['DOCX_AUTHOR'] + '"' + os.linesep,
'set DOCX_BUILDDIR="' + os.environ['DOCX_BUILDDIR'] + '"' + os.linesep,
'set DOCX_BUILDER="' + os.environ['DOCX_BUILDER'] + '"' + os.linesep,
'set DOCX_BUILDRELDIR="' + os.environ['DOCX_BUILDRELDIR'] + '"' + os.linesep,
'set DOCX_CLEAN="' + os.environ['DOCX_CLEAN'] + '"' + os.linesep,
'set DOCX_CONFIGPATH="' + os.environ['DOCX_CONFIGPATH'] + '"' + os.linesep,
'set DOCX_COPYRIGHT="' + os.environ['DOCX_COPYRIGHT'] + '"' + os.linesep,
'set DOCX_DEBUG="' + os.environ['DOCX_DEBUG'] + '"' + os.linesep,
'set DOCX_DOCNAME="' + os.environ['DOCX_DOCNAME'] + '"' + os.linesep,
'set DOCX_DOCSRC="' + os.environ['DOCX_DOCSRC'] + '"' + os.linesep,
'set DOCX_DOCTEMPLATE="' + os.environ['DOCX_DOCTEMPLATE'] + '"' + os.linesep,
'set DOCX_DOCTYPE="' + os.environ['DOCX_DOCTYPE'] + '"' + os.linesep,
'set DOCX_EMBED="' + os.environ['DOCX_EMBED'] + '"' + os.linesep,
'set DOCX_EXEC="' + os.environ['DOCX_EXEC'] + '"' + os.linesep,
'set DOCX_EXECOPTS="' + os.environ['DOCX_EXECOPTS'] + '"' + os.linesep,
'set DOCX_EXECOPTS_RESET="' + os.environ['DOCX_EXECOPTS_RESET'] + '"' + os.linesep,
'set DOCX_GENDOC="' + os.environ['DOCX_GENDOC'] + '"' + os.linesep,
'set DOCX_INDEXSRC="' + os.environ['DOCX_INDEXSRC'] + '"' + os.linesep,
'set DOCX_LIB="' + os.environ['DOCX_LIB'] + '"' + os.linesep,
'set DOCX_LICENSE="' + os.environ['DOCX_LICENSE'] + '"' + os.linesep,
'set DOCX_MISSION="' + os.environ['DOCX_MISSION'] + '"' + os.linesep,
'set DOCX_NAME="' + os.environ['DOCX_NAME'] + '"' + os.linesep,
'set DOCX_NOEXEC="' + os.environ['DOCX_NOEXEC'] + '"' + os.linesep,
'set DOCX_QUIET="' + os.environ['DOCX_QUIET'] + '"' + os.linesep,
'set DOCX_RAWDOC="' + os.environ['DOCX_RAWDOC'] + '"' + os.linesep,
'set DOCX_RELEASE="' + os.environ['DOCX_RELEASE'] + '"' + os.linesep,
'set DOCX_SRCDIR="' + os.environ['DOCX_SRCDIR'] + '"' + os.linesep,
'set DOCX_STATUS="' + os.environ['DOCX_STATUS'] + '"' + os.linesep,
'set DOCX_VERBOSE="' + os.environ['DOCX_VERBOSE'] + '"' + os.linesep,
'set DOCX_VERSION="' + os.environ['DOCX_VERSION'] + '"' + os.linesep,
'set DOCX_WRAPPER="' + os.environ['DOCX_WRAPPER'] + '"' + os.linesep,
'set DOCX_WRAPPEROPTS="' + os.environ['DOCX_WRAPPEROPTS'] + '"' + os.linesep,
'set DOCX_WRAPPEROPTS_RESET="' + os.environ['DOCX_WRAPPEROPTS_RESET'] + '"' + os.linesep,
)
)
def call_prologue(self):
"""Executed before the call of the wrapper.
The default version supports *Sphinx* and writes the project
data into the file '<build-dir>/<build-reldir>/project.rst'.
Replace this method in the derived class as required.
"""
#
# set environment for wrapper
#
self.set_environment()
if self.gendoc:
#
# write project data into 'project.rst'
#
_fpath = self.build_doc_path + os.sep + 'project.rst'
with open(_fpath, 'w') as _f:
_f.writelines(
(
'**Product Data**' + os.linesep + os.linesep,
'* MISSION=' + self.description + os.linesep + os.linesep,
'* AUTHOR=' + self.author + os.linesep + os.linesep,
'* PROJECT=' + self.name + os.linesep + os.linesep,
'* COPYRIGHT=' + self.copyright + os.linesep + os.linesep,
'* LICENSE=' + self.license + os.linesep + os.linesep,
'* VERSION=' + self.version + os.linesep + os.linesep,
'* RELEASE=' + self.release + os.linesep + os.linesep,
'* STATUS=' + self.status + os.linesep + os.linesep,
'* BUILDDATE=' + self.builddate + os.linesep + os.linesep,
)
)
#
# write environment data scripts command line application.
#
self.write_environment_setter()
def call_epilogue(self):
"""Executed after the call of the wrapper.
"""
pass