diff options
Diffstat (limited to 'toolkit/components/glean/build_scripts')
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 |