diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -1286,6 +1286,12 @@ generic=True, ) coreconfigitem( + b'extensions', + b'[^:]*:required', + default=False, + generic=True, +) +coreconfigitem( b'extdata', b'.*', default=None, diff --git a/mercurial/extensions.py b/mercurial/extensions.py --- a/mercurial/extensions.py +++ b/mercurial/extensions.py @@ -314,10 +314,23 @@ else: error_msg = _(b'failed to import extension "%s": %s') error_msg %= (name, msg) - ui.warn((b"*** %s\n") % error_msg) - if isinstance(inst, error.Hint) and inst.hint: - ui.warn(_(b"*** (%s)\n") % inst.hint) - ui.traceback() + + ext_options = ui.configsuboptions(b"extensions", name)[1] + if stringutil.parsebool(ext_options.get(b"required", b'no')): + hint = None + if isinstance(inst, error.Hint) and inst.hint: + hint = inst.hint + if hint is None: + hint = _( + b"loading of this extension was required, " + b"see `hg help config.extensions` for details" + ) + raise error.Abort(error_msg, hint=hint) + else: + ui.warn((b"*** %s\n") % error_msg) + if isinstance(inst, error.Hint) and inst.hint: + ui.warn(_(b"*** (%s)\n") % inst.hint) + ui.traceback() ui.log( b'extension', diff --git a/mercurial/helptext/config.txt b/mercurial/helptext/config.txt --- a/mercurial/helptext/config.txt +++ b/mercurial/helptext/config.txt @@ -850,6 +850,17 @@ # (this extension will get loaded from the file specified) myfeature = ~/.hgext/myfeature.py +If an extension fails to load, a warning will be issued, and Mercurial will +proceed. To enforce that an extension must be loaded, one can set the `required` +suboption in the config:: + + [extensions] + myfeature = ~/.hgext/myfeature.py + myfeature:required = yes + +To debug extension loading issue, one can add `--traceback` to their mercurial +invocation. + ``format`` ---------- diff --git a/tests/test-extension.t b/tests/test-extension.t --- a/tests/test-extension.t +++ b/tests/test-extension.t @@ -1944,3 +1944,94 @@ hg: unknown command 'dummy' (did you mean summary?) [10] + +Check the mandatory extension feature +------------------------------------- + + $ hg init mandatory-extensions + $ cat > $TESTTMP/mandatory-extensions/.hg/good.py << EOF + > pass + > EOF + $ cat > $TESTTMP/mandatory-extensions/.hg/bad.py << EOF + > raise RuntimeError("babar") + > EOF + $ cat > $TESTTMP/mandatory-extensions/.hg/syntax.py << EOF + > def ( + > EOF + +Check that the good one load : + + $ cat > $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > [extensions] + > good = $TESTTMP/mandatory-extensions/.hg/good.py + > EOF + + $ hg -R mandatory-extensions id + 000000000000 tip + +Make it mandatory to load + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > good:required = yes + > EOF + + $ hg -R mandatory-extensions id + 000000000000 tip + +Check that the bad one does not load + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > bad = $TESTTMP/mandatory-extensions/.hg/bad.py + > EOF + + $ hg -R mandatory-extensions id + *** failed to import extension "bad" from $TESTTMP/mandatory-extensions/.hg/bad.py: babar + 000000000000 tip + +Make it mandatory to load + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > bad:required = yes + > EOF + + $ hg -R mandatory-extensions id + abort: failed to import extension "bad" from $TESTTMP/mandatory-extensions/.hg/bad.py: babar + (loading of this extension was required, see `hg help config.extensions` for details) + [255] + +Make it not mandatory to load + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > bad:required = no + > EOF + + $ hg -R mandatory-extensions id + *** failed to import extension "bad" from $TESTTMP/mandatory-extensions/.hg/bad.py: babar + 000000000000 tip + +Same check with the syntax error one + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > bad = ! + > syntax = $TESTTMP/mandatory-extensions/.hg/syntax.py + > syntax:required = yes + > EOF + + $ hg -R mandatory-extensions id + abort: failed to import extension "syntax" from $TESTTMP/mandatory-extensions/.hg/syntax.py: invalid syntax (*syntax.py, line 1) (glob) + (loading of this extension was required, see `hg help config.extensions` for details) + [255] + +Same check with a missing one + + $ cat >> $TESTTMP/mandatory-extensions/.hg/hgrc << EOF + > syntax = ! + > syntax:required = + > missing = foo/bar/baz/I/do/not/exist/ + > missing:required = yes + > EOF + + $ hg -R mandatory-extensions id + abort: failed to import extension "missing" from foo/bar/baz/I/do/not/exist/: [Errno 2] $ENOENT$: 'foo/bar/baz/I/do/not/exist' + (loading of this extension was required, see `hg help config.extensions` for details) + [255]