Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
pantsbuild.pants / goal / artifact_cache_stats.py
Size: Mime:
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

import os
from collections import defaultdict, namedtuple

from pants.cache.artifact_cache import UnreadableArtifact
from pants.util.dirutil import safe_mkdir

# Lists of target addresses.
CacheStat = namedtuple("CacheStat", ["hit_targets", "miss_targets"])


class ArtifactCacheStats:
    """Tracks the hits and misses in the artifact cache.

    If dir is specified, writes the hits and misses to files in that dir.
    """

    def __init__(self, dir=None):
        def init_stat():
            return CacheStat([], [])

        self.stats_per_cache = defaultdict(init_stat)
        self._dir = dir
        safe_mkdir(self._dir)

    def add_hits(self, cache_name, targets):
        self._add_stat(0, cache_name, targets, None)

    # any cache misses, each target is paired with its cause for the miss.
    def add_misses(self, cache_name, targets, causes):
        self._add_stat(1, cache_name, targets, causes)

    def get_all(self):
        """Returns the cache stats as a list of dicts."""
        ret = []
        for cache_name, stat in self.stats_per_cache.items():
            ret.append(
                {
                    "cache_name": cache_name,
                    "num_hits": len(stat.hit_targets),
                    "num_misses": len(stat.miss_targets),
                    "hits": stat.hit_targets,
                    "misses": stat.miss_targets,
                }
            )
        return ret

    # hit_or_miss is the appropriate index in CacheStat, i.e., 0 for hit, 1 for miss.
    def _add_stat(self, hit_or_miss, cache_name, targets, causes):
        def format_vts(tgt, cause):
            """Format into (target, cause) tuple."""
            target_address = tgt.address.reference()
            if isinstance(cause, UnreadableArtifact):
                return (target_address, str(cause.err))
            elif cause == False:
                return (target_address, "uncached")
            else:
                return (target_address, "")

        causes = causes or [True] * len(targets)
        target_with_causes = [format_vts(tgt, cause) for tgt, cause in zip(targets, causes)]
        self.stats_per_cache[cache_name][hit_or_miss].extend(target_with_causes)
        suffix = "misses" if hit_or_miss else "hits"
        if self._dir and os.path.exists(self._dir):  # Check existence in case of a clean-all.
            with open(os.path.join(self._dir, "{}.{}".format(cache_name, suffix)), "a") as f:
                f.write(
                    "\n".join(
                        [
                            " ".join(target_with_cause).strip()
                            for target_with_cause in target_with_causes
                        ]
                    )
                )
                f.write("\n")