2323
2424import fcntl
2525import os
26+ import contextlib
2627from typing import List
2728
2829from source .common .package_manager import PackageManager
@@ -38,12 +39,21 @@ def __init__(self, log_handler, log_level,):
3839 # to prevent a warning: `debconf: unable to initialize frontend: Dialog`
3940 os .environ ['DEBIAN_FRONTEND' ] = 'noninteractive'
4041
42+ @contextlib .contextmanager
43+ def apt_lock (self ):
44+ """
45+ Contex manager for locking compatible with 'apt-get update' lock.
46+ """
47+ with open ("/var/lib/apt/lists/lock" , "rb+" ) as f_lock :
48+ fcntl .lockf (f_lock .fileno (), fcntl .LOCK_EX )
49+ yield
50+
4151 def wait_for_lock (self ):
4252 """
4353 Wait for any other apt-get instance to finish.
4454 """
45- with open ( "/var/lib/apt/lists/lock" ) as f_lock :
46- fcntl . flock ( f_lock . fileno (), fcntl . LOCK_EX )
55+ with self . apt_lock () :
56+ pass
4757
4858 def refresh (self , hard_fail : bool ) -> ProcessResult :
4959 """
@@ -52,9 +62,12 @@ def refresh(self, hard_fail: bool) -> ProcessResult:
5262 :param hard_fail: raise error if some repo is unavailable
5363 :return: (exit_code, stdout, stderr)
5464 """
55- self .wait_for_lock ()
56- cmd = [self .package_manager , "-q" , "update" ]
57- result = self .run_cmd (cmd )
65+ # apply lock externally to wait for it, until
66+ # https://bugs.debian.org/1069167 gets implemented
67+ with self .apt_lock ():
68+ cmd = [self .package_manager ,
69+ "-o" , "Debug::NoLocking=true" , "-q" , "update" ]
70+ result = self .run_cmd (cmd )
5871 # 'apt-get update' reports error with exit code 100, but updater as a
5972 # whole reserves it for "no updates"
6073 if result .code == 100 :
0 commit comments