equal
deleted
inserted
replaced
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com> |
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com> |
4 # |
4 # |
5 # This software may be used and distributed according to the terms of the |
5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2 or any later version. |
6 # GNU General Public License version 2 or any later version. |
7 |
7 |
8 from __future__ import absolute_import |
|
9 |
8 |
10 import ast |
9 import ast |
11 import collections |
10 import collections |
12 import functools |
11 import functools |
13 import imp |
12 import imp |
72 '''return module with given extension name''' |
71 '''return module with given extension name''' |
73 mod = None |
72 mod = None |
74 try: |
73 try: |
75 mod = _extensions[name] |
74 mod = _extensions[name] |
76 except KeyError: |
75 except KeyError: |
77 for k, v in pycompat.iteritems(_extensions): |
76 for k, v in _extensions.items(): |
78 if k.endswith(b'.' + name) or k.endswith(b'/' + name): |
77 if k.endswith(b'.' + name) or k.endswith(b'/' + name): |
79 mod = v |
78 mod = v |
80 break |
79 break |
81 if not mod: |
80 if not mod: |
82 raise KeyError(name) |
81 raise KeyError(name) |
169 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo') |
168 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo') |
170 |
169 |
171 |
170 |
172 def _validatecmdtable(ui, cmdtable): |
171 def _validatecmdtable(ui, cmdtable): |
173 """Check if extension commands have required attributes""" |
172 """Check if extension commands have required attributes""" |
174 for c, e in pycompat.iteritems(cmdtable): |
173 for c, e in cmdtable.items(): |
175 f = e[0] |
174 f = e[0] |
176 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] |
175 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] |
177 if not missing: |
176 if not missing: |
178 continue |
177 continue |
179 raise error.ProgrammingError( |
178 raise error.ProgrammingError( |
577 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks, |
576 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks, |
578 synopsis, docstring) |
577 synopsis, docstring) |
579 ''' |
578 ''' |
580 assert callable(wrapper) |
579 assert callable(wrapper) |
581 aliases, entry = cmdutil.findcmd(command, table) |
580 aliases, entry = cmdutil.findcmd(command, table) |
582 for alias, e in pycompat.iteritems(table): |
581 for alias, e in table.items(): |
583 if e is entry: |
582 if e is entry: |
584 key = alias |
583 key = alias |
585 break |
584 break |
586 |
585 |
587 origfn = entry[0] |
586 origfn = entry[0] |
620 |
619 |
621 if currcls is object: |
620 if currcls is object: |
622 raise AttributeError("type '%s' has no property '%s'" % (cls, propname)) |
621 raise AttributeError("type '%s' has no property '%s'" % (cls, propname)) |
623 |
622 |
624 |
623 |
625 class wrappedfunction(object): |
624 class wrappedfunction: |
626 '''context manager for temporarily wrapping a function''' |
625 '''context manager for temporarily wrapping a function''' |
627 |
626 |
628 def __init__(self, container, funcname, wrapper): |
627 def __init__(self, container, funcname, wrapper): |
629 assert callable(wrapper) |
628 assert callable(wrapper) |
630 self._container = container |
629 self._container = container |
754 if not os.path.exists(path): |
753 if not os.path.exists(path): |
755 continue |
754 continue |
756 if name in exts or name in _order or name == b'__init__': |
755 if name in exts or name in _order or name == b'__init__': |
757 continue |
756 continue |
758 exts[name] = path |
757 exts[name] = path |
759 for name, path in pycompat.iteritems(_disabledextensions): |
758 for name, path in _disabledextensions.items(): |
760 # If no path was provided for a disabled extension (e.g. "color=!"), |
759 # If no path was provided for a disabled extension (e.g. "color=!"), |
761 # don't replace the path we already found by the scan above. |
760 # don't replace the path we already found by the scan above. |
762 if path: |
761 if path: |
763 exts[name] = path |
762 exts[name] = path |
764 return exts |
763 return exts |
816 try: |
815 try: |
817 from hgext import __index__ # pytype: disable=import-error |
816 from hgext import __index__ # pytype: disable=import-error |
818 |
817 |
819 return { |
818 return { |
820 name: gettext(desc) |
819 name: gettext(desc) |
821 for name, desc in pycompat.iteritems(__index__.docs) |
820 for name, desc in __index__.docs.items() |
822 if name not in _order |
821 if name not in _order |
823 } |
822 } |
824 except (ImportError, AttributeError): |
823 except (ImportError, AttributeError): |
825 pass |
824 pass |
826 |
825 |
827 paths = _disabledpaths() |
826 paths = _disabledpaths() |
828 if not paths: |
827 if not paths: |
829 return {} |
828 return {} |
830 |
829 |
831 exts = {} |
830 exts = {} |
832 for name, path in pycompat.iteritems(paths): |
831 for name, path in paths.items(): |
833 doc = _disabledhelp(path) |
832 doc = _disabledhelp(path) |
834 if doc and name != b'__index__': |
833 if doc and name != b'__index__': |
835 exts[name] = doc.splitlines()[0] |
834 exts[name] = stringutil.firstline(doc) |
836 |
835 |
837 return exts |
836 return exts |
838 |
837 |
839 |
838 |
840 def disabled_help(name): |
839 def disabled_help(name): |
874 if not node.args: |
873 if not node.args: |
875 continue |
874 continue |
876 a = node.args[0] |
875 a = node.args[0] |
877 if isinstance(a, ast.Str): |
876 if isinstance(a, ast.Str): |
878 name = pycompat.sysbytes(a.s) |
877 name = pycompat.sysbytes(a.s) |
879 elif pycompat.ispy3 and isinstance(a, ast.Bytes): |
878 elif isinstance(a, ast.Bytes): |
880 name = a.s |
879 name = a.s |
881 else: |
880 else: |
882 continue |
881 continue |
883 cmdtable[name] = (None, [], b'') |
882 cmdtable[name] = (None, [], b'') |
884 return cmdtable |
883 return cmdtable |
916 path = paths.pop(cmd, None) |
915 path = paths.pop(cmd, None) |
917 if path: |
916 if path: |
918 ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict) |
917 ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict) |
919 if not ext: |
918 if not ext: |
920 # otherwise, interrogate each extension until there's a match |
919 # otherwise, interrogate each extension until there's a match |
921 for name, path in pycompat.iteritems(paths): |
920 for name, path in paths.items(): |
922 ext = _finddisabledcmd(ui, cmd, name, path, strict=strict) |
921 ext = _finddisabledcmd(ui, cmd, name, path, strict=strict) |
923 if ext: |
922 if ext: |
924 break |
923 break |
925 if ext: |
924 if ext: |
926 return ext |
925 return ext |
934 for ename, ext in extensions(): |
933 for ename, ext in extensions(): |
935 doc = gettext(ext.__doc__) or _(b'(no help text available)') |
934 doc = gettext(ext.__doc__) or _(b'(no help text available)') |
936 assert doc is not None # help pytype |
935 assert doc is not None # help pytype |
937 if shortname: |
936 if shortname: |
938 ename = ename.split(b'.')[-1] |
937 ename = ename.split(b'.')[-1] |
939 exts[ename] = doc.splitlines()[0].strip() |
938 exts[ename] = stringutil.firstline(doc).strip() |
940 |
939 |
941 return exts |
940 return exts |
942 |
941 |
943 |
942 |
944 def notloaded(): |
943 def notloaded(): |
945 '''return short names of extensions that failed to load''' |
944 '''return short names of extensions that failed to load''' |
946 return [ |
945 return [name for name, mod in _extensions.items() if mod is None] |
947 name for name, mod in pycompat.iteritems(_extensions) if mod is None |
|
948 ] |
|
949 |
946 |
950 |
947 |
951 def moduleversion(module): |
948 def moduleversion(module): |
952 '''return version information from given module as a string''' |
949 '''return version information from given module as a string''' |
953 if util.safehasattr(module, b'getversion') and callable(module.getversion): |
950 if util.safehasattr(module, b'getversion') and callable(module.getversion): |