[Python-checkins] r53194 - in sandbox/branches/setuptools-0.6: README.txt launcher.c setuptools.txt setuptools/cli.exe setuptools/command/easy_install.py setuptools/gui.exe
phillip.eby
python-checkins at python.org
Fri Dec 29 18:43:40 CET 2006
Author: phillip.eby
Date: Fri Dec 29 18:43:39 2006
New Revision: 53194
Modified:
sandbox/branches/setuptools-0.6/README.txt
sandbox/branches/setuptools-0.6/launcher.c
sandbox/branches/setuptools-0.6/setuptools.txt
sandbox/branches/setuptools-0.6/setuptools/cli.exe
sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py
sandbox/branches/setuptools-0.6/setuptools/gui.exe
Log:
Overhauled Windows script wrapping to support ``bdist_wininst`` better.
Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or
``#!pythonw.exe`` as the executable name (even when built on non-Windows
platforms!), and the wrappers will look for the executable in the script's
parent directory (which should find the right version of Python).
(backport from trunk)
Modified: sandbox/branches/setuptools-0.6/README.txt
==============================================================================
--- sandbox/branches/setuptools-0.6/README.txt (original)
+++ sandbox/branches/setuptools-0.6/README.txt Fri Dec 29 18:43:39 2006
@@ -14,7 +14,8 @@
Install setuptools using the provided ``.exe`` installer. If you've previously
installed older versions of setuptools, please delete all ``setuptools*.egg``
-files from your system FIRST.
+and ``setuptools.pth`` files from your system's ``site-packages`` directory
+(and any other ``sys.path`` directories) FIRST.
If you are upgrading a previous version of setuptools that was installed using
an ``.exe`` installer, please be sure to also *uninstall that older version*
@@ -23,9 +24,7 @@
Once installation is complete, you will find an ``easy_install.exe`` program in
your Python ``Scripts`` subdirectory. Be sure to add this directory to your
-``PATH`` environment variable, if you haven't already done so. You must also
-have your Python installation directory (e.g. ``C:\\Python23``) on the
-``PATH``.
+``PATH`` environment variable, if you haven't already done so.
RPM-Based Systems
Modified: sandbox/branches/setuptools-0.6/launcher.c
==============================================================================
--- sandbox/branches/setuptools-0.6/launcher.c (original)
+++ sandbox/branches/setuptools-0.6/launcher.c Fri Dec 29 18:43:39 2006
@@ -22,6 +22,7 @@
starting. So, we have to use spawnv() and wait for Python to exit before
continuing. :(
*/
+
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -29,20 +30,25 @@
#include "windows.h"
int fail(char *format, char *data) {
- /* Print error message to stderr and return 1 */
+ /* Print error message to stderr and return 2 */
fprintf(stderr, format, data);
return 2;
}
+
+
+
+
char *quoted(char *data) {
- int i, l = strlen(data), nb;
+ int i, ln = strlen(data), nb;
+
/* We allocate twice as much space as needed to deal with worse-case
of having to escape everything. */
- char *result = calloc(l*2+3, sizeof(char));
+ char *result = calloc(ln*2+3, sizeof(char));
char *presult = result;
*presult++ = '"';
- for (nb=0, i=0; i < l; i++)
+ for (nb=0, i=0; i < ln; i++)
{
if (data[i] == '\\')
nb += 1;
@@ -56,6 +62,7 @@
nb = 0;
*presult++ = data[i];
}
+
for (; nb > 0; nb--) /* Deal w trailing slashes */
*presult++ = '\\';
@@ -64,49 +71,108 @@
return result;
}
-char *getpyopt(char *python)
+
+
+
+
+
+
+
+
+
+char *loadable_exe(char *exename) {
+ HINSTANCE hPython; /* DLL handle for python executable */
+ char *result;
+
+ hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hPython) return NULL;
+
+ /* Return the absolute filename for spawnv */
+ result = calloc(MAX_PATH, sizeof(char));
+ if (result) GetModuleFileName(hPython, result, MAX_PATH);
+
+ FreeLibrary(hPython);
+ return result;
+}
+
+
+char *find_exe(char *exename, char *script) {
+ char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
+ char path[_MAX_PATH], c, *result;
+
+ /* convert slashes to backslashes for uniform search below */
+ result = exename;
+ while (c = *result++) if (c=='/') result[-1] = '\\';
+
+ _splitpath(exename, drive, dir, fname, ext);
+ if (drive[0] || dir[0]=='\\') {
+ return loadable_exe(exename); /* absolute path, use directly */
+ }
+ /* Use the script's parent directory, which should be the Python home
+ (This should only be used for bdist_wininst-installed scripts, because
+ easy_install-ed scripts use the absolute path to python[w].exe
+ */
+ _splitpath(script, drive, dir, fname, ext);
+ result = dir + strlen(dir) -1;
+ if (*result == '\\') result--;
+ while (*result != '\\' && result>=dir) *result-- = 0;
+ _makepath(path, drive, dir, exename, NULL);
+ return loadable_exe(path);
+}
+
+
+char **parse_argv(char *cmdline, int *argc)
{
- /* Search a Python command string, read from a #! line for an
- option. An option must be separated from an executable name by
- one or more spaces. An option consistes of a hyphen followed by
- one or more letters.
- */
- static char *letters =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ;
- char *p = python + strlen(python) - 1;
- if (strchr(letters, *p) == NULL)
- return NULL; /* Path doen't end with a letter. Odd. */
- while (p > python && strchr(letters, *p) != NULL)
- p--;
- if (p == python || *p != '-')
- return NULL; /* Can't be an option */
- p--;
- if (p > python && isspace(*p))
- { /* BINGO, we have an option */
- char *pyopt = p+1;
- /* strip trailing spaces from remainder of python command */
- while (p > python && isspace(*p))
- *p-- = '\0';
- return pyopt;
- }
- else
- return NULL;
+ /* Parse a command line in-place using MS C rules */
+
+ char **result = calloc(strlen(cmdline), sizeof(char *));
+ char *output = cmdline;
+ char c;
+ int nb = 0;
+ *argc = 0;
+
+ result[0] = output;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+
+ do {
+ c = *cmdline++;
+ if (!c || isspace(c)) {
+ while (nb) {*output++ = '\\'; nb--; }
+ *output++ = 0;
+ result[++*argc] = output;
+ if (!c) return result;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+ continue;
+ }
+ if (c == '\\')
+ ++nb; /* count \'s */
+ else {
+ if (c == '"') {
+ if (!(nb & 1)) c = 0; /* skip " unless odd # of \ */
+ nb = nb >> 1; /* cut \'s in half */
+ }
+ while (nb) {*output++ = '\\'; nb--; }
+ if (c) *output++ = c;
+ }
+ } while (1);
}
+
+
+
+
+
int run(int argc, char **argv, int is_gui) {
char python[256]; /* python executable's filename*/
char *pyopt; /* Python option */
char script[256]; /* the script's filename */
- HINSTANCE hPython; /* DLL handle for python executable */
int scriptf; /* file descriptor for script file */
- char **newargs, **newargsp; /* argument array for exec */
+ char **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */
- int i; /* loop counter */
+ int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/
GetModuleFileName(NULL, script, sizeof(script));
@@ -126,57 +192,51 @@
close(scriptf);
ptr = python-1;
- while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {
- if (*ptr=='/')
- *ptr='\\'; /* convert slashes to avoid LoadLibrary crashes... */
- }
+ while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
*ptr-- = '\0';
- while (ptr>python && isspace(*ptr)) *ptr-- = '\0'; /* strip trailing sp */
+
if (strncmp(python, "#!", 2)) {
/* default to python.exe if no #! header */
strcpy(python, "#!python.exe");
}
- /* Check for Python options */
- pyopt = getpyopt(python);
-
- /* At this point, the python buffer contains "#!pythonfilename" */
+ parsedargs = parse_argv(python+2, &parsedargc);
/* Using spawnv() can fail strangely if you e.g. find the Cygwin
Python, so we'll make sure Windows can find and load it */
- hPython = LoadLibraryEx(python+2, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- if (!hPython) {
- return fail("Cannot find Python executable %s\n", python+2);
+
+ ptr = find_exe(parsedargs[0], script);
+ if (!ptr) {
+ return fail("Cannot find Python executable %s\n", parsedargs[0]);
}
- /* And we'll use the absolute filename for spawnv */
- GetModuleFileName(hPython, python, sizeof(python));
+ /* printf("Python executable: %s\n", ptr); */
- /* printf("Python executable: %s\n", python); */
+ /* Argument array needs to be
+ parsedargc + argc, plus 1 for null sentinel */
- /* Argument array needs to be
- argc+1 for python executable,
- plus 1 for possible python opts,
- plus 1 for null sentinel */
- newargs = (char **)calloc(argc+3, sizeof(char *));
+ newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
newargsp = newargs;
- *newargsp++ = quoted(python);
- if (pyopt)
- *newargsp++ = pyopt;
+
+ *newargsp++ = quoted(ptr);
+ for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
+
*newargsp++ = quoted(script);
- for (i = 1; i < argc; i++)
- *newargsp++ = quoted(argv[i]);
+ for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
+
*newargsp++ = NULL;
/* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
+
if (is_gui) {
/* Use exec, we don't need to wait for the GUI to finish */
execv(python, (const char * const *)(newargs));
return fail("Could not exec %s", python); /* shouldn't get here! */
}
+
/* We *do* need to wait for a CLI to finish, so use spawn */
- return spawnv(P_WAIT, python, (const char * const *)(newargs));
+ return spawnv(P_WAIT, ptr, (const char * const *)(newargs));
}
@@ -184,8 +244,3 @@
return run(__argc, __argv, GUI);
}
-
-
-
-
-
Modified: sandbox/branches/setuptools-0.6/setuptools.txt
==============================================================================
--- sandbox/branches/setuptools-0.6/setuptools.txt (original)
+++ sandbox/branches/setuptools-0.6/setuptools.txt Fri Dec 29 18:43:39 2006
@@ -2601,6 +2601,13 @@
----------------------------
0.6c4
+
+ * Overhauled Windows script wrapping to support ``bdist_wininst`` better.
+ Scripts installed with ``bdist_wininst`` will always use ``#!python.exe`` or
+ ``#!pythonw.exe`` as the executable name (even when built on non-Windows
+ platforms!), and the wrappers will look for the executable in the script's
+ parent directory (which should find the right version of Python).
+
* Fix ``upload`` command not uploading files built by ``bdist_rpm`` or
``bdist_wininst`` under Python 2.3 and 2.4.
Modified: sandbox/branches/setuptools-0.6/setuptools/cli.exe
==============================================================================
Binary files. No diff available.
Modified: sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py
==============================================================================
--- sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py (original)
+++ sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py Fri Dec 29 18:43:39 2006
@@ -369,16 +369,13 @@
def install_egg_scripts(self, dist):
"""Write all the scripts for `dist`, unless scripts are excluded"""
-
+ if not self.exclude_scripts and dist.metadata_isdir('scripts'):
+ for script_name in dist.metadata_listdir('scripts'):
+ self.install_script(
+ dist, script_name,
+ dist.get_metadata('scripts/'+script_name).replace('\r','\n')
+ )
self.install_wrapper_scripts(dist)
- if self.exclude_scripts or not dist.metadata_isdir('scripts'):
- return
-
- for script_name in dist.metadata_listdir('scripts'):
- self.install_script(
- dist, script_name,
- dist.get_metadata('scripts/'+script_name).replace('\r','\n')
- )
def add_output(self, path):
if os.path.isdir(path):
@@ -408,6 +405,9 @@
+
+
+
def easy_install(self, spec, deps=False):
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
download = None
@@ -1407,7 +1407,6 @@
else:
return path
-
def get_script_header(script_text, executable=sys_executable, wininst=False):
"""Create a #! line, getting options (if any) from script_text"""
from distutils.command.build_scripts import first_line_re
@@ -1418,8 +1417,10 @@
options = match.group(1) or ''
if options:
options = ' '+options
- if wininst and sys.platform!='win32':
+ if wininst:
executable = "python.exe"
+ else:
+ executable = nt_quote_arg(executable)
hdr = "#!%(executable)s%(options)s\n" % locals()
if unicode(hdr,'ascii','ignore').encode('ascii') != hdr:
# Non-ascii path to sys.executable, use -x to prevent warnings
@@ -1432,7 +1433,6 @@
hdr = "#!%(executable)s%(options)s\n" % locals()
return hdr
-
def auto_chmod(func, arg, exc):
if func is os.remove and os.name=='nt':
os.chmod(arg, stat.S_IWRITE)
@@ -1474,6 +1474,47 @@
+def nt_quote_arg(arg):
+ """Quote a command line argument according to Windows parsing rules"""
+
+ result = []
+ needquote = False
+ nb = 0
+
+ needquote = (" " in arg) or ("\t" in arg)
+ if needquote:
+ result.append('"')
+
+ for c in arg:
+ if c == '\\':
+ nb += 1
+ elif c == '"':
+ # double preceding backslashes, then add a \"
+ result.append('\\' * (nb*2) + '\\"')
+ nb = 0
+ else:
+ if nb:
+ result.append('\\' * nb)
+ nb = 0
+ result.append(c)
+
+ if nb:
+ result.append('\\' * nb)
+
+ if needquote:
+ result.append('\\' * nb) # double the trailing backslashes
+ result.append('"')
+
+ return ''.join(result)
+
+
+
+
+
+
+
+
+
def is_python_script(script_text, filename):
"""Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
"""
@@ -1532,7 +1573,7 @@
")\n"
) % locals()
if sys.platform=='win32' or wininst:
- # On Windows, add a .py extension and an .exe launcher
+ # On Windows/wininst, add a .py extension and an .exe launcher
if group=='gui_scripts':
ext, launcher = '-script.pyw', 'gui.exe'
old = ['.pyw']
@@ -1540,9 +1581,9 @@
else:
ext, launcher = '-script.py', 'cli.exe'
old = ['.py','.pyc','.pyo']
- new_header = re.sub('(?i)pythonw.exe','pythonw.exe',header)
+ new_header = re.sub('(?i)pythonw.exe','python.exe',header)
- if os.path.exists(new_header[2:-1]):
+ if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header
else:
hdr = header
Modified: sandbox/branches/setuptools-0.6/setuptools/gui.exe
==============================================================================
Binary files. No diff available.
More information about the Python-checkins
mailing list