|
8 | 8 | import sys
|
9 | 9 | import uuid
|
10 | 10 | from functools import lru_cache
|
| 11 | +from pathlib import Path |
11 | 12 | from threading import Thread
|
12 | 13 | from typing import Any, Callable, Dict, Union
|
13 | 14 |
|
@@ -74,8 +75,7 @@ def is_enabled(self):
|
74 | 75 | return (
|
75 | 76 | os.environ.get(DO_NOT_TRACK_ENV, None) is None and self.enabled()
|
76 | 77 | if callable(self.enabled)
|
77 |
| - else self.enabled |
78 |
| - and _find_or_create_user_id() != DO_NOT_TRACK_VALUE |
| 78 | + else self.enabled and _find_or_create_user_id() is not None |
79 | 79 | )
|
80 | 80 |
|
81 | 81 | def send(
|
@@ -154,7 +154,7 @@ def _runtime_info(self):
|
154 | 154 | # "scm_class": _scm_in_use(),
|
155 | 155 | **_system_info(),
|
156 | 156 | "user_id": _find_or_create_user_id(),
|
157 |
| - "group_id": _find_or_create_user_id(), # TODO |
| 157 | + "group_id": "", # TODO |
158 | 158 | }
|
159 | 159 |
|
160 | 160 |
|
@@ -187,39 +187,64 @@ def _system_info():
|
187 | 187 | raise NotImplementedError
|
188 | 188 |
|
189 | 189 |
|
| 190 | +def _generate_id(): |
| 191 | + """A randomly generated ID string""" |
| 192 | + return str(uuid.uuid4()) # TODO: CI env-based ID |
| 193 | + |
| 194 | + |
| 195 | +def _read_user_id(config_file: Path): |
| 196 | + try: |
| 197 | + with config_file.open(encoding="utf8") as fobj: |
| 198 | + return json.load(fobj)["user_id"] |
| 199 | + except (FileNotFoundError, ValueError, KeyError): |
| 200 | + pass |
| 201 | + return None |
| 202 | + |
| 203 | + |
| 204 | +def _read_user_id_locked(config_file: Path): |
| 205 | + lockfile = str(config_file.with_suffix(".lock")) |
| 206 | + if config_file.parent.is_dir(): |
| 207 | + with FileLock(lockfile, timeout=5): |
| 208 | + return _read_user_id(config_file) |
| 209 | + return None |
| 210 | + |
| 211 | + |
190 | 212 | @lru_cache(None)
|
191 | 213 | def _find_or_create_user_id():
|
192 | 214 | """
|
193 | 215 | The user's ID is stored on a file under the global config directory.
|
194 | 216 | The file should contain a JSON with a "user_id" key:
|
195 | 217 | {"user_id": "16fd2706-8baf-433b-82eb-8c7fada847da"}
|
196 |
| - IDs are generated randomly with UUID. |
| 218 | + IDs are generated randomly with UUID4. |
197 | 219 | """
|
198 |
| - |
199 |
| - config_dir = user_config_dir("telemetry", "iterative") |
200 |
| - fname = os.path.join(config_dir, "user_id") |
201 |
| - lockfile = os.path.join(config_dir, "user_id.lock") |
202 |
| - |
203 |
| - # Since the `fname` and `lockfile` are under the global config, |
204 |
| - # we need to make sure such directory exist already. |
205 |
| - os.makedirs(config_dir, exist_ok=True) |
| 220 | + config_file = Path( |
| 221 | + user_config_dir(os.path.join("iterative", "telemetry"), False) |
| 222 | + ) |
| 223 | + config_file.parent.mkdir(mode=0o755, parents=True, exist_ok=True) |
| 224 | + lockfile = str(config_file.with_suffix(".lock")) |
| 225 | + # DVC backwards-compatibility |
| 226 | + config_file_old = Path( |
| 227 | + user_config_dir(os.path.join("dvc", "user_id"), "iterative") |
| 228 | + ) |
206 | 229 |
|
207 | 230 | try:
|
208 | 231 | with FileLock( # pylint: disable=abstract-class-instantiated
|
209 | 232 | lockfile, timeout=5
|
210 | 233 | ):
|
211 |
| - try: |
212 |
| - with open(fname, encoding="utf8") as fobj: |
213 |
| - user_id = json.load(fobj)["user_id"] |
214 |
| - |
215 |
| - except (FileNotFoundError, ValueError, KeyError): |
216 |
| - user_id = str(uuid.uuid4()) |
217 |
| - |
218 |
| - with open(fname, "w", encoding="utf8") as fobj: |
| 234 | + user_id = _read_user_id(config_file) |
| 235 | + if user_id is None: |
| 236 | + try: |
| 237 | + user_id = _read_user_id_locked(config_file_old) |
| 238 | + except Timeout: |
| 239 | + logger.debug( |
| 240 | + "Failed to acquire %s", |
| 241 | + config_file_old.with_suffix(".lock"), |
| 242 | + ) |
| 243 | + return None |
| 244 | + if user_id is None: |
| 245 | + user_id = _generate_id() |
| 246 | + with config_file.open(mode="w", encoding="utf8") as fobj: |
219 | 247 | json.dump({"user_id": user_id}, fobj)
|
220 |
| - |
221 |
| - return user_id |
222 |
| - |
223 | 248 | except Timeout:
|
224 | 249 | logger.debug("Failed to acquire %s", lockfile)
|
225 |
| - return None |
| 250 | + return user_id if user_id.lower() != DO_NOT_TRACK_VALUE.lower() else None |
0 commit comments