mirror of
https://github.com/flatcar/scripts.git
synced 2025-09-26 16:11:56 +02:00
Merge branch 'master' of ssh://gitrw.chromium.org:9222/crosutils
This commit is contained in:
commit
a25cede07d
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
@ -23,29 +23,16 @@ from cros_build_lib import Warning
|
|||||||
|
|
||||||
import cros_test_proxy
|
import cros_test_proxy
|
||||||
|
|
||||||
# VM Constants.
|
|
||||||
_FULL_VDISK_SIZE = 6072
|
|
||||||
_FULL_STATEFULFS_SIZE = 3074
|
|
||||||
_KVM_PID_FILE = '/tmp/harness_pid'
|
|
||||||
_VERIFY_SUITE = 'suite_Smoke'
|
|
||||||
|
|
||||||
# Globals to communicate options to unit tests.
|
|
||||||
global base_image_path
|
|
||||||
global board
|
|
||||||
global remote
|
|
||||||
global target_image_path
|
|
||||||
global vm_graphics_flag
|
|
||||||
|
|
||||||
class UpdateException(Exception):
|
class UpdateException(Exception):
|
||||||
"""Exception thrown when UpdateImage or UpdateUsingPayload fail"""
|
"""Exception thrown when _UpdateImage or _UpdateUsingPayload fail"""
|
||||||
def __init__(self, code, stdout):
|
def __init__(self, code, stdout):
|
||||||
self.code = code
|
self.code = code
|
||||||
self.stdout = stdout
|
self.stdout = stdout
|
||||||
|
|
||||||
|
|
||||||
class AUTest(object):
|
class AUTest(object):
|
||||||
"""Abstract interface that defines an Auto Update test."""
|
"""Abstract interface that defines an Auto Update test."""
|
||||||
source_image = ''
|
|
||||||
use_delta_updates = False
|
|
||||||
verbose = False
|
verbose = False
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -57,6 +44,8 @@ class AUTest(object):
|
|||||||
if not os.path.exists(self.download_folder):
|
if not os.path.exists(self.download_folder):
|
||||||
os.makedirs(self.download_folder)
|
os.makedirs(self.download_folder)
|
||||||
|
|
||||||
|
# -------- Helper functions ---------
|
||||||
|
|
||||||
def GetStatefulChangeFlag(self, stateful_change):
|
def GetStatefulChangeFlag(self, stateful_change):
|
||||||
"""Returns the flag to pass to image_to_vm for the stateful change."""
|
"""Returns the flag to pass to image_to_vm for the stateful change."""
|
||||||
stateful_change_flag = ''
|
stateful_change_flag = ''
|
||||||
@ -65,7 +54,7 @@ class AUTest(object):
|
|||||||
|
|
||||||
return stateful_change_flag
|
return stateful_change_flag
|
||||||
|
|
||||||
def ParseGenerateTestReportOutput(self, output):
|
def _ParseGenerateTestReportOutput(self, output):
|
||||||
"""Returns the percentage of tests that passed based on output."""
|
"""Returns the percentage of tests that passed based on output."""
|
||||||
percent_passed = 0
|
percent_passed = 0
|
||||||
lines = output.split('\n')
|
lines = output.split('\n')
|
||||||
@ -79,38 +68,60 @@ class AUTest(object):
|
|||||||
|
|
||||||
return int(percent_passed)
|
return int(percent_passed)
|
||||||
|
|
||||||
# TODO(sosa) - Remove try and convert function to DeltaUpdateImage().
|
def AssertEnoughTestsPassed(self, unittest, output, percent_required_to_pass):
|
||||||
def TryDeltaAndFallbackToFull(self, src_image, image, stateful_change='old'):
|
"""Helper function that asserts a sufficient number of tests passed.
|
||||||
"""Tries the delta update first if set and falls back to full update."""
|
|
||||||
if self.use_delta_updates:
|
|
||||||
try:
|
|
||||||
self.source_image = src_image
|
|
||||||
self._UpdateImageReportError(image, stateful_change)
|
|
||||||
except:
|
|
||||||
Warning('Delta update failed, disabling delta updates and retrying.')
|
|
||||||
self.use_delta_updates = False
|
|
||||||
self.source_image = ''
|
|
||||||
self._UpdateImageReportError(image, stateful_change)
|
|
||||||
else:
|
|
||||||
self._UpdateImageReportError(image, stateful_change)
|
|
||||||
|
|
||||||
def _UpdateImageReportError(self, image_path, stateful_change='old',
|
Args:
|
||||||
proxy_port=None):
|
unittest: Handle to the unittest.
|
||||||
"""Calls UpdateImage and reports any error to the console.
|
output: stdout from a test run.
|
||||||
|
percent_required_to_pass: percentage required to pass. This should be
|
||||||
|
fall between 0-100.
|
||||||
|
Returns:
|
||||||
|
percent that passed.
|
||||||
|
"""
|
||||||
|
Info('Output from VerifyImage():')
|
||||||
|
print >> sys.stderr, output
|
||||||
|
sys.stderr.flush()
|
||||||
|
percent_passed = self._ParseGenerateTestReportOutput(output)
|
||||||
|
Info('Percent passed: %d vs. Percent required: %d' % (
|
||||||
|
percent_passed, percent_required_to_pass))
|
||||||
|
unittest.assertTrue(percent_passed >= percent_required_to_pass)
|
||||||
|
return percent_passed
|
||||||
|
|
||||||
Still throws the exception.
|
def PerformUpdate(self, image_path, src_image_path='', stateful_change='old',
|
||||||
|
proxy_port=None):
|
||||||
|
"""Performs an update using _UpdateImage and reports any error.
|
||||||
|
|
||||||
|
Subclasses should not override this method but override _UpdateImage
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_path: Path to the image to update with. This image must be a test
|
||||||
|
image.
|
||||||
|
src_image_path: Optional. If set, perform a delta update using the
|
||||||
|
image specified by the path as the source image.
|
||||||
|
stateful_change: How to modify the stateful partition. Values are:
|
||||||
|
'old': Don't modify stateful partition. Just update normally.
|
||||||
|
'clean': Uses clobber-state to wipe the stateful partition with the
|
||||||
|
exception of code needed for ssh.
|
||||||
|
proxy_port: Port to have the client connect to. For use with
|
||||||
|
CrosTestProxy.
|
||||||
|
Raises an UpdateException if _UpdateImage returns an error.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.UpdateImage(image_path, stateful_change, proxy_port)
|
if not self.use_delta_updates:
|
||||||
|
src_image_path = ''
|
||||||
|
|
||||||
|
self._UpdateImage(image_path, src_image_path, stateful_change, proxy_port)
|
||||||
except UpdateException as err:
|
except UpdateException as err:
|
||||||
# If the update fails, print it out
|
# If the update fails, print it out
|
||||||
Warning(err.stdout)
|
Warning(err.stdout)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg):
|
def AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg):
|
||||||
"""Attempt a payload update, expect it to fail with expected log"""
|
"""Attempt a payload update, expect it to fail with expected log"""
|
||||||
try:
|
try:
|
||||||
self.UpdateUsingPayload(payload)
|
self._UpdateUsingPayload(payload)
|
||||||
except UpdateException as err:
|
except UpdateException as err:
|
||||||
# Will raise ValueError if expected is not found.
|
# Will raise ValueError if expected is not found.
|
||||||
if re.search(re.escape(expected_msg), err.stdout, re.MULTILINE):
|
if re.search(re.escape(expected_msg), err.stdout, re.MULTILINE):
|
||||||
@ -120,10 +131,10 @@ class AUTest(object):
|
|||||||
Warning(err.stdout)
|
Warning(err.stdout)
|
||||||
self.fail('We managed to update when failure was expected')
|
self.fail('We managed to update when failure was expected')
|
||||||
|
|
||||||
def _AttemptUpdateWithFilter(self, filter):
|
def AttemptUpdateWithFilter(self, filter):
|
||||||
"""Update through a proxy, with a specified filter, and expect success."""
|
"""Update through a proxy, with a specified filter, and expect success."""
|
||||||
|
|
||||||
self.PrepareBase(target_image_path)
|
self.PrepareBase(self.target_image_path)
|
||||||
|
|
||||||
# The devserver runs at port 8080 by default. We assume that here, and
|
# The devserver runs at port 8080 by default. We assume that here, and
|
||||||
# start our proxy at 8081. We then tell our update tools to have the
|
# start our proxy at 8081. We then tell our update tools to have the
|
||||||
@ -137,34 +148,58 @@ class AUTest(object):
|
|||||||
|
|
||||||
# This update is expected to fail...
|
# This update is expected to fail...
|
||||||
try:
|
try:
|
||||||
self._UpdateImageReportError(target_image_path, proxy_port=proxy_port)
|
self.PerformUpdate(self.target_image_path, proxy_port=proxy_port)
|
||||||
finally:
|
finally:
|
||||||
proxy.shutdown()
|
proxy.shutdown()
|
||||||
|
|
||||||
|
# -------- Functions that subclasses should override ---------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ProcessOptions(cls, parser, options):
|
||||||
|
"""Processes options.
|
||||||
|
|
||||||
|
Static method that should be called from main. Subclasses should also
|
||||||
|
call their parent method if they override it.
|
||||||
|
"""
|
||||||
|
cls.verbose = options.verbose
|
||||||
|
cls.base_image_path = options.base_image
|
||||||
|
cls.target_image_path = options.target_image
|
||||||
|
cls.use_delta_updates = options.delta
|
||||||
|
if options.quick_test:
|
||||||
|
cls.verify_suite = 'build_RootFilesystemSize'
|
||||||
|
else:
|
||||||
|
cls.verify_suite = 'suite_Smoke'
|
||||||
|
|
||||||
|
# Sanity checks.
|
||||||
|
if not cls.base_image_path:
|
||||||
|
parser.error('Need path to base image for vm.')
|
||||||
|
elif not os.path.exists(cls.base_image_path):
|
||||||
|
Die('%s does not exist' % cls.base_image_path)
|
||||||
|
|
||||||
|
if not cls.target_image_path:
|
||||||
|
parser.error('Need path to target image to update with.')
|
||||||
|
elif not os.path.exists(cls.target_image_path):
|
||||||
|
Die('%s does not exist' % cls.target_image_path)
|
||||||
|
|
||||||
def PrepareBase(self, image_path):
|
def PrepareBase(self, image_path):
|
||||||
"""Prepares target with base_image_path."""
|
"""Prepares target with base_image_path."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def UpdateImage(self, image_path, stateful_change='old', proxy_port=None):
|
def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
||||||
"""Updates target with the image given by the image_path.
|
proxy_port=None):
|
||||||
|
"""Implementation of an actual update.
|
||||||
|
|
||||||
Args:
|
See PerformUpdate for description of args. Subclasses must override this
|
||||||
image_path: Path to the image to update with. This image must be a test
|
method with the correct update procedure for the class.
|
||||||
image.
|
|
||||||
stateful_change: How to modify the stateful partition. Values are:
|
|
||||||
'old': Don't modify stateful partition. Just update normally.
|
|
||||||
'clean': Uses clobber-state to wipe the stateful partition with the
|
|
||||||
exception of code needed for ssh.
|
|
||||||
proxy_port: Port to have the client connect to. For use with
|
|
||||||
CrosTestProxy.
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def UpdateUsingPayload(self,
|
def _UpdateUsingPayload(self, update_path, stateful_change='old',
|
||||||
update_path,
|
|
||||||
stateful_change='old',
|
|
||||||
proxy_port=None):
|
proxy_port=None):
|
||||||
"""Updates target with the pre-generated update stored in update_path
|
"""Updates target with the pre-generated update stored in update_path.
|
||||||
|
|
||||||
|
Subclasses must override this method with the correct update procedure for
|
||||||
|
the class.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
update_path: Path to the image to update with. This directory should
|
update_path: Path to the image to update with. This directory should
|
||||||
@ -177,7 +212,8 @@ class AUTest(object):
|
|||||||
def VerifyImage(self, percent_required_to_pass):
|
def VerifyImage(self, percent_required_to_pass):
|
||||||
"""Verifies the image with tests.
|
"""Verifies the image with tests.
|
||||||
|
|
||||||
Verifies that the test images passes the percent required.
|
Verifies that the test images passes the percent required. Subclasses must
|
||||||
|
override this method with the correct update procedure for the class.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
percent_required_to_pass: percentage required to pass. This should be
|
percent_required_to_pass: percentage required to pass. This should be
|
||||||
@ -188,29 +224,7 @@ class AUTest(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def CommonVerifyImage(self, unittest, output, percent_required_to_pass):
|
# -------- Tests ---------
|
||||||
"""Helper function for VerifyImage that returns percent of tests passed.
|
|
||||||
|
|
||||||
Takes output from a test suite, verifies the number of tests passed is
|
|
||||||
sufficient and outputs info.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
unittest: Handle to the unittest.
|
|
||||||
output: stdout from a test run.
|
|
||||||
percent_required_to_pass: percentage required to pass. This should be
|
|
||||||
fall between 0-100.
|
|
||||||
Returns:
|
|
||||||
percent that passed.
|
|
||||||
"""
|
|
||||||
Info('Output from VerifyImage():')
|
|
||||||
print >> sys.stderr, output
|
|
||||||
sys.stderr.flush()
|
|
||||||
percent_passed = self.ParseGenerateTestReportOutput(output)
|
|
||||||
Info('Percent passed: %d vs. Percent required: %d' % (
|
|
||||||
percent_passed, percent_required_to_pass))
|
|
||||||
unittest.assertTrue(percent_passed >=
|
|
||||||
percent_required_to_pass)
|
|
||||||
return percent_passed
|
|
||||||
|
|
||||||
def testFullUpdateKeepStateful(self):
|
def testFullUpdateKeepStateful(self):
|
||||||
"""Tests if we can update normally.
|
"""Tests if we can update normally.
|
||||||
@ -220,19 +234,19 @@ class AUTest(object):
|
|||||||
"""
|
"""
|
||||||
# Just make sure some tests pass on original image. Some old images
|
# Just make sure some tests pass on original image. Some old images
|
||||||
# don't pass many tests.
|
# don't pass many tests.
|
||||||
self.PrepareBase(base_image_path)
|
self.PrepareBase(self.base_image_path)
|
||||||
# TODO(sosa): move to 100% once we start testing using the autotest paired
|
# TODO(sosa): move to 100% once we start testing using the autotest paired
|
||||||
# with the dev channel.
|
# with the dev channel.
|
||||||
percent_passed = self.VerifyImage(10)
|
percent_passed = self.VerifyImage(10)
|
||||||
|
|
||||||
# Update to - all tests should pass on new image.
|
# Update to - all tests should pass on new image.
|
||||||
Info('Updating from base image on vm to target image.')
|
Info('Updating from base image on vm to target image.')
|
||||||
self.TryDeltaAndFallbackToFull(base_image_path, target_image_path)
|
self.PerformUpdate(self.base_image_path, self.target_image_path)
|
||||||
self.VerifyImage(100)
|
self.VerifyImage(100)
|
||||||
|
|
||||||
# Update from - same percentage should pass that originally passed.
|
# Update from - same percentage should pass that originally passed.
|
||||||
Info('Updating from updated image on vm back to base image.')
|
Info('Updating from updated image on vm back to base image.')
|
||||||
self.TryDeltaAndFallbackToFull(target_image_path, base_image_path)
|
self.PerformUpdate(self.target_image_path, self.base_image_path)
|
||||||
self.VerifyImage(percent_passed)
|
self.VerifyImage(percent_passed)
|
||||||
|
|
||||||
def testFullUpdateWipeStateful(self):
|
def testFullUpdateWipeStateful(self):
|
||||||
@ -243,25 +257,25 @@ class AUTest(object):
|
|||||||
"""
|
"""
|
||||||
# Just make sure some tests pass on original image. Some old images
|
# Just make sure some tests pass on original image. Some old images
|
||||||
# don't pass many tests.
|
# don't pass many tests.
|
||||||
self.PrepareBase(base_image_path)
|
self.PrepareBase(self.base_image_path)
|
||||||
# TODO(sosa): move to 100% once we start testing using the autotest paired
|
# TODO(sosa): move to 100% once we start testing using the autotest paired
|
||||||
# with the dev channel.
|
# with the dev channel.
|
||||||
percent_passed = self.VerifyImage(10)
|
percent_passed = self.VerifyImage(10)
|
||||||
|
|
||||||
# Update to - all tests should pass on new image.
|
# Update to - all tests should pass on new image.
|
||||||
Info('Updating from base image on vm to target image and wiping stateful.')
|
Info('Updating from base image on vm to target image and wiping stateful.')
|
||||||
self.TryDeltaAndFallbackToFull(base_image_path, target_image_path, 'clean')
|
self.PerformUpdate(self.base_image_path, self.target_image_path, 'clean')
|
||||||
self.VerifyImage(100)
|
self.VerifyImage(100)
|
||||||
|
|
||||||
# Update from - same percentage should pass that originally passed.
|
# Update from - same percentage should pass that originally passed.
|
||||||
Info('Updating from updated image back to base image and wiping stateful.')
|
Info('Updating from updated image back to base image and wiping stateful.')
|
||||||
self.TryDeltaAndFallbackToFull(target_image_path, base_image_path, 'clean')
|
self.PerformUpdate(self.target_image_path, self.base_image_path, 'clean')
|
||||||
self.VerifyImage(percent_passed)
|
self.VerifyImage(percent_passed)
|
||||||
|
|
||||||
def testPartialUpdate(self):
|
def testPartialUpdate(self):
|
||||||
"""Tests what happens if we attempt to update with a truncated payload."""
|
"""Tests what happens if we attempt to update with a truncated payload."""
|
||||||
# Preload with the version we are trying to test.
|
# Preload with the version we are trying to test.
|
||||||
self.PrepareBase(target_image_path)
|
self.PrepareBase(self.target_image_path)
|
||||||
|
|
||||||
# Image can be updated at:
|
# Image can be updated at:
|
||||||
# ~chrome-eng/chromeos/localmirror/autest-images
|
# ~chrome-eng/chromeos/localmirror/autest-images
|
||||||
@ -273,12 +287,12 @@ class AUTest(object):
|
|||||||
urllib.urlretrieve(url, payload)
|
urllib.urlretrieve(url, payload)
|
||||||
|
|
||||||
expected_msg = 'download_hash_data == update_check_response_hash failed'
|
expected_msg = 'download_hash_data == update_check_response_hash failed'
|
||||||
self._AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
|
self.AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
|
||||||
|
|
||||||
def testCorruptedUpdate(self):
|
def testCorruptedUpdate(self):
|
||||||
"""Tests what happens if we attempt to update with a corrupted payload."""
|
"""Tests what happens if we attempt to update with a corrupted payload."""
|
||||||
# Preload with the version we are trying to test.
|
# Preload with the version we are trying to test.
|
||||||
self.PrepareBase(target_image_path)
|
self.PrepareBase(self.target_image_path)
|
||||||
|
|
||||||
# Image can be updated at:
|
# Image can be updated at:
|
||||||
# ~chrome-eng/chromeos/localmirror/autest-images
|
# ~chrome-eng/chromeos/localmirror/autest-images
|
||||||
@ -291,7 +305,7 @@ class AUTest(object):
|
|||||||
|
|
||||||
# This update is expected to fail...
|
# This update is expected to fail...
|
||||||
expected_msg = 'zlib inflate() error:-3'
|
expected_msg = 'zlib inflate() error:-3'
|
||||||
self._AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
|
self.AttemptUpdateWithPayloadExpectedFailure(payload, expected_msg)
|
||||||
|
|
||||||
def testInterruptedUpdate(self):
|
def testInterruptedUpdate(self):
|
||||||
"""Tests what happens if we interrupt payload delivery 3 times."""
|
"""Tests what happens if we interrupt payload delivery 3 times."""
|
||||||
@ -325,7 +339,7 @@ class AUTest(object):
|
|||||||
self.data_size += len(data)
|
self.data_size += len(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
self._AttemptUpdateWithFilter(InterruptionFilter())
|
self.AttemptUpdateWithFilter(InterruptionFilter())
|
||||||
|
|
||||||
def testDelayedUpdate(self):
|
def testDelayedUpdate(self):
|
||||||
"""Tests what happens if some data is delayed during update delivery"""
|
"""Tests what happens if some data is delayed during update delivery"""
|
||||||
@ -355,7 +369,7 @@ class AUTest(object):
|
|||||||
self.data_size += len(data)
|
self.data_size += len(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
self._AttemptUpdateWithFilter(DelayedFilter())
|
self.AttemptUpdateWithFilter(DelayedFilter())
|
||||||
|
|
||||||
def SimpleTest(self):
|
def SimpleTest(self):
|
||||||
"""A simple update that updates the target image to itself.
|
"""A simple update that updates the target image to itself.
|
||||||
@ -363,8 +377,8 @@ class AUTest(object):
|
|||||||
We explicitly don't use test prefix so that isn't run by default. Can be
|
We explicitly don't use test prefix so that isn't run by default. Can be
|
||||||
run using test_prefix option.
|
run using test_prefix option.
|
||||||
"""
|
"""
|
||||||
self.PrepareBase(target_image_path)
|
self.PrepareBase(self.target_image_path)
|
||||||
self.UpdateImage(target_image_path)
|
self._UpdateImage(self.target_image_path)
|
||||||
self.VerifyImage(100)
|
self.VerifyImage(100)
|
||||||
|
|
||||||
|
|
||||||
@ -374,19 +388,29 @@ class RealAUTest(unittest.TestCase, AUTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
AUTest.setUp(self)
|
AUTest.setUp(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ProcessOptions(cls, parser, options):
|
||||||
|
"""Processes non-vm-specific options."""
|
||||||
|
AUTest.ProcessOptions(parser, options)
|
||||||
|
cls.remote = options.remote
|
||||||
|
|
||||||
|
if not cls.remote:
|
||||||
|
parser.error('We require a remote address for real tests.')
|
||||||
|
|
||||||
def PrepareBase(self, image_path):
|
def PrepareBase(self, image_path):
|
||||||
"""Auto-update to base image to prepare for test."""
|
"""Auto-update to base image to prepare for test."""
|
||||||
self._UpdateImageReportError(image_path)
|
self.PerformUpdate(image_path)
|
||||||
|
|
||||||
def UpdateImage(self, image_path, stateful_change='old', proxy_port=None):
|
def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
||||||
|
proxy_port=None):
|
||||||
"""Updates a remote image using image_to_live.sh."""
|
"""Updates a remote image using image_to_live.sh."""
|
||||||
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
||||||
cmd = ['%s/image_to_live.sh' % self.crosutils,
|
cmd = ['%s/image_to_live.sh' % self.crosutils,
|
||||||
'--image=%s' % image_path,
|
'--image=%s' % image_path,
|
||||||
'--remote=%s' % remote,
|
'--remote=%s' % self.remote,
|
||||||
stateful_change_flag,
|
stateful_change_flag,
|
||||||
'--verify',
|
'--verify',
|
||||||
'--src_image=%s' % self.source_image
|
'--src_image=%s' % src_image_path
|
||||||
]
|
]
|
||||||
|
|
||||||
if proxy_port:
|
if proxy_port:
|
||||||
@ -402,15 +426,13 @@ class RealAUTest(unittest.TestCase, AUTest):
|
|||||||
if code != 0:
|
if code != 0:
|
||||||
raise UpdateException(code, stdout)
|
raise UpdateException(code, stdout)
|
||||||
|
|
||||||
def UpdateUsingPayload(self,
|
def _UpdateUsingPayload(self, update_path, stateful_change='old',
|
||||||
update_path,
|
|
||||||
stateful_change='old',
|
|
||||||
proxy_port=None):
|
proxy_port=None):
|
||||||
"""Updates a remote image using image_to_live.sh."""
|
"""Updates a remote image using image_to_live.sh."""
|
||||||
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
||||||
cmd = ['%s/image_to_live.sh' % self.crosutils,
|
cmd = ['%s/image_to_live.sh' % self.crosutils,
|
||||||
'--payload=%s' % update_path,
|
'--payload=%s' % update_path,
|
||||||
'--remote=%s' % remote,
|
'--remote=%s' % self.remote,
|
||||||
stateful_change_flag,
|
stateful_change_flag,
|
||||||
'--verify',
|
'--verify',
|
||||||
]
|
]
|
||||||
@ -432,16 +454,21 @@ class RealAUTest(unittest.TestCase, AUTest):
|
|||||||
"""Verifies an image using run_remote_tests.sh with verification suite."""
|
"""Verifies an image using run_remote_tests.sh with verification suite."""
|
||||||
output = RunCommand([
|
output = RunCommand([
|
||||||
'%s/run_remote_tests.sh' % self.crosutils,
|
'%s/run_remote_tests.sh' % self.crosutils,
|
||||||
'--remote=%s' % remote,
|
'--remote=%s' % self.remote,
|
||||||
_VERIFY_SUITE,
|
self.verify_suite,
|
||||||
], error_ok=True, enter_chroot=False, redirect_stdout=True)
|
], error_ok=True, enter_chroot=False, redirect_stdout=True)
|
||||||
return self.CommonVerifyImage(self, output, percent_required_to_pass)
|
return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass)
|
||||||
|
|
||||||
|
|
||||||
class VirtualAUTest(unittest.TestCase, AUTest):
|
class VirtualAUTest(unittest.TestCase, AUTest):
|
||||||
"""Test harness for updating virtual machines."""
|
"""Test harness for updating virtual machines."""
|
||||||
vm_image_path = None
|
vm_image_path = None
|
||||||
|
|
||||||
|
# VM Constants.
|
||||||
|
_FULL_VDISK_SIZE = 6072
|
||||||
|
_FULL_STATEFULFS_SIZE = 3074
|
||||||
|
_KVM_PID_FILE = '/tmp/harness_pid'
|
||||||
|
|
||||||
def _KillExistingVM(self, pid_file):
|
def _KillExistingVM(self, pid_file):
|
||||||
if os.path.exists(pid_file):
|
if os.path.exists(pid_file):
|
||||||
Warning('Existing %s found. Deleting and killing process' %
|
Warning('Existing %s found. Deleting and killing process' %
|
||||||
@ -454,7 +481,20 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Unit test overriden method. Is called before every test."""
|
"""Unit test overriden method. Is called before every test."""
|
||||||
AUTest.setUp(self)
|
AUTest.setUp(self)
|
||||||
self._KillExistingVM(_KVM_PID_FILE)
|
self._KillExistingVM(self._KVM_PID_FILE)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ProcessOptions(cls, parser, options):
|
||||||
|
"""Processes vm-specific options."""
|
||||||
|
AUTest.ProcessOptions(parser, options)
|
||||||
|
cls.board = options.board
|
||||||
|
|
||||||
|
# Communicate flags to tests.
|
||||||
|
cls.graphics_flag = ''
|
||||||
|
if options.no_graphics: cls.graphics_flag = '--no_graphics'
|
||||||
|
|
||||||
|
if not cls.board:
|
||||||
|
parser.error('Need board to convert base image to vm.')
|
||||||
|
|
||||||
def PrepareBase(self, image_path):
|
def PrepareBase(self, image_path):
|
||||||
"""Creates an update-able VM based on base image."""
|
"""Creates an update-able VM based on base image."""
|
||||||
@ -469,33 +509,32 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
|||||||
'--full',
|
'--full',
|
||||||
'--from=%s' % ReinterpretPathForChroot(
|
'--from=%s' % ReinterpretPathForChroot(
|
||||||
os.path.dirname(image_path)),
|
os.path.dirname(image_path)),
|
||||||
'--vdisk_size=%s' % _FULL_VDISK_SIZE,
|
'--vdisk_size=%s' % self._FULL_VDISK_SIZE,
|
||||||
'--statefulfs_size=%s' % _FULL_STATEFULFS_SIZE,
|
'--statefulfs_size=%s' % self._FULL_STATEFULFS_SIZE,
|
||||||
'--board=%s' % board,
|
'--board=%s' % self.board,
|
||||||
'--test_image'], enter_chroot=True)
|
'--test_image'], enter_chroot=True)
|
||||||
else:
|
else:
|
||||||
Info('Using existing VM image %s' % self.vm_image_path)
|
Info('Using existing VM image %s' % self.vm_image_path)
|
||||||
|
|
||||||
|
|
||||||
Info('Testing for %s' % self.vm_image_path)
|
Info('Testing for %s' % self.vm_image_path)
|
||||||
|
|
||||||
self.assertTrue(os.path.exists(self.vm_image_path))
|
self.assertTrue(os.path.exists(self.vm_image_path))
|
||||||
|
|
||||||
def UpdateImage(self, image_path, stateful_change='old', proxy_port=None):
|
def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
||||||
|
proxy_port=None):
|
||||||
"""Updates VM image with image_path."""
|
"""Updates VM image with image_path."""
|
||||||
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
||||||
if self.source_image == base_image_path:
|
if src_image_path == self.base_image_path:
|
||||||
self.source_image = self.vm_image_path
|
src_image_path = self.vm_image_path
|
||||||
|
|
||||||
cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
||||||
'--update_image_path=%s' % image_path,
|
'--update_image_path=%s' % image_path,
|
||||||
'--vm_image_path=%s' % self.vm_image_path,
|
'--vm_image_path=%s' % self.vm_image_path,
|
||||||
'--snapshot',
|
'--snapshot',
|
||||||
vm_graphics_flag,
|
self.graphics_flag,
|
||||||
'--persist',
|
'--persist',
|
||||||
'--kvm_pid=%s' % _KVM_PID_FILE,
|
'--kvm_pid=%s' % self._KVM_PID_FILE,
|
||||||
stateful_change_flag,
|
stateful_change_flag,
|
||||||
'--src_image=%s' % self.source_image,
|
'--src_image=%s' % src_image_path,
|
||||||
]
|
]
|
||||||
|
|
||||||
if proxy_port:
|
if proxy_port:
|
||||||
@ -511,24 +550,18 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
|||||||
if code != 0:
|
if code != 0:
|
||||||
raise UpdateException(code, stdout)
|
raise UpdateException(code, stdout)
|
||||||
|
|
||||||
def UpdateUsingPayload(self,
|
def _UpdateUsingPayload(self, update_path, stateful_change='old',
|
||||||
update_path,
|
|
||||||
stateful_change='old',
|
|
||||||
proxy_port=None):
|
proxy_port=None):
|
||||||
"""Updates a remote image using image_to_live.sh."""
|
"""Updates a remote image using image_to_live.sh."""
|
||||||
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
||||||
if self.source_image == base_image_path:
|
|
||||||
self.source_image = self.vm_image_path
|
|
||||||
|
|
||||||
cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
||||||
'--payload=%s' % update_path,
|
'--payload=%s' % update_path,
|
||||||
'--vm_image_path=%s' % self.vm_image_path,
|
'--vm_image_path=%s' % self.vm_image_path,
|
||||||
'--snapshot',
|
'--snapshot',
|
||||||
vm_graphics_flag,
|
self.graphics_flag,
|
||||||
'--persist',
|
'--persist',
|
||||||
'--kvm_pid=%s' % _KVM_PID_FILE,
|
'--kvm_pid=%s' % self._KVM_PID_FILE,
|
||||||
stateful_change_flag,
|
stateful_change_flag,
|
||||||
'--src_image=%s' % self.source_image,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if proxy_port:
|
if proxy_port:
|
||||||
@ -553,19 +586,19 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
|||||||
'--image_path=%s' % self.vm_image_path,
|
'--image_path=%s' % self.vm_image_path,
|
||||||
'--snapshot',
|
'--snapshot',
|
||||||
'--persist',
|
'--persist',
|
||||||
'--kvm_pid=%s' % _KVM_PID_FILE,
|
'--kvm_pid=%s' % self._KVM_PID_FILE,
|
||||||
_VERIFY_SUITE,
|
self.verify_suite,
|
||||||
]
|
]
|
||||||
|
|
||||||
if vm_graphics_flag:
|
if self.graphics_flag:
|
||||||
commandWithArgs.append(vm_graphics_flag)
|
commandWithArgs.append(self.graphics_flag)
|
||||||
|
|
||||||
output = RunCommand(commandWithArgs, error_ok=True, enter_chroot=False,
|
output = RunCommand(commandWithArgs, error_ok=True, enter_chroot=False,
|
||||||
redirect_stdout=True)
|
redirect_stdout=True)
|
||||||
return self.CommonVerifyImage(self, output, percent_required_to_pass)
|
return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
parser.add_option('-b', '--base_image',
|
parser.add_option('-b', '--base_image',
|
||||||
help='path to the base image.')
|
help='path to the base image.')
|
||||||
@ -590,47 +623,25 @@ if __name__ == '__main__':
|
|||||||
parser.add_option('--verbose', default=False, action='store_true',
|
parser.add_option('--verbose', default=False, action='store_true',
|
||||||
help='Print out rather than capture output as much as '
|
help='Print out rather than capture output as much as '
|
||||||
'possible.')
|
'possible.')
|
||||||
# Set the usage to include flags.
|
(options, leftover_args) = parser.parse_args()
|
||||||
parser.set_usage(parser.format_help())
|
|
||||||
# Parse existing sys.argv so we can pass rest to unittest.main.
|
|
||||||
(options, sys.argv) = parser.parse_args(sys.argv)
|
|
||||||
|
|
||||||
AUTest.verbose = options.verbose
|
if leftover_args:
|
||||||
base_image_path = options.base_image
|
parser.error('Found extra options we do not support: %s' % leftover_args)
|
||||||
target_image_path = options.target_image
|
|
||||||
board = options.board
|
|
||||||
|
|
||||||
if not base_image_path:
|
|
||||||
parser.error('Need path to base image for vm.')
|
|
||||||
elif not os.path.exists(base_image_path):
|
|
||||||
Die('%s does not exist' % base_image_path)
|
|
||||||
|
|
||||||
if not target_image_path:
|
|
||||||
parser.error('Need path to target image to update with.')
|
|
||||||
elif not os.path.exists(target_image_path):
|
|
||||||
Die('%s does not exist' % target_image_path)
|
|
||||||
|
|
||||||
if not board:
|
|
||||||
parser.error('Need board to convert base image to vm.')
|
|
||||||
|
|
||||||
# Communicate flags to tests.
|
|
||||||
vm_graphics_flag = ''
|
|
||||||
if options.no_graphics: vm_graphics_flag = '--no_graphics'
|
|
||||||
if options.quick_test: _VERIFY_SUITE = 'build_RootFilesystemSize'
|
|
||||||
AUTest.use_delta_updates = options.delta
|
|
||||||
|
|
||||||
# Only run the test harness we care about.
|
|
||||||
test_loader = unittest.TestLoader()
|
|
||||||
test_loader.testMethodPrefix = options.test_prefix
|
|
||||||
|
|
||||||
if options.type == 'vm': test_class = VirtualAUTest
|
if options.type == 'vm': test_class = VirtualAUTest
|
||||||
elif options.type == 'real': test_class = RealAUTest
|
elif options.type == 'real': test_class = RealAUTest
|
||||||
else: parser.error('Could not parse harness type %s.' % options.type)
|
else: parser.error('Could not parse harness type %s.' % options.type)
|
||||||
|
|
||||||
remote = options.remote
|
test_class.ProcessOptions(parser, options)
|
||||||
|
|
||||||
|
test_loader = unittest.TestLoader()
|
||||||
|
test_loader.testMethodPrefix = options.test_prefix
|
||||||
test_suite = test_loader.loadTestsFromTestCase(test_class)
|
test_suite = test_loader.loadTestsFromTestCase(test_class)
|
||||||
test_result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
test_result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
||||||
|
|
||||||
if not test_result.wasSuccessful():
|
if not test_result.wasSuccessful():
|
||||||
Die('Test harness was not successful')
|
Die('Test harness was not successful')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
@ -142,6 +142,7 @@ function setup_env {
|
|||||||
then
|
then
|
||||||
mkdir -p "${TARGET_DIR}"
|
mkdir -p "${TARGET_DIR}"
|
||||||
cp -r "${HOME}/.ssh/known_hosts" "${TARGET_DIR}"
|
cp -r "${HOME}/.ssh/known_hosts" "${TARGET_DIR}"
|
||||||
|
cp -r "${HOME}/.ssh/config" "${TARGET_DIR}"
|
||||||
ASOCK="$(dirname "${SSH_AUTH_SOCK}")"
|
ASOCK="$(dirname "${SSH_AUTH_SOCK}")"
|
||||||
mkdir -p "${FLAGS_chroot}/${ASOCK}"
|
mkdir -p "${FLAGS_chroot}/${ASOCK}"
|
||||||
sudo mount --bind "${ASOCK}" "${FLAGS_chroot}/${ASOCK}" || \
|
sudo mount --bind "${ASOCK}" "${FLAGS_chroot}/${ASOCK}" || \
|
||||||
|
@ -82,11 +82,17 @@ from _emerge.main import emerge_main
|
|||||||
from _emerge.main import parse_opts
|
from _emerge.main import parse_opts
|
||||||
from _emerge.Package import Package
|
from _emerge.Package import Package
|
||||||
from _emerge.Scheduler import Scheduler
|
from _emerge.Scheduler import Scheduler
|
||||||
|
from _emerge.SetArg import SetArg
|
||||||
from _emerge.stdout_spinner import stdout_spinner
|
from _emerge.stdout_spinner import stdout_spinner
|
||||||
import portage
|
import portage
|
||||||
import portage.debug
|
import portage.debug
|
||||||
import portage.versions
|
import portage.versions
|
||||||
|
|
||||||
|
new_portage = not portage.VERSION.startswith("2.1.7.")
|
||||||
|
if new_portage:
|
||||||
|
from portage._global_updates import _global_updates
|
||||||
|
else:
|
||||||
|
from portage import _global_updates
|
||||||
|
|
||||||
def Usage():
|
def Usage():
|
||||||
"""Print usage."""
|
"""Print usage."""
|
||||||
@ -390,7 +396,7 @@ class DepGraphGenerator(object):
|
|||||||
#
|
#
|
||||||
# Portage normally handles this logic in emerge_main, but again, we can't
|
# Portage normally handles this logic in emerge_main, but again, we can't
|
||||||
# use that function here.
|
# use that function here.
|
||||||
if portage._global_updates(trees, mtimedb["updates"]):
|
if _global_updates(trees, mtimedb["updates"]):
|
||||||
mtimedb.commit()
|
mtimedb.commit()
|
||||||
settings, trees, mtimedb = load_emerge_config(trees=trees)
|
settings, trees, mtimedb = load_emerge_config(trees=trees)
|
||||||
|
|
||||||
@ -438,6 +444,9 @@ class DepGraphGenerator(object):
|
|||||||
root = settings["ROOT"]
|
root = settings["ROOT"]
|
||||||
emerge.root_config = trees[root]["root_config"]
|
emerge.root_config = trees[root]["root_config"]
|
||||||
|
|
||||||
|
if new_portage and "--usepkg" in opts:
|
||||||
|
emerge.trees[root]["bintree"].populate("--getbinpkg" in opts)
|
||||||
|
|
||||||
def CheckUseFlags(self, pkgsettings, cur_pkg, new_pkg):
|
def CheckUseFlags(self, pkgsettings, cur_pkg, new_pkg):
|
||||||
"""Are the use flags in cur_pkg up to date?
|
"""Are the use flags in cur_pkg up to date?
|
||||||
|
|
||||||
@ -498,26 +507,19 @@ class DepGraphGenerator(object):
|
|||||||
frozen_config = _frozen_depgraph_config(emerge.settings, emerge.trees,
|
frozen_config = _frozen_depgraph_config(emerge.settings, emerge.trees,
|
||||||
emerge_opts, emerge.spinner)
|
emerge_opts, emerge.spinner)
|
||||||
backtrack_max = emerge_opts.get('--backtrack', 5)
|
backtrack_max = emerge_opts.get('--backtrack', 5)
|
||||||
runtime_pkg_mask = None
|
backtrack_parameters = {}
|
||||||
allow_backtracking = backtrack_max > 0
|
allow_backtracking = backtrack_max > 0
|
||||||
|
|
||||||
# Try up to backtrack_max times to create a working depgraph. Each time we
|
# Try up to backtrack_max times to create a working depgraph. Each time we
|
||||||
# run into a conflict, mask the offending package and try again.
|
# run into a conflict, mask the offending package and try again.
|
||||||
# TODO(davidjames): When Portage supports --force-remote-binary directly,
|
# TODO(davidjames): When Portage supports --force-remote-binary directly,
|
||||||
# switch back to using the backtrack_depgraph function.
|
# switch back to using the backtrack_depgraph function.
|
||||||
for i in range(backtrack_max + 1):
|
for i in range(backtrack_max + 2):
|
||||||
if i == backtrack_max:
|
|
||||||
# Looks like we hit the backtracking limit. Run the dependency
|
|
||||||
# calculation one more time (from scratch) to show the original error
|
|
||||||
# message.
|
|
||||||
runtime_pkg_mask = None
|
|
||||||
allow_backtracking = False
|
|
||||||
|
|
||||||
# Create a depgraph object.
|
# Create a depgraph object.
|
||||||
depgraph = emerge_depgraph(emerge.settings, emerge.trees, emerge_opts,
|
depgraph = emerge_depgraph(emerge.settings, emerge.trees, emerge_opts,
|
||||||
params, emerge.spinner, frozen_config=frozen_config,
|
params, emerge.spinner, frozen_config=frozen_config,
|
||||||
allow_backtracking=allow_backtracking,
|
allow_backtracking=allow_backtracking,
|
||||||
runtime_pkg_mask=runtime_pkg_mask)
|
**backtrack_parameters)
|
||||||
|
|
||||||
if i == 0:
|
if i == 0:
|
||||||
for cpv in self.forced_remote_binary_packages:
|
for cpv in self.forced_remote_binary_packages:
|
||||||
@ -537,15 +539,19 @@ class DepGraphGenerator(object):
|
|||||||
success, favorites = depgraph.select_files(packages)
|
success, favorites = depgraph.select_files(packages)
|
||||||
if success:
|
if success:
|
||||||
break
|
break
|
||||||
elif depgraph.need_restart():
|
elif depgraph.need_restart() and i < backtrack_max:
|
||||||
# Looks like we found some packages that can't be installed due to
|
# Looks like we found some packages that can't be installed due to
|
||||||
# conflicts. Try again, masking out the conflicting packages.
|
# conflicts. Try again, masking out the conflicting packages.
|
||||||
runtime_pkg_mask = depgraph.get_runtime_pkg_mask()
|
if new_portage:
|
||||||
|
backtrack_parameters = depgraph.get_backtrack_parameters()
|
||||||
|
else:
|
||||||
|
backtrack_parameters = {
|
||||||
|
'runtime_pkg_mask': depgraph.get_runtime_pkg_mask()
|
||||||
|
}
|
||||||
elif allow_backtracking and i > 0:
|
elif allow_backtracking and i > 0:
|
||||||
# Looks like we tried all the possible combinations, and we still can't
|
# Looks like we can't solve the graph. Stop backtracking and report an
|
||||||
# solve the graph. Stop backtracking, so that we can report an error
|
# error message.
|
||||||
# message.
|
backtrack_parameters.pop('runtime_pkg_mask', None)
|
||||||
runtime_pkg_mask = None
|
|
||||||
allow_backtracking = False
|
allow_backtracking = False
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@ -641,6 +647,7 @@ class DepGraphGenerator(object):
|
|||||||
# We just refer to CPVs as packages here because it's easier.
|
# We just refer to CPVs as packages here because it's easier.
|
||||||
deps = {}
|
deps = {}
|
||||||
for child, priorities in node_deps[0].items():
|
for child, priorities in node_deps[0].items():
|
||||||
|
if isinstance(child, SetArg): continue
|
||||||
deps[str(child.cpv)] = dict(action=str(child.operation),
|
deps[str(child.cpv)] = dict(action=str(child.operation),
|
||||||
deptype=str(priorities[-1]),
|
deptype=str(priorities[-1]),
|
||||||
deps={})
|
deps={})
|
||||||
@ -741,15 +748,13 @@ class DepGraphGenerator(object):
|
|||||||
try:
|
try:
|
||||||
return urllib2.urlopen(url)
|
return urllib2.urlopen(url)
|
||||||
except urllib2.HTTPError as e:
|
except urllib2.HTTPError as e:
|
||||||
|
print "Cannot GET %s: %s" % (url, str(e))
|
||||||
if i + 1 >= tries or e.code < 500:
|
if i + 1 >= tries or e.code < 500:
|
||||||
raise
|
raise
|
||||||
else:
|
|
||||||
print "Cannot GET %s: %s" % (url, str(e))
|
|
||||||
except urllib2.URLError as e:
|
except urllib2.URLError as e:
|
||||||
|
print "Cannot GET %s: %s" % (url, str(e))
|
||||||
if i + 1 >= tries:
|
if i + 1 >= tries:
|
||||||
raise
|
raise
|
||||||
else:
|
|
||||||
print "Cannot GET %s: %s" % (url, str(e))
|
|
||||||
print "Sleeping for 10 seconds before retrying..."
|
print "Sleeping for 10 seconds before retrying..."
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|
||||||
@ -1192,41 +1197,23 @@ class DepGraphGenerator(object):
|
|||||||
"""Update packages that can use prebuilts to do so."""
|
"""Update packages that can use prebuilts to do so."""
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
# The bintree is the database of binary packages. By default, it's
|
# Build list of prebuilt packages.
|
||||||
# empty.
|
|
||||||
bintree = emerge.trees[root]["bintree"]
|
|
||||||
bindb = bintree.dbapi
|
|
||||||
root_config = emerge.root_config
|
|
||||||
pkgsettings = emerge.depgraph._frozen_config.pkgsettings[root]
|
|
||||||
prebuilt_pkgs = {}
|
prebuilt_pkgs = {}
|
||||||
|
|
||||||
# Populate the DB with packages
|
|
||||||
bintree.populate("--getbinpkg" in emerge.opts,
|
|
||||||
"--getbinpkgonly" in emerge.opts)
|
|
||||||
|
|
||||||
# Build list of prebuilt packages
|
|
||||||
for pkg, info in deps_map.iteritems():
|
for pkg, info in deps_map.iteritems():
|
||||||
if info and info["action"] == "merge":
|
if info and info["action"] == "merge":
|
||||||
if (not info["force_remote_binary"] and info["mandatory_source"] or
|
if (not info["force_remote_binary"] and info["mandatory_source"] or
|
||||||
"--usepkgonly" not in emerge.opts and pkg not in remote_pkgs):
|
"--usepkgonly" not in emerge.opts and pkg not in remote_pkgs):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
db_keys = list(bindb._aux_cache_keys)
|
db_pkg = emerge.depgraph._pkg(pkg, "binary", emerge.root_config)
|
||||||
try:
|
if info["force_remote_binary"]:
|
||||||
db_vals = bindb.aux_get(pkg, db_keys + ["MTIME"])
|
# Undo our earlier hacks to the use flags so that the use flags
|
||||||
except KeyError:
|
# display correctly.
|
||||||
# No binary package
|
db_pkg.use.enabled = db_pkg.metadata["USE"].split()
|
||||||
continue
|
|
||||||
|
|
||||||
mtime = int(db_vals.pop() or 0)
|
|
||||||
metadata = zip(db_keys, db_vals)
|
|
||||||
db_pkg = Package(built=True, cpv=pkg, installed=False,
|
|
||||||
metadata=metadata, onlydeps=False, mtime=mtime,
|
|
||||||
operation="merge", root_config=root_config,
|
|
||||||
type_name="binary")
|
|
||||||
prebuilt_pkgs[pkg] = db_pkg
|
prebuilt_pkgs[pkg] = db_pkg
|
||||||
|
|
||||||
# Calculate what packages need to be rebuilt due to changes in use flags.
|
# Calculate what packages need to be rebuilt due to changes in use flags.
|
||||||
|
pkgsettings = emerge.depgraph._frozen_config.pkgsettings[root]
|
||||||
for pkg, db_pkg in prebuilt_pkgs.iteritems():
|
for pkg, db_pkg in prebuilt_pkgs.iteritems():
|
||||||
if not self.CheckUseFlags(pkgsettings, db_pkg, self.package_db[pkg]):
|
if not self.CheckUseFlags(pkgsettings, db_pkg, self.package_db[pkg]):
|
||||||
MergeChildren(pkg, "mandatory_source")
|
MergeChildren(pkg, "mandatory_source")
|
||||||
@ -1412,6 +1399,10 @@ def EmergeWorker(task_queue, job_queue, emerge, package_db):
|
|||||||
settings, trees, mtimedb = emerge.settings, emerge.trees, emerge.mtimedb
|
settings, trees, mtimedb = emerge.settings, emerge.trees, emerge.mtimedb
|
||||||
opts, spinner = emerge.opts, emerge.spinner
|
opts, spinner = emerge.opts, emerge.spinner
|
||||||
opts["--nodeps"] = True
|
opts["--nodeps"] = True
|
||||||
|
if new_portage:
|
||||||
|
# When Portage launches new processes, it goes on a rampage and closes all
|
||||||
|
# open file descriptors. Ask Portage not to do that, as it breaks us.
|
||||||
|
portage.process.get_open_fds = lambda: []
|
||||||
while True:
|
while True:
|
||||||
# Wait for a new item to show up on the queue. This is a blocking wait,
|
# Wait for a new item to show up on the queue. This is a blocking wait,
|
||||||
# so if there's nothing to do, we just sit here.
|
# so if there's nothing to do, we just sit here.
|
||||||
@ -1438,8 +1429,13 @@ def EmergeWorker(task_queue, job_queue, emerge, package_db):
|
|||||||
try:
|
try:
|
||||||
sys.stdout = output
|
sys.stdout = output
|
||||||
sys.stderr = output
|
sys.stderr = output
|
||||||
scheduler = Scheduler(settings, trees, mtimedb, opts, spinner,
|
if new_portage:
|
||||||
install_list, [], emerge.scheduler_graph)
|
emerge.scheduler_graph.mergelist = install_list
|
||||||
|
scheduler = Scheduler(settings, trees, mtimedb, opts, spinner,
|
||||||
|
favorites=[], graph_config=emerge.scheduler_graph)
|
||||||
|
else:
|
||||||
|
scheduler = Scheduler(settings, trees, mtimedb, opts, spinner,
|
||||||
|
install_list, [], emerge.scheduler_graph)
|
||||||
retcode = scheduler.merge()
|
retcode = scheduler.merge()
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc(file=output)
|
traceback.print_exc(file=output)
|
||||||
@ -1837,7 +1833,11 @@ def main():
|
|||||||
remote_pkgs = {}
|
remote_pkgs = {}
|
||||||
if "--getbinpkg" in emerge.opts:
|
if "--getbinpkg" in emerge.opts:
|
||||||
binhost = emerge.settings["PORTAGE_BINHOST"]
|
binhost = emerge.settings["PORTAGE_BINHOST"]
|
||||||
remote_pkgs = deps.RemotePackageDatabase(binhost)
|
try:
|
||||||
|
remote_pkgs = deps.RemotePackageDatabase(binhost)
|
||||||
|
except (urllib2.HTTPError, urllib2.URLError):
|
||||||
|
print "Cannot resolve binhost. Building from source..."
|
||||||
|
del emerge.opts["--getbinpkg"]
|
||||||
|
|
||||||
deps_tree, deps_info = deps.GenDependencyTree(remote_pkgs)
|
deps_tree, deps_info = deps.GenDependencyTree(remote_pkgs)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user