1"""Append module search paths for third-party packages to sys.path.
2
3****************************************************************
4* This module is automatically imported during initialization. *
5****************************************************************
6
7This is a UEFI-specific version of site.py.
8
9In earlier versions of Python (up to 1.5a3), scripts or modules that
10needed to use site-specific modules would place ``import site''
11somewhere near the top of their code.  Because of the automatic
12import, this is no longer necessary (but code that does it still
13works).
14
15This will append site-specific paths to the module search path.  It starts with sys.prefix and
16sys.exec_prefix (if different) and appends
17lib/python<version>/site-packages as well as lib/site-python.
18The
19resulting directories, if they exist, are appended to sys.path, and
20also inspected for path configuration files.
21
22A path configuration file is a file whose name has the form
23<package>.pth; its contents are additional directories (one per line)
24to be added to sys.path.  Non-existing directories (or
25non-directories) are never added to sys.path; no directory is added to
26sys.path more than once.  Blank lines and lines beginning with
27'#' are skipped. Lines starting with 'import' are executed.
28
29For example, suppose sys.prefix and sys.exec_prefix are set to
30/Efi/StdLib and there is a directory /Efi/StdLib/lib/python27.10/site-packages
31with three subdirectories, foo, bar and spam, and two path
32configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
33following:
34
35  # foo package configuration
36  foo
37  bar
38  bletch
39
40and bar.pth contains:
41
42  # bar package configuration
43  bar
44
45Then the following directories are added to sys.path, in this order:
46
47  /Efi/StdLib/lib/python27.10/site-packages/bar
48  /Efi/StdLib/lib/python27.10/site-packages/foo
49
50Note that bletch is omitted because it doesn't exist; bar precedes foo
51because bar.pth comes alphabetically before foo.pth; and spam is
52omitted because it is not mentioned in either path configuration file.
53
54After these path manipulations, an attempt is made to import a module
55named sitecustomize, which can perform arbitrary additional
56site-specific customizations.  If this import fails with an
57ImportError exception, it is silently ignored.
58
59Copyright (c) 2015, Daryl McDaniel. All rights reserved.<BR>
60Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
61This program and the accompanying materials are licensed and made available under
62the terms and conditions of the BSD License that accompanies this distribution.
63The full text of the license may be found at
64http://opensource.org/licenses/bsd-license.
65
66THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
67WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
68"""
69
70import sys
71import os
72import __builtin__
73import traceback
74
75# Prefixes for site-packages; add additional prefixes like /usr/local here
76PREFIXES = [sys.prefix, sys.exec_prefix]
77# Enable per user site-packages directory
78# set it to False to disable the feature or True to force the feature
79ENABLE_USER_SITE = False
80
81# for distutils.commands.install
82# These values are initialized by the getuserbase() and getusersitepackages()
83# functions, through the main() function when Python starts.
84USER_SITE = None
85USER_BASE = None
86
87
88def makepath(*paths):
89    dir = os.path.join(*paths)
90    try:
91        dir = os.path.abspath(dir)
92    except OSError:
93        pass
94    return dir, os.path.normcase(dir)
95
96
97def abs__file__():
98    """Set all module' __file__ attribute to an absolute path"""
99    for m in sys.modules.values():
100        if hasattr(m, '__loader__'):
101            continue   # don't mess with a PEP 302-supplied __file__
102        try:
103            m.__file__ = os.path.abspath(m.__file__)
104        except (AttributeError, OSError):
105            pass
106
107
108def removeduppaths():
109    """ Remove duplicate entries from sys.path along with making them
110    absolute"""
111    # This ensures that the initial path provided by the interpreter contains
112    # only absolute pathnames, even if we're running from the build directory.
113    L = []
114    known_paths = set()
115    for dir in sys.path:
116        # Filter out duplicate paths (on case-insensitive file systems also
117        # if they only differ in case); turn relative paths into absolute
118        # paths.
119        dir, dircase = makepath(dir)
120        if not dircase in known_paths:
121            L.append(dir)
122            known_paths.add(dircase)
123    sys.path[:] = L
124    return known_paths
125
126
127def _init_pathinfo():
128    """Return a set containing all existing directory entries from sys.path"""
129    d = set()
130    for dir in sys.path:
131        try:
132            if os.path.isdir(dir):
133                dir, dircase = makepath(dir)
134                d.add(dircase)
135        except TypeError:
136            continue
137    return d
138
139
140def addpackage(sitedir, name, known_paths):
141    """Process a .pth file within the site-packages directory:
142       For each line in the file, either combine it with sitedir to a path
143       and add that to known_paths, or execute it if it starts with 'import '.
144    """
145    if known_paths is None:
146        _init_pathinfo()
147        reset = 1
148    else:
149        reset = 0
150    fullname = os.path.join(sitedir, name)
151    try:
152        f = open(fullname, "rU")
153    except IOError:
154        return
155    with f:
156        for n, line in enumerate(f):
157            if line.startswith("#"):
158                continue
159            try:
160                if line.startswith(("import ", "import\t")):
161                    exec line
162                    continue
163                line = line.rstrip()
164                dir, dircase = makepath(sitedir, line)
165                if not dircase in known_paths and os.path.exists(dir):
166                    sys.path.append(dir)
167                    known_paths.add(dircase)
168            except Exception as err:
169                print >>sys.stderr, "Error processing line {:d} of {}:\n".format(
170                    n+1, fullname)
171                for record in traceback.format_exception(*sys.exc_info()):
172                    for line in record.splitlines():
173                        print >>sys.stderr, '  '+line
174                print >>sys.stderr, "\nRemainder of file ignored"
175                break
176    if reset:
177        known_paths = None
178    return known_paths
179
180
181def addsitedir(sitedir, known_paths=None):
182    """Add 'sitedir' argument to sys.path if missing and handle .pth files in
183    'sitedir'"""
184    if known_paths is None:
185        known_paths = _init_pathinfo()
186        reset = 1
187    else:
188        reset = 0
189    sitedir, sitedircase = makepath(sitedir)
190    if not sitedircase in known_paths:
191        sys.path.append(sitedir)        # Add path component
192    try:
193        names = os.listdir(sitedir)
194    except os.error:
195        return
196    dotpth = os.extsep + "pth"
197    names = [name for name in names if name.endswith(dotpth)]
198    for name in sorted(names):
199        addpackage(sitedir, name, known_paths)
200    if reset:
201        known_paths = None
202    return known_paths
203
204
205def check_enableusersite():
206    """Check if user site directory is safe for inclusion
207
208    The function tests for the command line flag (including environment var),
209    process uid/gid equal to effective uid/gid.
210
211    None: Disabled for security reasons
212    False: Disabled by user (command line option)
213    True: Safe and enabled
214    """
215    if sys.flags.no_user_site:
216        return False
217
218    if hasattr(os, "getuid") and hasattr(os, "geteuid"):
219        # check process uid == effective uid
220        if os.geteuid() != os.getuid():
221            return None
222    if hasattr(os, "getgid") and hasattr(os, "getegid"):
223        # check process gid == effective gid
224        if os.getegid() != os.getgid():
225            return None
226
227    return True
228
229def getuserbase():
230    """Returns the `user base` directory path.
231
232    The `user base` directory can be used to store data. If the global
233    variable ``USER_BASE`` is not initialized yet, this function will also set
234    it.
235    """
236    global USER_BASE
237    if USER_BASE is not None:
238        return USER_BASE
239    from sysconfig import get_config_var
240    USER_BASE = get_config_var('userbase')
241    return USER_BASE
242
243def getusersitepackages():
244    """Returns the user-specific site-packages directory path.
245
246    If the global variable ``USER_SITE`` is not initialized yet, this
247    function will also set it.
248    """
249    global USER_SITE
250    user_base = getuserbase() # this will also set USER_BASE
251
252    if USER_SITE is not None:
253        return USER_SITE
254
255    from sysconfig import get_path
256    import os
257
258    USER_SITE = get_path('purelib', '%s_user' % os.name)
259    return USER_SITE
260
261def addusersitepackages(known_paths):
262    """Add a per user site-package to sys.path
263
264    Each user has its own python directory with site-packages in the
265    home directory.
266    """
267    if ENABLE_USER_SITE and os.path.isdir(user_site):
268        # get the per user site-package path
269        # this call will also make sure USER_BASE and USER_SITE are set
270        user_site = getusersitepackages()
271
272        addsitedir(user_site, known_paths)
273    return known_paths
274
275def getsitepackages():
276    """Returns a list containing all global site-packages directories
277    (and possibly site-python).
278
279    For each directory present in the global ``PREFIXES``, this function
280    will find its `site-packages` subdirectory depending on the system
281    environment, and will return a list of full paths.
282    """
283    sitepackages = []
284    seen = set()
285
286    for prefix in PREFIXES:
287        if not prefix or prefix in seen:
288            continue
289        seen.add(prefix)
290
291        ix = sys.version.find(' ')
292        if ix != -1:
293            micro = sys.version[4:ix]
294        else:
295            micro = '0'
296
297        sitepackages.append(os.path.join(prefix, "lib",
298                                    "python" + sys.version[0] + sys.version[2] + '.' + micro,
299                                    "site-packages"))
300        sitepackages.append(os.path.join(prefix, "lib", "site-python"))
301    return sitepackages
302
303def addsitepackages(known_paths):
304    """Add site-packages (and possibly site-python) to sys.path"""
305    for sitedir in getsitepackages():
306        if os.path.isdir(sitedir):
307            addsitedir(sitedir, known_paths)
308
309    return known_paths
310
311def setBEGINLIBPATH():
312    """The UEFI port has optional extension modules that do double duty
313    as DLLs (even though they have .efi file extensions) for other extensions.
314    The library search path needs to be amended so these will be found
315    during module import.  Use BEGINLIBPATH so that these are at the start
316    of the library search path.
317
318    """
319    dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
320    libpath = os.environ['BEGINLIBPATH'].split(os.path.pathsep)
321    if libpath[-1]:
322        libpath.append(dllpath)
323    else:
324        libpath[-1] = dllpath
325    os.environ['BEGINLIBPATH'] = os.path.pathsep.join(libpath)
326
327
328def setquit():
329    """Define new builtins 'quit' and 'exit'.
330
331    These are objects which make the interpreter exit when called.
332    The repr of each object contains a hint at how it works.
333
334    """
335    eof = 'Ctrl-D (i.e. EOF)'
336
337    class Quitter(object):
338        def __init__(self, name):
339            self.name = name
340        def __repr__(self):
341            return 'Use %s() or %s to exit' % (self.name, eof)
342        def __call__(self, code=None):
343            # Shells like IDLE catch the SystemExit, but listen when their
344            # stdin wrapper is closed.
345            try:
346                sys.stdin.close()
347            except:
348                pass
349            raise SystemExit(code)
350    __builtin__.quit = Quitter('quit')
351    __builtin__.exit = Quitter('exit')
352
353
354class _Printer(object):
355    """interactive prompt objects for printing the license text, a list of
356    contributors and the copyright notice."""
357
358    MAXLINES = 23
359
360    def __init__(self, name, data, files=(), dirs=()):
361        self.__name = name
362        self.__data = data
363        self.__files = files
364        self.__dirs = dirs
365        self.__lines = None
366
367    def __setup(self):
368        if self.__lines:
369            return
370        data = None
371        for dir in self.__dirs:
372            for filename in self.__files:
373                filename = os.path.join(dir, filename)
374                try:
375                    fp = file(filename, "rU")
376                    data = fp.read()
377                    fp.close()
378                    break
379                except IOError:
380                    pass
381            if data:
382                break
383        if not data:
384            data = self.__data
385        self.__lines = data.split('\n')
386        self.__linecnt = len(self.__lines)
387
388    def __repr__(self):
389        self.__setup()
390        if len(self.__lines) <= self.MAXLINES:
391            return "\n".join(self.__lines)
392        else:
393            return "Type %s() to see the full %s text" % ((self.__name,)*2)
394
395    def __call__(self):
396        self.__setup()
397        prompt = 'Hit Return for more, or q (and Return) to quit: '
398        lineno = 0
399        while 1:
400            try:
401                for i in range(lineno, lineno + self.MAXLINES):
402                    print self.__lines[i]
403            except IndexError:
404                break
405            else:
406                lineno += self.MAXLINES
407                key = None
408                while key is None:
409                    key = raw_input(prompt)
410                    if key not in ('', 'q'):
411                        key = None
412                if key == 'q':
413                    break
414
415def setcopyright():
416    """Set 'copyright' and 'credits' in __builtin__"""
417    __builtin__.copyright = _Printer("copyright", sys.copyright)
418    __builtin__.credits = _Printer("credits", """\
419    Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
420    for supporting Python development.  See www.python.org for more information.""")
421    here = os.path.dirname(os.__file__)
422    __builtin__.license = _Printer(
423        "license", "See https://www.python.org/psf/license/",
424        ["LICENSE.txt", "LICENSE"],
425        [os.path.join(here, os.pardir), here, os.curdir])
426
427
428class _Helper(object):
429    """Define the builtin 'help'.
430    This is a wrapper around pydoc.help (with a twist).
431
432    """
433
434    def __repr__(self):
435        return "Type help() for interactive help, " \
436               "or help(object) for help about object."
437    def __call__(self, *args, **kwds):
438        import pydoc
439        return pydoc.help(*args, **kwds)
440
441def sethelper():
442    __builtin__.help = _Helper()
443
444def setencoding():
445    """Set the string encoding used by the Unicode implementation.  The
446    default is 'ascii', but if you're willing to experiment, you can
447    change this."""
448    encoding = "ascii" # Default value set by _PyUnicode_Init()
449    if 0:
450        # Enable to support locale aware default string encodings.
451        import locale
452        loc = locale.getdefaultlocale()
453        if loc[1]:
454            encoding = loc[1]
455    if 0:
456        # Enable to switch off string to Unicode coercion and implicit
457        # Unicode to string conversion.
458        encoding = "undefined"
459    if encoding != "ascii":
460        # On Non-Unicode builds this will raise an AttributeError...
461        sys.setdefaultencoding(encoding) # Needs Python Unicode build !
462
463
464def execsitecustomize():
465    """Run custom site specific code, if available."""
466    try:
467        import sitecustomize
468    except ImportError:
469        pass
470    except Exception:
471        if sys.flags.verbose:
472            sys.excepthook(*sys.exc_info())
473        else:
474            print >>sys.stderr, \
475                "'import sitecustomize' failed; use -v for traceback"
476
477
478def execusercustomize():
479    """Run custom user specific code, if available."""
480    try:
481        import usercustomize
482    except ImportError:
483        pass
484    except Exception:
485        if sys.flags.verbose:
486            sys.excepthook(*sys.exc_info())
487        else:
488            print>>sys.stderr, \
489                "'import usercustomize' failed; use -v for traceback"
490
491
492def main():
493    global ENABLE_USER_SITE
494
495    abs__file__()
496    known_paths = removeduppaths()
497    if ENABLE_USER_SITE is None:
498        ENABLE_USER_SITE = check_enableusersite()
499    known_paths = addusersitepackages(known_paths)
500    known_paths = addsitepackages(known_paths)
501    setquit()
502    setcopyright()
503    sethelper()
504    setencoding()
505    execsitecustomize()
506    # Remove sys.setdefaultencoding() so that users cannot change the
507    # encoding after initialization.  The test for presence is needed when
508    # this module is run as a script, because this code is executed twice.
509    if hasattr(sys, "setdefaultencoding"):
510        del sys.setdefaultencoding
511
512main()
513
514def _script():
515    help = """\
516    %s
517
518    Path elements are normally separated by '%s'.
519    """
520
521    print "sys.path = ["
522    for dir in sys.path:
523        print "    %r," % (dir,)
524    print "]"
525
526    import textwrap
527    print textwrap.dedent(help % (sys.argv[0], os.pathsep))
528    sys.exit(0)
529
530if __name__ == '__main__':
531    _script()
532