Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions bugwarrior/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import warnings

import click
from lockfile import LockTimeout
from lockfile.pidlockfile import PIDLockFile
from filelock import FileLock, Timeout

from bugwarrior.collect import aggregate_issues
from bugwarrior.config import get_config_path, get_keyring, load_config
Expand Down Expand Up @@ -123,21 +122,17 @@ def pull(
config = _try_load_config(main_section, quiet)

lockfile_path = os.path.join(config.main.data.path, 'bugwarrior.lockfile')
lockfile = PIDLockFile(lockfile_path)
lockfile.acquire(timeout=10)
try:
with FileLock(lockfile_path, timeout=10):
# Get all the issues. This can take a while.
issue_generator = aggregate_issues(config, debug)

# Stuff them in the taskwarrior db as necessary
synchronize(issue_generator, config, dry_run)
finally:
lockfile.release()
except LockTimeout:
except Timeout:
log.critical(
'Your taskrc repository is currently locked. '
'Remove the file at %s if you are sure no other '
'bugwarrior processes are currently running.' % (lockfile_path)
'Wait for any running bugwarrior processes to finish and try again. '
f'Lock file:{lockfile_path}'
)
sys.exit(1)
except RuntimeError as e:
Expand Down
4 changes: 2 additions & 2 deletions bugwarrior/config/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import subprocess
import typing

from lockfile.pidlockfile import PIDLockFile
from filelock import FileLock


def get_data_path(taskrc: str | Path) -> str:
Expand Down Expand Up @@ -65,7 +65,7 @@ def get(self, key: str) -> typing.Any:

def set(self, key: str, value: typing.Any) -> None:
"""Set a value in the ``bugwarrior.data`` file."""
with PIDLockFile(self._lockfile):
with FileLock(self._lockfile):
try:
data = self.get_data()
except OSError: # File does not exist.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dependencies = [
"click",
"dogpile.cache>=0.5.3",
"jinja2>=2.7.2",
"lockfile>=0.9.1",
"filelock>=3",
"pydantic[email]>=2",
"python-dateutil",
"requests>=1",
Expand Down
20 changes: 20 additions & 0 deletions tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ def test_partial_failure_database_integrity(self, bugzillalib):
self.assertNotIn('Closing 1 tasks', logs)
self.assertNotIn('Completing task', logs)

@mock.patch('bugwarrior.command.FileLock')
def test_locked_repository(self, file_lock):
"""
A locked task repository should abort the pull.
"""
lockfile_path = pathlib.Path(self.lists_path) / 'bugwarrior.lockfile'
file_lock.return_value.__enter__.side_effect = command.Timeout(
str(lockfile_path)
)

with self.caplog.at_level(logging.CRITICAL):
result = self.runner.invoke(command.cli, args=('pull', '--debug'))

self.assertEqual(result.exit_code, 1)
file_lock.assert_called_once_with(str(lockfile_path), timeout=10)
logs = [rec.message for rec in self.caplog.records]
self.assertTrue(
any('Your taskrc repository is currently locked.' in log for log in logs)
)

@mock.patch('bugwarrior.services.github.GithubService.issues', fake_github_issues)
def test_legacy_cli(self):
"""
Expand Down
Loading