There must be a way to be efficient and stream output instead of loading
    everything into memory at once, but, meh.

    Note that we augment `citednames` with all of the names in `maindict`. The
    intention is that if we've gone to the effort of getting good data for
    some record, we don't want to trash it if the citation is temporarily
    removed (even if it ought to be manually recoverable from version
    control). Seems better to err on the side of preservation; I can write a
    quick pruning tool later if needed.

def merge_bibtex_collections(citednames, maindict, extradicts, allow_missing=False):
    """There must be a way to be efficient and stream output instead of loading
    everything into memory at once, but, meh.

    Note that we augment `citednames` with all of the names in `maindict`. The
    intention is that if we've gone to the effort of getting good data for
    some record, we don't want to trash it if the citation is temporarily
    removed (even if it ought to be manually recoverable from version
    control). Seems better to err on the side of preservation; I can write a
    quick pruning tool later if needed.

    """
    allrecords = {}

    for ed in extradicts:
        allrecords.update(ed)

    allrecords.update(maindict)

    missing = []
    from collections import OrderedDict
    records = OrderedDict()
    from itertools import chain
    wantednames = sorted(chain(citednames, six.viewkeys(maindict)))

    for name in wantednames:
        rec = allrecords.get(name)
        if rec is None:
            missing.append(name)
        else:
            records[name] = rec

    if len(missing) and not allow_missing:
        # TODO: custom exception so caller can actually see what's missing;
        # could conceivably stub out missing records or something.
        raise PKError('missing BibTeX records: %s', ' '.join(missing))

    return records