Bug 1182677 - Aggressively prompt to run mach mercurial-setup; r=smacleod

Having not configured or out-of-date tools benefits nobody. It slows
people down.

Version control tools are an integral part of working on Firefox. It is
important for version control tools to be configured optimally and to be
continuously updated so they stay optimal.

The `mach mercurial-setup` command exists to optimally configure
Mercurial for working on Firefox and other Mozilla projects.

This commit adds a pre-dispatch handler to mach that will verify
Mercurial is in a happy state. If `mach mercurial-setup` has never
executed, it will complain. If `mach mercurial-setup` hasn't been
executed in the past 31 days, it will complain.

Yes, aborting command execution and forcing people to context switch to
run `mach mercurial-setup` is annoying. First, we have carved out
several exceptions to this behavior, including detection for running in
automation, on the machines of curmudgeons, when Mercurial isn't being
used, and from non-interactive processes. Second, I argue that people
ignore optional notifications and that having persistently
poorly-configured tools is worse than a single context switch at most
every month. Therefore, the heavyhanded approach is justified.

In addition, if we did support a non-fatal notification, we would
introduce the problem of extra output from commands. If anyone was e.g.
parsing mach output, we could very likely break those systems. These
cases should be caught by the isatty() check or be running in a context
with MOZ_AUTOMATION set. But you never know.

--HG--
extra : commitid : 7f7JQpa953u
extra : rebase_source : 47b6304b6ac2c9d8136f2023a7d03df7d1f45e4f
extra : source : f06616ee7b2b54d63d20ee4795539514d1df8c7b
This commit is contained in:
Gregory Szorc 2015-07-14 14:20:03 -07:00
parent 084089c2bc
commit 8b149c9e84

View File

@ -4,6 +4,7 @@
from __future__ import print_function, unicode_literals
import errno
import os
import platform
import sys
@ -22,6 +23,36 @@ use and re-run mach. For this change to take effect forever, you'll likely
want to export this environment variable from your shell's init scripts.
'''.lstrip()
NO_MERCURIAL_SETUP = '''
*** MERCURIAL NOT CONFIGURED ***
mach has detected that you have never run `mach mercurial-setup`.
Running this command will ensure your Mercurial version control tool is up
to date and optimally configured for a better, more productive experience
when working on Mozilla projects.
Please run `mach mercurial-setup` now.
'''.strip()
OLD_MERCURIAL_TOOLS = '''
*** MERCURIAL CONFIGURATION POTENTIALLY OUT OF DATE ***
mach has detected that it has been a while since you have run
`mach mercurial-setup`.
Having the latest Mercurial tools and configuration should lead to a better,
more productive experience when working on Mozilla projects.
Please run `mach mercurial-setup` now.
To avoid this message in the future, run `mach mercurial-setup` once a month.
Or, schedule `mach mercurial-setup --update-only` to run automatically in
the background at least once a month.
'''.strip()
MERCURIAL_SETUP_FATAL_INTERVAL = 31 * 24 * 60 * 60
# TODO Bug 794506 Integrate with the in-tree virtualenv configuration.
SEARCH_PATHS = [
@ -192,6 +223,54 @@ def bootstrap(topsrcdir, mozilla_dir=None):
sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
import mach.main
def pre_dispatch_handler(context, handler, args):
"""Perform global checks before command dispatch.
Currently, our goal is to ensure developers periodically run
`mach mercurial-setup` (when applicable) to ensure their Mercurial
tools are up to date.
"""
# Don't do anything when...
# The user is performing a maintenance command.
if handler.name in ('bootstrap', 'doctor', 'mercurial-setup'):
return
# We are running in automation.
if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
return
# We are a curmudgeon who has found this undocumented variable.
if 'I_PREFER_A_SUBOPTIMAL_MERCURIAL_EXPERIENCE' in os.environ:
return
# The environment is likely a machine invocation.
if not sys.stdin.isatty():
return
# Mercurial isn't managing this source checkout.
if not os.path.exists(os.path.join(topsrcdir, '.hg')):
return
state_dir = get_state_dir()[0]
last_check_path = os.path.join(state_dir, 'mercurial',
'setup.lastcheck')
mtime = None
try:
mtime = os.path.getmtime(last_check_path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
# No last run file means mercurial-setup has never completed.
if mtime is None:
print(NO_MERCURIAL_SETUP, file=sys.stderr)
sys.exit(2)
elif time.time() - mtime > MERCURIAL_SETUP_FATAL_INTERVAL:
print(OLD_MERCURIAL_TOOLS, file=sys.stderr)
sys.exit(2)
def populate_context(context, key=None):
if key is None:
return
@ -225,6 +304,9 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if key == 'topdir':
return topsrcdir
if key == 'pre_dispatch_handler':
return pre_dispatch_handler
raise AttributeError(key)
mach = mach.main.Mach(os.getcwd())