Last active
December 15, 2015 10:49
-
-
Save pfmoore/5248053 to your computer and use it in GitHub Desktop.
Virtualenv wrapper maker that (among other things) lets you specify things like -p 3.2 on Windows.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import sys | |
import shutil | |
import tempfile | |
import subprocess | |
from glob import glob | |
from argparse import ArgumentParser | |
ADDITIONAL_CODE = """ | |
import json | |
try: | |
import winreg | |
except ImportError: | |
import _winreg as winreg | |
try: | |
from urllib.parse import urlparse | |
except ImportError: | |
from urlparse import urlparse | |
try: | |
from urllib.request import url2pathname, pathname2url | |
except ImportError: | |
from urllib2 import url2pathname, pathname2url | |
def get_installed_pythons(): | |
python_core = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, | |
"Software\\Python\\PythonCore") | |
i = 0 | |
versions = [] | |
while True: | |
try: | |
versions.append(winreg.EnumKey(python_core, i)) | |
i = i + 1 | |
except WindowsError: | |
break | |
exes = dict() | |
for ver in versions: | |
path = winreg.QueryValue(python_core, "%s\\InstallPath" % ver) | |
exes[ver] = join(path, "python.exe") | |
winreg.CloseKey(python_core) | |
# Add the major versions | |
# Sort the keys, then repeatedly update the major version entry | |
# Last executable (i.e., highest version) wins with this approach | |
for ver in sorted(exes): | |
exes[ver[0]] = exes[ver] | |
return exes | |
def import_distlib(options): | |
try: | |
from distlib.locators import DirectoryLocator, AggregatingLocator | |
from distlib.wheel import Wheel | |
from distlib.compat import urlunparse | |
except ImportError: | |
for d in options.search_dirs: | |
candidates = glob.glob(join(d, 'distlib-*.whl')) | |
if candidates: | |
sys.path.append(candidates[0]) | |
break | |
try: | |
from distlib.locators import DirectoryLocator, AggregatingLocator | |
from distlib.wheel import Wheel | |
from distlib.compat import urlunparse | |
except ImportError: | |
return False, None, None, None | |
class WheelLocator(DirectoryLocator): | |
downloadable_extensions = ('.whl',) | |
return True, WheelLocator, AggregatingLocator, Wheel | |
def get_paths(python, name): | |
SCRIPT=''' | |
import sys | |
import json | |
from distutils.dist import Distribution | |
from distutils.command.install import install | |
d = Distribution({'name': sys.argv[1]}) | |
i = install(d) | |
i.initialize_options() | |
i.finalize_options() | |
paths = { | |
'prefix': i.prefix, | |
'purelib': i.install_purelib, | |
'platlib': i.install_platlib, | |
'scripts': i.install_scripts, | |
'headers': i.install_headers, | |
'data': i.install_data, | |
} | |
if hasattr(sys, 'real_prefix'): # virtualenv | |
paths['headers'] = os.path.join(sys.prefix, | |
'include', | |
'site', | |
'python' + sys.version[:3], | |
sys.argv[1]) | |
print(json.dumps(paths)) | |
''' | |
args = [python, '-c', SCRIPT, name] | |
popen = subprocess.Popen(args, stdout=subprocess.PIPE) | |
out, err = popen.communicate() | |
popen.wait() | |
return json.loads(out.decode('ascii')) | |
def wheelname(dist): | |
url = dist.download_url | |
return url2pathname(urlparse(url).path) | |
def extend_parser(parser): | |
parser.add_option('--extras', action='append', default=[], | |
help="Extra distributions to install") | |
wheels = [] | |
def adjust_options(options, args): | |
# Adjust the --python option to allow a version number which selects the | |
# installed Python of that version. | |
python_versions = get_installed_pythons() | |
if options.python in python_versions: | |
options.python = python_versions[options.python] | |
has_distlib, WheelLocator, AggregatingLocator, Wheel = import_distlib(options) | |
if has_distlib: | |
locator = AggregatingLocator(*[ | |
WheelLocator(d, recursive=False) for d in options.search_dirs | |
]) | |
if not options.no_pip: | |
pip = locator.locate('pip') | |
if pip: | |
wheels.append(Wheel(wheelname(pip))) | |
options.no_pip = True | |
if not options.no_setuptools: | |
setuptools = 'setuptools' | |
# If Python version > 2, always use distribute | |
# (use_distribute is set after adjust_options :-() | |
if majver > 2 or options.use_distribute: | |
setuptools = 'distribute' | |
setuptools = locator.locate(setuptools) | |
if setuptools: | |
wheels.append(Wheel(wheelname(setuptools))) | |
options.no_setuptools = True | |
for req in options.extras: | |
dist = locators.locate(req) | |
if dist: | |
wheels.append(Wheel(wheelname(dist))) | |
else: | |
logger.warn("Could not find requirement: %s" % (req,)) | |
else: | |
if options.extras: | |
logger.warn("Cannot install extras without distlib") | |
def after_install(options, home_dir): | |
if sys.platform == 'win32': | |
bin = 'Scripts' | |
python = 'python.exe' | |
else: | |
bin = 'bin' | |
python = 'python' | |
python = join(home_dir, bin, python) | |
paths = get_paths(python, '{}') | |
headers = paths['headers'] | |
for wheel in wheels: | |
paths['headers'] = headers.format(wheel.name) | |
logger.notify("Installing %s (%s)" % (wheel.name, wheel.version)) | |
wheel.install(paths, executable=python) | |
""" | |
def main(): | |
parser = ArgumentParser(description="Build a custom virtualenv installation") | |
parser.add_argument('--virtualenv', help="Location of virtualenv") | |
parser.add_argument('dest', help="The directory to contain the generated script") | |
args = parser.parse_args() | |
if args.virtualenv: | |
sys.path.insert(0, args.virtualenv) | |
import virtualenv | |
support = os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support') | |
script = virtualenv.create_bootstrap_script(ADDITIONAL_CODE) | |
# Fix up CRLF nastiness :-( | |
script = script.replace('\r\n', '\n') | |
script_name = os.path.join(args.dest, 'virtualenv.py') | |
support_dest = os.path.join(args.dest, 'virtualenv_support') | |
os.makedirs(args.dest) | |
with open(script_name, 'w') as f: | |
f.write(script) | |
shutil.copytree(support, support_dest) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment