# 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/.
"""
Outputter to generate Kotlin code for metrics. """
import enum import json from pathlib import Path from typing import Any, Dict, List, Optional, Union # noqa
from . import __version__ from . import metrics from . import pings from . import util
def kotlin_datatypes_filter(value: util.JSONType) -> str: """
A Jinja2 filter that renders Kotlin literals.
Based on Python's JSONEncoder, but overrides:
- lists to use listOf
- dicts to use mapOf
- sets to use setOf
- enums to use the like-named Kotlin enum
- Rate objects to a CommonMetricData initializer
(for external Denominators' Numerators lists) """
class KotlinEncoder(json.JSONEncoder): def iterencode(self, value): if isinstance(value, list): yield"listOf("
first = True for subvalue in value: ifnot first: yield", " yieldfrom self.iterencode(subvalue)
first = False yield")" elif isinstance(value, dict): yield"mapOf("
first = True for key, subvalue in value.items(): ifnot first: yield", " yieldfrom self.iterencode(key) yield" to " yieldfrom self.iterencode(subvalue)
first = False yield")" elif isinstance(value, enum.Enum): # UniFFI generates SCREAMING_CASE enum variants. yield (value.__class__.__name__ + "." + util.screaming_case(value.name)) elif isinstance(value, set): yield"setOf("
first = True for subvalue in sorted(list(value)): ifnot first: yield", " yieldfrom self.iterencode(subvalue)
first = False yield")" elif isinstance(value, metrics.Rate): yield"CommonMetricData("
first = True for arg_name in util.common_metric_args: if hasattr(value, arg_name): ifnot first: yield", " yield f"{util.camelize(arg_name)} = " yieldfrom self.iterencode(getattr(value, arg_name))
first = False yield")" else: yieldfrom super().iterencode(value)
return"".join(KotlinEncoder().iterencode(value))
def type_name(obj: Union[metrics.Metric, pings.Ping]) -> str: """
Returns the Kotlin type to use for a given metric or ping object. """
generate_enums = getattr(obj, "_generate_enums", []) if len(generate_enums):
generic = None for member, suffix in generate_enums: if len(getattr(obj, member)): if isinstance(obj, metrics.Event):
generic = util.Camelize(obj.name) + suffix else:
generic = util.camelize(obj.name) + suffix else: if isinstance(obj, metrics.Event):
generic = "NoExtras" else:
generic = "No" + suffix
def extra_type_name(typ: str) -> str: """
Returns the corresponding Kotlin type for event's extra key types. """
if typ == "boolean": return"Boolean" elif typ == "string": return"String" elif typ == "quantity": return"Int" else: return"UNSUPPORTED"
def structure_type_name(typ: str) -> str: """
Returns the corresponding Kotlin type for structure items. """
if typ == "boolean": return"Boolean" elif typ == "string": return"String" elif typ == "number": return"Int" else: return"UNSUPPORTED"
def class_name(obj_type: str) -> str: """
Returns the Kotlin class name for a given metric or ping type. """ if obj_type == "ping": return"PingType" if obj_type.startswith("labeled_"):
obj_type = obj_type[8:] return util.Camelize(obj_type) + "MetricType"
data = [
str(ts.year), # In Java the first month of the year in calendars is JANUARY which is 0. # In Python it's 1-based
str(ts.month - 1),
str(ts.day),
str(ts.hour),
str(ts.minute),
str(ts.second),
]
components = ", ".join(data)
# DatetimeMetricType takes a `Calendar` instance. return f'Calendar.getInstance(TimeZone.getTimeZone("GMT+0")).also {{ cal -> cal.set({components}) }}'# noqa
def output_kotlin(
objs: metrics.ObjectTree, output_dir: Path, options: Optional[Dict[str, Any]] = None
) -> None: """
Given a tree of objects, output Kotlin code to `output_dir`.
:param objects: A tree of objects (metrics and pings) as returned from
`parser.parse_objects`.
:param output_dir: Path to an output directory to write to.
:param options: options dictionary, with the following optional keys:
- `namespace`: The package namespace to declare at the top of the
generated files. Defaults to `GleanMetrics`.
- `glean_namespace`: The package namespace of the glean library itself.
This is where glean objects will be imported fromin the generated
code.
- `with_buildinfo`: If"true" a `GleanBuildInfo.kt` file is generated.
Otherwise generation of that file is skipped.
Defaults to "true".
- `build_date`: If set to `0` a static unix epoch time will be used. If set to a ISO8601 datetime string (e.g. `2022-01-03T17:30:00`)
it will use that date.
Other values will throw an error. Ifnot set it will use the current date & time. """ if options isNone:
options = {}
# Write out the special "build info" object
template = util.get_jinja2_template( "kotlin.buildinfo.jinja2",
)
if with_buildinfo:
build_date = generate_build_date(build_date) # This filename needs to start with "Glean" so it can never clash with a # metric category with (output_dir / "GleanBuildInfo.kt").open("w", encoding="utf-8") as fd:
fd.write(
template.render(
parser_version=__version__,
namespace=namespace,
namespace_package=namespace_package,
glean_namespace=glean_namespace,
build_date=build_date,
)
)
fd.write("\n")
for category_key, category_val in objs.items():
filename = util.Camelize(category_key) + ".kt"
filepath = output_dir / filename
obj_types = sorted(
list(set(class_name(obj.type) for obj in category_val.values()))
)
has_labeled_metrics = any(
getattr(metric, "labeled", False) for metric in category_val.values()
)
has_object_metrics = any(
isinstance(metric, metrics.Object) for metric in category_val.values()
)
with filepath.open("w", encoding="utf-8") as fd:
fd.write(
template.render(
parser_version=__version__,
category_name=category_key,
objs=category_val,
obj_types=obj_types,
common_metric_args=util.common_metric_args,
extra_metric_args=util.extra_metric_args,
ping_args=util.ping_args,
namespace=namespace,
has_labeled_metrics=has_labeled_metrics,
has_object_metrics=has_object_metrics,
glean_namespace=glean_namespace,
)
) # Jinja2 squashes the final newline, so we explicitly add it
fd.write("\n")
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.