Skip to content

bpo-30362 : Add list options to launcher. #1578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,21 @@ Changes in the C API
characters. (Contributed by Serhiy Storchaka in :issue:`30708`.)


Windows Only
------------
- The python launcher, (py.exe), can accept 32 & 64 bit specifiers **without**
having to specify a minor version as well. So ``py -3-32`` and ``py -3-64``
become valid as well as ``py -3.7-32``, also the -*m*-64 and -*m.n*-64 forms
are now accepted to force 64 bit python even if 32 bit would have otherwise
been used. If the specified version is not available py.exe will error exit.
(Contributed by Steve Barnes in :issue:`30291`.)

- The launcher can be run as "py -0" to produce a list of the installed pythons,
*with default marked with an asterix*. Running "py -0p" will include the paths.
If py is run with a version specifier that cannot be matched it will also print
the *short form* list of available specifiers.
(Contributed by Steve Barnes in :issue:`30362`.)

Removed
=======

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds list options (-0, -0p) to py.exe launcher. Contributed by Steve Barnes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow requiring 64-bit interpreters from py.exe using -64 suffix. Contributed
by Steve (Gadget) Barnes.
158 changes: 115 additions & 43 deletions PC/launcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,89 @@ get_version_info(wchar_t * version_text, size_t size)
}
}

static void
show_help_text(wchar_t ** argv)
{
wchar_t version_text [MAX_PATH];
#if defined(_M_X64)
BOOL canDo64bit = TRUE;
#else
/* If we are a 32bit process on a 64bit Windows, first hit the 64bit keys. */
BOOL canDo64bit = FALSE;
IsWow64Process(GetCurrentProcess(), &canDo64bit);
#endif

get_version_info(version_text, MAX_PATH);
fwprintf(stdout, L"\
Python Launcher for Windows Version %ls\n\n", version_text);
fwprintf(stdout, L"\
usage:\n\
%ls [launcher-args] [python-args] script [script-args]\n\n", argv[0]);
fputws(L"\
Launcher arguments:\n\n\
-2 : Launch the latest Python 2.x version\n\
-3 : Launch the latest Python 3.x version\n\
-X.Y : Launch the specified Python version\n", stdout);
if (canDo64bit) {
fputws(L"\
The above all default to 64 bit if a matching 64 bit python is present.\n\
-X.Y-32: Launch the specified 32bit Python version\n\
-X-32 : Launch the latest 32bit Python X version\n\
-X.Y-64: Launch the specified 64bit Python version\n\
-X-64 : Launch the latest 64bit Python X version", stdout);
}
fputws(L"\n-0 --list : List the available pythons", stdout);
fputws(L"\n-0p --list-paths : List with paths", stdout);
fputws(L"\n\nThe following help text is from Python:\n\n", stdout);
fflush(stdout);
}

static BOOL
show_python_list(wchar_t ** argv)
{
/*
* Display options -0
*/
INSTALLED_PYTHON * result = NULL;
INSTALLED_PYTHON * ip = installed_pythons; /* List of installed pythons */
INSTALLED_PYTHON * defpy = locate_python(L"", FALSE);
size_t i = 0;
wchar_t *p = argv[1];
wchar_t *fmt = L"\n -%ls-%d"; /* print VER-BITS */
wchar_t *defind = L" *"; /* Default indicator */

/*
* Output informational messages to stderr to keep output
* clean for use in pipes, etc.
*/
fwprintf(stderr,
L"Installed Pythons found by %s Launcher for Windows", argv[0]);
if (!_wcsicmp(p, L"-0p") || !_wcsicmp(p, L"--list-paths")) /* Show path? */
fmt = L"\n -%ls-%d\t%ls"; /* print VER-BITS path */

if (num_installed_pythons == 0) /* We have somehow got here without searching for pythons */
locate_all_pythons(); /* Find them, Populates installed_pythons */

if (num_installed_pythons == 0) /* No pythons found */
fwprintf(stderr, L"\nNo Installed Pythons Found!");
else
{
for (i = 0; i < num_installed_pythons; i++, ip++) {
fwprintf(stdout, fmt, ip->version, ip->bits, ip->executable);
Copy link
Contributor

@eryksun eryksun May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really need to print the executable path? It's trivial to get that information manually.

/* If there is a default indicate it */
if ((defpy != NULL) && !_wcsicmp(ip->executable, defpy->executable))
fwprintf(stderr, defind);
}
}

if ((defpy == NULL) && (num_installed_pythons > 0))
/* We have pythons but none is the default */
fwprintf(stderr, L"\n\nCan't find a Default Python.\n\n");
else
fwprintf(stderr, L"\n\n"); /* End with a blank line */
return(FALSE); /* If this has been called we cannot continue */
}

static int
process(int argc, wchar_t ** argv)
{
Expand All @@ -1380,12 +1463,12 @@ process(int argc, wchar_t ** argv)
wchar_t * p;
int rc = 0;
size_t plen;
size_t slen;
INSTALLED_PYTHON * ip;
BOOL valid;
DWORD size, attrs;
HRESULT hr;
wchar_t message[MSGSIZE];
wchar_t version_text [MAX_PATH];
void * version_data;
VS_FIXEDFILEINFO * file_info;
UINT block_size;
Expand Down Expand Up @@ -1516,12 +1599,22 @@ process(int argc, wchar_t ** argv)
else {
p = argv[1];
plen = wcslen(p);
valid = (*p == L'-') && validate_version(&p[1]);
if (argc == 2) {
slen = wcslen(L"-0");
if(!wcsncmp(p, L"-0", slen)) /* Starts with -0 */
valid = show_python_list(argv); /* Check for -0 FIRST */
}
valid = valid && (*p == L'-') && validate_version(&p[1]);
if (valid) {
ip = locate_python(&p[1], FALSE);
if (ip == NULL)
{
fwprintf(stdout, \
L"Python %ls not found!\n", &p[1]);
valid = show_python_list(argv);
error(RC_NO_PYTHON, L"Requested Python version (%ls) not \
installed", &p[1]);
installed, use -0 for available pythons", &p[1]);
}
executable = ip->executable;
command += wcslen(p);
command = skip_whitespace(command);
Expand All @@ -1540,49 +1633,28 @@ installed", &p[1]);
#endif

if (!valid) {
/* Look for an active virtualenv */
executable = find_python_by_venv();

/* If we didn't find one, look for the default Python */
if (executable == NULL) {
ip = locate_python(L"", FALSE);
if (ip == NULL)
error(RC_NO_PYTHON, L"Can't find a default Python.");
executable = ip->executable;
}
if ((argc == 2) && (!_wcsicmp(p, L"-h") || !_wcsicmp(p, L"--help"))) {
#if defined(_M_X64)
BOOL canDo64bit = TRUE;
#else
/* If we are a 32bit process on a 64bit Windows, first hit the 64bit keys. */
BOOL canDo64bit = FALSE;
IsWow64Process(GetCurrentProcess(), &canDo64bit);
#endif

get_version_info(version_text, MAX_PATH);
fwprintf(stdout, L"\
Python Launcher for Windows Version %ls\n\n", version_text);
fwprintf(stdout, L"\
usage:\n\
%ls [launcher-args] [python-args] script [script-args]\n\n", argv[0]);
fputws(L"\
Launcher arguments:\n\n\
-2 : Launch the latest Python 2.x version\n\
-3 : Launch the latest Python 3.x version\n\
-X.Y : Launch the specified Python version\n", stdout);
if (canDo64bit) {
fputws(L"\
The above all default to 64 bit if a matching 64 bit python is present.\n\
-X.Y-32: Launch the specified 32bit Python version\n\
-X-32 : Launch the latest 32bit Python X version\n\
-X.Y-64: Launch the specified 64bit Python version\n\
-X-64 : Launch the latest 64bit Python X version", stdout);
if ((argc == 2) && (!_wcsicmp(p, L"-h") || !_wcsicmp(p, L"--help")))
show_help_text(argv);
if ((argc == 2) && (!_wcsicmp(p, L"-0") || !_wcsicmp(p, L"-0p")))
executable = NULL; /* Info call only */
else
{
/* Look for an active virtualenv */
executable = find_python_by_venv();

/* If we didn't find one, look for the default Python */
if (executable == NULL) {
ip = locate_python(L"", FALSE);
if (ip == NULL)
error(RC_NO_PYTHON, L"Can't find a default Python.");
executable = ip->executable;
}
fputws(L"\n\nThe following help text is from Python:\n\n", stdout);
fflush(stdout);
}
}
invoke_child(executable, NULL, command);
if (executable != NULL)
invoke_child(executable, NULL, command);
else
rc = RC_NO_PYTHON;
return rc;
}

Expand Down