Build the cached data.

    Either by parsing the RDF taxonomy file or a vocabulary file.

    :param source_file: source file of the taxonomy, RDF file
    :param skip_cache: if True, build cache will not be
        saved (pickled) - it is saved as <source_file.db>

def _build_cache(source_file, skip_cache=False):
    """Build the cached data.

    Either by parsing the RDF taxonomy file or a vocabulary file.

    :param source_file: source file of the taxonomy, RDF file
    :param skip_cache: if True, build cache will not be
        saved (pickled) - it is saved as <source_file.db>
    """
    store = rdflib.ConjunctiveGraph()

    if skip_cache:
        current_app.logger.info("You requested not to save the cache to disk.")
    else:
        cache_path = _get_cache_path(source_file)
        cache_dir = os.path.dirname(cache_path)
        # Make sure we have a cache_dir readable and writable.
        if not os.path.isdir(cache_dir):
            os.makedirs(cache_dir)
        if os.access(cache_dir, os.R_OK):
            if not os.access(cache_dir, os.W_OK):
                raise TaxonomyError("Cache directory exists but is not"
                                    " writable. Check your permissions"
                                    " for: %s" % cache_dir)
        else:
            raise TaxonomyError("Cache directory does not exist"
                                " (and could not be created): %s" % cache_dir)

    timer_start = time.clock()

    namespace = None
    single_keywords, composite_keywords = {}, {}

    try:
        current_app.logger.info(
            "Building RDFLib's conjunctive graph from: %s" % source_file)
        try:
            store.parse(source_file)
        except urllib_error.URLError:
            if source_file[0] == '/':
                store.parse("file://" + source_file)
            else:
                store.parse("file:///" + source_file)

    except rdflib.exceptions.Error as e:
        current_app.logger.exception("Serious error reading RDF file")
        raise

    except (xml.sax.SAXParseException, ImportError) as e:
        # File is not a RDF file. We assume it is a controlled vocabulary.
        current_app.logger.error(e)
        current_app.logger.warning("The ontology file is probably not a valid RDF file. \
            Assuming it is a controlled vocabulary file.")

        filestream = open(source_file, "r")
        for line in filestream:
            keyword = line.strip()
            kt = KeywordToken(keyword)
            single_keywords[kt.short_id] = kt
        if not len(single_keywords):
            raise TaxonomyError('The ontology file is not well formated')

    else:  # ok, no exception happened
        current_app.logger.info("Now building cache of keywords")
        # File is a RDF file.
        namespace = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#")

        single_count = 0
        composite_count = 0

        subject_objects = store.subject_objects(namespace["prefLabel"])
        for subject, pref_label in subject_objects:
            kt = KeywordToken(subject, store=store, namespace=namespace)
            if kt.isComposite():
                composite_count += 1
                composite_keywords[kt.short_id] = kt
            else:
                single_keywords[kt.short_id] = kt
                single_count += 1

    cached_data = {}
    cached_data["single"] = single_keywords
    cached_data["composite"] = composite_keywords
    cached_data["creation_time"] = time.gmtime()
    cached_data["version_info"] = {'rdflib': rdflib.__version__}
    current_app.logger.debug(
        "Building taxonomy... %d terms built in %.1f sec." %
        (len(single_keywords) + len(composite_keywords),
         time.clock() - timer_start))

    current_app.logger.info(
        "Total count of single keywords: %d "
        % len(single_keywords)
    )
    current_app.logger.info(
        "Total count of composite keywords: %d "
        % len(composite_keywords)
    )

    if not skip_cache:
        cache_path = _get_cache_path(source_file)
        cache_dir = os.path.dirname(cache_path)
        current_app.logger.debug("Writing the cache into: %s" % cache_path)
        # test again, it could have changed
        if os.access(cache_dir, os.R_OK):
            if os.access(cache_dir, os.W_OK):
                # Serialize.
                filestream = None
                try:
                    filestream = open(cache_path, "wb")
                except IOError as msg:
                    # Impossible to write the cache.
                    current_app.logger.error(
                        "Impossible to write cache to '%s'."
                        % cache_path)
                    current_app.logger.error(msg)
                else:
                    current_app.logger.debug(
                        "Writing cache to file %s" % cache_path)
                    cPickle.dump(cached_data, filestream, 1)
                if filestream:
                    filestream.close()

            else:
                raise TaxonomyError("Cache directory exists but is not "
                                    "writable. Check your permissions "
                                    "for: %s" % cache_dir)
        else:
            raise TaxonomyError("Cache directory does not exist"
                                " (and could not be created): %s" % cache_dir)

    # now when the whole taxonomy was parsed,
    # find sub-components of the composite kws
    # it is important to keep this call after the taxonomy was saved,
    # because we don't  want to pickle regexes multiple times
    # (as they are must be re-compiled at load time)
    for kt in composite_keywords.values():
        kt.refreshCompositeOf(single_keywords, composite_keywords,
                              store=store, namespace=namespace)

    # house-cleaning
    if store:
        store.close()

    return (single_keywords, composite_keywords)