Merge lp:~smoser/charm-helpers/apt-install-noninteractive into lp:charm-helpers

Proposed by Scott Moser
Status: Merged
Merged at revision: 96
Proposed branch: lp:~smoser/charm-helpers/apt-install-noninteractive
Merge into: lp:charm-helpers
Diff against target: 153 lines (+44/-16)
2 files modified
charmhelpers/fetch/__init__.py (+12/-5)
tests/fetch/test_fetch.py (+32/-11)
To merge this branch: bzr merge lp:~smoser/charm-helpers/apt-install-noninteractive
Reviewer Review Type Date Requested Status
James Page Approve
Michael Nelson Approve
Review via email: mp+194748@code.launchpad.net

Commit message

Changes to 'install' to ensure non-interactive mode

This makes 2 changes to invocations of 'apt-get install'
 a.) adds DEBIAN_FRONTEND=noninteractive to the environment
 b.) uses options --option=Dpkg::Options::=--force-confold

Also changed:
 * change '-y' to '--assume-yes' for readability.
 * changes to tests to accommodate

Description of the change

Changes to 'install' to ensure non-interactive mode

This makes 2 changes to invocations of 'apt-get install'
 a.) adds DEBIAN_FRONTEND=noninteractive to the environment
 b.) uses options --option=Dpkg::Options::=--force-confold

Also changed:
 * change '-y' to '--assume-yes' for readability.
 * changes to tests to accommodate

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Excellent - thanks Scott. Out of interest, without the two extra options, in what situations were you seeing interactive mode?

Also, can we swap reviews? :-)

https://code.launchpad.net/~michael.nelson/charm-helpers/ansible-tags/+merge/194324

Most of the diff is moving a chunk of code to a more shareable location.

review: Approve
Revision history for this message
James Page (james-page) :
review: Approve
Revision history for this message
Scott Moser (smoser) wrote :

The one thing that hit me was 'apt-get install maas' has a priority 'high' dialog that just says "You can see _SOMEURL_/MAAS/".

This kills that.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/fetch/__init__.py'
2--- charmhelpers/fetch/__init__.py 2013-11-06 03:25:32 +0000
3+++ charmhelpers/fetch/__init__.py 2013-11-11 20:33:28 +0000
4@@ -13,6 +13,7 @@
5 log,
6 )
7 import apt_pkg
8+import os
9
10 CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
11 deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
12@@ -66,8 +67,10 @@
13
14 def apt_install(packages, options=None, fatal=False):
15 """Install one or more packages"""
16- options = options or []
17- cmd = ['apt-get', '-y']
18+ if options is None:
19+ options = ['--option=Dpkg::Options::=--force-confold']
20+
21+ cmd = ['apt-get', '--assume-yes']
22 cmd.extend(options)
23 cmd.append('install')
24 if isinstance(packages, basestring):
25@@ -76,10 +79,14 @@
26 cmd.extend(packages)
27 log("Installing {} with options: {}".format(packages,
28 options))
29+ env = os.environ.copy()
30+ if 'DEBIAN_FRONTEND' not in env:
31+ env['DEBIAN_FRONTEND'] = 'noninteractive'
32+
33 if fatal:
34- subprocess.check_call(cmd)
35+ subprocess.check_call(cmd, env=env)
36 else:
37- subprocess.call(cmd)
38+ subprocess.call(cmd, env=env)
39
40
41 def apt_update(fatal=False):
42@@ -93,7 +100,7 @@
43
44 def apt_purge(packages, fatal=False):
45 """Purge one or more packages"""
46- cmd = ['apt-get', '-y', 'purge']
47+ cmd = ['apt-get', '--assume-yes', 'purge']
48 if isinstance(packages, basestring):
49 cmd.append(packages)
50 else:
51
52=== modified file 'tests/fetch/test_fetch.py'
53--- tests/fetch/test_fetch.py 2013-11-06 03:30:37 +0000
54+++ tests/fetch/test_fetch.py 2013-11-11 20:33:28 +0000
55@@ -7,6 +7,7 @@
56 )
57 from urlparse import urlparse
58 from charmhelpers import fetch
59+import os
60 import yaml
61
62 FAKE_APT_CACHE = {
63@@ -36,6 +37,15 @@
64 return cache
65
66
67+def getenv(update=None):
68+ # return a copy of os.environ with update applied.
69+ # this was necessary because some modules modify os.environment directly
70+ copy = os.environ.copy()
71+ if update is not None:
72+ copy.update(update)
73+ return copy
74+
75+
76 class FetchTest(TestCase):
77 @patch('apt_pkg.Cache')
78 def test_filter_packages_missing(self, cache):
79@@ -359,8 +369,10 @@
80
81 fetch.apt_install(packages, options)
82
83- mock_call.assert_called_with(['apt-get', '-y', '--foo', '--bar',
84- 'install', 'foo', 'bar'])
85+ mock_call.assert_called_with(['apt-get', '--assume-yes',
86+ '--foo', '--bar', 'install', 'foo', 'bar'],
87+ env=getenv({'DEBIAN_FRONTEND': 'noninteractive'}))
88+
89
90 @patch('subprocess.call')
91 @patch.object(fetch, 'log')
92@@ -369,8 +381,12 @@
93
94 fetch.apt_install(packages)
95
96- mock_call.assert_called_with(['apt-get', '-y', 'install', 'foo',
97- 'bar'])
98+ expected = ['apt-get', '--assume-yes',
99+ '--option=Dpkg::Options::=--force-confold',
100+ 'install', 'foo', 'bar']
101+
102+ mock_call.assert_called_with(expected,
103+ env=getenv({'DEBIAN_FRONTEND': 'noninteractive'}))
104
105 @patch('subprocess.call')
106 @patch.object(fetch, 'log')
107@@ -380,8 +396,11 @@
108
109 fetch.apt_install(packages, options)
110
111- mock_call.assert_called_with(['apt-get', '-y', '--foo', '--bar',
112- 'install', 'foo bar'])
113+ expected = ['apt-get', '--assume-yes',
114+ '--foo', '--bar', 'install', 'foo bar']
115+
116+ mock_call.assert_called_with(expected,
117+ env=getenv({'DEBIAN_FRONTEND': 'noninteractive'}))
118
119 @patch('subprocess.check_call')
120 @patch.object(fetch, 'log')
121@@ -391,8 +410,9 @@
122
123 fetch.apt_install(packages, options, fatal=True)
124
125- check_call.assert_called_with(['apt-get', '-y', '--foo', '--bar',
126- 'install', 'foo', 'bar'])
127+ check_call.assert_called_with(['apt-get', '--assume-yes',
128+ '--foo', '--bar', 'install', 'foo', 'bar'],
129+ env=getenv({'DEBIAN_FRONTEND': 'noninteractive'}))
130
131 @patch('subprocess.check_call')
132 @patch.object(fetch, 'log')
133@@ -420,7 +440,8 @@
134 fetch.apt_purge(packages)
135
136 log.assert_called()
137- mock_call.assert_called_with(['apt-get', '-y', 'purge', 'foo bar'])
138+ mock_call.assert_called_with(['apt-get', '--assume-yes',
139+ 'purge', 'foo bar'])
140
141 @patch('subprocess.call')
142 @patch.object(fetch, 'log')
143@@ -430,8 +451,8 @@
144 fetch.apt_purge(packages)
145
146 log.assert_called()
147- mock_call.assert_called_with(['apt-get', '-y', 'purge', 'foo',
148- 'bar'])
149+ mock_call.assert_called_with(['apt-get', '--assume-yes',
150+ 'purge', 'foo', 'bar'])
151
152 @patch('subprocess.check_call')
153 @patch.object(fetch, 'log')

Subscribers

People subscribed via source and target branches