54
56
'icehouse/proposed': 'precise-proposed/icehouse',
55
57
'precise-icehouse/proposed': 'precise-proposed/icehouse',
56
58
'precise-proposed/icehouse': 'precise-proposed/icehouse',
60
'juno': 'trusty-updates/juno',
61
'trusty-juno': 'trusty-updates/juno',
62
'trusty-juno/updates': 'trusty-updates/juno',
63
'trusty-updates/juno': 'trusty-updates/juno',
64
'juno/proposed': 'trusty-proposed/juno',
65
'juno/proposed': 'trusty-proposed/juno',
66
'trusty-juno/proposed': 'trusty-proposed/juno',
67
'trusty-proposed/juno': 'trusty-proposed/juno',
70
# The order of this list is very important. Handlers should be listed in from
71
# least- to most-specific URL matching.
73
'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
74
'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
77
APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT.
78
APT_NO_LOCK_RETRY_DELAY = 10 # Wait 10 seconds between apt lock checks.
79
APT_NO_LOCK_RETRY_COUNT = 30 # Retry to acquire the lock X times.
82
class SourceConfigError(Exception):
86
class UnhandledSource(Exception):
90
class AptLockError(Exception):
94
class BaseFetchHandler(object):
96
"""Base class for FetchHandler implementations in fetch plugins"""
98
def can_handle(self, source):
99
"""Returns True if the source can be handled. Otherwise returns
100
a string explaining why it cannot"""
101
return "Wrong source type"
103
def install(self, source):
104
"""Try to download and unpack the source. Return the path to the
105
unpacked files or raise UnhandledSource."""
106
raise UnhandledSource("Wrong source type {}".format(source))
108
def parse_url(self, url):
111
def base_url(self, url):
112
"""Return url without querystring or fragment"""
113
parts = list(self.parse_url(url))
114
parts[4:] = ['' for i in parts[4:]]
115
return urlunparse(parts)
60
118
def filter_installed_packages(packages):
61
119
"""Returns a list of packages that require installation"""
122
# Tell apt to build an in-memory cache to prevent race conditions (if
123
# another process is already building the cache).
124
apt_pkg.config.set("Dir::Cache::pkgcache", "")
63
126
cache = apt_pkg.Cache()
65
128
for package in packages:
87
150
cmd.extend(packages)
88
151
log("Installing {} with options: {}".format(packages,
90
env = os.environ.copy()
91
if 'DEBIAN_FRONTEND' not in env:
92
env['DEBIAN_FRONTEND'] = 'noninteractive'
95
subprocess.check_call(cmd, env=env)
97
subprocess.call(cmd, env=env)
153
_run_apt_command(cmd, fatal)
100
156
def apt_upgrade(options=None, fatal=False, dist=False):
110
166
cmd.append('upgrade')
111
167
log("Upgrading with options: {}".format(options))
113
env = os.environ.copy()
114
if 'DEBIAN_FRONTEND' not in env:
115
env['DEBIAN_FRONTEND'] = 'noninteractive'
118
subprocess.check_call(cmd, env=env)
120
subprocess.call(cmd, env=env)
168
_run_apt_command(cmd, fatal)
123
171
def apt_update(fatal=False):
124
172
"""Update local apt cache"""
125
173
cmd = ['apt-get', 'update']
127
subprocess.check_call(cmd)
174
_run_apt_command(cmd, fatal)
132
177
def apt_purge(packages, fatal=False):
225
264
apt_update(fatal=True)
227
# The order of this list is very important. Handlers should be listed in from
228
# least- to most-specific URL matching.
230
'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
231
'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
235
class UnhandledSource(Exception):
239
267
def install_remote(source):
265
293
return install_remote(source)
268
class BaseFetchHandler(object):
270
"""Base class for FetchHandler implementations in fetch plugins"""
272
def can_handle(self, source):
273
"""Returns True if the source can be handled. Otherwise returns
274
a string explaining why it cannot"""
275
return "Wrong source type"
277
def install(self, source):
278
"""Try to download and unpack the source. Return the path to the
279
unpacked files or raise UnhandledSource."""
280
raise UnhandledSource("Wrong source type {}".format(source))
282
def parse_url(self, url):
285
def base_url(self, url):
286
"""Return url without querystring or fragment"""
287
parts = list(self.parse_url(url))
288
parts[4:] = ['' for i in parts[4:]]
289
return urlunparse(parts)
292
296
def plugins(fetch_handlers=None):
293
297
if not fetch_handlers:
294
298
fetch_handlers = FETCH_HANDLERS
306
310
log("FetchHandler {} not found, skipping plugin".format(
308
312
return plugin_list
315
def _run_apt_command(cmd, fatal=False):
317
Run an APT command, checking output and retrying if the fatal flag is set
320
:param: cmd: str: The apt command to run.
321
:param: fatal: bool: Whether the command's output should be checked and
324
env = os.environ.copy()
326
if 'DEBIAN_FRONTEND' not in env:
327
env['DEBIAN_FRONTEND'] = 'noninteractive'
333
# If the command is considered "fatal", we need to retry if the apt
334
# lock was not acquired.
336
while result is None or result == APT_NO_LOCK:
338
result = subprocess.check_call(cmd, env=env)
339
except subprocess.CalledProcessError, e:
340
retry_count = retry_count + 1
341
if retry_count > APT_NO_LOCK_RETRY_COUNT:
343
result = e.returncode
344
log("Couldn't acquire DPKG lock. Will retry in {} seconds."
345
"".format(APT_NO_LOCK_RETRY_DELAY))
346
time.sleep(APT_NO_LOCK_RETRY_DELAY)
349
subprocess.call(cmd, env=env)