2016-02-23 00:20:15 +00:00
|
|
|
#! /usr/bin/python
|
|
|
|
# -*- coding: utf8 -*-
|
|
|
|
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
|
2016-02-23 05:22:42 +00:00
|
|
|
import os
|
2016-02-23 00:20:15 +00:00
|
|
|
import sys
|
2016-02-25 19:39:18 +00:00
|
|
|
import logging
|
2016-02-27 06:19:30 +00:00
|
|
|
from argparse import Namespace
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-02-23 19:05:04 +00:00
|
|
|
import tldp
|
2016-03-01 18:30:18 +00:00
|
|
|
import tldp.typeguesser
|
2016-03-01 04:33:33 +00:00
|
|
|
|
|
|
|
from tldp.inventory import status_classes, status_types
|
2016-02-27 06:19:30 +00:00
|
|
|
from tldp.utils import arg_isloglevel
|
2016-03-01 04:33:33 +00:00
|
|
|
from tldp.sources import arg_issourcedoc
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-02-27 18:52:35 +00:00
|
|
|
logformat = '%(levelname)-9s %(name)s %(filename)s#%(lineno)s %(funcName)s %(message)s'
|
|
|
|
logging.basicConfig(stream=sys.stderr, format=logformat, level=logging.ERROR)
|
2016-02-27 06:19:30 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-02-23 17:00:27 +00:00
|
|
|
|
2016-03-01 05:32:20 +00:00
|
|
|
def summary(config, inv=None, **kwargs):
|
2016-03-01 04:33:33 +00:00
|
|
|
if inv is None:
|
|
|
|
inv = tldp.inventory.Inventory(config.pubdir, config.sourcedir)
|
2016-03-01 05:32:20 +00:00
|
|
|
file = kwargs.get('file', sys.stdout)
|
2016-02-23 17:00:27 +00:00
|
|
|
width = Namespace()
|
2016-03-01 04:33:33 +00:00
|
|
|
width.status = max([len(x) for x in status_types])
|
|
|
|
width.count = len(str(len(inv.source.keys())))
|
|
|
|
for status in status_types:
|
2016-02-23 05:22:42 +00:00
|
|
|
if status == 'all':
|
|
|
|
continue
|
2016-03-01 04:33:33 +00:00
|
|
|
count = len(getattr(inv, status, 0))
|
2016-02-23 17:00:27 +00:00
|
|
|
s = '{0:{w.status}} {1:{w.count}} '.format(status, count, w=width)
|
2016-03-01 05:32:20 +00:00
|
|
|
print(s, end="", file=file)
|
2016-02-23 17:00:27 +00:00
|
|
|
if config.verbose:
|
2016-03-01 05:32:20 +00:00
|
|
|
print(', '.join(getattr(inv, status).keys()), file=file)
|
2016-02-23 17:00:27 +00:00
|
|
|
else:
|
2016-03-01 04:33:33 +00:00
|
|
|
abbrev = getattr(inv, status).keys()
|
2016-02-27 06:19:30 +00:00
|
|
|
s = ''
|
|
|
|
if abbrev:
|
|
|
|
s = s + abbrev.pop(0)
|
|
|
|
while abbrev and len(s) < 50:
|
2016-03-01 04:33:33 +00:00
|
|
|
s = s + ', ' + abbrev.pop(0)
|
2016-02-27 06:19:30 +00:00
|
|
|
if abbrev:
|
|
|
|
s = s + ', and %d more ...' % (len(abbrev))
|
2016-03-01 05:32:20 +00:00
|
|
|
print(s, file=file)
|
2016-02-23 05:22:42 +00:00
|
|
|
return 0
|
2016-02-23 00:20:15 +00:00
|
|
|
|
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
def detail(config, docs, inv, **kwargs):
|
|
|
|
if inv is None:
|
|
|
|
inv = tldp.inventory.Inventory(config.pubdir, config.sourcedir)
|
|
|
|
if not docs:
|
|
|
|
docs = inv.work.values()
|
|
|
|
width = Namespace()
|
|
|
|
width.status = max([len(x) for x in status_types])
|
|
|
|
width.stem = max([len(x) for x in inv.source.keys()])
|
|
|
|
# -- if user just said "list" with no args, then give the user something
|
|
|
|
# sane, "all"; it would make sense for this to be "work", too, but
|
|
|
|
# "all" seems to be less surprising
|
|
|
|
#
|
|
|
|
for doc in docs:
|
|
|
|
stdout = kwargs.get('file', sys.stdout)
|
|
|
|
doc.detail(width, config.verbose, file=stdout)
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2016-03-01 05:32:20 +00:00
|
|
|
def build(config, docs, inv, **kwargs):
|
2016-03-01 04:33:33 +00:00
|
|
|
if inv is None:
|
|
|
|
inv = tldp.inventory.Inventory(config.pubdir, config.sourcedir)
|
|
|
|
if not docs:
|
|
|
|
docs = inv.work.values()
|
|
|
|
for source in docs:
|
2016-03-01 15:31:52 +00:00
|
|
|
if not isinstance(source, tldp.sources.SourceDocument):
|
|
|
|
logger.info("%s skipping, no source for orphan", source.stem)
|
|
|
|
continue
|
2016-02-23 19:05:04 +00:00
|
|
|
if not source.output:
|
|
|
|
dirname = os.path.join(config.pubdir, source.stem)
|
|
|
|
source.output = tldp.outputs.OutputDirectory(dirname)
|
2016-02-24 05:58:56 +00:00
|
|
|
if not source.doctype:
|
2016-03-01 04:33:33 +00:00
|
|
|
logger.warning("%s skipping document of unknown doctype",
|
2016-02-24 05:58:56 +00:00
|
|
|
source.stem)
|
|
|
|
continue
|
2016-02-23 19:05:04 +00:00
|
|
|
output = source.output
|
|
|
|
runner = source.doctype(source=source, output=output, config=config)
|
|
|
|
runner.generate()
|
2016-02-23 05:22:42 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2016-03-01 05:32:20 +00:00
|
|
|
# def script(config, docs, inv, **kwargs):
|
|
|
|
# return 0
|
2016-03-01 04:33:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
def getDocumentNames(args):
|
|
|
|
sought = set()
|
|
|
|
for arg in args:
|
|
|
|
doc = arg_issourcedoc(arg)
|
|
|
|
if doc is not None:
|
|
|
|
sought.add(doc)
|
|
|
|
remainder = set(args).difference(sought)
|
|
|
|
return sought, remainder
|
|
|
|
|
|
|
|
|
|
|
|
def getStatusNames(args):
|
|
|
|
found = set()
|
|
|
|
sought = set()
|
|
|
|
for arg in args:
|
|
|
|
stati = status_classes.get(arg, None)
|
|
|
|
if stati:
|
|
|
|
sought.update(stati)
|
|
|
|
found.add(arg)
|
|
|
|
remainder = set(args).difference(found)
|
|
|
|
return sought, remainder
|
|
|
|
|
|
|
|
|
2016-03-01 18:30:18 +00:00
|
|
|
def getDocumentClasses(args):
|
2016-03-01 19:01:32 +00:00
|
|
|
largs = [x.lower() for x in args]
|
|
|
|
sought = list()
|
2016-03-01 18:30:18 +00:00
|
|
|
for cls in tldp.typeguesser.knowndoctypes:
|
2016-03-01 19:01:32 +00:00
|
|
|
if cls.__name__.lower() in largs:
|
|
|
|
sought.append(cls)
|
|
|
|
else:
|
|
|
|
sought.append(None)
|
|
|
|
remainder = set([y for x, y in zip(sought, args) if x])
|
|
|
|
sought = set(sought)
|
2016-03-01 18:30:18 +00:00
|
|
|
return sought, remainder
|
|
|
|
|
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
def getStemNames(config, stati, args, inv=None):
|
|
|
|
if inv is None:
|
|
|
|
inv = tldp.inventory.Inventory(config.pubdir, config.sourcedir)
|
|
|
|
sought = set()
|
|
|
|
for stem, doc in inv.all.items():
|
|
|
|
if stem in args:
|
|
|
|
sought.add(doc)
|
|
|
|
if doc.status in stati:
|
|
|
|
sought.add(doc)
|
|
|
|
soughtstems = [x.stem for x in sought]
|
|
|
|
remainder = set(args).difference(soughtstems)
|
|
|
|
return sought, remainder, inv
|
|
|
|
|
|
|
|
|
2016-03-01 18:30:18 +00:00
|
|
|
def skipDocuments(config, docs, inv):
|
|
|
|
if not docs:
|
|
|
|
if inv is None:
|
|
|
|
inv = tldp.inventory.Inventory(config.pubdir, config.sourcedir)
|
|
|
|
docs = inv.all.values()
|
|
|
|
included = list()
|
|
|
|
excluded = list()
|
|
|
|
skip_stati, remainder = getStatusNames(config.skip)
|
|
|
|
skip_doctypes, skip_stems = getDocumentClasses(remainder)
|
|
|
|
for doc in docs:
|
|
|
|
stem = doc.stem
|
|
|
|
if hasattr(doc, 'doctype'):
|
|
|
|
if doc.doctype in skip_doctypes:
|
|
|
|
logger.info("%s skipping doctype %s", stem, doc.doctype)
|
|
|
|
excluded.append(doc)
|
|
|
|
continue
|
|
|
|
if doc.status in skip_stati:
|
|
|
|
logger.info("%s skipping status %s", stem, doc.status)
|
|
|
|
excluded.append(doc)
|
|
|
|
continue
|
|
|
|
if doc.stem in skip_stems:
|
|
|
|
logger.info("%s skipping stem %s", stem, stem)
|
|
|
|
excluded.append(doc)
|
|
|
|
continue
|
|
|
|
included.append(doc)
|
|
|
|
return included, excluded
|
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
def run(argv):
|
2016-02-27 06:19:30 +00:00
|
|
|
# -- may want to see option parsing, so set --loglevel as
|
|
|
|
# soon as possible
|
2016-03-01 04:33:33 +00:00
|
|
|
if '--loglevel' in argv:
|
|
|
|
levelarg = 1 + argv.index('--loglevel')
|
|
|
|
level = arg_isloglevel(argv[levelarg])
|
2016-02-27 18:52:35 +00:00
|
|
|
# -- set the root logger's level
|
|
|
|
logging.getLogger().setLevel(level)
|
2016-02-27 06:19:30 +00:00
|
|
|
|
|
|
|
# -- produce a configuration from CLI, ENV and CFG
|
|
|
|
#
|
2016-02-27 18:52:35 +00:00
|
|
|
tag = 'ldptool'
|
2016-02-23 17:00:27 +00:00
|
|
|
config, args = tldp.config.collectconfiguration(tag, argv)
|
2016-02-23 05:22:42 +00:00
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
# -- summary does not require any args
|
|
|
|
if config.summary:
|
|
|
|
|
|
|
|
if args:
|
|
|
|
return "Unknown args received for --summary: " + ' '.join(args)
|
|
|
|
if not config.pubdir:
|
|
|
|
return "Option --pubdir (and --sourcedir) required for --summary."
|
|
|
|
if not config.sourcedir:
|
|
|
|
return "Option --sourcedir (and --pubdir) required for --summary."
|
|
|
|
|
|
|
|
return summary(config)
|
|
|
|
|
|
|
|
# -- args can be a mix of full paths to documents (file or directory)
|
|
|
|
# stem names (for operating on inventory) and status_type names
|
|
|
|
#
|
|
|
|
# -- sort them out into each of the different types
|
2016-02-23 05:22:42 +00:00
|
|
|
#
|
2016-03-01 04:33:33 +00:00
|
|
|
docs = list()
|
|
|
|
inv = None
|
|
|
|
if args:
|
|
|
|
rawdocs, remainder = getDocumentNames(args)
|
|
|
|
logger.debug("args included %d documents in filesystem: %r",
|
|
|
|
len(rawdocs), rawdocs)
|
|
|
|
if rawdocs:
|
|
|
|
for doc in rawdocs:
|
|
|
|
docs.append(tldp.sources.SourceDocument(doc))
|
|
|
|
|
|
|
|
if remainder:
|
|
|
|
stati, remainder = getStatusNames(remainder)
|
|
|
|
logger.debug("args included %d status type args: %r",
|
|
|
|
len(stati), stati)
|
|
|
|
|
|
|
|
if remainder or stati:
|
|
|
|
logger.debug("Checking inventory (%d stems, %d status_classes).",
|
|
|
|
len(remainder), len(stati))
|
|
|
|
if not config.pubdir:
|
|
|
|
return " --pubdir (and --sourcedir) required for inventory."
|
|
|
|
if not config.sourcedir:
|
|
|
|
return " --sourcedir (and --pubdir) required for inventory."
|
|
|
|
|
|
|
|
stems, remainder, inv = getStemNames(config, stati, remainder)
|
|
|
|
if stems:
|
|
|
|
for doc in stems:
|
|
|
|
docs.append(doc)
|
|
|
|
|
|
|
|
if remainder:
|
|
|
|
return "Unknown argument (not stem, file nor status_class): " \
|
|
|
|
+ ' '.join(remainder)
|
|
|
|
|
2016-03-01 18:30:18 +00:00
|
|
|
if config.skip:
|
|
|
|
docs, excluded = skipDocuments(config, docs, inv)
|
|
|
|
|
|
|
|
# -- one last check to see that config.pubdir and config.sourcedir are set
|
|
|
|
# appropriately; before we try to use them
|
|
|
|
#
|
|
|
|
if not inv:
|
|
|
|
if not config.pubdir:
|
|
|
|
return " --pubdir (and --sourcedir) required for inventory."
|
|
|
|
if not config.sourcedir:
|
|
|
|
return " --sourcedir (and --pubdir) required for inventory."
|
|
|
|
|
2016-02-23 05:22:42 +00:00
|
|
|
if config.detail:
|
2016-03-01 04:33:33 +00:00
|
|
|
return detail(config, docs, inv)
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
if config.script:
|
|
|
|
return script(config, docs, inv)
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
if not config.build:
|
|
|
|
logger.info("Assuming --build, since no other action was specified...")
|
2016-02-23 00:20:15 +00:00
|
|
|
|
2016-03-01 04:33:33 +00:00
|
|
|
return build(config, docs, inv)
|
2016-02-27 06:19:30 +00:00
|
|
|
|
2016-03-01 15:15:35 +00:00
|
|
|
def main():
|
2016-03-01 04:33:33 +00:00
|
|
|
sys.exit(run(sys.argv[1:]))
|
2016-02-27 06:19:30 +00:00
|
|
|
|
2016-03-01 15:15:35 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|
|
|
|
|
2016-02-23 00:20:15 +00:00
|
|
|
#
|
|
|
|
# -- end of file
|