1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
#!/usr/bin/env python
#
# 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()
|