First Regards Signés Commit. Caution : ldt is not installed in the virtualenv, we have to copy the ldt folder to the site-packages. Otherwise, it works perfectly.
--- a/.project Thu Sep 29 14:00:12 2011 +0200
+++ b/.project Fri Sep 30 16:06:04 2011 +0200
@@ -5,7 +5,13 @@
<projects>
</projects>
<buildSpec>
+ <buildCommand>
+ <name>org.python.pydev.PyDevBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
+ <nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/res/lib/lib_create_env.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,300 @@
+import sys
+import os
+import os.path
+import shutil
+import tarfile
+import zipfile
+import urllib
+import platform
+import patch
+
+join = os.path.join
+system_str = platform.system()
+
+
+URLS = {
+ #'': {'setup': '', 'url':'', 'local':''},
+ 'DISTRIBUTE': {'setup': 'distribute', 'url':'http://pypi.python.org/packages/source/d/distribute/distribute-0.6.14.tar.gz', 'local':"distribute-0.6.14.tar.gz"},
+ 'DJANGO': {'setup': 'django', 'url': 'http://www.djangoproject.com/download/1.3/tarball/', 'local':"Django-1.3.tar.gz"},
+ 'DJANGO-EXTENSIONS': { 'setup': 'django-extensions', 'url':'https://github.com/django-extensions/django-extensions/tarball/0.6', 'local':"django-extensions-0.6.tar.gz"},
+ 'DJANGO-REGISTRATION': { 'setup': 'django-registration', 'url':'http://bitbucket.org/ubernostrum/django-registration/get/tip.tar.gz', 'local':"django-registration.tar.gz"},
+ 'DJANGO-TAGGING': { 'setup': 'django-tagging', 'url':'http://django-tagging.googlecode.com/files/django-tagging-0.3.1.tar.gz', 'local':"django-tagging-0.3.1.tar.gz"},
+ 'DJANGO-PISTON': { 'setup': 'django-piston', 'url':"django-piston-0.2.2-modified.tar.gz", 'local':"django-piston-0.2.2-modified.tar.gz"},
+ 'OAUTH2': { 'setup': 'python-oauth2', 'url':"http://pypi.python.org/packages/source/o/oauth2/oauth2-1.5.168.tar.gz", 'local':"oauth2-1.5.167.tar.gz"},
+ 'HTTPLIB2': { 'setup': 'python-httplib2', 'url':'http://httplib2.googlecode.com/files/httplib2-0.6.0.tar.gz', 'local':"httplib2-0.6.0.tar.gz"},
+ 'DJANGO-OAUTH-PLUS': { 'setup': 'django-oauth-plus', 'url':'http://bitbucket.org/david/django-oauth-plus/get/f314f018e473.gz', 'local':"django-oauth-plus.tar.gz"},
+ 'MYSQL': { 'setup': 'mysql-python', 'url': 'http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download', 'local':"MySQL-python-1.2.3.tar.gz"},
+ 'SETUPTOOLS-HG': { 'setup':'mercurial_hg', 'url':'http://pypi.python.org/packages/source/s/setuptools_hg/setuptools_hg-0.2.tar.gz', 'local':"setuptools_hg-0.2.tar.gz"},
+ 'MERCURIAL': {'setup':'mercurial', 'url':'http://pypi.python.org/packages/source/d/mercurial/mercurial-1.7.5.tar.gz', 'local':"mercurial-1.7.5.tar.gz"},
+ 'OPENID': {'setup':'openid', 'url':'http://pypi.python.org/packages/source/p/python-openid/python-openid-2.2.5.tar.gz', 'local':"python-openid-2.2.5.tar.gz"},
+ 'DJANGO_OPENID_CONSUMER': {'setup':'django_openid_consumer', 'url':'http://pypi.python.org/packages/source/d/django-openid-consumer/django-openid-consumer-0.1.1.tar.gz', 'local':"django-openid-consumer-0.1.1.tar.gz"},
+ 'SOCIAL_AUTH': {'setup':'social_auth', 'url':'https://github.com/omab/django-social-auth/tarball/v0.3.10', 'local':"omab-django-social-auth-v0.3.10-modified.tar.gz"},
+ 'SOUTH': { 'setup': 'South', 'url':'http://www.aeracode.org/releases/south/south-0.7.3.tar.gz', 'local':"south-0.7.3.tar.gz"},
+}
+
+if system_str == 'Windows':
+ URLS.update({
+ 'PSYCOPG2': {'setup': 'psycopg2','url': 'psycopg2-2.0.14.win32-py2.6-pg8.4.3-release.zip', 'local':"psycopg2-2.0.14.win32-py2.6-pg8.4.3-release.zip"},
+ 'JCC': {'setup': 'jcc', 'url': 'http://pylucene-win32-binary.googlecode.com/files/JCC-2.6-py2.6-win32.egg', 'local':"JCC-2.6-py2.6-win32.egg"},
+ 'PYLUCENE': {'setup': 'pylucene', 'url': 'http://pylucene-win32-binary.googlecode.com/files/lucene-3.0.2-py2.6-win32.egg', 'local':"lucene-3.0.2-py2.6-win32.egg"},
+ 'PIL': {'setup': 'pil', 'url': 'http://effbot.org/media/downloads/PIL-1.1.7.win32-py2.6.exe', 'local':"PIL-1.1.7.win32-py2.6.exe"},
+ 'LXML': {'setup': 'lxml', 'url': 'http://pypi.python.org/packages/2.6/l/lxml/lxml-2.2.2-py2.6-win32.egg', 'local':"lxml-2.2.2-py2.6-win32.egg"}
+ })
+else:
+ URLS.update({
+ 'PSYCOPG2': {'setup': 'psycopg2','url': 'http://www.psycopg.org/psycopg/tarballs/PSYCOPG-2-4/psycopg2-2.4.tar.gz', 'local':"psycopg2-2.4.tar.gz"},
+ 'PYLUCENE': {'setup': 'pylucene', 'url': 'http://apache.crihan.fr/dist//lucene/pylucene/pylucene-3.1.0-1-src.tar.gz', 'local':"pylucene-3.1.0-1-src.tar.gz"},
+ 'PIL': {'setup': 'pil', 'url': 'http://effbot.org/downloads/Imaging-1.1.7.tar.gz', 'local':"Imaging-1.1.7.tar.gz"},
+ 'LXML': {'setup': 'lxml', 'url':"lxml-2.3.tar.bz2", 'local':"lxml-2.3.tar.bz2"}
+ })
+
+
+
+class ResourcesEnv(object):
+
+ def __init__(self, src_base, urls, normal_installs):
+ self.src_base = src_base
+ self.URLS = {}
+ self.__init_url(urls)
+ self.NORMAL_INSTALL = normal_installs
+
+ def get_src_base_path(self, fpath):
+ return os.path.abspath(os.path.join(self.src_base, fpath)).replace("\\","/")
+
+ def __add_package_def(self, key, setup, url, local):
+ self.URLS[key] = {'setup':setup, 'url':url, 'local':self.get_src_base_path(local)}
+
+ def __init_url(self, urls):
+ for key, url_dict in urls.items():
+ url = url_dict['url']
+ if not url.startswith("http://"):
+ url = self.get_src_base_path(url)
+ self.__add_package_def(key, url_dict["setup"], url, url_dict["local"])
+
+def ensure_dir(dir, logger):
+ if not os.path.exists(dir):
+ logger.notify('Creating directory %s' % dir)
+ os.makedirs(dir)
+
+def extend_parser(parser):
+ parser.add_option(
+ '--index-url',
+ metavar='INDEX_URL',
+ dest='index_url',
+ default='http://pypi.python.org/simple/',
+ help='base URL of Python Package Index')
+ parser.add_option(
+ '--type-install',
+ metavar='type_install',
+ dest='type_install',
+ default='local',
+ help='type install : local, url, setup')
+ parser.add_option(
+ '--ignore-packages',
+ metavar='ignore_packages',
+ dest='ignore_packages',
+ default=None,
+ help='list of comma separated keys for package to ignore')
+
+def adjust_options(options, args):
+ pass
+
+
+def install_pylucene(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
+
+ logger.notify("Get Pylucene from %s " % res_env.URLS['PYLUCENE'][res_source_key])
+ pylucene_src = os.path.join(src_dir,"pylucene.tar.gz")
+ if res_source_key == 'local':
+ shutil.copy(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
+ else:
+ urllib.urlretrieve(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
+ tf = tarfile.open(pylucene_src,'r:gz')
+ pylucene_base_path = os.path.join(src_dir,"pylucene")
+ logger.notify("Extract Pylucene to %s " % pylucene_base_path)
+ tf.extractall(pylucene_base_path)
+ tf.close()
+
+ pylucene_src_path = os.path.join(pylucene_base_path, os.listdir(pylucene_base_path)[0])
+ jcc_src_path = os.path.abspath(os.path.join(pylucene_src_path,"jcc"))
+
+ #install jcc
+
+ #patch for linux
+ if system_str == 'Linux' :
+ olddir = os.getcwd()
+ setuptools_path = os.path.join(lib_dir, 'site-packages', 'setuptools')
+ if os.path.exists(setuptools_path) and os.path.isdir(setuptools_path):
+ patch_dest_path = os.path.join(lib_dir, 'site-packages')
+ else:
+ patch_dest_path = os.path.join(lib_dir,'site-packages','setuptools-0.6c11-py%s.%s.egg' % (sys.version_info[0], sys.version_info[1]))
+ if os.path.isfile(patch_dest_path):
+ # must unzip egg
+ # rename file and etract all
+ shutil.move(patch_dest_path, patch_dest_path + ".zip")
+ zf = zipfile.ZipFile(patch_dest_path + ".zip",'r')
+ zf.extractall(patch_dest_path)
+ os.remove(patch_dest_path + ".zip")
+ logger.notify("Patch jcc : %s " % (patch_dest_path))
+ os.chdir(patch_dest_path)
+ p = patch.fromfile(os.path.join(jcc_src_path,"jcc","patches","patch.43.0.6c11"))
+ p.apply()
+ os.chdir(olddir)
+
+ logger.notify("Install jcc")
+ call_subprocess([os.path.abspath(os.path.join(home_dir, 'bin', 'python')), 'setup.py', 'install'],
+ cwd=jcc_src_path,
+ filter_stdout=filter_python_develop,
+ show_stdout=True)
+ #install pylucene
+
+ logger.notify("Install pylucene")
+ #modify makefile
+ makefile_path = os.path.join(pylucene_src_path,"Makefile")
+ logger.notify("Modify makefile %s " % makefile_path)
+ shutil.move( makefile_path, makefile_path+"~" )
+
+ destination= open( makefile_path, "w" )
+ source= open( makefile_path+"~", "r" )
+ destination.write("PREFIX_PYTHON="+os.path.abspath(home_dir)+"\n")
+ destination.write("ANT=ant\n")
+ destination.write("PYTHON=$(PREFIX_PYTHON)/bin/python\n")
+
+ if system_str == "Darwin":
+ if sys.version_info >= (2,6):
+ destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\n")
+ else:
+ destination.write("JCC=$(PYTHON) -m jcc --shared --arch x86_64 --arch i386\n")
+ destination.write("NUM_FILES=2\n")
+ elif system_str == "Windows":
+ destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\n")
+ destination.write("NUM_FILES=2\n")
+ else:
+ if sys.version_info >= (2,6) and sys.version_info <= (2,7):
+ destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared\n")
+ else:
+ destination.write("JCC=$(PYTHON) -m jcc --shared\n")
+ destination.write("NUM_FILES=2\n")
+ for line in source:
+ destination.write( line )
+ source.close()
+ destination.close()
+ os.remove(makefile_path+"~" )
+
+ logger.notify("pylucene make")
+ call_subprocess(['make'],
+ cwd=os.path.abspath(pylucene_src_path),
+ filter_stdout=filter_python_develop,
+ show_stdout=True)
+
+ logger.notify("pylucene make install")
+ call_subprocess(['make', 'install'],
+ cwd=os.path.abspath(pylucene_src_path),
+ filter_stdout=filter_python_develop,
+ show_stdout=True)
+
+
+def install_psycopg2(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
+ psycopg2_src = os.path.join(src_dir,"psycopg2.zip")
+ shutil.copy(res_env.URLS['PSYCOPG2'][res_source_key], psycopg2_src)
+ #extract psycopg2
+ zf = zipfile.ZipFile(psycopg2_src)
+ psycopg2_base_path = os.path.join(src_dir,"psycopg2")
+ zf.extractall(psycopg2_base_path)
+ zf.close()
+
+ psycopg2_src_path = os.path.join(psycopg2_base_path, os.listdir(psycopg2_base_path)[0])
+ shutil.copytree(os.path.join(psycopg2_src_path, 'psycopg2'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'psycopg2')))
+ shutil.copy(os.path.join(psycopg2_src_path, 'psycopg2-2.0.14-py2.6.egg-info'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'site-packages')))
+
+
+
+def lib_generate_install_methods(path_locations, src_base, Logger, call_subprocess, normal_installs, urls=None):
+
+ all_urls = URLS.copy()
+ if urls is not None:
+ all_urls.update(urls)
+
+ res_env = ResourcesEnv(src_base, all_urls, normal_installs)
+
+ def filter_python_develop(line):
+ if not line.strip():
+ return Logger.DEBUG
+ for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ',
+ 'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
+ 'creating ', 'Copying ']:
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.NOTIFY
+
+
+ def normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess):
+ logger.notify("Install %s from %s with %s" % (key,res_env.URLS[key][res_source_key],method))
+ if method == 'pip':
+ if sys.platform == 'win32':
+ args = [os.path.abspath(os.path.join(home_dir, 'Scripts', 'pip')), 'install', '-E', os.path.abspath(home_dir), res_env.URLS[key][res_source_key]]
+ else:
+ args = [os.path.abspath(os.path.join(home_dir, 'bin', 'pip')), 'install', '-E', os.path.abspath(home_dir), res_env.URLS[key][res_source_key]]
+ if option_str :
+ args.insert(4,option_str)
+ call_subprocess(args,
+ cwd=os.path.abspath(tmp_dir),
+ filter_stdout=filter_python_develop,
+ show_stdout=True,
+ extra_env=extra_env)
+ else:
+ if sys.platform == 'win32':
+ args = [os.path.abspath(os.path.join(home_dir, 'Scripts', 'easy_install')), res_env.URLS[key][res_source_key]]
+ else:
+ args = [os.path.abspath(os.path.join(home_dir, 'bin', 'easy_install')), res_env.URLS[key][res_source_key]]
+ if option_str :
+ args.insert(1,option_str)
+ call_subprocess(args,
+ cwd=os.path.abspath(tmp_dir),
+ filter_stdout=filter_python_develop,
+ show_stdout=True,
+ extra_env=extra_env)
+
+
+ def after_install(options, home_dir):
+
+ global logger
+
+ verbosity = options.verbose - options.quiet
+ logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
+
+
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ base_dir = os.path.dirname(home_dir)
+ src_dir = os.path.join(home_dir, 'src')
+ tmp_dir = os.path.join(home_dir, 'tmp')
+ ensure_dir(src_dir, logger)
+ ensure_dir(tmp_dir, logger)
+ system_str = platform.system()
+
+ res_source_key = options.type_install
+
+ ignore_packages = []
+
+ if options.ignore_packages :
+ ignore_packages = options.ignore_packages.split(",")
+
+ logger.indent += 2
+ try:
+ for key, method, option_str, extra_env in res_env.NORMAL_INSTALL:
+ if key not in ignore_packages:
+ if callable(method):
+ method(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop)
+ else:
+ normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess)
+
+ logger.notify("Clear source dir")
+ shutil.rmtree(src_dir)
+
+ finally:
+ logger.indent -= 2
+ script_dir = join(base_dir, bin_dir)
+ logger.notify('Run "%s Package" to install new packages that provide builds'
+ % join(script_dir, 'easy_install'))
+
+
+ return adjust_options, extend_parser, after_install
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/res/lib/patch.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,589 @@
+""" Patch utility to apply unified diffs
+
+ Brute-force line-by-line non-recursive parsing
+
+ Copyright (c) 2008-2010 anatoly techtonik
+ Available under the terms of MIT license
+
+ Project home: http://code.google.com/p/python-patch/
+
+
+ $Id: patch.py 76 2010-04-08 19:10:21Z techtonik $
+ $HeadURL: https://python-patch.googlecode.com/svn/trunk/patch.py $
+"""
+
+__author__ = "techtonik.rainforce.org"
+__version__ = "10.04"
+
+import copy
+import logging
+import re
+# cStringIO doesn't support unicode in 2.5
+from StringIO import StringIO
+from logging import debug, info, warning
+
+from os.path import exists, isfile, abspath
+from os import unlink
+
+
+#------------------------------------------------
+# Logging is controlled by "python_patch" logger
+
+debugmode = False
+
+logger = logging.getLogger("python_patch")
+loghandler = logging.StreamHandler()
+logger.addHandler(loghandler)
+
+debug = logger.debug
+info = logger.info
+warning = logger.warning
+
+#: disable library logging by default
+logger.setLevel(logging.CRITICAL)
+
+#------------------------------------------------
+
+
+def fromfile(filename):
+ """ Parse patch file and return Patch() object
+ """
+
+ info("reading patch from file %s" % filename)
+ fp = open(filename, "rb")
+ patch = Patch(fp)
+ fp.close()
+ return patch
+
+
+def fromstring(s):
+ """ Parse text string and return Patch() object
+ """
+
+ return Patch(
+ StringIO.StringIO(s)
+ )
+
+
+
+class HunkInfo(object):
+ """ Parsed hunk data container (hunk starts with @@ -R +R @@) """
+
+ def __init__(self):
+ self.startsrc=None #: line count starts with 1
+ self.linessrc=None
+ self.starttgt=None
+ self.linestgt=None
+ self.invalid=False
+ self.text=[]
+
+ def copy(self):
+ return copy.copy(self)
+
+# def apply(self, estream):
+# """ write hunk data into enumerable stream
+# return strings one by one until hunk is
+# over
+#
+# enumerable stream are tuples (lineno, line)
+# where lineno starts with 0
+# """
+# pass
+
+
+
+class Patch(object):
+
+ def __init__(self, stream=None):
+
+ # define Patch data members
+ # table with a row for every source file
+
+ #: list of source filenames
+ self.source=None
+ self.target=None
+ #: list of lists of hunks
+ self.hunks=None
+ #: file endings statistics for every hunk
+ self.hunkends=None
+
+ if stream:
+ self.parse(stream)
+
+ def copy(self):
+ return copy.copy(self)
+
+ def parse(self, stream):
+ """ parse unified diff """
+ self.source = []
+ self.target = []
+ self.hunks = []
+ self.hunkends = []
+
+ # define possible file regions that will direct the parser flow
+ header = False # comments before the patch body
+ filenames = False # lines starting with --- and +++
+
+ hunkhead = False # @@ -R +R @@ sequence
+ hunkbody = False #
+ hunkskip = False # skipping invalid hunk mode
+
+ header = True
+ lineends = dict(lf=0, crlf=0, cr=0)
+ nextfileno = 0
+ nexthunkno = 0 #: even if index starts with 0 user messages number hunks from 1
+
+ # hunkinfo holds parsed values, hunkactual - calculated
+ hunkinfo = HunkInfo()
+ hunkactual = dict(linessrc=None, linestgt=None)
+
+ fe = enumerate(stream)
+ for lineno, line in fe:
+
+ # analyze state
+ if header and line.startswith("--- "):
+ header = False
+ # switch to filenames state
+ filenames = True
+ #: skip hunkskip and hunkbody code until you read definition of hunkhead
+ if hunkbody:
+ # process line first
+ if re.match(r"^[- \+\\]", line):
+ # gather stats about line endings
+ if line.endswith("\r\n"):
+ self.hunkends[nextfileno-1]["crlf"] += 1
+ elif line.endswith("\n"):
+ self.hunkends[nextfileno-1]["lf"] += 1
+ elif line.endswith("\r"):
+ self.hunkends[nextfileno-1]["cr"] += 1
+
+ if line.startswith("-"):
+ hunkactual["linessrc"] += 1
+ elif line.startswith("+"):
+ hunkactual["linestgt"] += 1
+ elif not line.startswith("\\"):
+ hunkactual["linessrc"] += 1
+ hunkactual["linestgt"] += 1
+ hunkinfo.text.append(line)
+ # todo: handle \ No newline cases
+ else:
+ warning("invalid hunk no.%d at %d for target file %s" % (nexthunkno, lineno+1, self.target[nextfileno-1]))
+ # add hunk status node
+ self.hunks[nextfileno-1].append(hunkinfo.copy())
+ self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True
+ # switch to hunkskip state
+ hunkbody = False
+ hunkskip = True
+
+ # check exit conditions
+ if hunkactual["linessrc"] > hunkinfo.linessrc or hunkactual["linestgt"] > hunkinfo.linestgt:
+ warning("extra hunk no.%d lines at %d for target %s" % (nexthunkno, lineno+1, self.target[nextfileno-1]))
+ # add hunk status node
+ self.hunks[nextfileno-1].append(hunkinfo.copy())
+ self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True
+ # switch to hunkskip state
+ hunkbody = False
+ hunkskip = True
+ elif hunkinfo.linessrc == hunkactual["linessrc"] and hunkinfo.linestgt == hunkactual["linestgt"]:
+ self.hunks[nextfileno-1].append(hunkinfo.copy())
+ # switch to hunkskip state
+ hunkbody = False
+ hunkskip = True
+
+ # detect mixed window/unix line ends
+ ends = self.hunkends[nextfileno-1]
+ if ((ends["cr"]!=0) + (ends["crlf"]!=0) + (ends["lf"]!=0)) > 1:
+ warning("inconsistent line ends in patch hunks for %s" % self.source[nextfileno-1])
+ if debugmode:
+ debuglines = dict(ends)
+ debuglines.update(file=self.target[nextfileno-1], hunk=nexthunkno)
+ debug("crlf: %(crlf)d lf: %(lf)d cr: %(cr)d\t - file: %(file)s hunk: %(hunk)d" % debuglines)
+
+ if hunkskip:
+ match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line)
+ if match:
+ # switch to hunkhead state
+ hunkskip = False
+ hunkhead = True
+ elif line.startswith("--- "):
+ # switch to filenames state
+ hunkskip = False
+ filenames = True
+ if debugmode and len(self.source) > 0:
+ debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1]))
+
+ if filenames:
+ if line.startswith("--- "):
+ if nextfileno in self.source:
+ warning("skipping invalid patch for %s" % self.source[nextfileno])
+ del self.source[nextfileno]
+ # double source filename line is encountered
+ # attempt to restart from this second line
+ re_filename = "^--- ([^\t]+)"
+ match = re.match(re_filename, line)
+ # todo: support spaces in filenames
+ if match:
+ self.source.append(match.group(1).strip())
+ else:
+ warning("skipping invalid filename at line %d" % lineno)
+ # switch back to header state
+ filenames = False
+ header = True
+ elif not line.startswith("+++ "):
+ if nextfileno in self.source:
+ warning("skipping invalid patch with no target for %s" % self.source[nextfileno])
+ del self.source[nextfileno]
+ else:
+ # this should be unreachable
+ warning("skipping invalid target patch")
+ filenames = False
+ header = True
+ else:
+ if nextfileno in self.target:
+ warning("skipping invalid patch - double target at line %d" % lineno)
+ del self.source[nextfileno]
+ del self.target[nextfileno]
+ nextfileno -= 1
+ # double target filename line is encountered
+ # switch back to header state
+ filenames = False
+ header = True
+ else:
+ re_filename = "^\+\+\+ ([^\t]+)"
+ match = re.match(re_filename, line)
+ if not match:
+ warning("skipping invalid patch - no target filename at line %d" % lineno)
+ # switch back to header state
+ filenames = False
+ header = True
+ else:
+ self.target.append(match.group(1).strip())
+ nextfileno += 1
+ # switch to hunkhead state
+ filenames = False
+ hunkhead = True
+ nexthunkno = 0
+ self.hunks.append([])
+ self.hunkends.append(lineends.copy())
+ continue
+
+ if hunkhead:
+ match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line)
+ if not match:
+ if nextfileno-1 not in self.hunks:
+ warning("skipping invalid patch with no hunks for file %s" % self.target[nextfileno-1])
+ # switch to header state
+ hunkhead = False
+ header = True
+ continue
+ else:
+ # switch to header state
+ hunkhead = False
+ header = True
+ else:
+ hunkinfo.startsrc = int(match.group(1))
+ hunkinfo.linessrc = 1
+ if match.group(3): hunkinfo.linessrc = int(match.group(3))
+ hunkinfo.starttgt = int(match.group(4))
+ hunkinfo.linestgt = 1
+ if match.group(6): hunkinfo.linestgt = int(match.group(6))
+ hunkinfo.invalid = False
+ hunkinfo.text = []
+
+ hunkactual["linessrc"] = hunkactual["linestgt"] = 0
+
+ # switch to hunkbody state
+ hunkhead = False
+ hunkbody = True
+ nexthunkno += 1
+ continue
+ else:
+ if not hunkskip:
+ warning("patch file incomplete - %s" % filename)
+ # sys.exit(?)
+ else:
+ # duplicated message when an eof is reached
+ if debugmode and len(self.source) > 0:
+ debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1]))
+
+ info("total files: %d total hunks: %d" % (len(self.source), sum(len(hset) for hset in self.hunks)))
+
+
+ def apply(self):
+ """ apply parsed patch """
+
+ total = len(self.source)
+ for fileno, filename in enumerate(self.source):
+
+ f2patch = filename
+ if not exists(f2patch):
+ f2patch = self.target[fileno]
+ if not exists(f2patch):
+ warning("source/target file does not exist\n--- %s\n+++ %s" % (filename, f2patch))
+ continue
+ if not isfile(f2patch):
+ warning("not a file - %s" % f2patch)
+ continue
+ filename = f2patch
+
+ info("processing %d/%d:\t %s" % (fileno+1, total, filename))
+
+ # validate before patching
+ f2fp = open(filename)
+ hunkno = 0
+ hunk = self.hunks[fileno][hunkno]
+ hunkfind = []
+ hunkreplace = []
+ validhunks = 0
+ canpatch = False
+ for lineno, line in enumerate(f2fp):
+ if lineno+1 < hunk.startsrc:
+ continue
+ elif lineno+1 == hunk.startsrc:
+ hunkfind = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " -"]
+ hunkreplace = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " +"]
+ #pprint(hunkreplace)
+ hunklineno = 0
+
+ # todo \ No newline at end of file
+
+ # check hunks in source file
+ if lineno+1 < hunk.startsrc+len(hunkfind)-1:
+ if line.rstrip("\r\n") == hunkfind[hunklineno]:
+ hunklineno+=1
+ else:
+ debug("hunk no.%d doesn't match source file %s" % (hunkno+1, filename))
+ # file may be already patched, but we will check other hunks anyway
+ hunkno += 1
+ if hunkno < len(self.hunks[fileno]):
+ hunk = self.hunks[fileno][hunkno]
+ continue
+ else:
+ break
+
+ # check if processed line is the last line
+ if lineno+1 == hunk.startsrc+len(hunkfind)-1:
+ debug("file %s hunk no.%d -- is ready to be patched" % (filename, hunkno+1))
+ hunkno+=1
+ validhunks+=1
+ if hunkno < len(self.hunks[fileno]):
+ hunk = self.hunks[fileno][hunkno]
+ else:
+ if validhunks == len(self.hunks[fileno]):
+ # patch file
+ canpatch = True
+ break
+ else:
+ if hunkno < len(self.hunks[fileno]):
+ warning("premature end of source file %s at hunk %d" % (filename, hunkno+1))
+
+ f2fp.close()
+
+ if validhunks < len(self.hunks[fileno]):
+ if self._match_file_hunks(filename, self.hunks[fileno]):
+ warning("already patched %s" % filename)
+ else:
+ warning("source file is different - %s" % filename)
+ if canpatch:
+ backupname = filename+".orig"
+ if exists(backupname):
+ warning("can't backup original file to %s - aborting" % backupname)
+ else:
+ import shutil
+ shutil.move(filename, backupname)
+ if self.write_hunks(backupname, filename, self.hunks[fileno]):
+ warning("successfully patched %s" % filename)
+ unlink(backupname)
+ else:
+ warning("error patching file %s" % filename)
+ shutil.copy(filename, filename+".invalid")
+ warning("invalid version is saved to %s" % filename+".invalid")
+ # todo: proper rejects
+ shutil.move(backupname, filename)
+
+ # todo: check for premature eof
+
+
+ def can_patch(self, filename):
+ """ Check if specified filename can be patched. Returns None if file can
+ not be found among source filenames. False if patch can not be applied
+ clearly. True otherwise.
+
+ :returns: True, False or None
+ """
+ idx = self._get_file_idx(filename, source=True)
+ if idx == None:
+ return None
+ return self._match_file_hunks(filename, self.hunks[idx])
+
+
+ def _match_file_hunks(self, filepath, hunks):
+ matched = True
+ fp = open(abspath(filepath))
+
+ class NoMatch(Exception):
+ pass
+
+ lineno = 1
+ line = fp.readline()
+ hno = None
+ try:
+ for hno, h in enumerate(hunks):
+ # skip to first line of the hunk
+ while lineno < h.starttgt:
+ if not len(line): # eof
+ debug("check failed - premature eof before hunk: %d" % (hno+1))
+ raise NoMatch
+ line = fp.readline()
+ lineno += 1
+ for hline in h.text:
+ if hline.startswith("-"):
+ continue
+ if not len(line):
+ debug("check failed - premature eof on hunk: %d" % (hno+1))
+ # todo: \ No newline at the end of file
+ raise NoMatch
+ if line.rstrip("\r\n") != hline[1:].rstrip("\r\n"):
+ debug("file is not patched - failed hunk: %d" % (hno+1))
+ raise NoMatch
+ line = fp.readline()
+ lineno += 1
+
+ except NoMatch:
+ matched = False
+ # todo: display failed hunk, i.e. expected/found
+
+ fp.close()
+ return matched
+
+
+ def patch_stream(self, instream, hunks):
+ """ Generator that yields stream patched with hunks iterable
+
+ Converts lineends in hunk lines to the best suitable format
+ autodetected from input
+ """
+
+ # todo: At the moment substituted lineends may not be the same
+ # at the start and at the end of patching. Also issue a
+ # warning/throw about mixed lineends (is it really needed?)
+
+ hunks = iter(hunks)
+
+ srclineno = 1
+
+ lineends = {'\n':0, '\r\n':0, '\r':0}
+ def get_line():
+ """
+ local utility function - return line from source stream
+ collecting line end statistics on the way
+ """
+ line = instream.readline()
+ # 'U' mode works only with text files
+ if line.endswith("\r\n"):
+ lineends["\r\n"] += 1
+ elif line.endswith("\n"):
+ lineends["\n"] += 1
+ elif line.endswith("\r"):
+ lineends["\r"] += 1
+ return line
+
+ for hno, h in enumerate(hunks):
+ debug("hunk %d" % (hno+1))
+ # skip to line just before hunk starts
+ while srclineno < h.startsrc:
+ yield get_line()
+ srclineno += 1
+
+ for hline in h.text:
+ # todo: check \ No newline at the end of file
+ if hline.startswith("-") or hline.startswith("\\"):
+ get_line()
+ srclineno += 1
+ continue
+ else:
+ if not hline.startswith("+"):
+ get_line()
+ srclineno += 1
+ line2write = hline[1:]
+ # detect if line ends are consistent in source file
+ if sum([bool(lineends[x]) for x in lineends]) == 1:
+ newline = [x for x in lineends if lineends[x] != 0][0]
+ yield line2write.rstrip("\r\n")+newline
+ else: # newlines are mixed
+ yield line2write
+
+ for line in instream:
+ yield line
+
+
+ def write_hunks(self, srcname, tgtname, hunks):
+ src = open(srcname, "rb")
+ tgt = open(tgtname, "wb")
+
+ debug("processing target file %s" % tgtname)
+
+ tgt.writelines(self.patch_stream(src, hunks))
+
+ tgt.close()
+ src.close()
+ return True
+
+
+ def _get_file_idx(self, filename, source=None):
+ """ Detect index of given filename within patch.
+
+ :param filename:
+ :param source: search filename among sources (True),
+ targets (False), or both (None)
+ :returns: int or None
+ """
+ filename = abspath(filename)
+ if source == True or source == None:
+ for i,fnm in enumerate(self.source):
+ if filename == abspath(fnm):
+ return i
+ if source == False or source == None:
+ for i,fnm in enumerate(self.target):
+ if filename == abspath(fnm):
+ return i
+
+
+
+
+from optparse import OptionParser
+from os.path import exists
+import sys
+
+if __name__ == "__main__":
+ opt = OptionParser(usage="%prog [options] unipatch-file", version="python-patch %s" % __version__)
+ opt.add_option("--debug", action="store_true", dest="debugmode", help="debug mode")
+ (options, args) = opt.parse_args()
+
+ if not args:
+ opt.print_version()
+ opt.print_help()
+ sys.exit()
+ debugmode = options.debugmode
+ patchfile = args[0]
+ if not exists(patchfile) or not isfile(patchfile):
+ sys.exit("patch file does not exist - %s" % patchfile)
+
+
+ if debugmode:
+ loglevel = logging.DEBUG
+ logformat = "%(levelname)8s %(message)s"
+ else:
+ loglevel = logging.INFO
+ logformat = "%(message)s"
+ logger.setLevel(loglevel)
+ loghandler.setFormatter(logging.Formatter(logformat))
+
+
+
+ patch = fromfile(patchfile)
+ #pprint(patch)
+ patch.apply()
+
+ # todo: document and test line ends handling logic - patch.py detects proper line-endings
+ # for inserted hunks and issues a warning if patched file has incosistent line ends
Binary file virtualenv/res/src/Django-1.3.tar.gz has changed
Binary file virtualenv/res/src/Imaging-1.1.7.tar.gz has changed
Binary file virtualenv/res/src/JCC-2.6-py2.6-win32.egg has changed
Binary file virtualenv/res/src/MySQL-python-1.2.3.tar.gz has changed
Binary file virtualenv/res/src/PIL-1.1.7.win32-py2.6.exe has changed
Binary file virtualenv/res/src/distribute-0.6.14.tar.gz has changed
Binary file virtualenv/res/src/django-extensions-0.6.tar.gz has changed
Binary file virtualenv/res/src/django-oauth-plus.tar.gz has changed
Binary file virtualenv/res/src/django-openid-consumer-0.1.1.tar.gz has changed
Binary file virtualenv/res/src/django-piston-0.2.2-modified.tar.gz has changed
Binary file virtualenv/res/src/django-registration.tar.gz has changed
Binary file virtualenv/res/src/django-tagging-0.3.1.tar.gz has changed
Binary file virtualenv/res/src/httplib2-0.6.0.tar.gz has changed
Binary file virtualenv/res/src/lucene-3.0.2-py2.6-win32.egg has changed
Binary file virtualenv/res/src/lxml-2.2.2-py2.6-win32.egg has changed
Binary file virtualenv/res/src/lxml-2.3.tar.bz2 has changed
Binary file virtualenv/res/src/mercurial-1.7.5.tar.gz has changed
Binary file virtualenv/res/src/oauth2-1.5.167.tar.gz has changed
Binary file virtualenv/res/src/omab-django-social-auth-v0.3.10-modified.tar.gz has changed
Binary file virtualenv/res/src/psycopg2-2.0.14.win32-py2.6-pg8.4.3-release.zip has changed
Binary file virtualenv/res/src/psycopg2-2.4.tar.gz has changed
Binary file virtualenv/res/src/pylucene-3.1.0-1-src.tar.gz has changed
Binary file virtualenv/res/src/python-openid-2.2.5.tar.gz has changed
Binary file virtualenv/res/src/setuptools_hg-0.2.tar.gz has changed
Binary file virtualenv/res/src/south-0.7.3.tar.gz has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/setup/create_python_env.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,64 @@
+"""
+Call this like ``python create_python_env.py``; it will
+refresh the project-boot.py script
+
+-prerequisite:
+
+- virtualenv
+
+- python project-boot.py --unzip-setuptools --no-site-packages --clear --type-install=local <path_to_venv>
+
+"""
+
+import os
+import subprocess
+import re
+import sys
+
+
+here = os.path.dirname(os.path.abspath(__file__))
+base_dir = here
+script_name = os.path.join(base_dir, 'project-boot.py')
+
+import virtualenv
+
+# things to install
+# - psycopg2 -> pip
+# - PIL -> pip
+# - pyxml -> pip
+# - 4Suite-xml - easy_install ftp://ftp.4suite.org/pub/4Suite/4Suite-XML-1.0.2.tar.bz2
+# - pylucene - script
+
+src_base = os.path.abspath(os.path.join(here,"..","res","src")).replace("\\","/")
+lib_path = os.path.abspath(os.path.join(here,"..","res","lib")).replace("\\","/")
+patch_path = os.path.abspath(os.path.join(here,"res","patch")).replace("\\","/")
+
+
+EXTRA_TEXT = "import sys\n"
+EXTRA_TEXT += "sys.path.append('%s')\n" % (lib_path)
+EXTRA_TEXT += "sys.path.append('%s')\n" % (os.path.abspath(os.path.join(here,"res")).replace("\\","/"))
+EXTRA_TEXT += "from res_create_env import generate_install_methods\n"
+EXTRA_TEXT += "adjust_options, extend_parser, after_install = generate_install_methods(path_locations, '%s', Logger, call_subprocess)\n" % (src_base)
+
+
+def main():
+ python_version = ".".join(map(str,sys.version_info[0:2]))
+ text = virtualenv.create_bootstrap_script(EXTRA_TEXT, python_version=python_version)
+ if os.path.exists(script_name):
+ f = open(script_name)
+ cur_text = f.read()
+ f.close()
+ else:
+ cur_text = ''
+ print 'Updating %s' % script_name
+ if cur_text == 'text':
+ print 'No update'
+ else:
+ print 'Script changed; updating...'
+ f = open(script_name, 'w')
+ f.write(text)
+ f.close()
+
+if __name__ == '__main__':
+ main()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/setup/res/res_create_env.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,15 @@
+import platform
+
+from lib_create_env import lib_generate_install_methods, install_pylucene, install_psycopg2
+
+system_str = platform.system()
+
+
+INSTALLS = [#(key,method, option_str, dict_extra_env)
+ ('DISTRIBUTE', 'pip', None, None),
+ ('MERCURIAL', 'pip', None, None),
+ ('SETUPTOOLS-HG', 'pip', None, None),
+]
+
+def generate_install_methods(path_locations, src_base, Logger, call_subprocess):
+ return lib_generate_install_methods(path_locations, src_base, Logger, call_subprocess, INSTALLS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/create_python_env.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,75 @@
+"""
+Call this like ``python create_python_env.py``; it will
+refresh the project-boot.py script
+
+-prerequisite:
+
+- virtualenv
+- distribute
+- psycopg2 requires the PostgreSQL libpq libraries and the pg_config utility
+
+- python project-boot.py --distribute --no-site-packages --index-url=http://pypi.websushi.org/ --clear --type-install=local --ignore-packages=MYSQL <path_to_venv>
+- python project-boot.py --no-site-packages --clear --ignore-packages=MYSQL --type-install=local <path_to_venv>
+- For Linux :
+python project-boot.py --unzip-setuptools --no-site-packages --index-url=http://pypi.websushi.org/ --clear --type-install=local <path_to_venv>
+
+"""
+
+import os
+import subprocess
+import re
+import sys
+
+
+here = os.path.dirname(os.path.abspath(__file__))
+base_dir = here
+script_name = os.path.join(base_dir, 'project-boot.py')
+
+import virtualenv
+
+# things to install
+# - psycopg2 -> pip
+# - PIL -> pip
+# - pyxml -> pip
+# - 4Suite-xml - easy_install ftp://ftp.4suite.org/pub/4Suite/4Suite-XML-1.0.2.tar.bz2
+# - pylucene - script
+
+src_base = os.path.abspath(os.path.join(here,"..","res","src")).replace("\\","/")
+lib_path = os.path.abspath(os.path.join(here,"..","res","lib")).replace("\\","/")
+patch_path = os.path.abspath(os.path.join(here,"res","patch")).replace("\\","/")
+
+
+EXTRA_TEXT = "import sys\n"
+EXTRA_TEXT += "sys.path.append('%s')\n" % (lib_path)
+EXTRA_TEXT += "sys.path.append('%s')\n" % (os.path.abspath(os.path.join(here,"res")).replace("\\","/"))
+EXTRA_TEXT += "from res_create_env import generate_install_methods\n"
+EXTRA_TEXT += "adjust_options, extend_parser, after_install = generate_install_methods(path_locations, '%s', Logger, call_subprocess)\n" % (src_base)
+
+
+
+#f = open(os.path.join(os.path. os.path.join(os.path.dirname(os.path.abspath(__file__)),"res"),'res_create_env.py'), 'r')
+#EXTRA_TEXT += f.read()
+#EXTRA_TEXT += "\n"
+#EXTRA_TEXT += "RES_ENV = ResourcesEnv('%s')\n" % (src_base)
+
+def main():
+ python_version = ".".join(map(str,sys.version_info[0:2]))
+ text = virtualenv.create_bootstrap_script(EXTRA_TEXT, python_version=python_version)
+ if os.path.exists(script_name):
+ f = open(script_name)
+ cur_text = f.read()
+ f.close()
+ else:
+ cur_text = ''
+ print 'Updating %s' % script_name
+ if cur_text == 'text':
+ print 'No update'
+ else:
+ print 'Script changed; updating...'
+ f = open(script_name, 'w')
+ f.write(text)
+ f.close()
+
+if __name__ == '__main__':
+ main()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/project-boot.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,1963 @@
+#!/usr/bin/env python2.6
+## WARNING: This file is generated
+#!/usr/bin/env python
+"""Create a "virtual" Python installation
+"""
+
+# If you change the version here, change it in setup.py
+# and docs/conf.py as well.
+virtualenv_version = "1.6.4"
+
+import base64
+import sys
+import os
+import optparse
+import re
+import shutil
+import logging
+import tempfile
+import zlib
+import errno
+import distutils.sysconfig
+try:
+ import subprocess
+except ImportError:
+ if sys.version_info <= (2, 3):
+ print('ERROR: %s' % sys.exc_info()[1])
+ print('ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.')
+ print('If you copy subprocess.py from a newer version of Python this script will probably work')
+ sys.exit(101)
+ else:
+ raise
+try:
+ set
+except NameError:
+ from sets import Set as set
+try:
+ basestring
+except NameError:
+ basestring = str
+
+join = os.path.join
+py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
+
+is_jython = sys.platform.startswith('java')
+is_pypy = hasattr(sys, 'pypy_version_info')
+is_win = (sys.platform == 'win32')
+abiflags = getattr(sys, 'abiflags', '')
+
+if is_pypy:
+ expected_exe = 'pypy'
+elif is_jython:
+ expected_exe = 'jython'
+else:
+ expected_exe = 'python'
+
+
+REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
+ 'fnmatch', 'locale', 'encodings', 'codecs',
+ 'stat', 'UserDict', 'readline', 'copy_reg', 'types',
+ 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
+ 'zlib']
+
+REQUIRED_FILES = ['lib-dynload', 'config']
+
+majver, minver = sys.version_info[:2]
+if majver == 2:
+ if minver >= 6:
+ REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
+ if minver >= 7:
+ REQUIRED_MODULES.extend(['_weakrefset'])
+ if minver <= 3:
+ REQUIRED_MODULES.extend(['sets', '__future__'])
+elif majver == 3:
+ # Some extra modules are needed for Python 3, but different ones
+ # for different versions.
+ REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',
+ '_weakrefset', 'copyreg', 'tempfile', 'random',
+ '__future__', 'collections', 'keyword', 'tarfile',
+ 'shutil', 'struct', 'copy'])
+ if minver >= 2:
+ REQUIRED_FILES[-1] = 'config-%s' % majver
+ if minver == 3:
+ # The whole list of 3.3 modules is reproduced below - the current
+ # uncommented ones are required for 3.3 as of now, but more may be
+ # added as 3.3 development continues.
+ REQUIRED_MODULES.extend([
+ #"aifc",
+ #"antigravity",
+ #"argparse",
+ #"ast",
+ #"asynchat",
+ #"asyncore",
+ "base64",
+ #"bdb",
+ #"binhex",
+ "bisect",
+ #"calendar",
+ #"cgi",
+ #"cgitb",
+ #"chunk",
+ #"cmd",
+ #"codeop",
+ #"code",
+ #"colorsys",
+ #"_compat_pickle",
+ #"compileall",
+ #"concurrent",
+ #"configparser",
+ #"contextlib",
+ #"cProfile",
+ #"crypt",
+ #"csv",
+ #"ctypes",
+ #"curses",
+ #"datetime",
+ #"dbm",
+ #"decimal",
+ #"difflib",
+ #"dis",
+ #"doctest",
+ #"dummy_threading",
+ "_dummy_thread",
+ #"email",
+ #"filecmp",
+ #"fileinput",
+ #"formatter",
+ #"fractions",
+ #"ftplib",
+ #"functools",
+ #"getopt",
+ #"getpass",
+ #"gettext",
+ #"glob",
+ #"gzip",
+ "hashlib",
+ "heapq",
+ "hmac",
+ #"html",
+ #"http",
+ #"idlelib",
+ #"imaplib",
+ #"imghdr",
+ #"importlib",
+ #"inspect",
+ #"json",
+ #"lib2to3",
+ #"logging",
+ #"macpath",
+ #"macurl2path",
+ #"mailbox",
+ #"mailcap",
+ #"_markupbase",
+ #"mimetypes",
+ #"modulefinder",
+ #"multiprocessing",
+ #"netrc",
+ #"nntplib",
+ #"nturl2path",
+ #"numbers",
+ #"opcode",
+ #"optparse",
+ #"os2emxpath",
+ #"pdb",
+ #"pickle",
+ #"pickletools",
+ #"pipes",
+ #"pkgutil",
+ #"platform",
+ #"plat-linux2",
+ #"plistlib",
+ #"poplib",
+ #"pprint",
+ #"profile",
+ #"pstats",
+ #"pty",
+ #"pyclbr",
+ #"py_compile",
+ #"pydoc_data",
+ #"pydoc",
+ #"_pyio",
+ #"queue",
+ #"quopri",
+ "reprlib",
+ "rlcompleter",
+ #"runpy",
+ #"sched",
+ #"shelve",
+ #"shlex",
+ #"smtpd",
+ #"smtplib",
+ #"sndhdr",
+ #"socket",
+ #"socketserver",
+ #"sqlite3",
+ #"ssl",
+ #"stringprep",
+ #"string",
+ #"_strptime",
+ #"subprocess",
+ #"sunau",
+ #"symbol",
+ #"symtable",
+ #"sysconfig",
+ #"tabnanny",
+ #"telnetlib",
+ #"test",
+ #"textwrap",
+ #"this",
+ #"_threading_local",
+ #"threading",
+ #"timeit",
+ #"tkinter",
+ #"tokenize",
+ #"token",
+ #"traceback",
+ #"trace",
+ #"tty",
+ #"turtledemo",
+ #"turtle",
+ #"unittest",
+ #"urllib",
+ #"uuid",
+ #"uu",
+ #"wave",
+ "weakref",
+ #"webbrowser",
+ #"wsgiref",
+ #"xdrlib",
+ #"xml",
+ #"xmlrpc",
+ #"zipfile",
+ ])
+
+if is_pypy:
+ # these are needed to correctly display the exceptions that may happen
+ # during the bootstrap
+ REQUIRED_MODULES.extend(['traceback', 'linecache'])
+
+class Logger(object):
+
+ """
+ Logging object for use in command-line script. Allows ranges of
+ levels, to avoid some redundancy of displayed information.
+ """
+
+ DEBUG = logging.DEBUG
+ INFO = logging.INFO
+ NOTIFY = (logging.INFO+logging.WARN)/2
+ WARN = WARNING = logging.WARN
+ ERROR = logging.ERROR
+ FATAL = logging.FATAL
+
+ LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
+
+ def __init__(self, consumers):
+ self.consumers = consumers
+ self.indent = 0
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def debug(self, msg, *args, **kw):
+ self.log(self.DEBUG, msg, *args, **kw)
+ def info(self, msg, *args, **kw):
+ self.log(self.INFO, msg, *args, **kw)
+ def notify(self, msg, *args, **kw):
+ self.log(self.NOTIFY, msg, *args, **kw)
+ def warn(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def error(self, msg, *args, **kw):
+ self.log(self.WARN, msg, *args, **kw)
+ def fatal(self, msg, *args, **kw):
+ self.log(self.FATAL, msg, *args, **kw)
+ def log(self, level, msg, *args, **kw):
+ if args:
+ if kw:
+ raise TypeError(
+ "You may give positional or keyword arguments, not both")
+ args = args or kw
+ rendered = None
+ for consumer_level, consumer in self.consumers:
+ if self.level_matches(level, consumer_level):
+ if (self.in_progress_hanging
+ and consumer in (sys.stdout, sys.stderr)):
+ self.in_progress_hanging = False
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ if rendered is None:
+ if args:
+ rendered = msg % args
+ else:
+ rendered = msg
+ rendered = ' '*self.indent + rendered
+ if hasattr(consumer, 'write'):
+ consumer.write(rendered+'\n')
+ else:
+ consumer(rendered)
+
+ def start_progress(self, msg):
+ assert not self.in_progress, (
+ "Tried to start_progress(%r) while in_progress %r"
+ % (msg, self.in_progress))
+ if self.level_matches(self.NOTIFY, self._stdout_level()):
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ self.in_progress_hanging = True
+ else:
+ self.in_progress_hanging = False
+ self.in_progress = msg
+
+ def end_progress(self, msg='done.'):
+ assert self.in_progress, (
+ "Tried to end_progress without start_progress")
+ if self.stdout_level_matches(self.NOTIFY):
+ if not self.in_progress_hanging:
+ # Some message has been printed out since start_progress
+ sys.stdout.write('...' + self.in_progress + msg + '\n')
+ sys.stdout.flush()
+ else:
+ sys.stdout.write(msg + '\n')
+ sys.stdout.flush()
+ self.in_progress = None
+ self.in_progress_hanging = False
+
+ def show_progress(self):
+ """If we are in a progress scope, and no log messages have been
+ shown, write out another '.'"""
+ if self.in_progress_hanging:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+
+ def stdout_level_matches(self, level):
+ """Returns true if a message at this level will go to stdout"""
+ return self.level_matches(level, self._stdout_level())
+
+ def _stdout_level(self):
+ """Returns the level that stdout runs at"""
+ for level, consumer in self.consumers:
+ if consumer is sys.stdout:
+ return level
+ return self.FATAL
+
+ def level_matches(self, level, consumer_level):
+ """
+ >>> l = Logger([])
+ >>> l.level_matches(3, 4)
+ False
+ >>> l.level_matches(3, 2)
+ True
+ >>> l.level_matches(slice(None, 3), 3)
+ False
+ >>> l.level_matches(slice(None, 3), 2)
+ True
+ >>> l.level_matches(slice(1, 3), 1)
+ True
+ >>> l.level_matches(slice(2, 3), 1)
+ False
+ """
+ if isinstance(level, slice):
+ start, stop = level.start, level.stop
+ if start is not None and start > consumer_level:
+ return False
+ if stop is not None and stop <= consumer_level:
+ return False
+ return True
+ else:
+ return level >= consumer_level
+
+ #@classmethod
+ def level_for_integer(cls, level):
+ levels = cls.LEVELS
+ if level < 0:
+ return levels[0]
+ if level >= len(levels):
+ return levels[-1]
+ return levels[level]
+
+ level_for_integer = classmethod(level_for_integer)
+
+# create a silent logger just to prevent this from being undefined
+# will be overridden with requested verbosity main() is called.
+logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
+
+def mkdir(path):
+ if not os.path.exists(path):
+ logger.info('Creating %s', path)
+ os.makedirs(path)
+ else:
+ logger.info('Directory %s already exists', path)
+
+def copyfileordir(src, dest):
+ if os.path.isdir(src):
+ shutil.copytree(src, dest, True)
+ else:
+ shutil.copy2(src, dest)
+
+def copyfile(src, dest, symlink=True):
+ if not os.path.exists(src):
+ # Some bad symlink in the src
+ logger.warn('Cannot find file %s (bad symlink)', src)
+ return
+ if os.path.exists(dest):
+ logger.debug('File %s already exists', dest)
+ return
+ if not os.path.exists(os.path.dirname(dest)):
+ logger.info('Creating parent directories for %s' % os.path.dirname(dest))
+ os.makedirs(os.path.dirname(dest))
+ if not os.path.islink(src):
+ srcpath = os.path.abspath(src)
+ else:
+ srcpath = os.readlink(src)
+ if symlink and hasattr(os, 'symlink'):
+ logger.info('Symlinking %s', dest)
+ try:
+ os.symlink(srcpath, dest)
+ except (OSError, NotImplementedError):
+ logger.info('Symlinking failed, copying to %s', dest)
+ copyfileordir(src, dest)
+ else:
+ logger.info('Copying to %s', dest)
+ copyfileordir(src, dest)
+
+def writefile(dest, content, overwrite=True):
+ if not os.path.exists(dest):
+ logger.info('Writing %s', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ return
+ else:
+ f = open(dest, 'rb')
+ c = f.read()
+ f.close()
+ if c != content:
+ if not overwrite:
+ logger.notify('File %s exists with different content; not overwriting', dest)
+ return
+ logger.notify('Overwriting %s with new content', dest)
+ f = open(dest, 'wb')
+ f.write(content.encode('utf-8'))
+ f.close()
+ else:
+ logger.info('Content %s already in place', dest)
+
+def rmtree(dir):
+ if os.path.exists(dir):
+ logger.notify('Deleting tree %s', dir)
+ shutil.rmtree(dir)
+ else:
+ logger.info('Do not need to delete %s; already gone', dir)
+
+def make_exe(fn):
+ if hasattr(os, 'chmod'):
+ oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
+ newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
+ os.chmod(fn, newmode)
+ logger.info('Changed mode of %s to %s', fn, oct(newmode))
+
+def _find_file(filename, dirs):
+ for dir in dirs:
+ if os.path.exists(join(dir, filename)):
+ return join(dir, filename)
+ return filename
+
+def _install_req(py_executable, unzip=False, distribute=False,
+ search_dirs=None, never_download=False):
+
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ if not distribute:
+ setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
+ project_name = 'setuptools'
+ bootstrap_script = EZ_SETUP_PY
+ source = None
+ else:
+ setup_fn = None
+ source = 'distribute-0.6.19.tar.gz'
+ project_name = 'distribute'
+ bootstrap_script = DISTRIBUTE_SETUP_PY
+
+ # If we are running under -p, we need to remove the current
+ # directory from sys.path temporarily here, so that we
+ # definitely get the pkg_resources from the site directory of
+ # the interpreter we are running under, not the one
+ # virtualenv.py is installed under (which might lead to py2/py3
+ # incompatibility issues)
+ _prev_sys_path = sys.path
+ if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
+ sys.path = sys.path[1:]
+
+ try:
+ try:
+ # check if the global Python has distribute installed or plain
+ # setuptools
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ location = os.path.dirname(pkg_resources.__file__)
+ logger.notify("A globally installed setuptools was found (in %s)" % location)
+ logger.notify("Use the --no-site-packages option to use distribute in "
+ "the virtualenv.")
+ except ImportError:
+ pass
+ finally:
+ sys.path = _prev_sys_path
+
+ if setup_fn is not None:
+ setup_fn = _find_file(setup_fn, search_dirs)
+
+ if source is not None:
+ source = _find_file(source, search_dirs)
+
+ if is_jython and os._name == 'nt':
+ # Jython's .bat sys.executable can't handle a command line
+ # argument with newlines
+ fd, ez_setup = tempfile.mkstemp('.py')
+ os.write(fd, bootstrap_script)
+ os.close(fd)
+ cmd = [py_executable, ez_setup]
+ else:
+ cmd = [py_executable, '-c', bootstrap_script]
+ if unzip:
+ cmd.append('--always-unzip')
+ env = {}
+ remove_from_env = []
+ if logger.stdout_level_matches(logger.DEBUG):
+ cmd.append('-v')
+
+ old_chdir = os.getcwd()
+ if setup_fn is not None and os.path.exists(setup_fn):
+ logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
+ cmd.append(setup_fn)
+ if os.environ.get('PYTHONPATH'):
+ env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
+ else:
+ env['PYTHONPATH'] = setup_fn
+ else:
+ # the source is found, let's chdir
+ if source is not None and os.path.exists(source):
+ logger.info('Using existing %s egg: %s' % (project_name, source))
+ os.chdir(os.path.dirname(source))
+ # in this case, we want to be sure that PYTHONPATH is unset (not
+ # just empty, really unset), else CPython tries to import the
+ # site.py that it's in virtualenv_support
+ remove_from_env.append('PYTHONPATH')
+ else:
+ if never_download:
+ logger.fatal("Can't find any local distributions of %s to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a %s "
+ "distribution (%s) in one of these "
+ "locations: %r" % (project_name, project_name,
+ setup_fn or source,
+ search_dirs))
+ sys.exit(1)
+
+ logger.info('No %s egg found; downloading' % project_name)
+ cmd.extend(['--always-copy', '-U', project_name])
+ logger.start_progress('Installing %s...' % project_name)
+ logger.indent += 2
+ cwd = None
+ if project_name == 'distribute':
+ env['DONT_PATCH_SETUPTOOLS'] = 'true'
+
+ def _filter_ez_setup(line):
+ return filter_ez_setup(line, project_name)
+
+ if not os.access(os.getcwd(), os.W_OK):
+ cwd = tempfile.mkdtemp()
+ if source is not None and os.path.exists(source):
+ # the current working dir is hostile, let's copy the
+ # tarball to a temp dir
+ target = os.path.join(cwd, os.path.split(source)[-1])
+ shutil.copy(source, target)
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_ez_setup,
+ extra_env=env,
+ remove_from_env=remove_from_env,
+ cwd=cwd)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+ if os.getcwd() != old_chdir:
+ os.chdir(old_chdir)
+ if is_jython and os._name == 'nt':
+ os.remove(ez_setup)
+
+def file_search_dirs():
+ here = os.path.dirname(os.path.abspath(__file__))
+ dirs = ['.', here,
+ join(here, 'virtualenv_support')]
+ if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
+ # Probably some boot script; just in case virtualenv is installed...
+ try:
+ import virtualenv
+ except ImportError:
+ pass
+ else:
+ dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
+ return [d for d in dirs if os.path.isdir(d)]
+
+def install_setuptools(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip,
+ search_dirs=search_dirs, never_download=never_download)
+
+def install_distribute(py_executable, unzip=False,
+ search_dirs=None, never_download=False):
+ _install_req(py_executable, unzip, distribute=True,
+ search_dirs=search_dirs, never_download=never_download)
+
+_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
+def install_pip(py_executable, search_dirs=None, never_download=False):
+ if search_dirs is None:
+ search_dirs = file_search_dirs()
+
+ filenames = []
+ for dir in search_dirs:
+ filenames.extend([join(dir, fn) for fn in os.listdir(dir)
+ if _pip_re.search(fn)])
+ filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
+ filenames.sort()
+ filenames = [filename for basename, i, filename in filenames]
+ if not filenames:
+ filename = 'pip'
+ else:
+ filename = filenames[-1]
+ easy_install_script = 'easy_install'
+ if sys.platform == 'win32':
+ easy_install_script = 'easy_install-script.py'
+ cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
+ if filename == 'pip':
+ if never_download:
+ logger.fatal("Can't find any local distributions of pip to install "
+ "and --never-download is set. Either re-run virtualenv "
+ "without the --never-download option, or place a pip "
+ "source distribution (zip/tar.gz/tar.bz2) in one of these "
+ "locations: %r" % search_dirs)
+ sys.exit(1)
+ logger.info('Installing pip from network...')
+ else:
+ logger.info('Installing existing %s distribution: %s' % (
+ os.path.basename(filename), filename))
+ logger.start_progress('Installing pip...')
+ logger.indent += 2
+ def _filter_setup(line):
+ return filter_ez_setup(line, 'pip')
+ try:
+ call_subprocess(cmd, show_stdout=False,
+ filter_stdout=_filter_setup)
+ finally:
+ logger.indent -= 2
+ logger.end_progress()
+
+def filter_ez_setup(line, project_name='setuptools'):
+ if not line.strip():
+ return Logger.DEBUG
+ if project_name == 'distribute':
+ for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
+ 'Scanning', 'Setuptools', 'Egg', 'Already',
+ 'running', 'writing', 'reading', 'installing',
+ 'creating', 'copying', 'byte-compiling', 'removing',
+ 'Processing'):
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.DEBUG
+ for prefix in ['Reading ', 'Best match', 'Processing setuptools',
+ 'Copying setuptools', 'Adding setuptools',
+ 'Installing ', 'Installed ']:
+ if line.startswith(prefix):
+ return Logger.DEBUG
+ return Logger.INFO
+
+def main():
+ parser = optparse.OptionParser(
+ version=virtualenv_version,
+ usage="%prog [OPTIONS] DEST_DIR")
+
+ parser.add_option(
+ '-v', '--verbose',
+ action='count',
+ dest='verbose',
+ default=0,
+ help="Increase verbosity")
+
+ parser.add_option(
+ '-q', '--quiet',
+ action='count',
+ dest='quiet',
+ default=0,
+ help='Decrease verbosity')
+
+ parser.add_option(
+ '-p', '--python',
+ dest='python',
+ metavar='PYTHON_EXE',
+ help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
+ 'interpreter to create the new environment. The default is the interpreter that '
+ 'virtualenv was installed with (%s)' % sys.executable)
+
+ parser.add_option(
+ '--clear',
+ dest='clear',
+ action='store_true',
+ help="Clear out the non-root install and start from scratch")
+
+ parser.add_option(
+ '--no-site-packages',
+ dest='no_site_packages',
+ action='store_true',
+ help="Don't give access to the global site-packages dir to the "
+ "virtual environment")
+
+ parser.add_option(
+ '--unzip-setuptools',
+ dest='unzip_setuptools',
+ action='store_true',
+ help="Unzip Setuptools or Distribute when installing it")
+
+ parser.add_option(
+ '--relocatable',
+ dest='relocatable',
+ action='store_true',
+ help='Make an EXISTING virtualenv environment relocatable. '
+ 'This fixes up scripts and makes all .pth files relative')
+
+ parser.add_option(
+ '--distribute',
+ dest='use_distribute',
+ action='store_true',
+ help='Use Distribute instead of Setuptools. Set environ variable '
+ 'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
+
+ default_search_dirs = file_search_dirs()
+ parser.add_option(
+ '--extra-search-dir',
+ dest="search_dirs",
+ action="append",
+ default=default_search_dirs,
+ help="Directory to look for setuptools/distribute/pip distributions in. "
+ "You can add any number of additional --extra-search-dir paths.")
+
+ parser.add_option(
+ '--never-download',
+ dest="never_download",
+ action="store_true",
+ help="Never download anything from the network. Instead, virtualenv will fail "
+ "if local distributions of setuptools/distribute/pip are not present.")
+
+ parser.add_option(
+ '--prompt=',
+ dest='prompt',
+ help='Provides an alternative prompt prefix for this environment')
+
+ if 'extend_parser' in globals():
+ extend_parser(parser)
+
+ options, args = parser.parse_args()
+
+ global logger
+
+ if 'adjust_options' in globals():
+ adjust_options(options, args)
+
+ verbosity = options.verbose - options.quiet
+ logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
+
+ if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
+ env = os.environ.copy()
+ interpreter = resolve_interpreter(options.python)
+ if interpreter == sys.executable:
+ logger.warn('Already using interpreter %s' % interpreter)
+ else:
+ logger.notify('Running virtualenv with interpreter %s' % interpreter)
+ env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
+ file = __file__
+ if file.endswith('.pyc'):
+ file = file[:-1]
+ popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
+ raise SystemExit(popen.wait())
+
+ if not args:
+ print('You must provide a DEST_DIR')
+ parser.print_help()
+ sys.exit(2)
+ if len(args) > 1:
+ print('There must be only one argument: DEST_DIR (you gave %s)' % (
+ ' '.join(args)))
+ parser.print_help()
+ sys.exit(2)
+
+ home_dir = args[0]
+
+ if os.environ.get('WORKING_ENV'):
+ logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
+ logger.fatal('Please deactivate your workingenv, then re-run this script')
+ sys.exit(3)
+
+ if 'PYTHONHOME' in os.environ:
+ logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
+ del os.environ['PYTHONHOME']
+
+ if options.relocatable:
+ make_environment_relocatable(home_dir)
+ return
+
+ create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
+ unzip_setuptools=options.unzip_setuptools,
+ use_distribute=options.use_distribute or majver > 2,
+ prompt=options.prompt,
+ search_dirs=options.search_dirs,
+ never_download=options.never_download)
+ if 'after_install' in globals():
+ after_install(options, home_dir)
+
+def call_subprocess(cmd, show_stdout=True,
+ filter_stdout=None, cwd=None,
+ raise_on_returncode=True, extra_env=None,
+ remove_from_env=None):
+ cmd_parts = []
+ for part in cmd:
+ if len(part) > 45:
+ part = part[:20]+"..."+part[-20:]
+ if ' ' in part or '\n' in part or '"' in part or "'" in part:
+ part = '"%s"' % part.replace('"', '\\"')
+ cmd_parts.append(part)
+ cmd_desc = ' '.join(cmd_parts)
+ if show_stdout:
+ stdout = None
+ else:
+ stdout = subprocess.PIPE
+ logger.debug("Running command %s" % cmd_desc)
+ if extra_env or remove_from_env:
+ env = os.environ.copy()
+ if extra_env:
+ env.update(extra_env)
+ if remove_from_env:
+ for varname in remove_from_env:
+ env.pop(varname, None)
+ else:
+ env = None
+ try:
+ proc = subprocess.Popen(
+ cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
+ cwd=cwd, env=env)
+ except Exception:
+ e = sys.exc_info()[1]
+ logger.fatal(
+ "Error %s while executing command %s" % (e, cmd_desc))
+ raise
+ all_output = []
+ if stdout is not None:
+ stdout = proc.stdout
+ encoding = sys.getdefaultencoding()
+ while 1:
+ line = stdout.readline().decode(encoding)
+ if not line:
+ break
+ line = line.rstrip()
+ all_output.append(line)
+ if filter_stdout:
+ level = filter_stdout(line)
+ if isinstance(level, tuple):
+ level, line = level
+ logger.log(level, line)
+ if not logger.stdout_level_matches(level):
+ logger.show_progress()
+ else:
+ logger.info(line)
+ else:
+ proc.communicate()
+ proc.wait()
+ if proc.returncode:
+ if raise_on_returncode:
+ if all_output:
+ logger.notify('Complete output from command %s:' % cmd_desc)
+ logger.notify('\n'.join(all_output) + '\n----------------------------------------')
+ raise OSError(
+ "Command %s failed with error code %s"
+ % (cmd_desc, proc.returncode))
+ else:
+ logger.warn(
+ "Command %s had error code %s"
+ % (cmd_desc, proc.returncode))
+
+
+def create_environment(home_dir, site_packages=True, clear=False,
+ unzip_setuptools=False, use_distribute=False,
+ prompt=None, search_dirs=None, never_download=False):
+ """
+ Creates a new environment in ``home_dir``.
+
+ If ``site_packages`` is true (the default) then the global
+ ``site-packages/`` directory will be on the path.
+
+ If ``clear`` is true (default False) then the environment will
+ first be cleared.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+
+ py_executable = os.path.abspath(install_python(
+ home_dir, lib_dir, inc_dir, bin_dir,
+ site_packages=site_packages, clear=clear))
+
+ install_distutils(home_dir)
+
+ if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
+ install_distribute(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+ else:
+ install_setuptools(py_executable, unzip=unzip_setuptools,
+ search_dirs=search_dirs, never_download=never_download)
+
+ install_pip(py_executable, search_dirs=search_dirs, never_download=never_download)
+
+ install_activate(home_dir, bin_dir, prompt)
+
+def path_locations(home_dir):
+ """Return the path locations for the environment (where libraries are,
+ where scripts go, etc)"""
+ # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
+ # prefix arg is broken: http://bugs.python.org/issue3386
+ if sys.platform == 'win32':
+ # Windows has lots of problems with executables with spaces in
+ # the name; this function will remove them (using the ~1
+ # format):
+ mkdir(home_dir)
+ if ' ' in home_dir:
+ try:
+ import win32api
+ except ImportError:
+ print('Error: the path "%s" has a space in it' % home_dir)
+ print('To handle these kinds of paths, the win32api module must be installed:')
+ print(' http://sourceforge.net/projects/pywin32/')
+ sys.exit(3)
+ home_dir = win32api.GetShortPathName(home_dir)
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'Scripts')
+ elif is_jython:
+ lib_dir = join(home_dir, 'Lib')
+ inc_dir = join(home_dir, 'Include')
+ bin_dir = join(home_dir, 'bin')
+ elif is_pypy:
+ lib_dir = home_dir
+ inc_dir = join(home_dir, 'include')
+ bin_dir = join(home_dir, 'bin')
+ else:
+ lib_dir = join(home_dir, 'lib', py_version)
+ inc_dir = join(home_dir, 'include', py_version + abiflags)
+ bin_dir = join(home_dir, 'bin')
+ return home_dir, lib_dir, inc_dir, bin_dir
+
+
+def change_prefix(filename, dst_prefix):
+ prefixes = [sys.prefix]
+
+ if sys.platform == "darwin":
+ prefixes.extend((
+ os.path.join("/Library/Python", sys.version[:3], "site-packages"),
+ os.path.join(sys.prefix, "Extras", "lib", "python"),
+ os.path.join("~", "Library", "Python", sys.version[:3], "site-packages")))
+
+ if hasattr(sys, 'real_prefix'):
+ prefixes.append(sys.real_prefix)
+ prefixes = list(map(os.path.abspath, prefixes))
+ filename = os.path.abspath(filename)
+ for src_prefix in prefixes:
+ if filename.startswith(src_prefix):
+ _, relpath = filename.split(src_prefix, 1)
+ assert relpath[0] == os.sep
+ relpath = relpath[1:]
+ return join(dst_prefix, relpath)
+ assert False, "Filename %s does not start with any of these prefixes: %s" % \
+ (filename, prefixes)
+
+def copy_required_modules(dst_prefix):
+ import imp
+ for modname in REQUIRED_MODULES:
+ if modname in sys.builtin_module_names:
+ logger.info("Ignoring built-in bootstrap module: %s" % modname)
+ continue
+ try:
+ f, filename, _ = imp.find_module(modname)
+ except ImportError:
+ logger.info("Cannot import bootstrap module: %s" % modname)
+ else:
+ if f is not None:
+ f.close()
+ dst_filename = change_prefix(filename, dst_prefix)
+ copyfile(filename, dst_filename)
+ if filename.endswith('.pyc'):
+ pyfile = filename[:-1]
+ if os.path.exists(pyfile):
+ copyfile(pyfile, dst_filename[:-1])
+
+
+def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
+ """Install just the base environment, no distutils patches etc"""
+ if sys.executable.startswith(bin_dir):
+ print('Please use the *system* python to run this script')
+ return
+
+ if clear:
+ rmtree(lib_dir)
+ ## FIXME: why not delete it?
+ ## Maybe it should delete everything with #!/path/to/venv/python in it
+ logger.notify('Not deleting %s', bin_dir)
+
+ if hasattr(sys, 'real_prefix'):
+ logger.notify('Using real prefix %r' % sys.real_prefix)
+ prefix = sys.real_prefix
+ else:
+ prefix = sys.prefix
+ mkdir(lib_dir)
+ fix_lib64(lib_dir)
+ fix_local_scheme(home_dir)
+ stdlib_dirs = [os.path.dirname(os.__file__)]
+ if sys.platform == 'win32':
+ stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
+ elif sys.platform == 'darwin':
+ stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
+ if hasattr(os, 'symlink'):
+ logger.info('Symlinking Python bootstrap modules')
+ else:
+ logger.info('Copying Python bootstrap modules')
+ logger.indent += 2
+ try:
+ # copy required files...
+ for stdlib_dir in stdlib_dirs:
+ if not os.path.isdir(stdlib_dir):
+ continue
+ for fn in os.listdir(stdlib_dir):
+ bn = os.path.splitext(fn)[0]
+ if fn != 'site-packages' and bn in REQUIRED_FILES:
+ copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
+ # ...and modules
+ copy_required_modules(home_dir)
+ finally:
+ logger.indent -= 2
+ mkdir(join(lib_dir, 'site-packages'))
+ import site
+ site_filename = site.__file__
+ if site_filename.endswith('.pyc'):
+ site_filename = site_filename[:-1]
+ elif site_filename.endswith('$py.class'):
+ site_filename = site_filename.replace('$py.class', '.py')
+ site_filename_dst = change_prefix(site_filename, home_dir)
+ site_dir = os.path.dirname(site_filename_dst)
+ writefile(site_filename_dst, SITE_PY)
+ writefile(join(site_dir, 'orig-prefix.txt'), prefix)
+ site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
+ if not site_packages:
+ writefile(site_packages_filename, '')
+ else:
+ if os.path.exists(site_packages_filename):
+ logger.info('Deleting %s' % site_packages_filename)
+ os.unlink(site_packages_filename)
+
+ if is_pypy or is_win:
+ stdinc_dir = join(prefix, 'include')
+ else:
+ stdinc_dir = join(prefix, 'include', py_version + abiflags)
+ if os.path.exists(stdinc_dir):
+ copyfile(stdinc_dir, inc_dir)
+ else:
+ logger.debug('No include dir %s' % stdinc_dir)
+
+ # pypy never uses exec_prefix, just ignore it
+ if sys.exec_prefix != prefix and not is_pypy:
+ if sys.platform == 'win32':
+ exec_dir = join(sys.exec_prefix, 'lib')
+ elif is_jython:
+ exec_dir = join(sys.exec_prefix, 'Lib')
+ else:
+ exec_dir = join(sys.exec_prefix, 'lib', py_version)
+ for fn in os.listdir(exec_dir):
+ copyfile(join(exec_dir, fn), join(lib_dir, fn))
+
+ if is_jython:
+ # Jython has either jython-dev.jar and javalib/ dir, or just
+ # jython.jar
+ for name in 'jython-dev.jar', 'javalib', 'jython.jar':
+ src = join(prefix, name)
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, name))
+ # XXX: registry should always exist after Jython 2.5rc1
+ src = join(prefix, 'registry')
+ if os.path.exists(src):
+ copyfile(src, join(home_dir, 'registry'), symlink=False)
+ copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
+ symlink=False)
+
+ mkdir(bin_dir)
+ py_executable = join(bin_dir, os.path.basename(sys.executable))
+ if 'Python.framework' in prefix:
+ if re.search(r'/Python(?:-32|-64)*$', py_executable):
+ # The name of the python executable is not quite what
+ # we want, rename it.
+ py_executable = os.path.join(
+ os.path.dirname(py_executable), 'python')
+
+ logger.notify('New %s executable in %s', expected_exe, py_executable)
+ if sys.executable != py_executable:
+ ## FIXME: could I just hard link?
+ executable = sys.executable
+ if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
+ # Cygwin misreports sys.executable sometimes
+ executable += '.exe'
+ py_executable += '.exe'
+ logger.info('Executable actually exists in %s' % executable)
+ shutil.copyfile(executable, py_executable)
+ make_exe(py_executable)
+ if sys.platform == 'win32' or sys.platform == 'cygwin':
+ pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
+ if os.path.exists(pythonw):
+ logger.info('Also created pythonw.exe')
+ shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
+ if is_pypy:
+ # make a symlink python --> pypy-c
+ python_executable = os.path.join(os.path.dirname(py_executable), 'python')
+ logger.info('Also created executable %s' % python_executable)
+ copyfile(py_executable, python_executable)
+
+ if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
+ secondary_exe = os.path.join(os.path.dirname(py_executable),
+ expected_exe)
+ py_executable_ext = os.path.splitext(py_executable)[1]
+ if py_executable_ext == '.exe':
+ # python2.4 gives an extension of '.4' :P
+ secondary_exe += py_executable_ext
+ if os.path.exists(secondary_exe):
+ logger.warn('Not overwriting existing %s script %s (you must use %s)'
+ % (expected_exe, secondary_exe, py_executable))
+ else:
+ logger.notify('Also creating executable in %s' % secondary_exe)
+ shutil.copyfile(sys.executable, secondary_exe)
+ make_exe(secondary_exe)
+
+ if 'Python.framework' in prefix:
+ logger.debug('MacOSX Python framework detected')
+
+ # Make sure we use the the embedded interpreter inside
+ # the framework, even if sys.executable points to
+ # the stub executable in ${sys.prefix}/bin
+ # See http://groups.google.com/group/python-virtualenv/
+ # browse_thread/thread/17cab2f85da75951
+ original_python = os.path.join(
+ prefix, 'Resources/Python.app/Contents/MacOS/Python')
+ shutil.copy(original_python, py_executable)
+
+ # Copy the framework's dylib into the virtual
+ # environment
+ virtual_lib = os.path.join(home_dir, '.Python')
+
+ if os.path.exists(virtual_lib):
+ os.unlink(virtual_lib)
+ copyfile(
+ os.path.join(prefix, 'Python'),
+ virtual_lib)
+
+ # And then change the install_name of the copied python executable
+ try:
+ call_subprocess(
+ ["install_name_tool", "-change",
+ os.path.join(prefix, 'Python'),
+ '@executable_path/../.Python',
+ py_executable])
+ except:
+ logger.fatal(
+ "Could not call install_name_tool -- you must have Apple's development tools installed")
+ raise
+
+ # Some tools depend on pythonX.Y being present
+ py_executable_version = '%s.%s' % (
+ sys.version_info[0], sys.version_info[1])
+ if not py_executable.endswith(py_executable_version):
+ # symlinking pythonX.Y > python
+ pth = py_executable + '%s.%s' % (
+ sys.version_info[0], sys.version_info[1])
+ if os.path.exists(pth):
+ os.unlink(pth)
+ os.symlink('python', pth)
+ else:
+ # reverse symlinking python -> pythonX.Y (with --python)
+ pth = join(bin_dir, 'python')
+ if os.path.exists(pth):
+ os.unlink(pth)
+ os.symlink(os.path.basename(py_executable), pth)
+
+ if sys.platform == 'win32' and ' ' in py_executable:
+ # There's a bug with subprocess on Windows when using a first
+ # argument that has a space in it. Instead we have to quote
+ # the value:
+ py_executable = '"%s"' % py_executable
+ cmd = [py_executable, '-c', 'import sys; print(sys.prefix)']
+ logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
+ try:
+ proc = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE)
+ proc_stdout, proc_stderr = proc.communicate()
+ except OSError:
+ e = sys.exc_info()[1]
+ if e.errno == errno.EACCES:
+ logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
+ sys.exit(100)
+ else:
+ raise e
+
+ proc_stdout = proc_stdout.strip().decode(sys.getdefaultencoding())
+ proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
+ if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
+ logger.fatal(
+ 'ERROR: The executable %s is not functioning' % py_executable)
+ logger.fatal(
+ 'ERROR: It thinks sys.prefix is %r (should be %r)'
+ % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
+ logger.fatal(
+ 'ERROR: virtualenv is not compatible with this system or executable')
+ if sys.platform == 'win32':
+ logger.fatal(
+ 'Note: some Windows users have reported this error when they installed Python for "Only this user". The problem may be resolvable if you install Python "For all users". (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
+ sys.exit(100)
+ else:
+ logger.info('Got sys.prefix result: %r' % proc_stdout)
+
+ pydistutils = os.path.expanduser('~/.pydistutils.cfg')
+ if os.path.exists(pydistutils):
+ logger.notify('Please make sure you remove any previous custom paths from '
+ 'your %s file.' % pydistutils)
+ ## FIXME: really this should be calculated earlier
+ return py_executable
+
+def install_activate(home_dir, bin_dir, prompt=None):
+ if sys.platform == 'win32' or is_jython and os._name == 'nt':
+ files = {'activate.bat': ACTIVATE_BAT,
+ 'deactivate.bat': DEACTIVATE_BAT}
+ if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
+ files['activate'] = ACTIVATE_SH
+ else:
+ files = {'activate': ACTIVATE_SH}
+
+ # suppling activate.fish in addition to, not instead of, the
+ # bash script support.
+ files['activate.fish'] = ACTIVATE_FISH
+
+ # same for csh/tcsh support...
+ files['activate.csh'] = ACTIVATE_CSH
+
+
+
+ files['activate_this.py'] = ACTIVATE_THIS
+ vname = os.path.basename(os.path.abspath(home_dir))
+ for name, content in files.items():
+ content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
+ content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
+ content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
+ content = content.replace('__VIRTUAL_NAME__', vname)
+ content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
+ writefile(os.path.join(bin_dir, name), content)
+
+def install_distutils(home_dir):
+ distutils_path = change_prefix(distutils.__path__[0], home_dir)
+ mkdir(distutils_path)
+ ## FIXME: maybe this prefix setting should only be put in place if
+ ## there's a local distutils.cfg with a prefix setting?
+ home_dir = os.path.abspath(home_dir)
+ ## FIXME: this is breaking things, removing for now:
+ #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
+ writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
+ writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
+
+def fix_local_scheme(home_dir):
+ """
+ Platforms that use the "posix_local" install scheme (like Ubuntu with
+ Python 2.7) need to be given an additional "local" location, sigh.
+ """
+ try:
+ import sysconfig
+ except ImportError:
+ pass
+ else:
+ if sysconfig._get_default_scheme() == 'posix_local':
+ local_path = os.path.join(home_dir, 'local')
+ if not os.path.exists(local_path):
+ os.symlink(os.path.abspath(home_dir), local_path)
+
+def fix_lib64(lib_dir):
+ """
+ Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
+ instead of lib/pythonX.Y. If this is such a platform we'll just create a
+ symlink so lib64 points to lib
+ """
+ if [p for p in distutils.sysconfig.get_config_vars().values()
+ if isinstance(p, basestring) and 'lib64' in p]:
+ logger.debug('This system uses lib64; symlinking lib64 to lib')
+ assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
+ "Unexpected python lib dir: %r" % lib_dir)
+ lib_parent = os.path.dirname(lib_dir)
+ assert os.path.basename(lib_parent) == 'lib', (
+ "Unexpected parent dir: %r" % lib_parent)
+ copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
+
+def resolve_interpreter(exe):
+ """
+ If the executable given isn't an absolute path, search $PATH for the interpreter
+ """
+ if os.path.abspath(exe) != exe:
+ paths = os.environ.get('PATH', '').split(os.pathsep)
+ for path in paths:
+ if os.path.exists(os.path.join(path, exe)):
+ exe = os.path.join(path, exe)
+ break
+ if not os.path.exists(exe):
+ logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
+ raise SystemExit(3)
+ if not is_executable(exe):
+ logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
+ raise SystemExit(3)
+ return exe
+
+def is_executable(exe):
+ """Checks a file is executable"""
+ return os.access(exe, os.X_OK)
+
+############################################################
+## Relocating the environment:
+
+def make_environment_relocatable(home_dir):
+ """
+ Makes the already-existing environment use relative paths, and takes out
+ the #!-based environment selection in scripts.
+ """
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ activate_this = os.path.join(bin_dir, 'activate_this.py')
+ if not os.path.exists(activate_this):
+ logger.fatal(
+ 'The environment doesn\'t have a file %s -- please re-run virtualenv '
+ 'on this environment to update it' % activate_this)
+ fixup_scripts(home_dir)
+ fixup_pth_and_egg_link(home_dir)
+ ## FIXME: need to fix up distutils.cfg
+
+OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
+ 'activate', 'activate.bat', 'activate_this.py']
+
+def fixup_scripts(home_dir):
+ # This is what we expect at the top of scripts:
+ shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
+ # This is what we'll put:
+ new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
+ activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
+ if sys.platform == 'win32':
+ bin_suffix = 'Scripts'
+ else:
+ bin_suffix = 'bin'
+ bin_dir = os.path.join(home_dir, bin_suffix)
+ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
+ for filename in os.listdir(bin_dir):
+ filename = os.path.join(bin_dir, filename)
+ if not os.path.isfile(filename):
+ # ignore subdirs, e.g. .svn ones.
+ continue
+ f = open(filename, 'rb')
+ lines = f.readlines()
+ f.close()
+ if not lines:
+ logger.warn('Script %s is an empty file' % filename)
+ continue
+ if not lines[0].strip().startswith(shebang):
+ if os.path.basename(filename) in OK_ABS_SCRIPTS:
+ logger.debug('Cannot make script %s relative' % filename)
+ elif lines[0].strip() == new_shebang:
+ logger.info('Script %s has already been made relative' % filename)
+ else:
+ logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
+ % (filename, shebang))
+ continue
+ logger.notify('Making script %s relative' % filename)
+ lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
+ f = open(filename, 'wb')
+ f.writelines(lines)
+ f.close()
+
+def fixup_pth_and_egg_link(home_dir, sys_path=None):
+ """Makes .pth and .egg-link files use relative paths"""
+ home_dir = os.path.normcase(os.path.abspath(home_dir))
+ if sys_path is None:
+ sys_path = sys.path
+ for path in sys_path:
+ if not path:
+ path = '.'
+ if not os.path.isdir(path):
+ continue
+ path = os.path.normcase(os.path.abspath(path))
+ if not path.startswith(home_dir):
+ logger.debug('Skipping system (non-environment) directory %s' % path)
+ continue
+ for filename in os.listdir(path):
+ filename = os.path.join(path, filename)
+ if filename.endswith('.pth'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .pth file %s, skipping' % filename)
+ else:
+ fixup_pth_file(filename)
+ if filename.endswith('.egg-link'):
+ if not os.access(filename, os.W_OK):
+ logger.warn('Cannot write .egg-link file %s, skipping' % filename)
+ else:
+ fixup_egg_link(filename)
+
+def fixup_pth_file(filename):
+ lines = []
+ prev_lines = []
+ f = open(filename)
+ prev_lines = f.readlines()
+ f.close()
+ for line in prev_lines:
+ line = line.strip()
+ if (not line or line.startswith('#') or line.startswith('import ')
+ or os.path.abspath(line) != line):
+ lines.append(line)
+ else:
+ new_value = make_relative_path(filename, line)
+ if line != new_value:
+ logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
+ lines.append(new_value)
+ if lines == prev_lines:
+ logger.info('No changes to .pth file %s' % filename)
+ return
+ logger.notify('Making paths in .pth file %s relative' % filename)
+ f = open(filename, 'w')
+ f.write('\n'.join(lines) + '\n')
+ f.close()
+
+def fixup_egg_link(filename):
+ f = open(filename)
+ link = f.read().strip()
+ f.close()
+ if os.path.abspath(link) != link:
+ logger.debug('Link in %s already relative' % filename)
+ return
+ new_link = make_relative_path(filename, link)
+ logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
+ f = open(filename, 'w')
+ f.write(new_link)
+ f.close()
+
+def make_relative_path(source, dest, dest_is_directory=True):
+ """
+ Make a filename relative, where the filename is dest, and it is
+ being referred to from the filename source.
+
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/usr/share/another-place/src/Directory')
+ '../another-place/src/Directory'
+ >>> make_relative_path('/usr/share/something/a-file.pth',
+ ... '/home/user/src/Directory')
+ '../../../home/user/src/Directory'
+ >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
+ './'
+ """
+ source = os.path.dirname(source)
+ if not dest_is_directory:
+ dest_filename = os.path.basename(dest)
+ dest = os.path.dirname(dest)
+ dest = os.path.normpath(os.path.abspath(dest))
+ source = os.path.normpath(os.path.abspath(source))
+ dest_parts = dest.strip(os.path.sep).split(os.path.sep)
+ source_parts = source.strip(os.path.sep).split(os.path.sep)
+ while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
+ dest_parts.pop(0)
+ source_parts.pop(0)
+ full_parts = ['..']*len(source_parts) + dest_parts
+ if not dest_is_directory:
+ full_parts.append(dest_filename)
+ if not full_parts:
+ # Special case for the current directory (otherwise it'd be '')
+ return './'
+ return os.path.sep.join(full_parts)
+
+
+
+############################################################
+## Bootstrap script creation:
+
+def create_bootstrap_script(extra_text, python_version=''):
+ """
+ Creates a bootstrap script, which is like this script but with
+ extend_parser, adjust_options, and after_install hooks.
+
+ This returns a string that (written to disk of course) can be used
+ as a bootstrap script with your own customizations. The script
+ will be the standard virtualenv.py script, with your extra text
+ added (your extra text should be Python code).
+
+ If you include these functions, they will be called:
+
+ ``extend_parser(optparse_parser)``:
+ You can add or remove options from the parser here.
+
+ ``adjust_options(options, args)``:
+ You can change options here, or change the args (if you accept
+ different kinds of arguments, be sure you modify ``args`` so it is
+ only ``[DEST_DIR]``).
+
+ ``after_install(options, home_dir)``:
+
+ After everything is installed, this function is called. This
+ is probably the function you are most likely to use. An
+ example would be::
+
+ def after_install(options, home_dir):
+ subprocess.call([join(home_dir, 'bin', 'easy_install'),
+ 'MyPackage'])
+ subprocess.call([join(home_dir, 'bin', 'my-package-script'),
+ 'setup', home_dir])
+
+ This example immediately installs a package, and runs a setup
+ script from that package.
+
+ If you provide something like ``python_version='2.4'`` then the
+ script will start with ``#!/usr/bin/env python2.4`` instead of
+ ``#!/usr/bin/env python``. You can use this when the script must
+ be run with a particular Python version.
+ """
+ filename = __file__
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ f = open(filename, 'rb')
+ content = f.read()
+ f.close()
+ py_exe = 'python%s' % python_version
+ content = (('#!/usr/bin/env %s\n' % py_exe)
+ + '## WARNING: This file is generated\n'
+ + content)
+ return content.replace('##EXT' 'END##', extra_text)
+
+import sys
+sys.path.append('/Users/tc/dev/eclipse_workspace/regardssignes_hg/virtualenv/res/lib')
+sys.path.append('/Users/tc/dev/eclipse_workspace/regardssignes_hg/virtualenv/web/res')
+from res_create_env import generate_install_methods
+adjust_options, extend_parser, after_install = generate_install_methods(path_locations, '/Users/tc/dev/eclipse_workspace/regardssignes_hg/virtualenv/res/src', Logger, call_subprocess)
+
+
+def convert(s):
+ b = base64.b64decode(s.encode('ascii'))
+ return zlib.decompress(b).decode('utf-8')
+
+##file site.py
+SITE_PY = convert("""
+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
+""")
+
+##file ez_setup.py
+EZ_SETUP_PY = convert("""
+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
+BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7
+""")
+
+##file distribute_setup.py
+DISTRIBUTE_SETUP_PY = convert("""
+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
+""")
+
+##file activate.sh
+ACTIVATE_SH = convert("""
+eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
+H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
+DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
+cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
+G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
+EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
+wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
+5eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
+JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
+huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
+Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
+Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
+WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
+LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
+""")
+
+##file activate.fish
+ACTIVATE_FISH = convert("""
+eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
+Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
+pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
+lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
+g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
+grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
+xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
+MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
+H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
+L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
+fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
+pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
+MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
+O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
+7SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
+m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
+djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
+mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
+jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
+""")
+
+##file activate.csh
+ACTIVATE_CSH = convert("""
+eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
+XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
+kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
+pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
+sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
+yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
+E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
+lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
+r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
+""")
+
+##file activate.bat
+ACTIVATE_BAT = convert("""
+eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
+qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
+sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
+ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
+""")
+
+##file deactivate.bat
+DEACTIVATE_BAT = convert("""
+eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
+FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
+i2dASrm4rFz9XLgAwJNbyQ==
+""")
+
+##file distutils-init.py
+DISTUTILS_INIT = convert("""
+eJytV92L4zYQf/dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313dG8odkO9d7aGBB
+luZLv/nNjFacOqUtKJMIvzK3cXlhWgp5MDBsqK5SNYftsBAGpLLA4F1oe2Ytl+9wUvW55TswCi4c
+KibhbFDSglXQCFmDPXIwtm7FawLRbwtPzg2T9gf4gupKv4GS0N262w7V0NvpbCy8cvTo3eAus6C5
+ETU3ICQZX1hFTw/dzR6V/AW1RCN4/XAtbsVXqIXmlVX6liS4lOzEYY9QFB2zx6LfoSNjz1a0pqT9
+QOIfJWQ2E888NEVZNqLlZZnvIB0NpHkimlFdKn2iRRY7yGG/CCJb6Iz280d34SFXBS2yEYPNF0Q7
+yM7oCjpWvbEDQmnhRwOs6zjThpKE8HogwRAgraqYFZgGZvzmzVh+mgz9vskT3hruwyjdFcqyENJw
+bbMPO5jdzonxK68QKT7B57CMRRG5shRSWDTX3dI8LzRndZbnSWL1zfvriUmK4TcGWSnZiEPCrxXv
+bM+sP7VW2is2WgWXCO3sAu3Rzysz3FiNCA8WPyM4gb1JAAmCiyTZbhFjWx3h9SzauuRXC9MFoVbc
+yNTCm1QXOOIfIn/g1kGMhDUBN72hI5XCBQtIXQw8UEEdma6Jaz4vJIJ51Orc15hzzmu6TdFp3ogr
+Aof0c98tsw1SiaiWotHffk3XYCkqdToxWRfTFXqgpg2khcLluOHMVC0zZhLKIomesfSreUNNgbXi
+Ky9VRzwzkBneNoGQyyvGjbsFQqOZvpWIjqH281lJ/jireFgR3cPzSyTGWzQpDNIU+03Fs4XKLkhp
+/n0uFnuF6VphB44b3uWRneSbBoMSioqE8oeF0JY+qTvYfEK+bPLYdoR4McfYQ7wMZj39q0kfP8q+
+FfsymO0GzNlPh644Jje06ulqHpOEQqdJUfoidI2O4CWx4qOglLye6RrFQirpCRXvhoRqXH3sYdVJ
+AItvc+VUsLO2v2hVAWrNIfVGtkG351cUMNncbh/WdowtSPtCdkzYFv6mwYc9o2Jt68ud6wectBr8
+hYAulPSlgzH44YbV3ikjrulEaNJxt+/H3wZ7bXSXje/YY4tfVVrVmUstaDwwOBLMg6iduDB0lMVC
+UyzYx7Ab4kjCqdViEJmDcdk/SKbgsjYXgfMznUWcrtS4z4fmJ/XOM1LPk/iIpqass5XwNbdnLb1Y
+8h3ERXSWZI6rZJxKs1LBqVH65w0Oy4ra0CBYxEeuOMbDmV5GI6E0Ha/wgVTtkX0+OXvqsD02CKLf
+XHbeft85D7tTCMYy2Njp4DJP7gWJr6paVWXZ1+/6YXLv/iE0M90FktiI7yFJD9e7SOLhEkkaMTUO
+azq9i2woBNR0/0eoF1HFMf0H8ChxH/jgcB34GZIz3Qn4/vid+VEamQrOVqAPTrOfmD4MPdVh09tb
+8dLLjvh/61lEP4yW5vJaH4vHcevG8agXvzPGoOhhXNncpTr99PTHx6e/UvffFLaxUSjuSeP286Dw
+gtEMcW1xKr/he4/6IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLn7fAY78k4aiR387bCr5XT
+5C4rFgwLGfMvJuAMew==
+""")
+
+##file distutils.cfg
+DISTUTILS_CFG = convert("""
+eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
+xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
+9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
+""")
+
+##file activate_this.py
+ACTIVATE_THIS = convert("""
+eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
+VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
+Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
+qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
+4lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
+HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
+xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
+1Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
+3vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
+""")
+
+if __name__ == '__main__':
+ main()
+
+## TODO:
+## Copy python.exe.manifest
+## Monkeypatch distutils.sysconfig
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/README Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,22 @@
+README - Platform virtualenv lib modifications
+-------------------------------------------------
+
+1. DJANGO-PISTON
+https://bitbucket.org/jespern/django-piston/overview
+------------------------------------------------------
+Model name collision with python-oauth.
+Described here: https://bitbucket.org/david/django-oauth/issue/3/collision-with-django-piston-on-syncdb
+
+Piston and Django-oauth use the same model for Tokens, and same related name to their ForeignKey User.
+One of the related_name has to be modified.
+See platform/virtualenv/web/res/patch/piston.diff
+
+
+2. PYTHON-OAUTH2
+https://github.com/simplegeo/python-oauth2
+---------------------------------------------
+Request paramters are not handled correctly, and sometimes appear twice in the request query_string.
+Described here: https://github.com/simplegeo/python-oauth2/issues#issue/21
+
+Modification made in get_normalized_parameters in order to avoid doubling the parameters, and making the request non-valid.
+See platform/virtualenv/web/res/patch/oauth2.diff
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/patch/django_contrib_auth_views.diff Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,20 @@
+--- Django-1.3/django/contrib/auth/views.py.OLD jeu. avr. 14 15:48:14 2011
++++ Django-1.3/django/contrib/auth/views.py jeu. avr. 14 15:48:32 2011
+@@ -18,6 +18,9 @@
+ from django.contrib.auth.tokens import default_token_generator
+ from django.contrib.sites.models import get_current_site
+
++#CHANGE BY TC FOR IRI'S PLATFORM
++from social_auth.views import list as social_list
++#END TC
+
+ @csrf_protect
+ @never_cache
+@@ -63,6 +66,7 @@
+ redirect_field_name: redirect_to,
+ 'site': current_site,
+ 'site_name': current_site.name,
++ 'social_list': social_list
+ }
+ context.update(extra_context or {})
+ return render_to_response(template_name, context,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/patch/oauth2.diff Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,11 @@
+diff -r 7ea87e3229fd5c4eebd0 oauth2/__init__.py
+@@ -385,386 +385,391 @@
+ url_items = self._split_url_string(query).items()
+ non_oauth_url_items = list([(k, v) for k, v in url_items if not k.startswith('oauth_')])
+
+- items.extend(non_oauth_url_items)
++ for (key,value) in non_oauth_url_items:
++ if (key,value) not in items:
++ items.append((key,value))
+
+ encoded_str = urllib.urlencode(sorted(items))
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/patch/piston.diff Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,8 @@
+diff -r 278:c4b2d21db51a piston/models.py
+@@ -118 +118 @@
+ timestamp = models.IntegerField()
+ is_approved = models.BooleanField(default=False)
+
+- user = models.ForeignKey(User, null=True, blank=True, related_name='tokens')
++ user = models.ForeignKey(User, null=True, blank=True, related_name='piston_tokens')
+ consumer = models.ForeignKey(Consumer)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/patch/social_auth_views_diff.diff Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,31 @@
+--- D:/CavalieT/My Documents/Flex Builder 3/platform_diane/platform/virtualenv/web/res/src/omab-django-social-auth-v0.3.8-9-g5d610a5/omab-django-social-auth-5d610a5/social_auth/views.py lun. mars 28 12:03:45 2011
++++ D:/CavalieT/My Documents/Flex Builder 3/platform_diane/platform/virtualenv/web/env/myplatformenv/Lib/site-packages/django_social_auth-0.3.8-py2.6.egg/social_auth/views.py ven. avr. 8 12:06:02 2011
+@@ -7,13 +7,27 @@
+ from django.contrib.auth import login, REDIRECT_FIELD_NAME
+ from django.contrib.auth.decorators import login_required
+
+-from social_auth.backends import get_backend
++from social_auth.backends import get_backend, get_backends
+ from social_auth.utils import sanitize_redirect
+
+
+ DEFAULT_REDIRECT = getattr(settings, 'LOGIN_REDIRECT_URL', '')
+
++#TC
++def list():
++ """Start list process"""
++ log_url = getattr(settings, 'LOGIN_URL', '')
++ response = "<ul>"
++ # We list all wanted backends among all availables
++ for backend in get_backends():
++ for backend_str in settings.AUTHENTICATION_BACKENDS:
++ if backend in backend_str:
++ response += "<li><a href=\"" + log_url + backend + "\">" + backend + "</a></li>"
++ response += "</ul>"
++ return response
++#END change by TC
+
++
+ def auth(request, backend):
+ """Start authentication process"""
+ complete_url = getattr(settings, 'SOCIAL_AUTH_COMPLETE_URL_NAME',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtualenv/web/res/res_create_env.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,54 @@
+import platform
+
+from lib_create_env import lib_generate_install_methods, install_pylucene, install_psycopg2
+
+system_str = platform.system()
+
+if system_str == 'Windows':
+ INSTALLS = [
+ ('JCC','easy_install',None,None),
+ ('PSYCOPG2',install_psycopg2,None,None),
+ ('PYLUCENE','easy_install',None,None),
+ ]
+else:
+ INSTALLS = [
+ ('PYLUCENE',install_pylucene,None,None),
+ ('PSYCOPG2', 'pip', None, None),
+ ]
+
+if system_str == 'Linux':
+ INSTALLS.extend([
+ ('DISTRIBUTE', 'pip', None, None),
+ ])
+
+INSTALLS.extend([ #(key,method, option_str, dict_extra_env)
+ ('SOUTH', 'pip', None, None),
+ ('SETUPTOOLS-HG', 'pip', None, None),
+ ('MYSQL', 'pip', None, None),
+ ('PIL', 'easy_install', None, None),
+ ('DJANGO','pip', None, None),
+ ('DJANGO-EXTENSIONS', 'pip', None, None),
+ ('DJANGO-REGISTRATION', 'easy_install', '-Z', None),
+ ('DJANGO-TAGGING', 'pip', None, None),
+ ('DJANGO-PISTON', 'pip', None, None),
+ ('HTTPLIB2', 'pip', None, None),
+ ('OAUTH2', 'easy_install', None, None),
+ ('DJANGO-OAUTH-PLUS', 'pip', None, None),
+ ('OPENID', 'pip', None, None),
+ ('DJANGO_OPENID_CONSUMER', 'pip', None, None),
+ ('SOCIAL_AUTH', 'easy_install', None, None),
+])
+
+if system_str == "Darwin":
+ INSTALLS.extend([
+ #('LXML', 'easy_install', None, {'STATIC_DEPS': 'true', 'LIBXML2_VERSION': '2.7.8', 'LIBXSLT_VERSION': '1.1.26', 'LIBICONV_VERSION': '1.13.1'}),
+ ('LXML', 'easy_install', None, {'LIBXML2_VERSION': '2.7.8', 'LIBXSLT_VERSION': '1.1.26', 'LIBICONV_VERSION': '1.13.1'}),
+ ])
+else:
+ INSTALLS.extend([
+ ('LXML', 'easy_install', None, None),
+ ])
+
+
+def generate_install_methods(path_locations, src_base, Logger, call_subprocess):
+ return lib_generate_install_methods(path_locations, src_base, Logger, call_subprocess, INSTALLS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/__init__.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,17 @@
+VERSION = (0, 3, 0, "final", 0)
+
+VERSION_STR = unicode(".".join(map(lambda i:"%02d" % (i,), VERSION[:2])))
+
+
+def get_version():
+ version = '%s.%s' % (VERSION[0], VERSION[1])
+ if VERSION[2]:
+ version = '%s.%s' % (version, VERSION[2])
+ if VERSION[3:] == ('alpha', 0):
+ version = '%s pre-alpha' % version
+ else:
+ if VERSION[3] != 'final':
+ version = '%s %s %s' % (version, VERSION[3], VERSION[4])
+ return version
+
+__version__ = get_version()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/config.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,82 @@
+import os, logging
+
+SITE_ID = 1
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__)).rstrip("/")+"/"
+BASE_URL = '/regards/'
+WEB_URL = 'http://localhost/'
+STATIC_URL = BASE_URL + 'static/'
+
+
+STREAM_URL = "rtmp://localhost/vod/"
+
+STREAM_SRC_PREFIX = ""
+
+#BASE_STATIC_ROOT = os.path.abspath(BASE_DIR + "../static/").rstrip("/")+"/"
+BASE_STATIC_ROOT = os.path.abspath(BASE_DIR + "static/").rstrip("/")+"/"
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = BASE_STATIC_ROOT + "media/"
+
+
+# Absolute path to the directory that static files (js, css, swf...)
+# DO NOT forget to do command line ./manage.py collectstatic to gather static media into the web/static folder
+#STATIC_ROOT = BASE_STATIC_ROOT + "site/"
+STATIC_ROOT = BASE_STATIC_ROOT
+
+# PATH to the ffmpeg executable, used to know automatically the media file duration
+FFMPEG_PATH = "/Applications/Lignes de temps/pkg/ffmpeg_mac"
+
+
+CONTENT_ROOT = BASE_STATIC_ROOT + "media/content/"
+
+# PATH where uploaded media are put.
+STREAM_PATH = "/Users/tc/dev/wowza_medias/"
+
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': 'regards_hg', # Or path to database file if using sqlite3.
+ 'USER': 'admin', # Not used with sqlite3.
+ 'PASSWORD': 'admin', # Not used with sqlite3.
+ 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '5432', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+#LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"../log/log.txt"))
+LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"log/log.txt"))
+LOG_LEVEL = logging.DEBUG
+
+#INDEX_PATH = os.path.abspath(BASE_DIR + "../index/")
+INDEX_PATH = os.path.abspath(BASE_DIR + "index/")
+
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+EMAIL_USE_TLS = True
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_HOST_USER = 'contact.iri@gmail.com'
+EMAIL_HOST_PASSWORD = 'Oach8quo'
+EMAIL_PORT = 587
+
+ACCOUNT_ACTIVATION_DAYS = 7
+REGISTRATION_OPEN = False
+
+LDT_MAX_SEARCH_NUMBER = 50
+LDT_MAX_FRAGMENT_PER_SEARCH = 3
+LDT_RESULTS_PER_PAGE = 1
+LDT_JSON_DEFAULT_INDENT = 0
+
+EMPTY_MEDIA_EXTERNALID = None
+
+AUTO_INDEX_AFTER_SAVE = True
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/config.py.tmpl Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,85 @@
+import os, logging
+
+SITE_ID = 1
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__)).rstrip("/")+"/"
+BASE_URL = '/~ymh/platform/'
+WEB_URL = 'http://localhost/'
+STATIC_URL = BASE_URL + 'static/'
+
+
+STREAM_URL = "rtmp://localhost/vod/media/"
+
+STREAM_SRC_PREFIX = ""
+
+BASE_STATIC_ROOT = os.path.abspath(BASE_DIR + "../static/").rstrip("/")+"/"
+BASE_STATIC_URL = BASE_URL + 'static/'
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = BASE_STATIC_ROOT + "media/"
+
+
+# Absolute path to the directory that static files (js, css, swf...)
+# DO NOT forget to do command line ./manage.py collectstatic to gather static media into the web/static folder
+#STATIC_ROOT = BASE_STATIC_ROOT + "site/"
+STATIC_ROOT = BASE_STATIC_ROOT
+
+# PATH to the ffmpeg executable, used to know automatically the media file duration
+FFMPEG_PATH = "C:/path/to/ffmpeg.exe"
+
+
+CONTENT_ROOT = BASE_STATIC_ROOT + "content/"
+
+# PATH where uploaded media are put.
+STREAM_PATH = CONTENT_ROOT
+
+ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
+LDT_MEDIA_PREFIX = STATIC_URL + 'ldt/'
+
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': 'regardssignes_hg', # Or path to database file if using sqlite3.
+ 'USER': 'iri', # Not used with sqlite3.
+ 'PASSWORD': 'iri', # Not used with sqlite3.
+ 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '5432', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+#LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"../log/log.txt"))
+LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"log/log.txt"))
+LOG_LEVEL = logging.DEBUG
+
+#INDEX_PATH = os.path.abspath(BASE_DIR + "../index/")
+INDEX_PATH = os.path.abspath(BASE_DIR + "index/")
+
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+EMAIL_USE_TLS = True
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_HOST_USER = 'iri.ddc@gmail.com'
+EMAIL_HOST_PASSWORD = 'ddciripompidou'
+EMAIL_PORT = 587
+
+ACCOUNT_ACTIVATION_DAYS = 7
+REGISTRATION_OPEN = False
+
+LDT_MAX_SEARCH_NUMBER = 50
+LDT_MAX_FRAGMENT_PER_SEARCH = 3
+LDT_RESULTS_PER_PAGE = 1
+LDT_JSON_DEFAULT_INDENT = 0
+
+EMPTY_MEDIA_EXTERNALID = None
+
+AUTO_INDEX_AFTER_SAVE = True
Binary file web/locale/fr/LC_MESSAGES/django.mo has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/locale/fr/LC_MESSAGES/django.po Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,51 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-09-14 16:54+0200\n"
+"PO-Revision-Date: 2010-02-17 02:57+0100\n"
+"Last-Translator: Yves-Marie Haussonne <ymh.work@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: \n"
+
+#: .\settings.py:40
+msgid "French"
+msgstr "Français"
+
+#: .\settings.py:41
+msgid "English"
+msgstr ""
+
+#: .\templates\registration\login.html.py:21
+msgid "Log in"
+msgstr "Connexion"
+
+#: .\templates\registration\login.html.py:24
+msgid "Sorry, that's not a valid username or password."
+msgstr "Désolé, mais ce n'est pas un identifiant ou un mot de passe valide"
+
+#: .\templates\registration\login.html.py:35
+msgid "Forget password?"
+msgstr "Mot de passe oublié ?"
+
+#: .\templates\registration\login.html.py:38
+msgid "login"
+msgstr "Connexion"
+
+#: .\templates\registration\login.html.py:45
+msgid "Or login with your external account"
+msgstr "Ou bien utilisez l'un de vos comptes externes"
+
+#~ msgid "header_title"
+#~ msgstr "Plateforme LDT"
+
+#~ msgid "page_title"
+#~ msgstr "Plateforme LDT"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/manage.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+ import settings # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/modwsgi.wsgi Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,35 @@
+import os, sys, site
+
+def application(environ, start_response):
+
+ global g_env_set
+
+ if 'g_env_set' not in globals() or not g_env_set:
+ os.environ['DJANGO_SETTINGS_MODULE'] = environ['DJANGO_SETTINGS_MODULE']
+
+ prev_sys_path = list(sys.path)
+
+ sys.path.append(environ['PROJECT_PATH'])
+ for path in environ.get('PYTHON_PATH',"").split(os.pathsep):
+ if path:
+ site.addsitedir(path)
+
+ new_sys_path = []
+ for item in list(sys.path):
+ if item not in prev_sys_path and item not in new_sys_path:
+ new_sys_path.append(item)
+ sys.path.remove(item)
+ sys.path[:0] = new_sys_path
+ g_env_set = True
+
+ import django.core.handlers.wsgi
+
+ _application = django.core.handlers.wsgi.WSGIHandler()
+
+ if environ.get('PYDEV_DEBUG', "False").lower() in ["true", "1", "t"]:
+ import pydevd #@UnresolvedImport
+ pydevd.settrace(suspend=False)
+
+
+ return _application(environ, start_response)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/settings.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,255 @@
+#@PydevCodeAnalysisIgnore
+import os.path
+#import ldtplatform
+VERSION = (0, 3, 0, "final", 0)
+VERSION_STR = unicode(".".join(map(lambda i:"%02d" % (i,), VERSION[:2])))
+def get_version():
+ version = '%s.%s' % (VERSION[0], VERSION[1])
+ if VERSION[2]:
+ version = '%s.%s' % (version, VERSION[2])
+ if VERSION[3:] == ('alpha', 0):
+ version = '%s pre-alpha' % version
+ else:
+ if VERSION[3] != 'final':
+ version = '%s %s %s' % (version, VERSION[3], VERSION[4])
+ return version
+__version__ = get_version()
+
+# Django settings for project.
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': '', # Or path to database file if using sqlite3.
+ 'USER': '', # Not used with sqlite3.
+ 'PASSWORD': '', # Not used with sqlite3.
+ 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Paris'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'fr-fr'
+
+ugettext = lambda s: s
+
+LANGUAGES = (
+ ('fr', ugettext('French')),
+ ('en', ugettext('English')),
+)
+
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+#MEDIA_ROOT = ''
+
+# Root of static files used by each app, generated by code or uploaded by users
+#STATIC_URL = '/static/'
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+#MEDIA_URL = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+#ADMIN_MEDIA_PREFIX = '/media/'
+
+#LDT_MEDIA_PREFIX = '/ldt/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 't^lii5_z@tho$%6t&b#dm#t9nz$$ylyclxvkdiyqbl+(dnt(ma'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+# 'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.gzip.GZipMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'ldt.ldt_utils.middleware.swfupload.SWFUploadMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ #'django.middleware.locale.LocaleMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django_openid_consumer.middleware.OpenIDMiddleware',
+ 'ldt.ldt_utils.middleware.userprofile.LanguageMiddleware',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.core.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.media",
+ "django.core.context_processors.static",
+ "ldt.utils.context_processors.ldt_context",
+)
+
+
+#ROOT_URLCONF = 'ldtplatform.urls'
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+ os.path.join(os.path.basename(__file__), 'templates'),
+ os.path.join(os.path.dirname(__file__), 'templates'),
+)
+
+FIXTURES_DIRS = (
+ os.path.join(os.path.basename(__file__), 'fixtures'),
+)
+
+INSTALLED_APPS = (
+ 'django_extensions',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.messages',
+ 'django.contrib.admin',
+ 'django.contrib.staticfiles',
+ #'ldtplatform',
+ 'registration',
+ 'tagging',
+ 'ldt',
+ 'ldt.core',
+ 'ldt.ldt_utils',
+ 'ldt.text',
+ 'ldt.user',
+ 'ldt.management',
+ 'oauth_provider',
+ 'django_openid_consumer',
+ 'piston',
+ 'social_auth',
+ 'south',
+)
+
+AUTH_PROFILE_MODULE = 'user.UserProfile'
+
+DECOUPAGE_BLACKLIST = (
+ "de_PPP",
+)
+
+ZIP_BLACKLIST = (
+ "__MACOSX",
+)
+
+AUTHENTICATION_BACKENDS = (
+ 'social_auth.backends.twitter.TwitterBackend',
+ 'social_auth.backends.facebook.FacebookBackend',
+# 'social_auth.backends.google.GoogleOAuthBackend',
+# 'social_auth.backends.google.GoogleOAuth2Backend',
+ 'social_auth.backends.google.GoogleBackend',
+ 'social_auth.backends.yahoo.YahooBackend',
+# 'social_auth.backends.contrib.linkedin.LinkedinBackend',
+# 'social_auth.backends.contrib.LiveJournalBackend',
+# 'social_auth.backends.contrib.orkut.OrkutBackend',
+ 'social_auth.backends.OpenIDBackend',
+ 'django.contrib.auth.backends.ModelBackend',
+)
+SOCIAL_AUTH_IMPORT_BACKENDS = (
+ 'myproy.social_auth_extra_services',
+)
+
+ACCOUNT_ACTIVATION_DAYS = 7
+
+LDT_MAX_SEARCH_NUMBER = 50
+LDT_JSON_DEFAULT_INDENT = 2
+
+OAUTH_PROVIDER_KEY_SIZE = 32
+OAUTH_PROVIDER_SECRET_SIZE = 32
+OAUTH_PROVIDER_VERIFIER_SIZE = 10
+OAUTH_PROVIDER_CONSUMER_KEY_SIZE = 256
+OAUTH_AUTHORIZE_VIEW = 'oauth_provider.views.fake_authorize_view'
+OAUTH_CALLBACK_VIEW = 'oauth_provider.views.fake_callback_view'
+TEST_WEBSERVER_ADDRPORT = "127.0.0.1:8888"
+
+TWITTER_CONSUMER_KEY = 'UxAdbOLSo4Mx3CXIwDG9Eg'
+TWITTER_CONSUMER_SECRET = '2PcWgdjnJL6Vp8srB40jeAo0fjMEtDnUwmAia6EUww'
+FACEBOOK_APP_ID = '163134140411313'
+FACEBOOK_API_SECRET = 'f25e0754a44f0d90d3f4d9ea961ff012'
+
+SOCIAL_AUTH_COMPLETE_URL_NAME = 'complete'
+SOCIAL_AUTH_ASSOCIATE_URL_NAME = 'associate_complete'
+
+# twitter testing
+TEST_TWITTER_USER = 'jacquesverrier@gmail.com'
+TEST_TWITTER_PASSWORD = ''
+
+# facebook testing
+#TEST_FACEBOOK_USER = 'testing_account'
+#TEST_FACEBOOK_PASSWORD = 'password_for_testing_account'
+
+# google testing
+TEST_GOOGLE_USER = 'jacquesverrier@gmail.com'
+TEST_GOOGLE_PASSWORD = ''
+
+AUTO_INDEX_AFTER_SAVE = True
+
+#WEB_VERSION = ldtplatform.get_version()
+WEB_VERSION = get_version()
+
+from config import *
+
+if not "LOGIN_URL" in locals():
+ LOGIN_URL = BASE_URL + 'accounts/login/'
+if not "LOGOUT_URL" in locals():
+ LOGOUT_URL = BASE_URL + 'accounts/disconnect/'
+if not "LOGIN_REDIRECT_URL" in locals():
+ LOGIN_REDIRECT_URL = BASE_URL + 'ldt/'
+if not "LOGOUT_REDIRECT_URL" in locals():
+ LOGOUT_REDIRECT_URL = BASE_URL + 'accounts/login'
+if not "PROFILE_REDIRECT_URL" in locals():
+ PROFILE_REDIRECT_URL = BASE_URL + 'auth_accounts/create/profile'
+
+if not "LOGIN_ERROR_URL" in locals():
+ LOGIN_ERROR_URL = BASE_URL + 'accounts/login'
+
+if not "GLOBAL_LOG_LEVEL" in locals():
+ GLOBAL_LOG_LEVEL = LOG_LEVEL
+if not "GLOBAL_LOG_HANDLERS" in locals():
+ GLOBAL_LOG_HANDLERS = [{'handler':logging.FileHandler(LOG_FILE), 'format':"%(asctime)s - %(levelname)s : %(message)s"}]
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+if not "ADMIN_MEDIA_PREFIX" in locals():
+ ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
+# Used in a lot of templates
+if not "LDT_MEDIA_PREFIX" in locals():
+ LDT_MEDIA_PREFIX = STATIC_URL + 'ldt/'
+# URL that handles the media served from MEDIA_ROOT.
+if not "MEDIA_URL" in locals():
+ MEDIA_URL = BASE_URL + 'static/media/'
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/templates/admin/base_site.html Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,21 @@
+{% extends "admin/base.html" %}
+{% load i18n %}
+
+{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
+
+{% block branding %}
+<h1 id="site-name">{% trans 'Django administration' %}</h1>
+{% endblock %}
+
+{% block nav-global %}
+ <style type="text/css">
+ .adminlink {
+ margin:0 10px 10px;
+ display:block;
+ float:left;
+ }
+ </style>
+
+ <a href="{% url admin:index %}" class="adminlink">Admin home</a>
+ <a href="{% url root-view %}" class="adminlink">Website home</a>
+{% endblock %}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/templates/ldt/ldt_utils/workspace.html Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,2 @@
+{% extends "ldt/ldt_utils/workspace_base.html" %}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/templates/registration/login.html Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,60 @@
+{% extends "registration/base.html" %}
+{% load i18n %}
+{% block js_declaration %}{{ block.super }}
+ <script type="text/javascript">
+ $(document).ready(function() {
+ $("#login-form").validate();
+ });
+ </script>
+{% endblock %}
+
+{% block css_import %}
+ {{ block.super }}
+ <link rel="stylesheet" href="{{LDT_MEDIA_PREFIX}}css/ldt.css" />
+ <link rel="stylesheet" href="{{LDT_MEDIA_PREFIX}}css/ldtform.css" />
+{% endblock %}
+
+
+{% block login %}
+{% endblock %}
+
+{% block content_title %}{% trans 'Log in' %}{% endblock %}
+{% block iricontent %}
+ {% if form.errors %}
+ <p class="error">{% trans "Sorry, that's not a valid username or password." %}</p>
+ {% endif %}
+ <div class="span-24 last">
+ <form action="" method='post' id="login-form">
+ <div id="loginform_div" class="span-12">
+ {% csrf_token %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ <ul id="login_fields_list">
+ {{form.as_ul}}
+ </ul>
+ <ul>
+ <li><a href="{% url django.contrib.auth.views.password_reset %}" >{% trans "Forget password?" %}</a></li>
+ </ul>
+ <div id="submitcontent-buttons-login" class="span-24 last">
+ <button class="button"type="submit" value="login">{% trans "login" %}</button>
+ </div>
+ </div>
+ </form>
+ <div id="login_links" class="span-12 last">
+ <div id="login_links_list" class="span-12 last">
+ {% if social_list %}
+ <p>{% trans "Or login with your external account" %} :</p>
+ <ul>
+ {% for backend_name in social_list %}
+ <li><a href="{{ backend_name }}"><img src="{{LDT_MEDIA_PREFIX}}img/logo_{{backend_name}}.png" /> {{ backend_name }}</a></li>
+ {% endfor %}
+ {% comment %}{{social_list|safe}}{% endcomment %}
+ </ul>
+ {% endif %}
+ </div>
+ </div>
+ </div>
+
+{% endblock %}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/urls.py Fri Sep 30 16:06:04 2011 +0200
@@ -0,0 +1,45 @@
+from django.conf.urls.defaults import patterns, include, url
+from django.contrib import admin
+from ldt.auth.views import login as pf_login
+from ldt.text import VERSION_STR
+
+#from django.conf import settings
+
+# Uncomment the next two lines to enable the admin:
+admin.autodiscover()
+
+js_info_dict = {
+ 'packages': ('django.contrib.admin',),
+}
+
+urlpatterns = patterns('',
+ # Example:
+
+ # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
+ # to INSTALLED_APPS to enable admin documentation:
+ # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+ # Uncomment the next line to enable the admin:
+ (r'^admin/', include(admin.site.urls)),
+ (r'^i18n/', include('django.conf.urls.i18n')),
+
+ (r'^ldt/', include('ldt.ldt_utils.urls')),
+ (r'^user/', include('ldt.user.urls')),
+ (r'^api/', include('ldt.api.urls')),
+ (r'^api/' + VERSION_STR + '/text/', include('ldt.text.urls')),
+
+ (r'^auth_accounts/', include('registration.backends.simple.urls')),
+
+ #(r'^accounts/', include('socialauth.urls')),
+ (r'^accounts/', include('social_auth.urls')),
+ url(r'^accounts/login/$',pf_login,{'template_name': 'registration/login.html'},name='auth_login'),
+ (r'^oauth/', include('oauth_provider.urls')),
+
+ #(r'^$', 'socialauth.views.signin_complete'),
+ #(r'^$', 'social_auth.views.complete'),
+
+ (r'^/?$', 'django.views.generic.simple.redirect_to', {'url': 'ldt'}),
+ #(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
+
+ (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
+)