From patchwork Wed Jun 13 14:31:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milo Casagrande X-Patchwork-Id: 9272 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 0B15223E1B for ; Wed, 13 Jun 2012 14:31:17 +0000 (UTC) Received: from mail-yw0-f52.google.com (mail-yw0-f52.google.com [209.85.213.52]) by fiordland.canonical.com (Postfix) with ESMTP id B04D8A18734 for ; Wed, 13 Jun 2012 14:31:16 +0000 (UTC) Received: by yhpp61 with SMTP id p61so607857yhp.11 for ; Wed, 13 Jun 2012 07:31:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :content-type:mime-version:x-launchpad-project:x-launchpad-branch :x-launchpad-message-rationale:x-launchpad-branch-revision-number :x-launchpad-notification-type:to:from:subject:message-id:date :reply-to:sender:errors-to:precedence:x-generated-by :x-launchpad-hash:x-gm-message-state; bh=itL2zEO5LmdOXCsnsADMCjh6HyDu3K0ercE16gG3uyo=; b=dCCcJJ5XZu9dp4bLDRhkS6J0eWEutrtNcSate1mVXwbDUA1Y/C0K8RSawkIFvVP2fk xZ6RA406SGL5MqpLZ0lBo5+PP7qPiJmt2YPaYeOWFtmWZXff8niEiCQOW87Wm/o/C3Wk Y+hS8BMVTMhrUpqkMkZBP6FSX+YJgZGAGgPGz3MSgBkDNzkrV9oAc4htlbmUxehgcMrC RMwbbenS2ZtMModhGAM0TKyS/O467bmFYaRnFm4OR+6KLf3i+jCVZwIXw4HeAftONHW1 oFQMu+d/HpBKagH7wiFMPDD9RHaWG/ojk9gIZ4ure0GFtKmEDbQi9kYJq4kFqErJ6bjS TQAA== Received: by 10.50.40.193 with SMTP id z1mr10830724igk.0.1339597875990; Wed, 13 Jun 2012 07:31:15 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp25114ibb; Wed, 13 Jun 2012 07:31:14 -0700 (PDT) Received: by 10.180.95.100 with SMTP id dj4mr38321779wib.17.1339597873851; Wed, 13 Jun 2012 07:31:13 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id 4si4279948wej.37.2012.06.13.07.31.13 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 13 Jun 2012 07:31:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1SeobJ-00071m-5O for ; Wed, 13 Jun 2012 14:31:13 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 1EC2FE0023 for ; Wed, 13 Jun 2012 14:31:13 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: linaro-image-tools X-Launchpad-Branch: ~linaro-image-tools/linaro-image-tools/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 526 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-image-tools/linaro-image-tools/trunk] Rev 526: [merge] Merged fixes for bug 704029. Message-Id: <20120613143113.18271.28213.launchpad@ackee.canonical.com> Date: Wed, 13 Jun 2012 14:31:13 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="15389"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: f498c9ef3c5d419e65ba08b39a31ed51ec726d7e X-Gm-Message-State: ALoCoQlB4LtrxMAlP9K5Kz1NIvN+LOJIE5Yr0ch8dtQt6DvbG+gUIJxvQwlxbIRf3TK/AG50yM6i Merge authors: Milo Casagrande (milo) Related merge proposals: https://code.launchpad.net/~milo/linaro-image-tools/bug704029/+merge/108910 proposed by: Milo Casagrande (milo) review: Needs Fixing - Deepti B. Kalakeri (deeptik) review: Needs Fixing - Milo Casagrande (milo) ------------------------------------------------------------ revno: 526 [merge] committer: Milo Casagrande branch nick: trunk timestamp: Wed 2012-06-13 16:27:25 +0200 message: [merge] Merged fixes for bug 704029. modified: linaro_image_tools/tests/fixtures.py linaro_image_tools/tests/test_utils.py linaro_image_tools/utils.py --- lp:linaro-image-tools https://code.launchpad.net/~linaro-image-tools/linaro-image-tools/trunk You are subscribed to branch lp:linaro-image-tools. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-image-tools/linaro-image-tools/trunk/+edit-subscription === modified file 'linaro_image_tools/tests/fixtures.py' --- linaro_image_tools/tests/fixtures.py 2012-06-07 13:22:47 +0000 +++ linaro_image_tools/tests/fixtures.py 2012-06-11 12:49:40 +0000 @@ -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' --- linaro_image_tools/tests/test_utils.py 2012-06-06 13:59:32 +0000 +++ linaro_image_tools/tests/test_utils.py 2012-06-13 08:19:55 +0000 @@ -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' --- linaro_image_tools/utils.py 2012-06-06 13:59:32 +0000 +++ linaro_image_tools/utils.py 2012-06-13 08:19:55 +0000 @@ -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."""