123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- #!/usr/bin/env python3
- # Copyright 2024 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- import argparse
- import json
- import logging
- import os
- import subprocess
- import sys
- import textwrap
- import utils
- _DEFAULT_CONFIG_PATH = utils.depot_tools_config_path("build_telemetry.cfg")
- _DEFAULT_COUNTDOWN = 10
- VERSION = 1
- class Config:
- def __init__(self, config_path, countdown):
- self._config_path = config_path
- self._config = None
- self._notice_displayed = False
- self._countdown = countdown
- def load(self):
- """Loads the build telemetry config."""
- if self._config:
- return
- config = {}
- if os.path.isfile(self._config_path):
- with open(self._config_path) as f:
- try:
- config = json.load(f)
- except Exception:
- pass
- if config.get("version") != VERSION:
- config = None # Reset the state for version change.
- if not config:
- config = {
- "user": check_auth().get("email", ""),
- "status": None,
- "countdown": self._countdown,
- "version": VERSION,
- }
- if not config.get("user"):
- config["user"] = check_auth().get("email", "")
- self._config = config
- def save(self):
- with open(self._config_path, "w") as f:
- json.dump(self._config, f)
- @property
- def path(self):
- return self._config_path
- @property
- def is_googler(self):
- return self.user.endswith("@google.com")
- @property
- def user(self):
- if not self._config:
- return
- return self._config.get("user", "")
- @property
- def countdown(self):
- if not self._config:
- return
- return self._config.get("countdown")
- @property
- def version(self):
- if not self._config:
- return
- return self._config.get("version")
- def enabled(self):
- if not self._config:
- print("WARNING: depot_tools.build_telemetry: %s is not loaded." %
- self._config_path,
- file=sys.stderr)
- return False
- if not self.is_googler:
- return False
- if self._config.get("status") == "opt-out":
- return False
- if self._should_show_notice():
- remaining = max(0, self._config["countdown"] - 1)
- self._show_notice(remaining)
- self._notice_displayed = True
- self._config["countdown"] = remaining
- self.save()
- # Telemetry collection will happen.
- return True
- def _should_show_notice(self):
- if self._notice_displayed:
- return False
- if self._config.get("countdown") == 0:
- return False
- if self._config.get("status") == "opt-in":
- return False
- return True
- def _show_notice(self, remaining):
- """Dispalys notice when necessary."""
- print(
- textwrap.dedent(f"""\
- *** NOTICE ***
- Google-internal telemetry (including build logs, username, and hostname) is collected on corp machines to diagnose performance and fix build issues. This reminder will be shown {remaining} more times. See http://go/chrome-build-telemetry for details. Hide this notice or opt out by running: build_telemetry [opt-in] [opt-out]
- *** END NOTICE ***
- """))
- def opt_in(self):
- self._config["status"] = "opt-in"
- self.save()
- print("build telemetry collection is opted in")
- def opt_out(self):
- self._config["status"] = "opt-out"
- self.save()
- print("build telemetry collection is opted out")
- def status(self):
- return self._config["status"]
- def load_config(cfg_path=_DEFAULT_CONFIG_PATH, countdown=_DEFAULT_COUNTDOWN):
- """Loads the config from the default location."""
- cfg = Config(cfg_path, countdown)
- cfg.load()
- return cfg
- def check_auth():
- """Checks auth information."""
- try:
- out = subprocess.check_output(
- "cipd auth-info --json-output -",
- text=True,
- shell=True,
- stderr=subprocess.DEVNULL,
- timeout=3,
- )
- except Exception as e:
- return {}
- try:
- return json.loads(out)
- except json.JSONDecodeError as e:
- logging.error(e)
- return {}
- def enabled():
- """Checks whether the build can upload build telemetry."""
- cfg = load_config()
- return cfg.enabled()
- def print_status(cfg):
- status = cfg.status()
- if status == "opt-in":
- print("build telemetry collection is enabled. You have opted in.")
- elif status == "opt-out":
- print("build telemetry collection is disabled. You have opted out.")
- else:
- print("build telemetry collection is enabled.")
- print("")
- def main():
- parser = argparse.ArgumentParser(prog="build_telemetry")
- parser.add_argument('status',
- nargs='?',
- choices=["opt-in", "opt-out", "status"])
- args = parser.parse_args()
- cfg = load_config()
- if not cfg.is_googler:
- cfg.save()
- return
- if args.status == "opt-in":
- cfg.opt_in()
- return
- if args.status == "opt-out":
- cfg.opt_out()
- return
- if args.status == "status":
- print_status(cfg)
- return
- print_status(cfg)
- parser.print_help()
- if __name__ == "__main__":
- sys.exit(main())
|