=== modified file 'linaro_image_tools/tests/fixtures.py'
@@ -69,8 +69,9 @@
# used in tests to make sure all callsites wait for their child.
child_finished = True
- def __init__(self, assert_child_finished=True):
+ def __init__(self, output_string='', assert_child_finished=True):
self.assert_child_finished = assert_child_finished
+ self.output_string = output_string
def __call__(self, cmd, *args, **kwargs):
if self.assert_child_finished and not self.child_finished:
@@ -91,7 +92,7 @@
def communicate(self, input=None):
self.wait()
- return '', ''
+ return self.output_string, ''
def wait(self):
self.child_finished = True
@@ -112,9 +113,9 @@
If no mock is given, a MockCmdRunnerPopen instance is used.
"""
- def __init__(self, assert_child_finished=True):
+ def __init__(self, output_string='', assert_child_finished=True):
super(MockCmdRunnerPopenFixture, self).__init__(
- cmd_runner, 'Popen', MockCmdRunnerPopen(assert_child_finished))
+ cmd_runner, 'Popen', MockCmdRunnerPopen(output_string, assert_child_finished))
def tearDown(self):
super(MockCmdRunnerPopenFixture, self).tearDown()
=== modified file 'linaro_image_tools/tests/test_utils.py'
@@ -24,6 +24,7 @@
import logging
import tempfile
import tarfile
+from StringIO import StringIO
from linaro_image_tools import cmd_runner, utils
from linaro_image_tools.testing import TestCaseWithFixtures
@@ -249,19 +250,45 @@
class TestInstallPackageProviding(TestCaseWithFixtures):
- def test_found_package(self):
- self.useFixture(MockSomethingFixture(
- sys, 'stdout', open('/dev/null', 'w')))
- fixture = self.useFixture(MockCmdRunnerPopenFixture())
+ # This is the package we need to fake the installation of, it is a
+ # slightly changed version of 'apt-get -s install' output.
+ # It is used as an argument to MockCmdRunnerPopenFixture in order to
+ # pass a string that should be expected as output from the command that
+ # is being executed.
+ output_string = 'Inst dosfstools (3.0.12-1ubuntu1 Ubuntu:12.04)'
+
+ def test_package_installation_accepted(self):
+ self.useFixture(MockSomethingFixture(sys,
+ 'stdout',
+ open('/dev/null', 'w')))
+ # We need this since we are getting user input via raw_input
+ # and we need a 'Y' to proceed with the operations.
+ self.useFixture(MockSomethingFixture(sys,
+ 'stdin',
+ StringIO('Y')))
+ fixture = self.useFixture(MockCmdRunnerPopenFixture(self.output_string))
install_package_providing('mkfs.vfat')
self.assertEqual(
- ['%s apt-get --yes install dosfstools' % sudo_args],
- fixture.mock.commands_executed)
+ ['apt-get -s install dosfstools',
+ '%s apt-get --yes install dosfstools' %
+ sudo_args],
+ fixture.mock.commands_executed)
+
+ def test_package_installation_refused(self):
+ self.useFixture(MockSomethingFixture(sys,
+ 'stdout',
+ open('/dev/null', 'w')))
+ # We need this since we are getting user input via raw_input
+ # and we need a 'n' to mimic a refused package installation.
+ self.useFixture(MockSomethingFixture(sys,
+ 'stdin',
+ StringIO('n')))
+ self.useFixture(MockCmdRunnerPopenFixture(self.output_string))
+ self.assertRaises(SystemExit, install_package_providing, 'mkfs.vfat')
def test_not_found_package(self):
- self.assertRaises(
- UnableToFindPackageProvidingCommand,
- install_package_providing, 'mkfs.lean')
+ self.assertRaises(UnableToFindPackageProvidingCommand,
+ install_package_providing, 'mkfs.lean')
class Args():
@@ -288,7 +315,7 @@
board="testboard")))
-class TestPrepMediaPath(TestCaseWithFixtures):
+class TestAdditionalOptionChecks(TestCaseWithFixtures):
def test_additional_option_checks(self):
self.useFixture(MockSomethingFixture(os.path, 'abspath', lambda x: x))
=== modified file 'linaro_image_tools/utils.py'
@@ -171,7 +171,10 @@
If we can't find any package which provides it, raise
UnableToFindPackageProvidingCommand.
+
+ If the user denies installing the package, the program exits.
"""
+
if CommandNotFound is None:
raise UnableToFindPackageProvidingCommand(
"Cannot lookup a package which provides %s" % command)
@@ -182,12 +185,35 @@
"Unable to find any package providing %s" % command)
# TODO: Ask the user to pick a package when there's more than one that
- # provide the given command.
+ # provides the given command.
package, _ = packages[0]
- print ("Installing required command %s from package %s"
- % (command, package))
- cmd_runner.run(
- ['apt-get', '--yes', 'install', package], as_root=True).wait()
+ output, _ = cmd_runner.run(['apt-get', '-s', 'install', package],
+ stdout=subprocess.PIPE).communicate()
+ to_install = []
+ for line in output.splitlines():
+ if line.startswith("Inst"):
+ to_install.append(line.split()[1])
+ if not to_install:
+ raise UnableToFindPackageProvidingCommand(
+ "Unable to find any package to be installed.")
+
+ try:
+ print ("In order to use the '%s' command, the following package/s have "
+ "to be installed: %s" % (command, " ".join(to_install)))
+ resp = raw_input("Install? (Y/n) ")
+ if resp.lower() != 'y':
+ print "Package installation is necessary to continue. Exiting."
+ sys.exit(1)
+ print ("Installing required command '%s' from package '%s'..."
+ % (command, package))
+ cmd_runner.run(['apt-get', '--yes', 'install', package],
+ as_root=True).wait()
+ except EOFError:
+ raise PackageInstallationRefused(
+ "Package installation interrupted: input error.")
+ except KeyboardInterrupt:
+ raise PackageInstallationRefused(
+ "Package installation interrupted by the user.")
def has_command(command):
@@ -272,6 +298,10 @@
"""We can't find a package which provides the given command."""
+class PackageInstallationRefused(Exception):
+ """User has chosen not to install a package."""
+
+
class InvalidHwpackFile(Exception):
"""The hwpack parameter is not a regular file."""