From 2232d33977735d6720f9ca1946614155baab7735 Mon Sep 17 00:00:00 2001 From: Michele Citterio Date: Mon, 30 Jun 2014 01:36:08 +0200 Subject: [PATCH] Fix Tcl inside a virtualenv on Windows (issue #93) --- virtualenv.py | 28 +++++++++++++ virtualenv_embedded/FixTk.py | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 virtualenv_embedded/FixTk.py diff --git a/virtualenv.py b/virtualenv.py index 68928126b..8df15c1cd 100755 --- a/virtualenv.py +++ b/virtualenv.py @@ -1191,6 +1191,9 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy site_filename_dst = change_prefix(site_filename, home_dir) site_dir = os.path.dirname(site_filename_dst) writefile(site_filename_dst, SITE_PY) + if is_win: + fixtk_filename = join(site_dir, 'FixTk.py') + writefile(fixtk_filename, FIXTK_PY) writefile(join(site_dir, 'orig-prefix.txt'), prefix) site_packages_filename = join(site_dir, 'no-global-site-packages.txt') if not site_packages: @@ -2001,6 +2004,31 @@ def convert(s): AVijEPwfucjncQ== """) +##file FixTk.py +FIXTK_PY = convert(""" +eJy9VltP4zgUfq/U/3AUHkg12dCB1e4ILbMqpTARTEGlMLOiKHJTl3rr2pXtlObf77GTtAlQlofV ++qFK7XP9zpUtllIZ0JkOQOpmo9nYgzPKSQYsf4nNnAlDFaTCMA7PFGZkRUFTA8PuVXwVnQ46g78C +y6clmBnB+4TH50xMemuapIaMueXRQCCZEZFQMBK4TIihwIy2jFQkcsLEE0yYoomRKgtzS+7EFG1I +BdLyLLDKEyKENDAX8hmV0aoNW27LyqaWfCLFfoXaJBxWVGkmBUqbsWRWkTlFk0GmxnI/MzPDzxIE +9CiE86opeINEnFsXKJ+iQ3IOTFjePyo2fR2F4Qi1urv73uA2uu5/DSxSRGRmZn1OuNQWE8tqbVSU +cCees7EiKsvVTGQBSW+9JGinzhZjyVmCVGKuQQq4Z9qQZsOo7LjZADyF7YnJllTnV/l3+Iyech7O +qRKUHx2GF9RgvAi/IWbWJwt6mn1DHZz+aDboOqFLA37khPWUkiqAjjGKjVND3f9WoW9Cp5BIgfia +eImSfF2+2KOoSZUANIRyTT/EQrTGB2CaCXQNM8fHJNVGtfBtz6ZsuFR0ytZWhCFIhDDwDMaZKf21 +J8W0gBPQ4YRillHfW4wT7bW2BLOcYAc2oy2hPV0Mj6HnDMHxreQA2usv7QDtOY+uevGg1zmLO8Ph +IDq9G/Zu67zV8znYfhe8t986g1zCbra+FDSAoyBnu77p9ePez+h2GPUvdjO11+3DtjsbO8+vOhfx +aad7eXcT3/a+d/rDqPuOtVZtBTGsrRy0E/jl83GdbQ+6eTnJJRXbkgzgiWHbSJd16m1WlDfjdLoN +RuLQjlPBbOhifJtS5aeehxgc/v7bl1Y1v/SHg7gz3/2ZCynqCYBT4eNHK9gNywuYW+j8/fXV3fde +3O/gz9l1BdIdlnVt9efanfI6ys6pE2i/xtgVje1jMCWYjBPwafgUgqDmWap53l/xtfVvcFvQ0MuH +Y1T1GLpG/EaJ7EH0JKSiCApxjXo0+nNUs1SHWKLKaNs4fW80sgQjr/XCcKtNP/x6/PgO712/+yYf +CvXgE7IfVdm3HjUbRTc4wUEW2m4S/i2Z8G2fsD01zp8DD9ux9Q0VuzQtaOka+6f2c6JS/x52qBVG +5SAMD5DNzA+wKedPH1O2eV0S5VLLc2Iwfz2UVEL8ShYZa9cOC2uKeYbzQuMgwJywhjuDA/yEaapw +cCicyUThREMiQemETpyP7/q3UVxrwhutRXy8ykDznG4mrFwqVkxJUYkVTmsQWFAFAUeV6PULpZXI +W9pa8F1sjl9XHN7nXbqGdgGyldJ6zVNxnmlrRi7kLfH2bB16qDn8iFpzzjInunKxxOEHw8vN+uNW +DFsYbgFixi08dppri0ZRqiU/PuF8rw3pcsvKL5HeFopRfnkfVvaHamAuPxaX1Q7kYN/M9z+hunrb +eZEzNc5VnsORmNC113oJZgXE/a1x+xbDVen+j1dr2RBzcLOW4W6EO9ki1aZMaEtCcftUdFOV201v +A0X08//KUbZ+O0fZ+j/IUSfkQzlacdjlqONsNv4BOP1jtw== +""") + ##file activate.sh ACTIVATE_SH = convert(""" eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+ diff --git a/virtualenv_embedded/FixTk.py b/virtualenv_embedded/FixTk.py new file mode 100644 index 000000000..e3b5d38a5 --- /dev/null +++ b/virtualenv_embedded/FixTk.py @@ -0,0 +1,78 @@ +import sys, os + +# Delay import _tkinter until we have set TCL_LIBRARY, +# so that Tcl_FindExecutable has a chance to locate its +# encoding directory. + +# Unfortunately, we cannot know the TCL_LIBRARY directory +# if we don't know the tcl version, which we cannot find out +# without import Tcl. Fortunately, Tcl will itself look in +# \..\tcl, so anything close to +# the real Tcl library will do. + +# Expand symbolic links on Vista +try: + import ctypes + ctypes.windll.kernel32.GetFinalPathNameByHandleW +except (ImportError, AttributeError): + def convert_path(s): + return s +else: + def convert_path(s): + assert isinstance(s, str) # sys.prefix contains only bytes + udir = s.decode("mbcs") + hdir = ctypes.windll.kernel32.\ + CreateFileW(udir, 0x80, # FILE_READ_ATTRIBUTES + 1, # FILE_SHARE_READ + None, 3, # OPEN_EXISTING + 0x02000000, # FILE_FLAG_BACKUP_SEMANTICS + None) + if hdir == -1: + # Cannot open directory, give up + return s + buf = ctypes.create_unicode_buffer(u"", 32768) + res = ctypes.windll.kernel32.\ + GetFinalPathNameByHandleW(hdir, buf, len(buf), + 0) # VOLUME_NAME_DOS + ctypes.windll.kernel32.CloseHandle(hdir) + if res == 0: + # Conversion failed (e.g. network location) + return s + s = buf[:res].encode("mbcs") + # Ignore leading \\?\ + if s.startswith("\\\\?\\"): + s = s[4:] + if s.startswith("UNC"): + s = "\\" + s[3:] + return s + +prefix = os.path.join(sys.real_prefix,"tcl") +if not os.path.exists(prefix): + # devdir/../tcltk/lib + prefix = os.path.join(sys.real_prefix, os.path.pardir, "tcltk", "lib") + prefix = os.path.abspath(prefix) +# if this does not exist, no further search is needed +if os.path.exists(prefix): + prefix = convert_path(prefix) + if "TCL_LIBRARY" not in os.environ: + for name in os.listdir(prefix): + if name.startswith("tcl"): + tcldir = os.path.join(prefix,name) + if os.path.isdir(tcldir): + os.environ["TCL_LIBRARY"] = tcldir + # Compute TK_LIBRARY, knowing that it has the same version + # as Tcl + import _tkinter + ver = str(_tkinter.TCL_VERSION) + if "TK_LIBRARY" not in os.environ: + v = os.path.join(prefix, 'tk'+ver) + if os.path.exists(os.path.join(v, "tclIndex")): + os.environ['TK_LIBRARY'] = v + # We don't know the Tix version, so we must search the entire + # directory + if "TIX_LIBRARY" not in os.environ: + for name in os.listdir(prefix): + if name.startswith("tix"): + tixdir = os.path.join(prefix,name) + if os.path.isdir(tixdir): + os.environ["TIX_LIBRARY"] = tixdir