From 6927957fa48720d579a977f04396e818a8bb42eb Mon Sep 17 00:00:00 2001 From: omesser Date: Mon, 4 Jul 2022 19:34:20 +0300 Subject: [PATCH 1/4] Move to new path --- .gitignore | 1 + src/iterative_telemetry/__init__.py | 34 ++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index a81c8ee..a14ca1a 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.idea/ # Spyder project settings .spyderproject diff --git a/src/iterative_telemetry/__init__.py b/src/iterative_telemetry/__init__.py index 4dc1f9b..fb0599a 100644 --- a/src/iterative_telemetry/__init__.py +++ b/src/iterative_telemetry/__init__.py @@ -196,26 +196,44 @@ def _find_or_create_user_id(): IDs are generated randomly with UUID. """ - config_dir = user_config_dir("telemetry", "iterative") - fname = os.path.join(config_dir, "user_id") + legacy_dvc_config_dir = user_config_dir("dvc", "iterative") + config_dir = user_config_dir(os.path.join("iterative", "telemetry"), "iterative") + legacy_user_id_file = os.path.join(legacy_dvc_config_dir, "user_id") + user_id_file = os.path.join(config_dir, "user_id") lockfile = os.path.join(config_dir, "user_id.lock") - # Since the `fname` and `lockfile` are under the global config, - # we need to make sure such directory exist already. - os.makedirs(config_dir, exist_ok=True) - try: with FileLock( # pylint: disable=abstract-class-instantiated lockfile, timeout=5 ): try: - with open(fname, encoding="utf8") as fobj: + + # Backwards compatibility with DVC legacy telemetry file location + # Will only try to copy over if config_dir doesn't exist (first run per machine) + if legacy_dvc_config_dir.exists() and not config_dir.exists(): + with open(legacy_user_id_file, encoding="utf8") as fobj_legacy: + with open(user_id_file, "w", encoding="utf8") as fobj_new: + user_id = json.load(fobj_legacy)["user_id"] + json.dump({"user_id": user_id}, fobj_new) + + except (FileNotFoundError, ValueError, KeyError): + + # Fail silently + pass + + try: + + # Since the `user_id_file` and `lockfile` are under the global config, + # we need to make sure such directory exist already. + os.makedirs(config_dir, exist_ok=True) + + with open(user_id_file, encoding="utf8") as fobj: user_id = json.load(fobj)["user_id"] except (FileNotFoundError, ValueError, KeyError): user_id = str(uuid.uuid4()) - with open(fname, "w", encoding="utf8") as fobj: + with open(user_id_file, "w", encoding="utf8") as fobj: json.dump({"user_id": user_id}, fobj) return user_id From b3c8df8eef3ff31a9742fd6077da0cacd1e8e604 Mon Sep 17 00:00:00 2001 From: omesser Date: Tue, 5 Jul 2022 01:10:10 +0300 Subject: [PATCH 2/4] Another pass --- src/iterative_telemetry/__init__.py | 53 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/iterative_telemetry/__init__.py b/src/iterative_telemetry/__init__.py index fb0599a..9e03b5b 100644 --- a/src/iterative_telemetry/__init__.py +++ b/src/iterative_telemetry/__init__.py @@ -196,44 +196,30 @@ def _find_or_create_user_id(): IDs are generated randomly with UUID. """ - legacy_dvc_config_dir = user_config_dir("dvc", "iterative") - config_dir = user_config_dir(os.path.join("iterative", "telemetry"), "iterative") - legacy_user_id_file = os.path.join(legacy_dvc_config_dir, "user_id") - user_id_file = os.path.join(config_dir, "user_id") + config_dir = user_config_dir( + os.path.join("iterative", "telemetry"), "iterative" + ) + fname = os.path.join(config_dir, "user_id") lockfile = os.path.join(config_dir, "user_id.lock") + # Since the `fname` and `lockfile` are under the global config, + # we need to make sure such directory exist already. + os.makedirs(config_dir, exist_ok=True) + try: with FileLock( # pylint: disable=abstract-class-instantiated lockfile, timeout=5 ): try: - - # Backwards compatibility with DVC legacy telemetry file location - # Will only try to copy over if config_dir doesn't exist (first run per machine) - if legacy_dvc_config_dir.exists() and not config_dir.exists(): - with open(legacy_user_id_file, encoding="utf8") as fobj_legacy: - with open(user_id_file, "w", encoding="utf8") as fobj_new: - user_id = json.load(fobj_legacy)["user_id"] - json.dump({"user_id": user_id}, fobj_new) - - except (FileNotFoundError, ValueError, KeyError): - - # Fail silently - pass - - try: - - # Since the `user_id_file` and `lockfile` are under the global config, - # we need to make sure such directory exist already. - os.makedirs(config_dir, exist_ok=True) - - with open(user_id_file, encoding="utf8") as fobj: + with open(fname, encoding="utf8") as fobj: user_id = json.load(fobj)["user_id"] except (FileNotFoundError, ValueError, KeyError): - user_id = str(uuid.uuid4()) - with open(user_id_file, "w", encoding="utf8") as fobj: + # Backwards compatibility with DVC legacy telemetry location. + user_id = _try_read_legacy_user_id() or str(uuid.uuid4()) + + with open(fname, "w", encoding="utf8") as fobj: json.dump({"user_id": user_id}, fobj) return user_id @@ -241,3 +227,16 @@ def _find_or_create_user_id(): except Timeout: logger.debug("Failed to acquire %s", lockfile) return None + + +def _try_read_legacy_user_id(): + fname = os.path.join(user_config_dir("dvc", "iterative"), "user_id") + + try: + with open(fname, encoding="utf8") as fobj: + return json.load(fobj)["user_id"] + + except (FileNotFoundError, ValueError, KeyError): + pass + + return None From 7fed0c0db6783aa3654f43bf8fc4563bfc8ba59f Mon Sep 17 00:00:00 2001 From: omesser Date: Tue, 5 Jul 2022 01:28:05 +0300 Subject: [PATCH 3/4] addressing CR --- src/iterative_telemetry/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/iterative_telemetry/__init__.py b/src/iterative_telemetry/__init__.py index 9e03b5b..6ab63af 100644 --- a/src/iterative_telemetry/__init__.py +++ b/src/iterative_telemetry/__init__.py @@ -230,7 +230,8 @@ def _find_or_create_user_id(): def _try_read_legacy_user_id(): - fname = os.path.join(user_config_dir("dvc", "iterative"), "user_id") + config_dir = user_config_dir("dvc", "iterative") + fname = os.path.join(config_dir, "user_id") try: with open(fname, encoding="utf8") as fobj: From 3c593d709839a55a1d5b245a65254bec1855b3df Mon Sep 17 00:00:00 2001 From: omesser Date: Tue, 5 Jul 2022 19:44:41 +0300 Subject: [PATCH 4/4] Add _try_write_legacy_user_id logic, move to pathlib --- src/iterative_telemetry/__init__.py | 52 ++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/iterative_telemetry/__init__.py b/src/iterative_telemetry/__init__.py index 6ab63af..b7a2a65 100644 --- a/src/iterative_telemetry/__init__.py +++ b/src/iterative_telemetry/__init__.py @@ -8,6 +8,7 @@ import sys import uuid from functools import lru_cache +from pathlib import Path from threading import Thread from typing import Any, Callable, Dict, Union @@ -191,19 +192,22 @@ def _system_info(): def _find_or_create_user_id(): """ The user's ID is stored on a file under the global config directory. + In Case the current file is not found, a legacy DVC location is checked, + and we try to dump the user_id there to support users working with + legacy DVC versions The file should contain a JSON with a "user_id" key: {"user_id": "16fd2706-8baf-433b-82eb-8c7fada847da"} IDs are generated randomly with UUID. """ - config_dir = user_config_dir( - os.path.join("iterative", "telemetry"), "iterative" - ) - fname = os.path.join(config_dir, "user_id") - lockfile = os.path.join(config_dir, "user_id.lock") + config_dir = user_config_dir(str(Path("iterative") / "telemetry"), False) + user_id_file = Path(config_dir / "user_id") + legacy_config_dir = user_config_dir("dvc", "iterative") + legacy_user_id_file = Path(legacy_config_dir / "user_id") + lockfile = Path(config_dir / "user_id.lock") - # Since the `fname` and `lockfile` are under the global config, - # we need to make sure such directory exist already. + # Since the `user_id_file` and `lockfile` are under the global config, + # we need to ensure directory exists. os.makedirs(config_dir, exist_ok=True) try: @@ -211,17 +215,27 @@ def _find_or_create_user_id(): lockfile, timeout=5 ): try: - with open(fname, encoding="utf8") as fobj: + with user_id_file.open(encoding="utf8") as fobj: user_id = json.load(fobj)["user_id"] except (FileNotFoundError, ValueError, KeyError): - # Backwards compatibility with DVC legacy telemetry location. - user_id = _try_read_legacy_user_id() or str(uuid.uuid4()) + # Backwards compatibility - if created by legacy DVC + user_id = _try_read_legacy_user_id(legacy_user_id_file) or str( + uuid.uuid4() + ) - with open(fname, "w", encoding="utf8") as fobj: + with user_id_file.open(mode="w", encoding="utf8") as fobj: json.dump({"user_id": user_id}, fobj) + # Backwards compatibility - write legacy file in case legacy DVC is + # still used + if ( + not legacy_user_id_file.exists() + and user_id.lower() != DO_NOT_TRACK_VALUE + ): + _try_write_legacy_user_id(legacy_user_id_file, user_id) + return user_id except Timeout: @@ -229,15 +243,21 @@ def _find_or_create_user_id(): return None -def _try_read_legacy_user_id(): - config_dir = user_config_dir("dvc", "iterative") - fname = os.path.join(config_dir, "user_id") - +def _try_read_legacy_user_id(filepath: Path): try: - with open(fname, encoding="utf8") as fobj: + with filepath.open(encoding="utf8") as fobj: return json.load(fobj)["user_id"] except (FileNotFoundError, ValueError, KeyError): pass return None + + +def _try_write_legacy_user_id(filepath: Path, user_id: str): + try: + with filepath.open(mode="w", encoding="utf8") as fobj: + json.dump({"user_id": user_id}, fobj) + + except (FileNotFoundError, ValueError, KeyError): + pass