Bug 1336555 - Ensure that cargo-vendor is new enough when running `mach vendor rust`. r=ted
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 24 Feb 2017 13:14:16 -0500
changeset 489444 86c5b56e42f622716028f93ed5475e94c42920c4
parent 489443 20e91e72e991503d24dfbe7e373ebceef60f00e6
child 489445 c0c6529432da5e4049950dabe907bc32115ebed6
push id46822
push userbmo:emilio+bugs@crisal.io
push dateFri, 24 Feb 2017 20:50:08 +0000
reviewersted
bugs1336555
milestone54.0a1
Bug 1336555 - Ensure that cargo-vendor is new enough when running `mach vendor rust`. r=ted MozReview-Commit-ID: 3wQ5bA7ZpS5
python/mozbuild/mozbuild/vendor_rust.py
--- a/python/mozbuild/mozbuild/vendor_rust.py
+++ b/python/mozbuild/mozbuild/vendor_rust.py
@@ -8,16 +8,17 @@ from distutils.version import LooseVersi
 import logging
 from mozbuild.base import (
     BuildEnvironmentNotFoundException,
     MozbuildObject,
 )
 import mozfile
 import mozpack.path as mozpath
 import os
+import re
 import subprocess
 import sys
 
 class VendorRust(MozbuildObject):
     def get_cargo_path(self):
         try:
             return self.substs['CARGO']
         except (BuildEnvironmentNotFoundException, KeyError):
@@ -30,16 +31,29 @@ class VendorRust(MozbuildObject):
         Ensure that cargo is new enough. cargo 0.12 added support
         for source replacement, which is required for vendoring to work.
         '''
         out = subprocess.check_output([cargo, '--version']).splitlines()[0]
         if not out.startswith('cargo'):
             return False
         return LooseVersion(out.split()[1]) >= b'0.13'
 
+    def check_cargo_vendor_version(self, cargo):
+        '''
+        Ensure that cargo-vendor is new enough. cargo-vendor 0.1.3 and newer
+        strips out .gitattributes files which we want.
+        '''
+        for l in subprocess.check_output([cargo, 'install', '--list']).splitlines():
+            # The line looks like `cargo-vendor v0.1.3:`
+            m = re.match('cargo-vendor v((\d\.)*\d):', l)
+            if m:
+                version = m.group(1)
+                return LooseVersion(version) >= b'0.1.3'
+        return False
+
     def check_modified_files(self):
         '''
         Ensure that there aren't any uncommitted changes to files
         in the working copy, since we're going to change some state
         on the user. Allow changes to Cargo.{toml,lock} since that's
         likely to be a common use case.
         '''
         modified = [f for f in self.repository.get_modified_files() if os.path.basename(f) not in ('Cargo.toml', 'Cargo.lock')]
@@ -89,22 +103,27 @@ Please commit or stash these changes bef
         cargo = self.get_cargo_path()
         if not self.check_cargo_version(cargo):
             self.log(logging.ERROR, 'cargo_version', {}, 'Cargo >= 0.13 required (install Rust 1.12 or newer)')
             return
         else:
             self.log(logging.DEBUG, 'cargo_version', {}, 'cargo is new enough')
         have_vendor = any(l.strip() == 'vendor' for l in subprocess.check_output([cargo, '--list']).splitlines())
         if not have_vendor:
-            self.log(logging.INFO, 'installing', {}, 'Installing cargo-vendor')
+            self.log(logging.INFO, 'installing', {}, 'Installing cargo-vendor (this may take a few minutes)...')
             env = self.check_openssl()
             self.run_process(args=[cargo, 'install', 'cargo-vendor'],
                              append_env=env)
+        elif not self.check_cargo_vendor_version(cargo):
+            self.log(logging.INFO, 'cargo_vendor', {}, 'cargo-vendor >= 0.1.3 required; force-reinstalling (this may take a few minutes)...')
+            env = self.check_openssl()
+            self.run_process(args=[cargo, 'install', '--force', 'cargo-vendor'],
+                             append_env=env)
         else:
-            self.log(logging.DEBUG, 'cargo_vendor', {}, 'cargo-vendor already intalled')
+            self.log(logging.DEBUG, 'cargo_vendor', {}, 'sufficiently new cargo-vendor is already intalled')
         relative_vendor_dir = 'third_party/rust'
         vendor_dir = mozpath.join(self.topsrcdir, relative_vendor_dir)
         self.log(logging.INFO, 'rm_vendor_dir', {}, 'rm -rf %s' % vendor_dir)
         mozfile.remove(vendor_dir)
         # Once we require a new enough cargo to switch to workspaces, we can
         # just do this once on the workspace root crate.
         crates_and_roots = (
             ('gkrust', 'toolkit/library/rust'),