mercurial/utils/resourceutil.py
author Martin von Zweigbergk <martinvonz@google.com>
Tue, 12 Apr 2022 21:25:56 -0700
changeset 49144 399439c12223
parent 49129 4ba27acdea63
child 49638 330d88217b83
permissions -rw-r--r--
rust-revlog: make unaware of `Repo` Differential Revision: https://phab.mercurial-scm.org/D12547
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
43712
664e24207728 procutil: move mainfrozen() to new resourceutil.py
Martin von Zweigbergk <martinvonz@google.com>
parents: 43701
diff changeset
     1
# resourceutil.py - utility for looking up resources
8226
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     2
#
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     3
#  Copyright 2005 K. Thananchayan <thananck@yahoo.com>
46819
d4ba4d51f85f contributor: change mentions of mpm to olivia
Raphaël Gomès <rgomes@octobus.net>
parents: 46411
diff changeset
     4
#  Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
8226
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     5
#  Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     6
#
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     7
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9996
diff changeset
     8
# GNU General Public License version 2 or any later version.
1082
ce96e316278a Update util.py docstrings, fix walk test
mpm@selenic.com
parents: 1081
diff changeset
     9
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    10
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    11
import imp
43713
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    12
import os
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    13
import sys
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43021
diff changeset
    14
43712
664e24207728 procutil: move mainfrozen() to new resourceutil.py
Martin von Zweigbergk <martinvonz@google.com>
parents: 43701
diff changeset
    15
from .. import pycompat
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
    16
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43021
diff changeset
    17
14228
116de1da2154 rename util.main_is_frozen to mainfrozen
Adrian Buehlmann <adrian@cadifra.com>
parents: 14167
diff changeset
    18
def mainfrozen():
6499
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
    19
    """return True if we are a frozen executable.
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
    20
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
    21
    The code supports py2exe (most common, Windows only) and tools/freeze
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
    22
    (portable, not much used).
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
    23
    """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 43021
diff changeset
    24
    return (
44802
6c8384afbf77 resourceutil: fix location of line comments
Manuel Jacob <me@manueljacob.de>
parents: 44174
diff changeset
    25
        pycompat.safehasattr(sys, "frozen")  # new py2exe
6c8384afbf77 resourceutil: fix location of line comments
Manuel Jacob <me@manueljacob.de>
parents: 44174
diff changeset
    26
        or pycompat.safehasattr(sys, "importers")  # old py2exe
6c8384afbf77 resourceutil: fix location of line comments
Manuel Jacob <me@manueljacob.de>
parents: 44174
diff changeset
    27
        or imp.is_frozen("__main__")  # tools/freeze
6c8384afbf77 resourceutil: fix location of line comments
Manuel Jacob <me@manueljacob.de>
parents: 44174
diff changeset
    28
    )
43713
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    29
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    30
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    31
# the location of data files matching the source code
44174
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    32
if mainfrozen() and getattr(sys, "frozen", None) != "macosx_app":
43713
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    33
    # executable version (py2exe) doesn't support __file__
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    34
    datapath = os.path.dirname(pycompat.sysexecutable)
44146
9e367157a990 resourceutil: correct the root path for file based lookup under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44136
diff changeset
    35
    _rootpath = datapath
44148
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    36
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    37
    # The installers store the files outside of library.zip, like
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    38
    # C:\Program Files\Mercurial\defaultrc\*.rc.  This strips the
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    39
    # leading "mercurial." off of the package name, so that these
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    40
    # pseudo resources are found in their directory next to the
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    41
    # executable.
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    42
    def _package_path(package):
44174
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    43
        dirs = package.split(b".")
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    44
        assert dirs[0] == b"mercurial"
44148
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    45
        return os.path.join(_rootpath, *dirs[1:])
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    46
44174
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    47
43713
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    48
else:
9fb85668ee15 util: move definition of datapath to resourceutil
Martin von Zweigbergk <martinvonz@google.com>
parents: 43712
diff changeset
    49
    datapath = os.path.dirname(os.path.dirname(pycompat.fsencode(__file__)))
44029
52f0140c2604 resourceutil: don't limit resources to the `mercurial` package
Matt Harbison <matt_harbison@yahoo.com>
parents: 43960
diff changeset
    50
    _rootpath = os.path.dirname(datapath)
43877
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    51
44148
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    52
    def _package_path(package):
44174
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    53
        return os.path.join(_rootpath, *package.split(b"."))
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    54
44148
aab70b540d3d resourceutil: account for the non-resource-like file hierarchy under py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 44146
diff changeset
    55
43877
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    56
try:
45463
dd9e28612468 resourceutil: document when we expect to take the importlib.resouces code path
Martin von Zweigbergk <martinvonz@google.com>
parents: 44802
diff changeset
    57
    # importlib.resources exists from Python 3.7; see fallback in except clause
dd9e28612468 resourceutil: document when we expect to take the importlib.resouces code path
Martin von Zweigbergk <martinvonz@google.com>
parents: 44802
diff changeset
    58
    # further down
48031
c0588d389c5f typing: suppress an import-error warning in `mercurial/utils/resourceutil.py`
Matt Harbison <matt_harbison@yahoo.com>
parents: 47911
diff changeset
    59
    from importlib import resources  # pytype: disable=import-error
43877
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    60
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    61
    # Force loading of the resources module
43960
75ec46c63657 resourceutil: use `from importlib import resources`
Martin von Zweigbergk <martinvonz@google.com>
parents: 43911
diff changeset
    62
    resources.open_binary  # pytype: disable=module-attr
43877
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    63
49129
4ba27acdea63 resourceutil: force filesystem access to resources when using py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 48966
diff changeset
    64
    # py2exe raises an AssertionError if uses importlib.resources
4ba27acdea63 resourceutil: force filesystem access to resources when using py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 48966
diff changeset
    65
    if getattr(sys, "frozen", None) in ("console_exe", "windows_exe"):
4ba27acdea63 resourceutil: force filesystem access to resources when using py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 48966
diff changeset
    66
        raise ImportError
4ba27acdea63 resourceutil: force filesystem access to resources when using py2exe
Matt Harbison <matt_harbison@yahoo.com>
parents: 48966
diff changeset
    67
43960
75ec46c63657 resourceutil: use `from importlib import resources`
Martin von Zweigbergk <martinvonz@google.com>
parents: 43911
diff changeset
    68
except (ImportError, AttributeError):
45463
dd9e28612468 resourceutil: document when we expect to take the importlib.resouces code path
Martin von Zweigbergk <martinvonz@google.com>
parents: 44802
diff changeset
    69
    # importlib.resources was not found (almost definitely because we're on a
dd9e28612468 resourceutil: document when we expect to take the importlib.resouces code path
Martin von Zweigbergk <martinvonz@google.com>
parents: 44802
diff changeset
    70
    # Python version before 3.7)
43877
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    71
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    72
    def open_resource(package, name):
1390bb81163e help: get helptext/ data from `resources` module if available
Martin von Zweigbergk <martinvonz@google.com>
parents: 43873
diff changeset
    73
        path = os.path.join(_package_path(package), name)
44174
27787a43712f resourceutil: blacken
Augie Fackler <augie@google.com>
parents: 44148
diff changeset
    74
        return open(path, "rb")
44030
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    75
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    76
    def is_resource(package, name):
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    77
        path = os.path.join(_package_path(package), name)
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    78
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    79
        try:
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    80
            return os.path.isfile(pycompat.fsdecode(path))
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    81
        except (IOError, OSError):
42a897bf678c resourceutil: implement `is_resource()`
Matt Harbison <matt_harbison@yahoo.com>
parents: 44029
diff changeset
    82
            return False
44031
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    83
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    84
    def contents(package):
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    85
        path = pycompat.fsdecode(_package_path(package))
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    86
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    87
        for p in os.listdir(path):
bba9149adc14 resourceutil: implement `contents()` to iterate over resources in a package
Matt Harbison <matt_harbison@yahoo.com>
parents: 44030
diff changeset
    88
            yield pycompat.fsencode(p)
47911
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    89
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    90
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    91
else:
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    92
    from .. import encoding
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    93
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    94
    def open_resource(package, name):
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    95
        return resources.open_binary(  # pytype: disable=module-attr
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    96
            pycompat.sysstr(package), pycompat.sysstr(name)
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    97
        )
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    98
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
    99
    def is_resource(package, name):
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   100
        return resources.is_resource(  # pytype: disable=module-attr
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   101
            pycompat.sysstr(package), encoding.strfromlocal(name)
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   102
        )
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   103
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   104
    def contents(package):
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   105
        # pytype: disable=module-attr
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   106
        for r in resources.contents(pycompat.sysstr(package)):
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   107
            # pytype: enable=module-attr
08f16b3331df resources: narrow the try:except clause to minimum
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47853
diff changeset
   108
            yield encoding.strtolocal(r)