author Emilio Cobos Álvarez <>
Wed, 24 Feb 2021 16:35:17 +0000
changeset 635363 fa8995f5a2c0f17c393675ff9d172de77dd5bd7c
parent 620830 994ae8e4833c90447d91f0e26a718573cff5a514
permissions -rw-r--r--
Bug 1692684 - Don't create transitions for invalid ::marker properties. r=hiro, a=tjr The test-case in the bug does something interesting, where it causes a transition on the parent by removing a CSS rule, and that causes us to transition text-underline-offset on our ::marker, via the magic of font-size-relative properties. text-underline-offset, while it gets inherited from ::marker, is not a valid CSS property to specify on marker per spec, so we trim it here: And that causes us to create a transition with an empty effect and everything goes downhill from here. For now, just bail out in a nicer way than we were doing. I still need to look into whether we should handle inherited transitions differently from non-inherited one in this case... I think our behavior after this patch would be correct for the test-case (because text-underline-offset would transition on the parent and ::marker would inherit it). If you specify transition only on the marker we'd refuse to transition (which I guess it is somewhat of a sensible behavior). Differential Revision:

# 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

from __future__ import print_function

import datetime
import json
import logging
import os
import sys

import requests
import voluptuous
import voluptuous.humanize

from mozbuild.telemetry import (
    schema as build_telemetry_schema,

BUILD_TELEMETRY_URL = "{endpoint}"
SUBMIT_ENDPOINT = "submit/eng-workflow/build/1/{ping_uuid}"

def delete_expired_files(directory, days=30):
    """Discards files in a directory older than a specified number
    of days
    now =
    for filename in os.listdir(directory):
        filepath = os.path.join(directory, filename)

        ctime = os.path.getctime(filepath)
        then = datetime.datetime.fromtimestamp(ctime)

        if (now - then) > datetime.timedelta(days=days):


def check_edge_server_status(session):
    """Returns True if the Telemetry Edge Server
    is ready to accept data
    status_url = BUILD_TELEMETRY_URL.format(endpoint=STATUS_ENDPOINT)
    response = session.get(status_url)
    if response.status_code != 200:
        return False
    return True

def send_telemetry_ping(session, data, ping_uuid):
    """Sends a single build telemetry ping to the
    edge server, returning the response object
    resource_url = SUBMIT_ENDPOINT.format(ping_uuid=str(ping_uuid))
    url = BUILD_TELEMETRY_URL.format(endpoint=resource_url)
    response =, json=data)

    return response

def submit_telemetry_data(outgoing, submitted):
    """Sends information about `./mach build` invocations to
    the Telemetry pipeline
    with requests.Session() as session:
        # Confirm the server is OK
        if not check_edge_server_status(session):
            logging.error('Error posting to telemetry: server status is not "200 OK"')
            return 1

        for filename in os.listdir(outgoing):
            path = os.path.join(outgoing, filename)

            if os.path.isdir(path) or not path.endswith(".json"):
      "skipping item {}".format(path))

            ping_uuid = os.path.splitext(filename)[0]  # strip ".json" to get ping UUID

                with open(path, "r") as f:
                    data = json.load(f)

                # Verify the data matches the schema
                    data, build_telemetry_schema

                response = send_telemetry_ping(session, data, ping_uuid)
                if response.status_code != 200:
                    msg = "response code {code} sending {uuid} to telemetry: {body}".format(

                # Move from "outgoing" to "submitted"
                    os.path.join(outgoing, filename), os.path.join(submitted, filename)

      "successfully posted {} to telemetry".format(ping_uuid))

            except ValueError as ve:
                # ValueError is thrown if JSON cannot be decoded
                logging.exception("exception parsing JSON at %s: %s" % (path, str(ve)))

            except voluptuous.Error as e:
                # Invalid is thrown if some data does not fit
                # the correct Schema
                logging.exception("invalid data found at %s: %s" % (path, e.message))

            except Exception as e:
                logging.error("exception posting to telemetry " "server: %s" % str(e))


    return 0

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("usage: python <statedir>")

    statedir = sys.argv[1]

        outgoing, submitted, telemetry_log = verify_statedir(statedir)

        # Configure logging
            format="%(asctime)s %(message)s",

        sys.exit(submit_telemetry_data(outgoing, submitted))

    except Exception as e:
        # Handle and print messages from `statedir` verification