File: util.py

package info (click to toggle)
firefox 145.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,653,528 kB
  • sloc: cpp: 7,594,999; javascript: 6,459,658; ansic: 3,752,909; python: 1,403,455; xml: 629,809; asm: 438,679; java: 186,421; sh: 67,287; makefile: 19,169; objc: 13,086; perl: 12,982; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10
file content (121 lines) | stat: -rw-r--r-- 4,130 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""
Utility functions for the glean_parser-based code generator
"""
import copy
from hashlib import sha1

from glean_parser import util


def generate_ping_ids(objs):
    """
    Return a lookup function for ping IDs per ping name.

    :param objs: A tree of objects as returned from `parser.parse_objects`.
    """

    if "pings" not in objs:

        def no_ping_ids_for_you():
            assert False

        return no_ping_ids_for_you

    # Ping ID 0 is reserved (but unused) right now.
    ping_id = 1

    ping_id_mapping = {}
    for ping_name in objs["pings"].keys():
        ping_id_mapping[ping_name] = ping_id
        ping_id += 1

    return lambda ping_name: ping_id_mapping[ping_name]


def generate_metric_ids(objs, options):
    """
    Return a lookup function for metric IDs per metric object.

    :param objs: A tree of metrics as returned from `parser.parse_objects`.
    """

    # Mapping from a tuple of (category name, metric name) to the metric's numeric ID
    metric_id_mapping = {}

    if options.get("is_local_build"):
        # Metric ID 0 is reserved (but unused) right now.
        metric_ids = {0}

        for category_name, metrics in objs.items():
            if category_name == "tags":
                continue
            for metric in metrics.values():
                metric_id = (
                    int(sha1(str.encode(metric.identifier())).hexdigest(), 16) % 2**25
                )
                # Avoid collisions by incrementing the number until we find an unused id.
                while metric_id in metric_ids:
                    metric_id = (metric_id + 1) % 2**25
                assert metric_id < 2**25
                metric_ids.add(metric_id)
                metric_id_mapping[(category_name, metric.name)] = metric_id
    else:
        # Metric ID 0 is reserved (but unused) right now.
        metric_id = 1

        for category_name, metrics in objs.items():
            for metric in metrics.values():
                metric_id_mapping[(category_name, metric.name)] = metric_id
                metric_id += 1

    return lambda metric: metric_id_mapping[(metric.category, metric.name)]


def get_metrics(objs):
    """
    Returns *just* the metrics in a set of Glean objects
    """
    ret = copy.copy(objs)
    for category in ["pings", "tags"]:
        if ret.get(category):
            del ret[category]
    return ret


def type_ids_and_categories(objs) -> tuple[dict[str, tuple[int, list[str]]], list[str]]:
    """
    Iterates over the metrics in objs, constructing two metadata structures:
     - metric_types: dict[str, tuple[int, list[str]]] - map from a metric
       type (snake_case) to its metric type id and ordered list of arguments.
     - categories: list[str] - category names (snake_case)

    Is stable across invocations: Will generate same ids for same objs.
    (If it doesn't, JOG's factory disagreeing with GleanJSMetricsLookup
    will break the build).
    Uses the same order of metric args set out in glean_parser.util's
    common_metric_args and extra_metric_args.
    (If it didn't, it would supply args in the wrong order to metric type
    constructors with multiple extra args (e.g. custom_distribution)).
    """
    metric_type_ids = {}
    categories = []

    for category_name, objs in get_metrics(objs).items():
        categories.append(category_name)

        for metric in objs.values():
            if metric.type not in metric_type_ids:
                type_id = len(metric_type_ids) + 1
                args = util.common_metric_args.copy()
                for arg_name in util.extra_metric_args:
                    if hasattr(metric, arg_name):
                        args.append(arg_name)
                metric_type_ids[metric.type] = {"id": type_id, "args": args}

    metric_type_ids = dict(sorted(metric_type_ids.items()))
    categories = sorted(categories)
    return (metric_type_ids, categories)