1"""Manages dvc lock file."""
2
3from __future__ import unicode_literals
4
5import os
6import time
7import zc.lockfile
8
9from dvc.exceptions import DvcException
10
11
12class LockError(DvcException):
13    """Thrown when unable to acquire the lock for dvc repo."""
14
15
16class Lock(object):
17    """Class for dvc repo lock.
18
19    Args:
20        dvc_dir (str): path to the directory that the lock should be created
21            in.
22        name (str): name of the lock file.
23    """
24
25    LOCK_FILE = "lock"
26    TIMEOUT = 5
27
28    def __init__(self, dvc_dir, name=LOCK_FILE):
29        self.lock_file = os.path.join(dvc_dir, name)
30        self._lock = None
31
32    def _do_lock(self):
33        try:
34            self._lock = zc.lockfile.LockFile(self.lock_file)
35        except zc.lockfile.LockError:
36            raise LockError(
37                "cannot perform the cmd since DVC is busy and "
38                "locked. Please retry the cmd later."
39            )
40
41    def lock(self):
42        """Acquire lock for dvc repo."""
43        try:
44            self._do_lock()
45            return
46        except LockError:
47            time.sleep(self.TIMEOUT)
48
49        self._do_lock()
50
51    def unlock(self):
52        """Release lock for dvc repo."""
53        self._lock.close()
54        self._lock = None
55
56    def __enter__(self):
57        self.lock()
58
59    def __exit__(self, typ, value, tbck):
60        self.unlock()
61