#!/usr/pkg/bin/python3.13
#
# thg - front-end script for TortoiseHg dialogs
#
# Copyright (C) 2008-2011 Steve Borho <steve@borho.org>
# Copyright (C) 2008 TK Soh <teekaysoh@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import annotations

import os
import sys


if hasattr(sys, "frozen"):
    if sys.frozen == 'windows_exe':
        # sys.stdin is invalid, should be None.  Fixes svn, git subrepos
        sys.stdin = None

        # py2exe blackholes stdout with a custom class to prevent random
        # exceptions when writing to it, but doesn't provide the ``.buffer``
        # attribute that mercurial.utils.procutil wants.  As of 0.11.1.0, it
        # also doesn't return the number of bytes written, and therefore
        # violates the interface contract.  For details, see:
        # https://github.com/py2exe/py2exe/blob/af0e841bffcf9c64abce6204718fecad17a59506/py2exe/boot_common.py#L3
        #
        # TODO: upstream write() return value and PROGRAMDATA usage in py2exe,
        #  and then most or all of this can go away.
        sys.stdout = open(os.devnull, "w")

        # py2exe writes its redirected stderr log file next to the executable
        # (so typically in %PROGRAMFILES%), but UAC blocks that when it is
        # enabled.  Replacing stderr with our own log file to an always
        # writeable area prevents that, fixes the missing write() return value,
        # and provides the `.buffer` attribute that procutil assumes is present.
        program_data = os.environ.get("PROGRAMDATA")

        if program_data is not None:
            import atexit, ctypes

            dir_name = os.path.join(program_data, "TortoiseHg")
            log_name = os.path.join(
                dir_name,
                os.path.splitext(
                    os.path.basename(sys.executable)
                )[0] + '.log'
            )

            try:
                os.makedirs(dir_name, exist_ok=True)
                sys.stderr = open(log_name, 'a', buffering=1)
            except Exception as details:
                sys.stderr = sys.stdout  # blackhole messages
                ctypes.windll.user32.MessageBoxW(
                    0,
                    "The logfile '%s' could not be opened:\n %s" % (
                        log_name, details,
                    ),
                    "Errors in %r" % os.path.basename(sys.executable),
                    0
                )
            else:
                orig_size = sys.stderr.seek(0, os.SEEK_END)

                def exit_check():
                    log_size = sys.stderr.tell()

                    if orig_size != log_size:
                        ctypes.windll.user32.MessageBoxW(
                            0,
                            "See the logfile '%s' for details" % log_name,
                            "Errors in %r" % os.path.basename(sys.executable),
                            0,
                        )

                atexit.register(exit_check)
        else:
            # py2exe messages come through sys.stderr; mercurial.ui.error()
            # messages come through sys.stderr.buffer.  Drop everything for the
            # *w.exe executable if the log file cannot be created, in order to
            # prevent various issues mentioned above.
            sys.stderr = sys.stdout

        # Make `pip install --user` packages visible, because py2exe doesn't
        # process sitecustomize.py.
        vi = sys.version_info
        sys.path.append(os.path.join(os.environ['APPDATA'], 'Python',
                                     'Python%d%d' % (vi[0], vi[1]),
                                     'site-packages'))

        if 'THGDEBUG' in os.environ:
            import win32traceutil
            print('starting')
    # os.Popen() needs this, and Mercurial still uses os.Popen
    if 'COMSPEC' not in os.environ and os.name == 'nt':
        comspec = os.path.join(os.environ.get('SystemRoot', r'C:\Windows'),
                               'system32', 'cmd.exe')
        os.environ['COMSPEC'] = comspec
else:
    thg_base_path = os.path.dirname(os.path.realpath(__file__))

    testpath = os.path.join(thg_base_path, 'tortoisehg')
    if os.path.isdir(testpath) and thg_base_path not in sys.path:
        sys.path.insert(0, thg_base_path)

    # compile .ui and .qrc for in-place use
    if os.path.exists(os.path.join(thg_base_path, 'setup.py')):
        # allow setuptools to patch distutils before we import Distribution
        from setup import build_ui
        from distutils.dist import Distribution
        build_ui(Distribution()).run()

    if 'HGPATH' in os.environ:
        hgpath = os.environ['HGPATH']
        testpath = os.path.join(hgpath, 'mercurial')
        if os.path.isdir(testpath) and hgpath not in sys.path:
            sys.path.insert(0, hgpath)

# Make sure to load threading by main thread; otherwise, _MainThread instance
# may have wrong thread id and results KeyError at exit.
import threading

from mercurial import demandimport
demandimport.IGNORES.update([
    'win32com.shell',
    'numpy',  # comtypes.npsupport does try-import
    'tortoisehg.util.config',
    'tortoisehg.hgqt.icons_rc',
    'tortoisehg.hgqt.translations_rc',
    # don't create troublesome demandmods for bunch of Q* attributes
    'tortoisehg.hgqt.qsci',
    'tortoisehg.hgqt.qtcore',
    'tortoisehg.hgqt.qtgui',
    'tortoisehg.hgqt.qtnetwork',
    # TODO: fix name resolution in demandimporter and remove these
    'qsci',
    'qtcore',
    'qtgui',
    'qtnetwork',
    # pygments seems to have trouble on loading plugins (see #4271, #4298)
    'pkgutil',
    'pkg_resources',
])
demandimport.enable()

# Verify we can reach TortoiseHg sources first
try:
    import tortoisehg.hgqt.run
except ImportError as e:
    sys.stderr.write(str(e)+'\n')
    sys.stderr.write("abort: couldn't find tortoisehg libraries in [%s]\n" %
                     os.pathsep.join(sys.path))
    sys.stderr.write("(check your install and PYTHONPATH)\n")
    sys.exit(-1)

tortoisehg.hgqt.run.run()
