Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow alternate binaries download urls generation and convert GoDistribution and LLVM subsystems to use it #5780

Merged
merged 62 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
3a64c8d
decouple full url list generation from the fetch method
cosmicexplorer May 4, 2018
c95187b
add urls optional arg for custom urls
cosmicexplorer May 4, 2018
937fc58
download go from the google site with the new urls method
cosmicexplorer May 4, 2018
d7e2235
add txz archiver
cosmicexplorer May 4, 2018
289618f
demonstrate platform-specific conditionals in clang.py
cosmicexplorer May 4, 2018
26a232b
switch go to download the official distribution
cosmicexplorer May 4, 2018
a2fc3bd
remove some cruft
cosmicexplorer May 4, 2018
cef7e9d
support xz decompression
cosmicexplorer May 4, 2018
6a888db
switch llvm to use the official binary distributions
cosmicexplorer May 4, 2018
dea596f
remove stray thought
cosmicexplorer May 4, 2018
24a9688
remove unused import
cosmicexplorer May 4, 2018
22b3d94
fix docstring and error on archive creation for xz
cosmicexplorer May 4, 2018
888289d
fix option names
cosmicexplorer May 4, 2018
c02984f
add extra line for lint
cosmicexplorer May 4, 2018
d6c6b3c
the magic of TODOs
cosmicexplorer May 4, 2018
b26651f
turn lzma.LZMAFile() into a contextmanager
cosmicexplorer May 4, 2018
d4490b4
refactor llvm.py
cosmicexplorer May 4, 2018
4a62557
remove gcc subsystem
cosmicexplorer May 4, 2018
9454ece
refactor the default urls into a classmethod
cosmicexplorer May 5, 2018
14d1cda
isolate the path and see what travis says
cosmicexplorer May 5, 2018
b2b4866
add back archive_extensions
cosmicexplorer May 5, 2018
9ee6c3a
deprecate pants.archive.archiver()
cosmicexplorer May 5, 2018
13adbeb
make it more ergonomic to use 3rdparty dists
cosmicexplorer May 5, 2018
5d705fd
add binary tool testing
cosmicexplorer May 5, 2018
3c2608a
fix lint errors
cosmicexplorer May 5, 2018
2860f4c
add entries to setup.py execution environment
cosmicexplorer May 5, 2018
b8b6ce9
unremove gcc
cosmicexplorer May 5, 2018
1944907
remove _make_tar_archiver()
cosmicexplorer May 5, 2018
3d2651d
Clang -> LLVM in native_toolchain.py
cosmicexplorer May 5, 2018
fc92529
default to gcc on travis until we can get this mess sorted out
cosmicexplorer May 5, 2018
cb35dc3
remove explicit LDSHARED
cosmicexplorer May 6, 2018
b29bca3
add back OrderedSet because the inline comment still applies
cosmicexplorer May 9, 2018
43b1994
skip outdated native toolchain subsystem unit test
cosmicexplorer May 9, 2018
5b3251e
add xz to the relevant travis shards
cosmicexplorer May 9, 2018
ad852dd
fix the ci failures for real hopefully
cosmicexplorer May 9, 2018
774d277
i heard you liked binary tools so i put a binary tool in your binary …
cosmicexplorer May 9, 2018
c6dc4aa
fix reading mode so we decompress and extract in one go instead of ma…
cosmicexplorer May 9, 2018
ac57d6b
split up BinaryUtilPrivate and make path_by_id a global option
cosmicexplorer May 10, 2018
977ce29
iterate on the data flow in BinaryUtil to make it testable (and test it)
cosmicexplorer May 11, 2018
f4cf5ce
fix a pretty obvious oversight
cosmicexplorer May 11, 2018
1ca2444
lint fixes
cosmicexplorer May 11, 2018
a5557be
isort.sh -f
cosmicexplorer May 11, 2018
e2cc759
Merge branch 'master' into fix-binaries-bandwidth-s3
cosmicexplorer May 11, 2018
1bdc88f
fix the panstd ci failures and add todo
cosmicexplorer May 11, 2018
65b2a07
Use custom fork of grpcio-compiler (#5810)
illicitonion May 11, 2018
a4faf38
Merge branch 'master' into fix-binaries-bandwidth-s3
cosmicexplorer May 11, 2018
796d5e2
provide LD_LIBRARY_PATH from the extracted archive when invoking xz
cosmicexplorer May 11, 2018
23b2536
fix remaining ci failure
cosmicexplorer May 12, 2018
3f99875
add some docstrings and add the --force-baseurls bootstrap option
cosmicexplorer May 12, 2018
9b6a4c5
add some docstrings, improve some error messages, and cull old TODOS
cosmicexplorer May 12, 2018
370fef0
fix the --force-baseurls option and make the LLVM BinaryTool work wit…
cosmicexplorer May 12, 2018
3b90467
describe the url_generator(self) method
cosmicexplorer May 12, 2018
1af5657
expand xz docstring
cosmicexplorer May 12, 2018
873d037
cleanup
cosmicexplorer May 12, 2018
dfb677b
add force_baseurls param to other BinaryUtilPrivate creation and add …
cosmicexplorer May 12, 2018
8ec8c9d
fill out a lot of docstrings
cosmicexplorer May 12, 2018
b1119a5
fix up some docstrings
cosmicexplorer May 12, 2018
8ff8f63
advance the docstrings further
cosmicexplorer May 12, 2018
c8bb85d
change --force-baseurls to --allow-external-binary-tool-downloads
cosmicexplorer May 13, 2018
e109d71
move external url generator tests in the file
cosmicexplorer May 13, 2018
8323c72
fix import sort order
cosmicexplorer May 13, 2018
55e6fb3
transplant PR comment from benjy directly into the source
cosmicexplorer May 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class GoDistribution(NativeTool):
default_version = '1.8.3'
archive_type = 'tgz'

def url_generator(self):
def get_external_url_generator(self):
return GoReleaseUrlGenerator()

@memoized_property
Expand Down
2 changes: 1 addition & 1 deletion src/python/pants/backend/native/subsystems/llvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class LLVM(NativeTool, ExecutablePathProvider):
default_version = '6.0.0'
archive_type = 'txz'

def url_generator(self):
def get_external_url_generator(self):
return LLVMReleaseUrlGenerator()

@memoized_method
Expand Down
13 changes: 7 additions & 6 deletions src/python/pants/binaries/binary_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,18 @@ def _get_archiver(self):

return create_archiver(self.archive_type)

def url_generator(self):
def get_external_url_generator(self):
"""Override and return an instance of BinaryToolUrlGenerator to download from those urls.

If this method returns None, urls to download the tool will be constructed from
--binaries-baseurls. Otherwise, generate_urls() will be invoked on the result with the requested
version and host platform.

If the bootstrap option --force-baseurls is set, the result of this method will be ignored. In
general, implementors of BinaryTool subclasses should try to ensure (within reason) that the
rest of their code can handle the result of downloading from different urls if url_generator()
is overridden yet again by a subclass, or if it is ignored with --force-baseurls.
If the bootstrap option --allow-external-binary-tool-downloads is False, the result of this
method will be ignored. In general, implementors of BinaryTool subclasses should try to ensure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this means? In what way would a BinaryTool subclass be affected by the download location, and how would an author mitigate that in code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Also, I think the word is spelled "implementer".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was thinking about how to make that more clear here. I was thinking specifically about what is done in the LLVM subsystem by overriding the select() method (and was going to explicitly call out that example here, but stopped short of doing that). Should I add in a comment describing that a bit (basically: we check if there's a single top-level directory and go down a level if so, or just return the result of select() if the extraction doesn't put everything into a single top-level directory inside our specified extraction directory), or take this clause out of the docstring? Let me know if that made sense.

The internet confirms that "implementer" is the correct spelling.

(within reason) that the rest of their code can handle the result of downloading from different
urls if get_external_url_generator() is overridden yet again by a subclass, or if it is ignored
with --no-allow-external-binary-tool-downloads.

See the :class:`LLVM` subsystem for an example of usage.
"""
Expand Down Expand Up @@ -168,7 +169,7 @@ def _make_binary_request(self, version):
version=version,
name=self._name_to_fetch(),
platform_dependent=self.platform_dependent,
url_generator=self.url_generator(),
external_url_generator=self.get_external_url_generator(),
archiver=self._get_archiver())

def _select_for_version(self, version):
Expand Down
40 changes: 23 additions & 17 deletions src/python/pants/binaries/binary_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class BinaryToolUrlGenerator(object):
:API: public

:class:`BinaryTool` subclasses can return an instance of a class mixing this in to
url_generator(self) to download their file or archive from some specified url or set of urls.
get_external_url_generator(self) to download their file or archive from some specified url or set
of urls.
"""

@abstractmethod
Expand All @@ -71,8 +72,8 @@ def generate_urls(self, version, host_platform):
class PantsHosted(BinaryToolUrlGenerator):
"""Given a binary request and --binaries-baseurls, generate urls to download the binary from.

This url generator is used if url_generator(self) is not overridden by a BinaryTool subclass, or
if --force-baseurls is set.
This url generator is used if get_external_url_generator(self) is not overridden by a BinaryTool
subclass, or if --allow-external-binary-tool-downloads is False.

NB: "pants-hosted" is referring to the organization of the urls being specific to pants. It also
happens that most binaries are downloaded from S3 hosting at binaries.pantsbuild.org by default --
Expand Down Expand Up @@ -111,7 +112,7 @@ class BinaryRequest(datatype([
'name',
'platform_dependent',
# NB: this can be None!
'url_generator',
'external_url_generator',
# NB: this can be None!
'archiver',
])):
Expand Down Expand Up @@ -263,7 +264,7 @@ def _create_for_cls(cls, binary_util_cls):
baseurls=options.binaries_baseurls,
binary_tool_fetcher=binary_tool_fetcher,
path_by_id=options.binaries_path_by_id,
force_baseurls=options.force_baseurls)
allow_external_binary_tool_downloads=options.allow_external_binary_tool_downloads)

class MissingMachineInfo(TaskError):
"""Indicates that pants was unable to map this machine's OS to a binary path prefix."""
Expand All @@ -281,8 +282,8 @@ def __init__(self, binary_request, base_exception):
"Error resolving binary request {}: {}".format(binary_request, base_exception),
base_exception)

def __init__(self, baseurls, binary_tool_fetcher, path_by_id=None, force_baseurls=False,
uname_func=None):
def __init__(self, baseurls, binary_tool_fetcher, path_by_id=None,
allow_external_binary_tool_downloads=True, uname_func=None):
"""Creates a BinaryUtil with the given settings to define binary lookup behavior.

This constructor is primarily used for testing. Production code will usually initialize
Expand All @@ -295,8 +296,9 @@ def __init__(self, baseurls, binary_tool_fetcher, path_by_id=None, force_baseurl
search for binaries in, or download binaries to if needed.
:param dict path_by_id: Additional mapping from (sysname, id) -> (os, arch) for tool
directory naming
:param bool force_baseurls: Whether to use --binaries-baseurls to download all binaries
regardless of whether a :class:`BinaryToolUrlGenerator` is provided.
:param bool allow_external_binary_tool_downloads: If False, use --binaries-baseurls to download
all binaries, regardless of whether an
external_url_generator field is provided.
:param function uname_func: method to use to emulate os.uname() in testing
"""
self._baseurls = baseurls
Expand All @@ -306,7 +308,7 @@ def __init__(self, baseurls, binary_tool_fetcher, path_by_id=None, force_baseurl
if path_by_id:
self._path_by_id.update((tuple(k), tuple(v)) for k, v in path_by_id.items())

self._force_baseurls = force_baseurls
self._allow_external_binary_tool_downloads = allow_external_binary_tool_downloads
self._uname_func = uname_func or os.uname

_ID_BY_OS = {
Expand Down Expand Up @@ -349,14 +351,18 @@ def _get_download_path(self, binary_request):
return binary_request.get_download_path(self._host_platform())

def _get_url_generator(self, binary_request):
url_generator = binary_request.url_generator

logger.debug("self._force_baseurls: {}".format(self._force_baseurls))
logger.debug("url_generator: {}".format(url_generator))
if self._force_baseurls or not url_generator:
external_url_generator = binary_request.external_url_generator

logger.debug("self._allow_external_binary_tool_downloads: {}"
.format(self._allow_external_binary_tool_downloads))
logger.debug("external_url_generator: {}".format(external_url_generator))

if external_url_generator and self._allow_external_binary_tool_downloads:
url_generator = external_url_generator
else:
if not self._baseurls:
raise self.NoBaseUrlsError("--binaries-baseurls is empty.")

url_generator = PantsHosted(binary_request=binary_request, baseurls=self._baseurls)

return url_generator
Expand Down Expand Up @@ -416,7 +422,7 @@ def _make_deprecated_binary_request(self, supportdir, version, name):
version=version,
name=name,
platform_dependent=True,
url_generator=None,
external_url_generator=None,
archiver=None)

def select_binary(self, supportdir, version, name):
Expand All @@ -429,7 +435,7 @@ def _make_deprecated_script_request(self, supportdir, version, name):
version=version,
name=name,
platform_dependent=False,
url_generator=None,
external_url_generator=None,
archiver=None)

def select_script(self, supportdir, version, name):
Expand Down
9 changes: 4 additions & 5 deletions src/python/pants/option/global_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,10 @@ def register_bootstrap_options(cls, register):
help=("Maps output of uname for a machine to a binary search path: "
"(sysname, id) -> (os, arch), e.g. {('darwin', '15'): ('mac', '10.11'), "
"('linux', 'arm32'): ('linux', 'arm32')}."))
# BinaryTool options.
register('--force-baseurls', type=bool, default=False, advanced=True,
help="Force BinaryTool subclasses to download from urls generated from "
"--binaries-baseurls, even if the tool has a custom url generator. "
"This can be necessary if using Pants in an environment which cannot "
register('--allow-external-binary-tool-downloads', type=bool, default=True, advanced=True,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the name and the help text mesh together nicely!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree!

help="If False, require BinaryTool subclasses to download their contents from urls "
"generated from --binaries-baseurls, even if the tool has an external url "
"generator. This can be necessary if using Pants in an environment which cannot "
"contact the wider Internet.")

# Pants Daemon options.
Expand Down
2 changes: 1 addition & 1 deletion src/python/pants/pantsd/watchman_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def create(cls, bootstrap_options):
binary_tool_fetcher=binary_tool_fetcher,
path_by_id=bootstrap_options.binaries_path_by_id,
# TODO(cosmicexplorer): do we need to test this?
force_baseurls=bootstrap_options.force_baseurls)
allow_external_binary_tool_downloads=bootstrap_options.allow_external_binary_tool_downloads)

return WatchmanLauncher(
binary_util,
Expand Down
4 changes: 2 additions & 2 deletions tests/python/pants_test/binaries/test_binary_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class CustomUrls(BinaryToolBase):
name = 'custom_urls_tool'
default_version = 'v2.1'

def url_generator(self):
def get_external_url_generator(self):
return CustomUrlGenerator()

def _select_for_version(self, version):
Expand Down Expand Up @@ -115,7 +115,7 @@ def test_replacing_legacy_options(self):

def test_urls(self):
default_version_tool = DefaultVersion.global_instance()
self.assertIsNone(default_version_tool.url_generator())
self.assertIsNone(default_version_tool.get_external_url_generator())

with self.assertRaises(BinaryUtilPrivate.BinaryResolutionError) as cm:
default_version_tool.select()
Expand Down
115 changes: 83 additions & 32 deletions tests/python/pants_test/binaries/test_binary_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import mock

from pants.binaries.binary_util import BinaryToolFetcher, BinaryUtilPrivate
from pants.binaries.binary_util import BinaryRequest, BinaryToolFetcher, BinaryToolUrlGenerator, BinaryUtilPrivate
from pants.net.http.fetcher import Fetcher
from pants.util.contextutil import temporary_dir
from pants.util.dirutil import safe_open
Expand All @@ -20,6 +20,16 @@
logger = logging.getLogger(__name__)


class ExternalUrlGenerator(BinaryToolUrlGenerator):

def generate_urls(self, version, host_platform):
return ['https://example.com/some-binary', 'https://example.com/same-binary']

# Make the __str__ deterministic, for testing exception messages.
def __str__(self):
return 'ExternalUrlGenerator(<example __str__()>)'


# TODO(cosmicexplorer): test requests with an archiver!
class BinaryUtilTest(BaseTest):
"""Tests binary_util's binaries_baseurls handling."""
Expand Down Expand Up @@ -62,19 +72,21 @@ def _fake_url(cls, binaries, base, binary_key):

@classmethod
def _gen_binary_tool_fetcher(cls, bootstrap_dir='/tmp', timeout_secs=30, fetcher=None,
ignore_cached_download=True):
ignore_cached_download=True):
return BinaryToolFetcher(
bootstrap_dir=bootstrap_dir,
timeout_secs=timeout_secs,
fetcher=fetcher,
ignore_cached_download=ignore_cached_download)

@classmethod
def _gen_binary_util(cls, baseurls=[], path_by_id=None, uname_func=None, **kwargs):
def _gen_binary_util(cls, baseurls=[], path_by_id=None, allow_external_binary_tool_downloads=True,
uname_func=None, **kwargs):
return BinaryUtilPrivate(
baseurls=baseurls,
binary_tool_fetcher=cls._gen_binary_tool_fetcher(**kwargs),
path_by_id=path_by_id,
allow_external_binary_tool_downloads=allow_external_binary_tool_downloads,
uname_func=uname_func)

@classmethod
Expand All @@ -97,18 +109,71 @@ def test_timeout(self):
path_or_fd=mock.ANY,
timeout_secs=timeout_value)

def test_nobases(self):
def test_no_base_urls_error(self):
"""Tests exception handling if build support urls are improperly specified."""
binary_util = self._gen_binary_util()
# TODO: test error message!
with self.assertRaises(binary_util.BinaryResolutionError) as cm:
# TODO: test select_binary() producing the right BinaryRequest to fulfill?
binary_util.select_binary(supportdir='bin/protobuf',
version='2.4.1',
name='protoc')
self.fail('Expected downloading the binary to raise.')
expected_msg = "--binaries-baseurls is empty."
self.assertIn(expected_msg, str(cm.exception))

with self.assertRaises(BinaryUtilPrivate.BinaryResolutionError) as cm:
binary_util.select_script("supportdir", "version", "name")
the_raised_exception_message = str(cm.exception)

self.assertIn(BinaryUtilPrivate.NoBaseUrlsError.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=supportdir, version=version, "
"name=name, platform_dependent=False, external_url_generator=None, archiver=None): "
"--binaries-baseurls is empty.")
self.assertIn(expected_msg, the_raised_exception_message)

def test_external_url_generator(self):
binary_util = self._gen_binary_util()

binary_request = BinaryRequest(
supportdir='supportdir',
version='version',
name='name',
platform_dependent=False,
external_url_generator=ExternalUrlGenerator(),
# TODO: test archiver!
archiver=None)

with self.assertRaises(BinaryUtilPrivate.BinaryResolutionError) as cm:
binary_util.select(binary_request)
the_raised_exception_message = str(cm.exception)

self.assertIn(BinaryToolFetcher.BinaryNotFound.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=supportdir, version=version, "
"name=name, platform_dependent=False, "
"external_url_generator=ExternalUrlGenerator(<example __str__()>), archiver=None): "
"Failed to fetch name binary from any source: (Failed to fetch binary from "
"https://example.com/some-binary: Fetch of https://example.com/some-binary failed with "
"status code 404, Failed to fetch binary from https://example.com/same-binary: Fetch of "
"https://example.com/same-binary failed with status code 404)'")
self.assertIn(expected_msg, the_raised_exception_message)

def test_disallowing_external_urls(self):
binary_util = self._gen_binary_util(allow_external_binary_tool_downloads=False)

binary_request = binary_request = BinaryRequest(
supportdir='supportdir',
version='version',
name='name',
platform_dependent=False,
external_url_generator=ExternalUrlGenerator(),
# TODO: test archiver!
archiver=None)

with self.assertRaises(BinaryUtilPrivate.BinaryResolutionError) as cm:
binary_util.select(binary_request)
the_raised_exception_message = str(cm.exception)

self.assertIn(BinaryUtilPrivate.NoBaseUrlsError.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=supportdir, version=version, "
"name=name, platform_dependent=False, "
"external_url_generator=ExternalUrlGenerator(<example __str__()>), archiver=None): "
"--binaries-baseurls is empty.")
self.assertIn(expected_msg, the_raised_exception_message)

def test_support_url_multi(self):
"""Tests to make sure existing base urls function as expected."""
Expand Down Expand Up @@ -214,7 +279,7 @@ def uname_func():
self.assertIn(BinaryUtilPrivate.MissingMachineInfo.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=supportdir, version=version, "
"name=name, platform_dependent=True, url_generator=None, archiver=None): "
"name=name, platform_dependent=True, external_url_generator=None, archiver=None): "
"Pants could not resolve binaries for the current host: platform 'vms' was not recognized. "
"Recognized platforms are: [u'darwin', u'linux'].")
self.assertIn(expected_msg, the_raised_exception_message)
Expand All @@ -232,7 +297,7 @@ def uname_func():
self.assertIn(BinaryUtilPrivate.MissingMachineInfo.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=mysupportdir, version=myversion, "
"name=myname, platform_dependent=True, url_generator=None, archiver=None): Pants could not "
"name=myname, platform_dependent=True, external_url_generator=None, archiver=None): Pants could not "
"resolve binaries for the current host. Update --binaries-path-by-id to find binaries for "
"the current host platform (u\'darwin\', u\'999\').\\n--binaries-path-by-id was:")
self.assertIn(expected_msg, the_raised_exception_message)
Expand All @@ -251,9 +316,9 @@ def uname_func():
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=mysupportdir, version=myversion, "
# platform_dependent=False when doing select_script()
"name=myname, platform_dependent=False, url_generator=None, archiver=None): Pants could not "
"resolve binaries for the current host. Update --binaries-path-by-id to find binaries for "
"the current host platform (u\'darwin\', u\'999\').\\n--binaries-path-by-id was:")
"name=myname, platform_dependent=False, external_url_generator=None, archiver=None): Pants "
"could not resolve binaries for the current host. Update --binaries-path-by-id to find "
"binaries for the current host platform (u\'darwin\', u\'999\').\\n--binaries-path-by-id was:")
self.assertIn(expected_msg, the_raised_exception_message)

def test_select_binary_base_path_override(self):
Expand All @@ -267,17 +332,3 @@ def uname_func():

self.assertEquals("supportdir/skynet/42/version/name",
binary_util._get_download_path(binary_request))

def test_no_base_urls_error(self):
binary_util = self._gen_binary_util()

with self.assertRaises(BinaryUtilPrivate.BinaryResolutionError) as cm:
binary_util.select_script("supportdir", "version", "name")
the_raised_exception_message = str(cm.exception)

self.assertIn(BinaryUtilPrivate.NoBaseUrlsError.__name__, the_raised_exception_message)
expected_msg = (
"Error resolving binary request BinaryRequest(supportdir=supportdir, version=version, "
"name=name, platform_dependent=False, url_generator=None, archiver=None): "
"--binaries-baseurls is empty.")
self.assertIn(expected_msg, the_raised_exception_message)