From 5b8f972e093157cc55185841db9ad33fa332a641 Mon Sep 17 00:00:00 2001 From: "Steve (Gadget) Barnes" Date: Wed, 28 Jun 2017 20:14:52 +0100 Subject: [PATCH] bpo-30362 : Add list options to launcher. (#1578) * bpo-30362 Add list options to launcher. * bpo-30362 Add list options to help message. * To avoid possible later conflict with python replaced flags with --launcher-list and --launcher-list-paths * bpo-30362 Changed flag to -0 as suggested on review. * bpo-30362: Modified to default to not path for -0, -0p to dispaly path and append * to default * bpo-30362: Modified to display list on required version not found. * bpo-30362 add --list and --list-paths added back in following review by paul.moore * bpo-30362 Cleaner handing of -0 & -0p by not calling exit directly per review by @zooba * bpo-30362: Tidy up and add news & what's new Removed commented out line of code in PC/launcher.c. Added the results of using blurb to add details of bpo-30362 & bpo-30291. Updated Doc/whatsnew/3.7.rst to add a Windows only section covering both tickets. * bpo-30362 Resolve conflict in Doc/whatsnew/3.7.rst * bpo-30362:Address Whitespace Issue in Doc\whatsnew\3.7.rst * Shorten NEWS message for bpo-30362 * Shorten NEWS item for bpo-30291 --- Doc/whatsnew/3.7.rst | 15 ++ .../2017-06-28-03-08-22.bpo-30362.XxeVMB.rst | 1 + .../2017-06-28-03-20-48.bpo-30291.zBpOl6.rst | 2 + PC/launcher.c | 156 +++++++++++++----- 4 files changed, 132 insertions(+), 42 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2017-06-28-03-08-22.bpo-30362.XxeVMB.rst create mode 100644 Misc/NEWS.d/next/Windows/2017-06-28-03-20-48.bpo-30291.zBpOl6.rst diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index e34268e0824..c75d7692a4d 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -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 ======= diff --git a/Misc/NEWS.d/next/Windows/2017-06-28-03-08-22.bpo-30362.XxeVMB.rst b/Misc/NEWS.d/next/Windows/2017-06-28-03-08-22.bpo-30362.XxeVMB.rst new file mode 100644 index 00000000000..fb24ec541f3 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2017-06-28-03-08-22.bpo-30362.XxeVMB.rst @@ -0,0 +1 @@ +Adds list options (-0, -0p) to py.exe launcher. Contributed by Steve Barnes. diff --git a/Misc/NEWS.d/next/Windows/2017-06-28-03-20-48.bpo-30291.zBpOl6.rst b/Misc/NEWS.d/next/Windows/2017-06-28-03-20-48.bpo-30291.zBpOl6.rst new file mode 100644 index 00000000000..2869823326d --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2017-06-28-03-20-48.bpo-30291.zBpOl6.rst @@ -0,0 +1,2 @@ +Allow requiring 64-bit interpreters from py.exe using -64 suffix. Contributed +by Steve (Gadget) Barnes. diff --git a/PC/launcher.c b/PC/launcher.c index 25fa4ca9c21..0733df7563f 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -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); + /* 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) { @@ -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; @@ -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); @@ -1540,49 +1633,28 @@ installed", &p[1]); #endif if (!valid) { - /* Look for an active virtualenv */ - executable = find_python_by_venv(); + 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; - } - 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 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; }