Bug 1279563 - Offer to clone Firefox source repo during bootstrap; r?glandium draft
authorGregory Szorc <gps@mozilla.com>
Thu, 09 Jun 2016 16:19:51 -0700
changeset 377561 5c35408a4f0e59d681ca28e5b23359c54927b513
parent 377551 64255f3e255c5418d8d3fe964ff3e7942e3383f9
child 377562 4c28f949d747a4f54ca68e102224c01c7a33d4b3
push id20826
push userbmo:gps@mozilla.com
push dateFri, 10 Jun 2016 17:54:03 +0000
reviewersglandium
bugs1279563
milestone50.0a1
Bug 1279563 - Offer to clone Firefox source repo during bootstrap; r?glandium I've always been bothered that the one-line bootstrap configures your system then leaves you on the hook to clone source code and configure the build system. I'd like the bootstrap wizard to guide you through end-to-end. This commit addresses part of the disconnect by offering to clone the Mercurial source repository at the end of bootstrap. We only offer to clone if we aren't running from a Firefox source checkout (likely the one-line bootstrap invocation) and if we are in interactive mode. I'd like to eventually offer Git support here. Mercurial is the canonical repo, so it makes sense to start with that. MozReview-Commit-ID: 6TSZwxB3702
python/mozboot/mozboot/bootstrap.py
--- a/python/mozboot/mozboot/bootstrap.py
+++ b/python/mozboot/mozboot/bootstrap.py
@@ -77,18 +77,21 @@ Would you like to create this directory?
 
   1. Yes
   2. No
 
 Your choice:
 '''
 
 FINISHED = '''
-Your system should be ready to build %s! If you have not already,
-obtain a copy of the source code by running:
+Your system should be ready to build %s!
+'''
+
+SOURCE_ADVERTISE = '''
+Source code can be obtained by running
 
     hg clone https://hg.mozilla.org/mozilla-central
 
 Or, if you prefer Git, you should install git-cinnabar, and follow the
 instruction here to clone from the Mercurial repository:
 
     https://github.com/glandium/git-cinnabar/wiki/Mozilla:-A-git-workflow-for-Gecko-development
 
@@ -104,16 +107,25 @@ experience with it.
 Would you like to run a configuration wizard to ensure Mercurial is
 optimally configured?
 
   1. Yes
   2. No
 
 Please enter your reply: '''.lstrip()
 
+CLONE_MERCURIAL = '''
+If you would like to clone the canonical Mercurial repository, please
+enter the destination path below.
+
+(If you prefer to use Git, leave this blank.)
+
+Destination directory for Mercurial clone (leave empty to not clone): '''.lstrip()
+
+
 DEBIAN_DISTROS = (
     'Debian',
     'debian',
     'Ubuntu',
     # Most Linux Mint editions are based on Ubuntu. One is based on Debian.
     # The difference is reported in dist_id from platform.linux_distribution.
     # But it doesn't matter since we share a bootstrapper between Debian and
     # Ubuntu.
@@ -243,16 +255,33 @@ class Bootstrapper(object):
                 if choice == 1:
                     configure_hg = True
             else:
                 configure_hg = self.hg_configure
 
             if configure_hg:
                 configure_mercurial(self.instance.which('hg'), state_dir)
 
+        # Offer to clone if we're not inside a clone.
+        checkout_type = current_firefox_checkout(check_output=self.instance.check_output,
+                                                 hg=self.instance.which('hg'))
+        have_clone = False
+
+        if checkout_type:
+            have_clone = True
+        elif hg_installed and not self.instance.no_interactive:
+            dest = raw_input(CLONE_MERCURIAL)
+            dest = dest.strip()
+            if dest:
+                dest = os.path.expanduser(dest)
+                have_clone = clone_firefox(self.instance.which('hg'), dest)
+
+        if not have_clone:
+            print(SOURCE_ADVERTISE)
+
         print(self.finished % name)
 
         # Like 'suggest_browser_mozconfig' or 'suggest_mobile_android_mozconfig'.
         getattr(self.instance, 'suggest_%s_mozconfig' % application)()
 
 
 def update_vct(hg, root_state_dir):
     """Ensure version-control-tools in the state directory is up to date."""
@@ -308,8 +337,65 @@ def update_mercurial_repo(hg, url, dest,
     print('=' * 80)
     print('Ensuring %s is up to date at %s' % (url, dest))
 
     try:
         subprocess.check_call(args, cwd=cwd)
         subprocess.check_call([hg, 'update', '-r', revision], cwd=dest)
     finally:
         print('=' * 80)
+
+
+def clone_firefox(hg, dest):
+    """Clone the Firefox repository to a specified destination."""
+    print('Cloning Firefox Mercurial repository to %s' % dest)
+
+    args = [
+        hg,
+        'clone',
+        'https://hg.mozilla.org/mozilla-central',
+        dest,
+    ]
+
+    res = subprocess.call(args)
+    print('')
+    if res:
+        print('error cloning; please try again')
+        return False
+    else:
+        print('Firefox source code available at %s' % dest)
+        return True
+
+
+def current_firefox_checkout(check_output, hg=None):
+    """Determine whether we're in a Firefox checkout.
+
+    Returns one of None, ``git``, or ``hg``.
+    """
+    HG_ROOT_REVISIONS = set([
+        # From mozilla-central.
+        '8ba995b74e18334ab3707f27e9eb8f4e37ba3d29',
+    ])
+
+    path = os.getcwd()
+    while path:
+        hg_dir = os.path.join(path, '.hg')
+        git_dir = os.path.join(path, '.git')
+        if hg and os.path.exists(hg_dir):
+            # Verify the hg repo is a Firefox repo by looking at rev 0.
+            try:
+                node = check_output([hg, 'log', '-r', '0', '-T', '{node}'], cwd=path)
+                if node in HG_ROOT_REVISIONS:
+                    return 'hg'
+                # Else the root revision is different. There could be nested
+                # repos. So keep traversing the parents.
+            except subprocess.CalledProcessError:
+                pass
+
+        # TODO check git remotes for signs of Firefox.
+        elif os.path.exists(git_dir):
+            return 'git'
+
+        path, child = os.path.split(path)
+        if child == '':
+            break
+
+    return None