mirror of https://github.com/python/cpython
gh-101135: Add backwards compatibility to Windows launcher for older 32-bit versions (GH-101138)
Python 2.x and up to 3.4 did not contain the "-32" in their registry name, so the 32 and 64-bit installs were treated equal. Since 3.5/PEP 514 this is no longer true, but we still want to detect the EOL versions correctly in case people are still using them. Additionally, the code to replace a node with one with a lower sort key was buggy (wrong node chosen, replace never happened since parent was always NULL, replaced node never freed, etc)
This commit is contained in:
parent
fee7a995a1
commit
daec3a463c
|
@ -0,0 +1,3 @@
|
||||||
|
Restore ability to launch older 32-bit versions from the :file:`py.exe`
|
||||||
|
launcher when both 32-bit and 64-bit installs of the same version are
|
||||||
|
available.
|
155
PC/launcher2.c
155
PC/launcher2.c
|
@ -1294,34 +1294,34 @@ _compareTag(const wchar_t *x, const wchar_t *y)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
|
addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo* parent, EnvironmentInfo *node)
|
||||||
{
|
{
|
||||||
EnvironmentInfo *r = *root;
|
EnvironmentInfo *r = *root;
|
||||||
if (!r) {
|
if (!r) {
|
||||||
*root = node;
|
*root = node;
|
||||||
node->parent = NULL;
|
node->parent = parent;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Sort by company name
|
// Sort by company name
|
||||||
switch (_compareCompany(node->company, r->company)) {
|
switch (_compareCompany(node->company, r->company)) {
|
||||||
case -1:
|
case -1:
|
||||||
return addEnvironmentInfo(&r->prev, node);
|
return addEnvironmentInfo(&r->prev, r, node);
|
||||||
case 1:
|
case 1:
|
||||||
return addEnvironmentInfo(&r->next, node);
|
return addEnvironmentInfo(&r->next, r, node);
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Then by tag (descending)
|
// Then by tag (descending)
|
||||||
switch (_compareTag(node->tag, r->tag)) {
|
switch (_compareTag(node->tag, r->tag)) {
|
||||||
case -1:
|
case -1:
|
||||||
return addEnvironmentInfo(&r->next, node);
|
return addEnvironmentInfo(&r->next, r, node);
|
||||||
case 1:
|
case 1:
|
||||||
return addEnvironmentInfo(&r->prev, node);
|
return addEnvironmentInfo(&r->prev, r, node);
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Then keep the one with the lowest internal sort key
|
// Then keep the one with the lowest internal sort key
|
||||||
if (r->internalSortKey < node->internalSortKey) {
|
if (node->internalSortKey < r->internalSortKey) {
|
||||||
// Replace the current node
|
// Replace the current node
|
||||||
node->parent = r->parent;
|
node->parent = r->parent;
|
||||||
if (node->parent) {
|
if (node->parent) {
|
||||||
|
@ -1334,9 +1334,16 @@ addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
|
||||||
freeEnvironmentInfo(node);
|
freeEnvironmentInfo(node);
|
||||||
return RC_INTERNAL_ERROR;
|
return RC_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If node has no parent, then it is the root.
|
||||||
|
*root = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->next = r->next;
|
node->next = r->next;
|
||||||
node->prev = r->prev;
|
node->prev = r->prev;
|
||||||
|
|
||||||
|
debug(L"# replaced %s/%s/%i in tree\n", node->company, node->tag, node->internalSortKey);
|
||||||
|
freeEnvironmentInfo(r);
|
||||||
} else {
|
} else {
|
||||||
debug(L"# not adding %s/%s/%i to tree\n", node->company, node->tag, node->internalSortKey);
|
debug(L"# not adding %s/%s/%i to tree\n", node->company, node->tag, node->internalSortKey);
|
||||||
return RC_DUPLICATE_ITEM;
|
return RC_DUPLICATE_ITEM;
|
||||||
|
@ -1392,6 +1399,100 @@ _combineWithInstallDir(const wchar_t **dest, const wchar_t *installDir, const wc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
_isLegacyVersion(EnvironmentInfo *env)
|
||||||
|
{
|
||||||
|
// Check if backwards-compatibility is required.
|
||||||
|
// Specifically PythonCore versions 2.X and 3.0 - 3.5 do not implement PEP 514.
|
||||||
|
if (0 != _compare(env->company, -1, L"PythonCore", -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int versionMajor, versionMinor;
|
||||||
|
int n = swscanf_s(env->tag, L"%d.%d", &versionMajor, &versionMinor);
|
||||||
|
if (n != 2) {
|
||||||
|
debug(L"# %s/%s has an invalid version tag\n", env->company, env->tag);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionMajor == 2
|
||||||
|
|| (versionMajor == 3 && versionMinor >= 0 && versionMinor <= 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_registryReadLegacyEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *env, const wchar_t *fallbackArch)
|
||||||
|
{
|
||||||
|
// Backwards-compatibility for PythonCore versions which do not implement PEP 514.
|
||||||
|
int exitCode = _combineWithInstallDir(
|
||||||
|
&env->executablePath,
|
||||||
|
env->installDir,
|
||||||
|
search->executable,
|
||||||
|
search->executableLength
|
||||||
|
);
|
||||||
|
if (exitCode) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search->windowed) {
|
||||||
|
exitCode = _registryReadString(&env->executableArgs, root, L"InstallPath", L"WindowedExecutableArguments");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exitCode = _registryReadString(&env->executableArgs, root, L"InstallPath", L"ExecutableArguments");
|
||||||
|
}
|
||||||
|
if (exitCode) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackArch) {
|
||||||
|
copyWstr(&env->architecture, fallbackArch);
|
||||||
|
} else {
|
||||||
|
DWORD binaryType;
|
||||||
|
BOOL success = GetBinaryTypeW(env->executablePath, &binaryType);
|
||||||
|
if (!success) {
|
||||||
|
return RC_NO_PYTHON;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (binaryType) {
|
||||||
|
case SCS_32BIT_BINARY:
|
||||||
|
copyWstr(&env->architecture, L"32bit");
|
||||||
|
break;
|
||||||
|
case SCS_64BIT_BINARY:
|
||||||
|
copyWstr(&env->architecture, L"64bit");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return RC_NO_PYTHON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == _compare(env->architecture, -1, L"32bit", -1)) {
|
||||||
|
size_t tagLength = wcslen(env->tag);
|
||||||
|
if (tagLength <= 3 || 0 != _compare(&env->tag[tagLength - 3], 3, L"-32", 3)) {
|
||||||
|
const wchar_t *rawTag = env->tag;
|
||||||
|
wchar_t *realTag = (wchar_t*) malloc(sizeof(wchar_t) * (tagLength + 4));
|
||||||
|
if (!realTag) {
|
||||||
|
return RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = swprintf_s(realTag, tagLength + 4, L"%s-32", env->tag);
|
||||||
|
if (count == -1) {
|
||||||
|
free(realTag);
|
||||||
|
return RC_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->tag = realTag;
|
||||||
|
free((void*)rawTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t buffer[MAXLEN];
|
||||||
|
if (swprintf_s(buffer, MAXLEN, L"Python %s", env->tag)) {
|
||||||
|
copyWstr(&env->displayName, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *env, const wchar_t *fallbackArch)
|
_registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *env, const wchar_t *fallbackArch)
|
||||||
{
|
{
|
||||||
|
@ -1403,6 +1504,10 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
|
||||||
return RC_NO_PYTHON;
|
return RC_NO_PYTHON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_isLegacyVersion(env)) {
|
||||||
|
return _registryReadLegacyEnvironment(search, root, env, fallbackArch);
|
||||||
|
}
|
||||||
|
|
||||||
// If pythonw.exe requested, check specific value
|
// If pythonw.exe requested, check specific value
|
||||||
if (search->windowed) {
|
if (search->windowed) {
|
||||||
exitCode = _registryReadString(&env->executablePath, root, L"InstallPath", L"WindowedExecutablePath");
|
exitCode = _registryReadString(&env->executablePath, root, L"InstallPath", L"WindowedExecutablePath");
|
||||||
|
@ -1425,6 +1530,11 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!env->executablePath) {
|
||||||
|
debug(L"# %s/%s has no executable path\n", env->company, env->tag);
|
||||||
|
return RC_NO_PYTHON;
|
||||||
|
}
|
||||||
|
|
||||||
exitCode = _registryReadString(&env->architecture, root, NULL, L"SysArchitecture");
|
exitCode = _registryReadString(&env->architecture, root, NULL, L"SysArchitecture");
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
return exitCode;
|
return exitCode;
|
||||||
|
@ -1435,29 +1545,6 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only PythonCore entries will infer executablePath from installDir and architecture from the binary
|
|
||||||
if (0 == _compare(env->company, -1, L"PythonCore", -1)) {
|
|
||||||
if (!env->executablePath) {
|
|
||||||
exitCode = _combineWithInstallDir(
|
|
||||||
&env->executablePath,
|
|
||||||
env->installDir,
|
|
||||||
search->executable,
|
|
||||||
search->executableLength
|
|
||||||
);
|
|
||||||
if (exitCode) {
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!env->architecture && env->executablePath && fallbackArch) {
|
|
||||||
copyWstr(&env->architecture, fallbackArch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!env->executablePath) {
|
|
||||||
debug(L"# %s/%s has no executable path\n", env->company, env->tag);
|
|
||||||
return RC_NO_PYTHON;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,7 +1573,7 @@ _registrySearchTags(const SearchInfo *search, EnvironmentInfo **result, HKEY roo
|
||||||
freeEnvironmentInfo(env);
|
freeEnvironmentInfo(env);
|
||||||
exitCode = 0;
|
exitCode = 0;
|
||||||
} else if (!exitCode) {
|
} else if (!exitCode) {
|
||||||
exitCode = addEnvironmentInfo(result, env);
|
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
freeEnvironmentInfo(env);
|
freeEnvironmentInfo(env);
|
||||||
if (exitCode == RC_DUPLICATE_ITEM) {
|
if (exitCode == RC_DUPLICATE_ITEM) {
|
||||||
|
@ -1574,7 +1661,7 @@ appxSearch(const SearchInfo *search, EnvironmentInfo **result, const wchar_t *pa
|
||||||
copyWstr(&env->displayName, buffer);
|
copyWstr(&env->displayName, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int exitCode = addEnvironmentInfo(result, env);
|
int exitCode = addEnvironmentInfo(result, NULL, env);
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
freeEnvironmentInfo(env);
|
freeEnvironmentInfo(env);
|
||||||
if (exitCode == RC_DUPLICATE_ITEM) {
|
if (exitCode == RC_DUPLICATE_ITEM) {
|
||||||
|
@ -1612,7 +1699,7 @@ explicitOverrideSearch(const SearchInfo *search, EnvironmentInfo **result)
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
exitCode = addEnvironmentInfo(result, env);
|
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1748,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
exitCode = addEnvironmentInfo(result, env);
|
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue