From 719d80346aca0aabcda0e11590acefc21d27821b Mon Sep 17 00:00:00 2001 From: Cherie Williams Date: Thu, 16 Feb 2017 14:39:17 -0800 Subject: [PATCH] Remove analytics reporting from pebble-tool --- pebble_tool/__init__.py | 6 - pebble_tool/commands/base.py | 2 - pebble_tool/commands/sdk/create.py | 3 - pebble_tool/commands/sdk/project/__init__.py | 13 +- pebble_tool/commands/sdk/project/build.py | 9 - pebble_tool/sdk/emulator.py | 3 - pebble_tool/util/analytics.py | 245 ------------------- pebble_tool/version.py | 2 +- 8 files changed, 2 insertions(+), 281 deletions(-) delete mode 100644 pebble_tool/util/analytics.py diff --git a/pebble_tool/__init__.py b/pebble_tool/__init__.py index 76d1bac..8d12c52 100644 --- a/pebble_tool/__init__.py +++ b/pebble_tool/__init__.py @@ -9,7 +9,6 @@ from .exceptions import ToolError from .sdk import sdk_version -from .util.analytics import wait_for_analytics, analytics_prompt from .util.config import config from .util.updates import wait_for_update_checks from .util.wsl import maybe_apply_wsl_hacks @@ -29,7 +28,6 @@ def run_tool(args=None): urllib3.disable_warnings() # sigh. :( logging.basicConfig() maybe_apply_wsl_hacks() - analytics_prompt() parser = argparse.ArgumentParser(description="Pebble Tool", prog="pebble", epilog="For help on an individual command, call that command with --help.") version_string = "Pebble Tool v{}".format(__version__) @@ -49,9 +47,5 @@ def run_tool(args=None): @atexit.register def wait_for_cleanup(): - import time - now = time.time() - wait_for_analytics(2) wait_for_update_checks(2) - logging.info("Spent %f seconds waiting for analytics.", time.time() - now) config.save() diff --git a/pebble_tool/commands/base.py b/pebble_tool/commands/base.py index 29ec3b2..c87aba0 100644 --- a/pebble_tool/commands/base.py +++ b/pebble_tool/commands/base.py @@ -18,7 +18,6 @@ from pebble_tool.sdk import pebble_platforms, sdk_version from pebble_tool.sdk.emulator import ManagedEmulatorTransport, get_all_emulator_info from pebble_tool.sdk.cloudpebble import CloudPebbleTransport -from pebble_tool.util.analytics import post_event _CommandRegistry = [] @@ -55,7 +54,6 @@ def _shared_parser(cls): def __call__(self, args): self._set_debugging(args.v) - post_event("invoke_command_{}".format(self.command)) def _set_debugging(self, level): self._verbosity = level diff --git a/pebble_tool/commands/sdk/create.py b/pebble_tool/commands/sdk/create.py index 34c76df..60b3d52 100644 --- a/pebble_tool/commands/sdk/create.py +++ b/pebble_tool/commands/sdk/create.py @@ -12,7 +12,6 @@ from . import SDKCommand from pebble_tool.sdk import SDK_VERSION, sdk_version from pebble_tool.exceptions import ToolError -from pebble_tool.util.analytics import post_event from pebble_tool.util.versions import version_to_key @@ -162,7 +161,6 @@ def __call__(self, args): _copy_from_template(template_layout, extant_path(template_paths), args.name, options) - post_event("sdk_create_project", javascript=args.javascript or args.rocky, worker=args.worker, rocky=args.rocky) print("Created new project {}".format(args.name)) @classmethod @@ -201,7 +199,6 @@ def __call__(self, args): _copy_from_template(template_layout, template_path, args.name, options) - post_event("sdk_create_package", javascript=args.javascript) print("Created new package {}".format(args.name)) @classmethod diff --git a/pebble_tool/commands/sdk/project/__init__.py b/pebble_tool/commands/sdk/project/__init__.py index 6eaac89..3e24d4e 100644 --- a/pebble_tool/commands/sdk/project/__init__.py +++ b/pebble_tool/commands/sdk/project/__init__.py @@ -8,7 +8,6 @@ from pebble_tool.exceptions import (PebbleProjectException, InvalidJSONException, InvalidProjectException, OutdatedProjectException) from pebble_tool.sdk.project import PebbleProject -from pebble_tool.util.analytics import post_event from pebble_tool.commands.sdk import SDKCommand logger = logging.getLogger("pebble_tool.commands.sdk") @@ -41,14 +40,4 @@ def _waf(self, command, extra_env=None, args=None): def __call__(self, args): super(SDKProjectCommand, self).__call__(args) - try: - self.project = PebbleProject() - except PebbleProjectException as e: - event_map = { - InvalidProjectException: "sdk_run_without_project", - InvalidJSONException: "sdk_json_error", - OutdatedProjectException: "sdk_json_error", - } - if type(e) in event_map: - post_event(event_map[type(e)]) - raise + self.project = PebbleProject() diff --git a/pebble_tool/commands/sdk/project/build.py b/pebble_tool/commands/sdk/project/build.py index d7cd1a4..7525b76 100644 --- a/pebble_tool/commands/sdk/project/build.py +++ b/pebble_tool/commands/sdk/project/build.py @@ -7,7 +7,6 @@ import time from pebble_tool.exceptions import BuildError -from pebble_tool.util.analytics import post_event import pebble_tool.util.npm as npm from pebble_tool.commands.sdk.project import SDKProjectCommand @@ -20,12 +19,10 @@ def __call__(self, args): super(BuildCommand, self).__call__(args) start_time = time.time() if len(self.project.dependencies) > 0: - post_event('app_build_with_npm_deps') try: npm.invoke_npm(["install"]) npm.invoke_npm(["dedupe"]) except subprocess.CalledProcessError: - post_event("app_build_failed_npm") raise BuildError("npm failed.") try: waf = list(args.args) @@ -39,13 +36,7 @@ def __call__(self, args): self._waf("configure", extra_env=extra_env, args=waf) self._waf("build", args=waf) except subprocess.CalledProcessError: - duration = time.time() - start_time - post_event("app_build_failed", build_time=duration) raise BuildError("Build failed.") - else: - duration = time.time() - start_time - has_js = os.path.exists(os.path.join('src', 'js')) - post_event("app_build_succeeded", has_js=has_js, line_counts=self._get_line_counts(), build_time=duration) @classmethod def _get_line_counts(cls): diff --git a/pebble_tool/sdk/emulator.py b/pebble_tool/sdk/emulator.py index bb63760..a691b56 100644 --- a/pebble_tool/sdk/emulator.py +++ b/pebble_tool/sdk/emulator.py @@ -24,7 +24,6 @@ from pebble_tool.account import get_default_account from pebble_tool.exceptions import MissingEmulatorError, ToolError -from pebble_tool.util.analytics import post_event from . import sdk_path, get_sdk_persist_dir, sdk_manager logger = logging.getLogger("pebble_tool.sdk.emulator") @@ -249,7 +248,6 @@ def _wait_for_qemu(self): else: break else: - post_event("qemu_launched", success=False, reason="qemu_launch_timeout") raise ToolError("Emulator launch timed out.") received = b'' while True: @@ -262,7 +260,6 @@ def _wait_for_qemu(self): if b"" in received or b"" in received or b"Ready for communication" in received: break s.close() - post_event("qemu_launched", success=True) logger.info("Firmware booted.") def _copy_spi_image(self, path): diff --git a/pebble_tool/util/analytics.py b/pebble_tool/util/analytics.py deleted file mode 100644 index af349ef..0000000 --- a/pebble_tool/util/analytics.py +++ /dev/null @@ -1,245 +0,0 @@ -from __future__ import absolute_import, print_function -__author__ = 'katharine' - -from six import iteritems -from six.moves import input - -import collections -from distutils.util import strtobool -import json -import logging -import os.path -import platform -import socket -import threading -import uuid - -import requests - -from pebble_tool.account import get_default_account -from pebble_tool.sdk.project import PebbleProject -from pebble_tool.exceptions import MissingSDK, PebbleProjectException -from pebble_tool.sdk import sdk_path, sdk_version, get_persist_dir -from pebble_tool.util.wsl import is_secretly_windows -from pebble_tool.version import __version__ - -logger = logging.getLogger("pebble_tool.util.analytics") - - -class PebbleAnalytics(threading.Thread): - TD_SERVER = "https://td.getpebble.com/td.pebble.sdk_events" - - def __init__(self): - self.mark = threading.Event() - self.should_run = True - self.file_lock = threading.Lock() - try: - with open(self.pending_filename) as f: - old_events = json.load(f) - except (IOError, ValueError): - old_events = [] - self.pending = collections.deque(old_events) - super(PebbleAnalytics, self).__init__() - self.daemon = True - self.start() - - @property - def pending_filename(self): - return os.path.join(get_persist_dir(), "pending_analytics.json") - - def run(self): - should_track = self._should_track() - first_run = True - while first_run or self.should_run: - first_run = False - while True: - try: - current = self.pending.popleft() - except IndexError: - break - if should_track: - requests.post(self.TD_SERVER, data=current) - else: - logger.debug("Analytics disabled; not posting.") - self._store_queue() - self.mark.wait() - self.mark.clear() - - def wait(self, timeout): - self.mark.set() - self.should_run = False - self.join(timeout) - return self.is_alive - - @classmethod - def _flatten(cls, d, parent_key=''): - items = [] - for k, v in iteritems(d): - new_key = parent_key + '_0_' + k if parent_key else k - if isinstance(v, collections.MutableMapping): - items.extend(iteritems(cls._flatten(v, new_key))) - else: - items.append((new_key, v)) - return dict(items) - - def submit_event(self, event, force=False, **data): - analytics = { - 'event': event, - 'identity': self._get_identity(), - 'platform': 'native_sdk', - 'sdk': { - 'host': self._get_host_info(), - 'version': sdk_version(), - 'tool_version': __version__, - }, - 'data': data.copy() - } - try: - analytics['sdk']['project'] = self._get_project_info() - except PebbleProjectException: - pass - - - td_obj = self._flatten(analytics) - - fields = { - 'json': json.dumps(td_obj) - } - if force: - requests.post(self.TD_SERVER, data=fields) - logger.debug("Synchronously transmitting analytics data: {}".format(analytics)) - else: - logger.debug("Queueing analytics data: {}".format(analytics)) - self._enqueue(fields) - - def _enqueue(self, fields): - self.pending.append(fields) - self._store_queue() - self.mark.set() - - def _store_queue(self): - with open(self.pending_filename, 'w') as f: - json.dump(list(self.pending), f) - - def _should_track(self): - # Should we track analytics? - permission_file = os.path.join(self.get_option_dir(), "ENABLE_ANALYTICS") - if not os.path.exists(permission_file): - return False - - # Don't track if internet connection is down - try: - # NOTE: This is the IP address of www.google.com. On certain - # flavors of linux (Ubuntu 13.04 and others), the timeout argument - # is ignored during the DNS lookup portion so we test connectivity - # using an IP address only. - requests.head("http://209.118.208.39", timeout=2) - except (requests.RequestException, socket.error): - logger.debug("Analytics collection disabled due to lack of internet connectivity") - return False - return True - - def _get_identity(self): - account = get_default_account() - identity = { - 'sdk_client_id': self._get_machine_identifier() - } - if account.is_logged_in: - identity['user'] = account.id - return identity - - def _get_machine_identifier(self): - # Get installation info. If we detect a new install, post an appropriate event - settings_dir = get_persist_dir() - client_id_file = os.path.join(settings_dir, "client_id") - - # Get (and create if necessary) the client id - try: - with open(client_id_file) as f: - return f.read() - except IOError: - client_id = str(uuid.uuid4()) - with open(client_id_file, 'w') as f: - f.write(client_id) - return client_id - - def _get_project_info(self): - project = PebbleProject() - return { - 'uuid': str(project.uuid), - 'app_name': project.long_name, - 'is_watchface': project.is_watchface, - 'type': 'native', - 'sdk': project.sdk_version, - } - - def _get_host_info(self): - return { - 'platform': platform.platform(), - 'is_vm': self._is_running_in_vm(), - 'is_wsl': is_secretly_windows(), - 'python_version': platform.python_version(), - } - - @classmethod - def get_option_dir(cls): - return get_persist_dir() - - _shared_analytics = None - @classmethod - def get_shared(cls, *args, **kwargs): - if cls._shared_analytics is None: - cls._shared_analytics = cls() - return cls._shared_analytics - - @staticmethod - def _is_running_in_vm(): - """ Return true if we are running in a VM """ - - try: - drv_name = "/proc/scsi/scsi" - if os.path.exists(drv_name): - contents = open(drv_name).read() - if "VBOX" in contents or "VMware" in contents: - return True - except (OSError, IOError): - pass - - return False - - -# Convenience method. -def post_event(event, **data): - PebbleAnalytics.get_shared().submit_event(event, **data) - - -def wait_for_analytics(timeout): - PebbleAnalytics.get_shared().wait(timeout) - - -def analytics_prompt(): - path = PebbleAnalytics.get_option_dir() - if (not os.path.exists(os.path.join(path, "ENABLE_ANALYTICS")) - and not os.path.exists(os.path.join(path, "NO_TRACKING"))): - print("Pebble collects metrics on your usage of our developer tools.") - print("We use this information to help prioritise further development of our tooling.") - print() - print("If you cannot respond interactively, create a file called ENABLE_ANALYTICS or") - print("NO_TRACKING in '{}/'.".format(path)) - print() - while True: - result = input("Would you like to opt in to this collection? [y/n] ") - try: - can_collect = strtobool(result) - except ValueError: - print("Please respond with either 'yes' or 'no'.") - else: - if can_collect: - with open(os.path.join(path, "ENABLE_ANALYTICS"), 'w') as f: - f.write('yay!') - else: - logger.debug("Logging opt-out.") - post_event("sdk_analytics_opt_out", force=True) - with open(os.path.join(path, "NO_TRACKING"), 'w') as f: - f.write('aww.') - break diff --git a/pebble_tool/version.py b/pebble_tool/version.py index 76ea861..3bf7ea2 100644 --- a/pebble_tool/version.py +++ b/pebble_tool/version.py @@ -1,4 +1,4 @@ -version_base = (4, 5, 0) +version_base = (4, 5, 1) version_suffix = None if version_suffix is None: