summaryrefslogtreecommitdiffstats
path: root/toolkit/components/glean/build_scripts
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/glean/build_scripts')
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/jog.py1
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/run_glean_parser.py27
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/rust.py37
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/templates/cpp.jinja22
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja215
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/templates/ohttp.jinja213
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2106
-rw-r--r--toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust_pings.jinja21
-rw-r--r--toolkit/components/glean/build_scripts/mach_commands.py17
9 files changed, 207 insertions, 12 deletions
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/jog.py b/toolkit/components/glean/build_scripts/glean_parser_ext/jog.py
index 81d92b0f5d..b42827989e 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/jog.py
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/jog.py
@@ -55,6 +55,7 @@ known_ping_args = [
"include_client_id",
"send_if_empty",
"precise_timestamps",
+ "include_info_sections",
"reason_codes",
]
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/run_glean_parser.py b/toolkit/components/glean/build_scripts/glean_parser_ext/run_glean_parser.py
index 1d7d97cf73..bc9f09f0d3 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/run_glean_parser.py
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/run_glean_parser.py
@@ -230,5 +230,32 @@ def jog_file(output_fd, *args):
return get_deps()
+def ohttp_pings(output_fd, *args):
+ all_objs, options = parse(args)
+ ohttp_pings = []
+ for ping in all_objs["pings"].values():
+ if ping.metadata.get("use_ohttp", False):
+ if ping.include_info_sections:
+ raise ParserError(
+ "Cannot send pings with OHTTP that contain {client|ping}_info sections. Specify `metadata: include_info_sections: false`"
+ )
+ ohttp_pings.append(ping.name)
+
+ env = jinja2.Environment(
+ loader=jinja2.PackageLoader("run_glean_parser", "templates"),
+ trim_blocks=True,
+ lstrip_blocks=True,
+ )
+ env.filters["quote_and_join"] = lambda l: "\n| ".join(f'"{x}"' for x in l)
+ template = env.get_template("ohttp.jinja2")
+ output_fd.write(
+ template.render(
+ ohttp_pings=ohttp_pings,
+ )
+ )
+ output_fd.write("\n")
+ return get_deps()
+
+
if __name__ == "__main__":
main(sys.stdout, *sys.argv[1:])
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/rust.py b/toolkit/components/glean/build_scripts/glean_parser_ext/rust.py
index 615784b481..4b2b35886b 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/rust.py
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/rust.py
@@ -68,9 +68,10 @@ def rust_datatypes_filter(value):
# CowString is also a 'str' but is a special case.
# Ensure its case is handled before str's (below).
elif isinstance(value, CowString):
- yield f'::std::borrow::Cow::from("{value.inner}")'
+ value = json.dumps(value)
+ yield f"::std::borrow::Cow::from({value})"
elif isinstance(value, str):
- yield '"' + value + '".into()'
+ yield f"{json.dumps(value)}.into()"
elif isinstance(value, Rate):
yield "CommonMetricData {"
for arg_name in common_metric_data_args:
@@ -118,6 +119,10 @@ def type_name(obj):
return "{}<{}>".format(
class_name(obj.type), util.Camelize(obj.name) + suffix
)
+ generate_structure = getattr(obj, "_generate_structure", [])
+ if len(generate_structure):
+ generic = util.Camelize(obj.name) + "Object"
+ return "{}<{}>".format(class_name(obj.type), generic)
return class_name(obj.type)
@@ -136,6 +141,21 @@ def extra_type_name(typ: str) -> str:
return "UNSUPPORTED"
+def structure_type_name(typ: str) -> str:
+ """
+ Returns the corresponding Rust type for structure items.
+ """
+
+ if typ == "boolean":
+ return "bool"
+ elif typ == "string":
+ return "String"
+ elif typ == "number":
+ return "i64"
+ else:
+ return "UNSUPPORTED"
+
+
def class_name(obj_type):
"""
Returns the Rust class name for a given metric or ping type.
@@ -208,6 +228,14 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
# 17 -> "test_only::an_event"
events_by_id = {}
+ # Map from a metric ID to the fully qualified path of the object metric in Rust.
+ # Required for the special handling of object lookups.
+ #
+ # Example:
+ #
+ # 18 -> "test_only::an_object"
+ objects_by_id = {}
+
# Map from a labeled type (e.g. "counter") to a map from metric ID to the
# fully qualified path of the labeled metric object in Rust paired with
# whether the labeled metric has an enum.
@@ -238,6 +266,9 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
if metric.type == "event":
events_by_id[get_metric_id(metric)] = full_path
continue
+ if metric.type == "object":
+ objects_by_id[get_metric_id(metric)] = full_path
+ continue
if getattr(metric, "labeled", False):
labeled_type = metric.type[8:]
@@ -261,6 +292,7 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
("snake_case", util.snake_case),
("type_name", type_name),
("extra_type_name", extra_type_name),
+ ("structure_type_name", structure_type_name),
("ctor", ctor),
("extra_keys", extra_keys),
("metric_id", get_metric_id),
@@ -275,6 +307,7 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
metric_by_type=objs_by_type,
extra_args=util.extra_args,
events_by_id=events_by_id,
+ objects_by_id=objects_by_id,
labeleds_by_id_by_type=labeleds_by_id_by_type,
submetric_bit=ID_BITS - ID_SIGNAL_BITS,
ping_names_by_app_id=ping_names_by_app_id,
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/cpp.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/cpp.jinja2
index 2a4e40d6ac..3e9d573232 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/cpp.jinja2
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/cpp.jinja2
@@ -78,6 +78,7 @@ enum class DynamicLabel: uint16_t { };
{% for category_name, objs in all_objs.items() %}
namespace {{ category_name|snake_case }} {
{% for obj in objs.values() %}
+ {% if obj.type != "object" %}{# TODO(bug 1881023): Add C++ support #}
/**
* generated from {{ category_name }}.{{ obj.name }}
*/
@@ -91,6 +92,7 @@ namespace {{ category_name|snake_case }} {
* {{ obj.description|wordwrap() | replace('\n', '\n * ') }}
*/
constexpr impl::{{ obj|type_name }} {{obj.name|snake_case }}({{obj|metric_id}});
+ {% endif %}
{% endfor %}
}
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja2
index 4b7838a47d..a31bdbabf0 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja2
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/jog_factory.jinja2
@@ -23,7 +23,9 @@ use crate::private::{
Ping,
LabeledMetric,
{% for metric_type_name in metric_types.keys() if not metric_type_name.startswith('labeled_') %}
+ {% if metric_type_name != "object" %}{# TODO(bug 1883857): Add JOG support #}
{{ metric_type_name|Camelize }}Metric,
+ {% endif %}
{% endfor %}};
use crate::private::traits::HistogramType;
@@ -50,7 +52,7 @@ pub(crate) mod __jog_metric_maps {
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
-{% for metric_type_name in metric_types.keys() if metric_type_name != "event" and not metric_type_name.startswith('labeled_') %}
+{% for metric_type_name in metric_types.keys() if metric_type_name != "event" and not metric_type_name.startswith('labeled_') and metric_type_name != "object" %}
pub static {{ metric_type_name.upper() }}_MAP: Lazy<Arc<RwLock<HashMap<MetricId, {{ metric_type_name|Camelize }}Metric>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
@@ -67,6 +69,10 @@ pub(crate) mod __jog_metric_maps {
{# Event metrics are special because they're EventMetric<K> #}
pub static EVENT_MAP: Lazy<Arc<RwLock<HashMap<MetricId, EventMetric<NoExtraKeys>>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
+{# Object metrics are special because they're ObjectMetric<K> #}
+ #[allow(dead_code)]
+ pub static OBJECT_MAP: Lazy<Arc<RwLock<HashMap<MetricId, ObjectMetric<()>>>>> =
+ Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
}
#[derive(Debug)]
@@ -105,6 +111,9 @@ map of argument name to argument type. I may regret this if I need it again. #}
let metric32 = match metric_type {
{% for metric_type_name, metric_type in metric_types.items() %}
"{{ metric_type_name }}" => {
+ {% if metric_type_name == "object" %}{# TODO(bug 1883857): Add JOG support #}
+ return Err(Box::new(MetricTypeNotFoundError(metric_type.to_string())));
+ {% else %}
let metric = {{ metric_type_name|Camelize if not metric_type_name.startswith('labeled_') else "Labeled"}}Metric::{% if metric_type_name == 'event' %}with_runtime_extra_keys{% else %}new{% endif %}(metric_id.into(), CommonMetricData {
{% for arg_name in common_metric_data_args if arg_name in metric_type.args %}
{{ arg_name }},
@@ -124,6 +133,7 @@ map of argument name to argument type. I may regret this if I need it again. #}
"We should never insert a runtime metric with an already-used id."
);
metric32
+ {% endif %}
}
{% endfor %}
_ => return Err(Box::new(MetricTypeNotFoundError(metric_type.to_string())))
@@ -137,10 +147,11 @@ pub fn create_and_register_ping(
include_client_id: bool,
send_if_empty: bool,
precise_timestamps: bool,
+ include_info_sections: bool,
reason_codes: Vec<String>,
) -> Result<u32, Box<dyn std::error::Error>> {
let ping_id = NEXT_PING_ID.fetch_add(1, Ordering::SeqCst);
- let ping = Ping::new(ping_name, include_client_id, send_if_empty, precise_timestamps, reason_codes);
+ let ping = Ping::new(ping_name, include_client_id, send_if_empty, precise_timestamps, include_info_sections, reason_codes);
assert!(
__jog_metric_maps::PING_MAP.write()?.insert(ping_id.into(), ping).is_none(),
"We should never insert a runtime ping with an already-used id."
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/ohttp.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/ohttp.jinja2
new file mode 100644
index 0000000000..d6e1248021
--- /dev/null
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/ohttp.jinja2
@@ -0,0 +1,13 @@
+// -*- mode: Rust -*-
+
+// AUTOGENERATED BY glean_parser. DO NOT EDIT.
+{# The rendered source is autogenerated, but this
+Jinja2 template is not. Please file bugs! #}
+
+/* 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/. */
+
+pub fn uses_ohttp(ping_name: &str) -> bool {
+ matches!(ping_name, {{ ohttp_pings|quote_and_join }})
+}
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2
index cc29805099..5723ff5d58 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust.jinja2
@@ -8,6 +8,41 @@ Jinja2 template is not. Please file bugs! #}
* 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/. */
+{% macro generate_structure(name, struct) %}
+{% if struct.type == "array" %}
+ pub type {{ name }} = Vec<{{ name }}Item>;
+
+ {{ generate_structure(name ~ "Item", struct["items"]) -}}
+
+{% elif struct.type == "object" %}
+ #[derive(Debug, Hash, Eq, PartialEq, ::glean::traits::__serde::Serialize, ::glean::traits::__serde::Deserialize)]
+ #[serde(deny_unknown_fields)]
+ pub struct {{ name }} {
+ {% for itemname, val in struct.properties.items() %}
+ {% if val.type == "object" %}
+ pub {{itemname|snake_case}}: {{ name ~ "Item" ~ itemname|Camelize ~ "Object" }},
+ {% elif val.type == "array" %}
+ pub {{itemname|snake_case}}: {{ name ~ "Item" ~ itemname|Camelize }},
+ {% else %}
+ pub {{itemname|snake_case}}: Option<{{val.type|structure_type_name}}>,
+ {% endif %}
+ {% endfor %}
+ }
+
+ {% for itemname, val in struct.properties.items() %}
+ {% if val.type == "array" %}
+ {% set nested_name = name ~ "Item" ~ itemname|Camelize %}
+ {{ generate_structure(nested_name, val) -}}
+ {% elif val.type == "object" %}
+ {% set nested_name = name ~ "Item" ~ itemname|Camelize ~ "Object" %}
+ {{ generate_structure(nested_name, val) -}}
+ {% endif %}
+ {% endfor %}
+{% else %}
+pub type {{ name }} = {{ struct.type|structure_type_name }};
+{% endif %}
+{% endmacro %}
+
{% macro generate_extra_keys(obj) -%}
{% for name, _ in obj["_generate_enums"] %}
{# we always use the `extra` suffix, because we only expose the new event API #}
@@ -81,6 +116,9 @@ pub mod {{ category_name|snake_case }} {
use glean::HistogramType;
use once_cell::sync::Lazy;
+ #[allow(unused_imports)]
+ use std::convert::TryFrom;
+
{% for obj in objs.values() %}
{% if obj|attr("_generate_enums") %}
{{ generate_extra_keys(obj) }}
@@ -88,6 +126,9 @@ pub mod {{ category_name|snake_case }} {
{% if obj.labeled and obj.labels and obj.labels|length %}
{{ generate_label_enum(obj)|indent }}
{% endif %}
+ {% if obj|attr("_generate_structure") %}
+ {{ generate_structure(obj.name|Camelize ~ "Object", obj._generate_structure) -}}
+ {% endif %}
#[allow(non_upper_case_globals)]
/// generated from {{ category_name }}.{{ obj.name }}
///
@@ -148,6 +189,71 @@ pub(crate) mod __glean_metric_maps {
{% endfor %}
+ pub(crate) fn set_object_by_id(metric_id: u32, value: String) -> Result<(), ()> {
+ match metric_id {
+{% for metric_id, object in objects_by_id.items() %}
+ {{metric_id}} => {
+ super::{{object}}.set_string(value);
+ Ok(())
+ }
+{% endfor %}
+ _ => Err(()),
+ }
+ }
+
+ /// Wrapper to get the currently stored object for object metric as a string.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ /// * `ping_name` - (Optional) The ping name to look into.
+ /// Defaults to the first value in `send_in_pings`.
+ ///
+ /// # Returns
+ ///
+ /// Returns the recorded object serialized as a JSON string or `None` if nothing stored.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no object by the given metric ID could be found.
+ pub(crate) fn object_test_get_value(metric_id: u32, ping_name: Option<String>) -> Option<String> {
+ match metric_id {
+{% for metric_id, object in objects_by_id.items() %}
+ {{metric_id}} => super::{{object}}.test_get_value_as_str(ping_name.as_deref()),
+{% endfor %}
+ _ => panic!("No object for metric id {}", metric_id),
+ }
+ }
+
+ /// Check the provided object for errors.
+ ///
+ /// # Arguments
+ ///
+ /// * `metric_id` - The metric's ID to look up
+ ///
+ /// # Returns
+ ///
+ /// Returns a string for the recorded error or `None`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if no object by the given metric ID could be found.
+ #[allow(unused_variables)]
+ pub(crate) fn object_test_get_error(metric_id: u32) -> Option<String> {
+ #[cfg(feature = "with_gecko")]
+ match metric_id {
+{% for metric_id, object in objects_by_id.items() %}
+ {{metric_id}} => test_get_errors!(super::{{object}}),
+{% endfor %}
+ _ => panic!("No object for metric id {}", metric_id),
+ }
+
+ #[cfg(not(feature = "with_gecko"))]
+ {
+ return None;
+ }
+ }
+
/// Wrapper to record an event based on its metric ID.
///
/// # Arguments
diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust_pings.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust_pings.jinja2
index c041f663a6..8afdae61ae 100644
--- a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust_pings.jinja2
+++ b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/rust_pings.jinja2
@@ -20,6 +20,7 @@ pub static {{ obj.name|snake_case }}: Lazy<Ping> = Lazy::new(|| {
{{ obj.include_client_id|rust }},
{{ obj.send_if_empty|rust }},
{{ obj.precise_timestamps|rust }},
+ {{ obj.include_info_sections|rust }},
{{ obj.reason_codes|rust }},
)
});
diff --git a/toolkit/components/glean/build_scripts/mach_commands.py b/toolkit/components/glean/build_scripts/mach_commands.py
index d385e53605..4a0f6dbc68 100644
--- a/toolkit/components/glean/build_scripts/mach_commands.py
+++ b/toolkit/components/glean/build_scripts/mach_commands.py
@@ -183,8 +183,13 @@ def update_glean(command_context, version):
)
replace_in_file_or_die(
topsrcdir / "gfx" / "wr" / "webrender" / "Cargo.toml",
- r'^glean = "[0-9.]+"',
- f'glean = "{version}"',
+ r'^glean = { version = "[0-9.]+"(.+)}',
+ f'glean = {{ version = "{version}"\\1}}',
+ )
+ replace_in_file_or_die(
+ topsrcdir / "gfx" / "wr" / "wr_glyph_rasterizer" / "Cargo.toml",
+ r'^glean = { version = "[0-9.]+"(.+)}',
+ f'glean = {{ version = "{version}"\\1}}',
)
replace_in_file_or_die(
topsrcdir / "python" / "sites" / "mach.txt",
@@ -193,13 +198,9 @@ def update_glean(command_context, version):
)
instructions = f"""
- We've edited most of the necessary files to require Glean SDK {version}.
-
- You will have to edit the following files yourself:
-
- gfx/wr/wr_glyph_rasterizer/Cargo.toml
+ We've edited the necessary files to require Glean SDK {version}.
- Then, to ensure Glean and Firefox's other Rust dependencies are appropriately vendored,
+ To ensure Glean and Firefox's other Rust dependencies are appropriately vendored,
please run the following commands:
cargo update -p glean