Bug 1286799 - mozboot: Ensure an up-to-date rust toolchain. r=gps
Add a check to `mach bootstrap` that a compatible version of
the rust toolchain is installed and in path. Note that we use
a separate minimum version from the one checked at configure
time, defined in build/moz.configure/rust.configure, because
this script may be running stand-alone.
If we don't find `rustc` in PATH, we check for it in CARGO_HOME
and suggest adding that to PATH.
If we don't find `rustc` but find a `rustup`, we call it with
the --version switch and report if that fails. This will detect
the older `rustup.rs` script.
MozReview-Commit-ID: EPfQhLz4Dvo
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -68,16 +68,40 @@ the $PATH environment variable.
We recommend the following tools for installing Python:
pyenv -- https://github.com/yyuu/pyenv)
pythonz -- https://github.com/saghul/pythonz
official installers -- http://www.python.org/
'''
+RUST_NOT_IN_PATH = '''
+You have some rust files in %(cargo_bin)s, but they're not part of the
+standard PATH.
+
+To make these available, please add this directory to the PATH variable
+in your shell initialization script, which may be called ~/.bashrc or
+~/.bash_profile or ~/.profile. Edit this and add the following line:
+
+ source %(cargo_home)s/env
+
+Then restart your shell and run the bootstrap script again.
+'''
+
+RUSTUP_OLD = '''
+We found an executable called `rustup` which we normally use to install
+and upgrade Rust programming language support, but we didn't understand
+its output. It may be an old version, or not be the installer from
+https://rustup.rs/
+
+Please move it out of the way and run the bootstrap script again.
+Or if you prefer and know how, use the current rustup to install
+a compatible version of the Rust programming language yourself.
+'''
+
BROWSER_ARTIFACT_MODE_MOZCONFIG = '''
Paste the lines between the chevrons (>>> and <<<) into your mozconfig file:
<<<
# Automatically download and use compiled C++ components:
ac_add_options --enable-artifact-builds
>>>
'''
@@ -85,16 +109,18 @@ ac_add_options --enable-artifact-builds
# Upgrade Mercurial older than this.
# This should match OLDEST_NON_LEGACY_VERSION from
# the hg setup wizard in version-control-tools.
MODERN_MERCURIAL_VERSION = LooseVersion('3.7.3')
# Upgrade Python older than this.
MODERN_PYTHON_VERSION = LooseVersion('2.7.3')
+# Upgrade rust older than this.
+MODERN_RUST_VERSION = LooseVersion('1.13.0')
class BaseBootstrapper(object):
"""Base class for system bootstrappers."""
def __init__(self, no_interactive=False):
self.package_manager_updated = False
self.no_interactive = no_interactive
@@ -449,16 +475,68 @@ class BaseBootstrapper(object):
def upgrade_python(self, current):
"""Upgrade Python.
Child classes should reimplement this.
"""
print(PYTHON_UNABLE_UPGRADE % (current, MODERN_PYTHON_VERSION))
+ def is_rust_modern(self):
+ rust = self.which('rustc')
+ if not rust:
+ print('Could not find rust compiler.')
+ return False, None
+
+ cargo = self.which('cargo')
+
+ our = self._parse_version(rust)
+ if not our:
+ return False, None
+
+ return our >= MODERN_RUST_VERSION, our
+
+ def ensure_rust_modern(self):
+ modern, version = self.is_rust_modern()
+
+ if modern:
+ print('Your version of Rust (%s) is new enough.' % version)
+ return
+
+ if not version:
+ '''Rust wasn't in PATH. Try a few things.'''
+ cargo_home = os.environ.get('CARGO_HOME',
+ os.path.expanduser(os.path.join('~', '.cargo')))
+ cargo_bin = os.path.join(cargo_home, 'bin')
+ have_rustc = os.path.exists(os.path.join(cargo_bin, 'rustc'))
+ have_cargo = os.path.exists(os.path.join(cargo_bin, 'cargo'))
+ if have_rustc or have_cargo:
+ print(RUST_NOT_IN_PATH % { 'cargo_bin': cargo_bin,
+ 'cargo_home': cargo_home })
+ sys.exit(1)
+
+ rustup = self.which('rustup')
+ if rustup:
+ print('Found rustup.')
+ version = self._parse_version(rustup)
+ if not version:
+ print(RUSTUP_OLD)
+ sys.exit(1)
+
+ print('Please download and run the installer from https://rustup.rs/')
+ sys.exit(1)
+
+ # TODO: Upgrade rust.
+
+ modern, after = self.is_rust_modern()
+
+ if not modern:
+ print(RUST_UPGRADE_FAILED % (MODERN_RUST_VERSION, after))
+ sys.exit(1)
+
def http_download_and_save(self, url, dest, sha256hexhash):
f = urllib2.urlopen(url)
h = hashlib.sha256()
with open(dest, 'wb') as out:
while True:
data = f.read(4096)
if data:
out.write(data)
--- a/python/mozboot/mozboot/bootstrap.py
+++ b/python/mozboot/mozboot/bootstrap.py
@@ -224,16 +224,17 @@ class Bootstrapper(object):
self.instance.install_system_packages()
# Like 'install_browser_packages' or 'install_mobile_android_packages'.
getattr(self.instance, 'install_%s_packages' % application)()
hg_installed, hg_modern = self.instance.ensure_mercurial_modern()
self.instance.ensure_python_modern()
+ self.instance.ensure_rust_modern()
# The state directory code is largely duplicated from mach_bootstrap.py.
# We can't easily import mach_bootstrap.py because the bootstrapper may
# run in self-contained mode and only the files in this directory will
# be available. We /could/ refactor parts of mach_bootstrap.py to be
# part of this directory to avoid the code duplication.
state_dir, _ = get_state_dir()