summaryrefslogtreecommitdiffstats
path: root/toolkit/components/nimbus/generate/generate_feature_manifest.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/nimbus/generate/generate_feature_manifest.py
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/nimbus/generate/generate_feature_manifest.py')
-rw-r--r--toolkit/components/nimbus/generate/generate_feature_manifest.py212
1 files changed, 212 insertions, 0 deletions
diff --git a/toolkit/components/nimbus/generate/generate_feature_manifest.py b/toolkit/components/nimbus/generate/generate_feature_manifest.py
new file mode 100644
index 0000000000..c17f320184
--- /dev/null
+++ b/toolkit/components/nimbus/generate/generate_feature_manifest.py
@@ -0,0 +1,212 @@
+# 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/.
+
+import json
+import sys
+from pathlib import Path
+
+import jsonschema
+import yaml
+
+HEADER_LINE = (
+ "// This file was generated by generate_feature_manifest.py from FeatureManifest.yaml."
+ " DO NOT EDIT.\n"
+)
+
+FEATURE_MANIFEST_SCHEMA = Path("schemas", "ExperimentFeatureManifest.schema.json")
+
+NIMBUS_FALLBACK_PREFS = (
+ "constexpr std::pair<nsLiteralCString, nsLiteralCString>"
+ "NIMBUS_FALLBACK_PREFS[]{{{}}};"
+)
+
+# Do not add new feature IDs to this list! isEarlyStartup is being deprecated.
+# See https://bugzilla.mozilla.org/show_bug.cgi?id=1875331 for details.
+ALLOWED_ISEARLYSTARTUP_FEATURE_IDS = {
+ "abouthomecache",
+ "aboutwelcome",
+ "backgroundThreads",
+ "backgroundUpdate",
+ "bookmarks",
+ "dapTelemetry",
+ "deviceMigration",
+ "frecency",
+ "fullPageTranslation",
+ "fullPageTranslationAutomaticPopup",
+ "fxaButtonVisibility",
+ "gcParallelMarking",
+ "gleanInternalSdk",
+ "jitHintsCache",
+ "jitThresholds",
+ "jsParallelParsing",
+ "majorRelease2022",
+ "migrationWizard",
+ "newtab",
+ "nimbus-qa-2",
+ "opaqueResponseBlocking",
+ "phc",
+ "pocketNewtab",
+ "powerSaver",
+ "reportBrokenSite",
+ "saveToPocket",
+ "searchConfiguration",
+ "shellService",
+ "testFeature",
+ "updatePrompt",
+ "upgradeDialog",
+ "windowsJumpList",
+}
+
+
+def write_fm_headers(fd):
+ fd.write(HEADER_LINE)
+
+
+def validate_feature_manifest(schema_path, manifest_path, manifest):
+ with open(schema_path, "r") as f:
+ schema = json.load(f)
+
+ set_prefs = {}
+ fallback_prefs = {}
+
+ for feature_id, feature in manifest.items():
+ try:
+ jsonschema.validate(feature, schema)
+
+ is_early_startup = feature.get("isEarlyStartup", False)
+ allowed_is_early_startup = feature_id in ALLOWED_ISEARLYSTARTUP_FEATURE_IDS
+ if is_early_startup != allowed_is_early_startup:
+ if is_early_startup:
+ print(f"Feature {feature_id} is marked isEarlyStartup: true")
+ print(
+ "isEarlyStartup is deprecated and no new isEarlyStartup features can be added"
+ )
+ print(
+ "See https://bugzilla.mozilla.org/show_bug.cgi?id=1875331 for details"
+ )
+ raise Exception("isEarlyStartup is deprecated")
+ else:
+ print(
+ f"Feature {feature_id} is not early startup but is in the allow list."
+ )
+ print("Please remove it from generate_feature_manifest.py")
+ raise Exception("isEarlyStatup is deprecated")
+
+ for variable, variable_def in feature.get("variables", {}).items():
+ set_pref = variable_def.get("setPref")
+
+ if isinstance(set_pref, dict):
+ set_pref = set_pref.get("pref")
+
+ if set_pref is not None:
+ if set_pref in set_prefs:
+ other_feature = set_prefs[set_pref][0]
+ other_variable = set_prefs[set_pref][1]
+ print("Multiple variables cannot declare the same setPref")
+ print(
+ f"{feature_id} variable {variable} wants to set pref {set_pref}"
+ )
+ print(
+ f"{other_feature} variable {other_variable} wants to set pref "
+ f"{set_pref}"
+ )
+ raise Exception("Set prefs are exclusive")
+
+ set_prefs[set_pref] = (feature_id, variable)
+
+ fallback_pref = variable_def.get("fallbackPref")
+ if fallback_pref is not None:
+ fallback_prefs[fallback_pref] = (feature_id, variable)
+
+ conflicts = [
+ (
+ "setPref",
+ fallback_pref,
+ "fallbackPref",
+ set_prefs.get(fallback_pref),
+ ),
+ ("fallbackPref", set_pref, "setPref", fallback_prefs.get(set_pref)),
+ ]
+
+ for kind, pref, other_kind, conflict in conflicts:
+ if conflict is not None:
+ print(
+ "The same pref cannot be specified in setPref and fallbackPref"
+ )
+ print(
+ f"{feature_id} variable {variable} has specified {kind} {pref}"
+ )
+ print(
+ f"{conflict[0]} variable {conflict[1]} has specified {other_kind} "
+ f"{pref}"
+ )
+ raise Exception("Set prefs and fallback prefs cannot overlap")
+
+ except Exception as e:
+ print("Error while validating FeatureManifest.yaml")
+ print(f"On key: {feature_id}")
+ print(f"Input file: {manifest_path}")
+ raise e
+
+
+def generate_feature_manifest(fd, input_file):
+ write_fm_headers(fd)
+
+ try:
+ with open(input_file, "r", encoding="utf-8") as f:
+ manifest = yaml.safe_load(f)
+
+ validate_feature_manifest(
+ Path(input_file).parent / FEATURE_MANIFEST_SCHEMA, input_file, manifest
+ )
+
+ fd.write(f"export const FeatureManifest = {json.dumps(manifest)};")
+ except IOError as e:
+ print(f"{input_file}: error:\n {e}\n")
+ sys.exit(1)
+
+
+def platform_feature_manifest_array(features):
+ entries = []
+ for feature, featureData in features.items():
+ # Features have to be tagged isEarlyStartup to be accessible
+ # to Nimbus platform API
+ if not featureData.get("isEarlyStartup", False):
+ continue
+ entries.extend(
+ '{{ "{}_{}"_ns, "{}"_ns }}'.format(
+ feature, variable, variableData["fallbackPref"]
+ )
+ for (variable, variableData) in featureData.get("variables", {}).items()
+ if variableData.get("fallbackPref", False)
+ )
+ return NIMBUS_FALLBACK_PREFS.format(", ".join(entries))
+
+
+def generate_platform_feature_manifest(fd, input_file):
+ write_fm_headers(fd)
+
+ def file_structure(data):
+ return "\n".join(
+ [
+ "#ifndef mozilla_NimbusFeaturesManifest_h",
+ "#define mozilla_NimbusFeaturesManifest_h",
+ "#include <utility>",
+ '#include "mozilla/Maybe.h"',
+ '#include "nsStringFwd.h"',
+ "namespace mozilla {",
+ platform_feature_manifest_array(data),
+ '#include "./lib/NimbusFeatureManifest.inc.h"',
+ "} // namespace mozilla",
+ "#endif // mozilla_NimbusFeaturesManifest_h",
+ ]
+ )
+
+ try:
+ with open(input_file, "r", encoding="utf-8") as yaml_input:
+ data = yaml.safe_load(yaml_input)
+ fd.write(file_structure(data))
+ except IOError as e:
+ print("{}: error:\n {}\n".format(input_file, e))
+ sys.exit(1)