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
|
||||
addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
|
||||
addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo* parent, EnvironmentInfo *node)
|
||||
{
|
||||
EnvironmentInfo *r = *root;
|
||||
if (!r) {
|
||||
*root = node;
|
||||
node->parent = NULL;
|
||||
node->parent = parent;
|
||||
return 0;
|
||||
}
|
||||
// Sort by company name
|
||||
switch (_compareCompany(node->company, r->company)) {
|
||||
case -1:
|
||||
return addEnvironmentInfo(&r->prev, node);
|
||||
return addEnvironmentInfo(&r->prev, r, node);
|
||||
case 1:
|
||||
return addEnvironmentInfo(&r->next, node);
|
||||
return addEnvironmentInfo(&r->next, r, node);
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
// Then by tag (descending)
|
||||
switch (_compareTag(node->tag, r->tag)) {
|
||||
case -1:
|
||||
return addEnvironmentInfo(&r->next, node);
|
||||
return addEnvironmentInfo(&r->next, r, node);
|
||||
case 1:
|
||||
return addEnvironmentInfo(&r->prev, node);
|
||||
return addEnvironmentInfo(&r->prev, r, node);
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
// Then keep the one with the lowest internal sort key
|
||||
if (r->internalSortKey < node->internalSortKey) {
|
||||
if (node->internalSortKey < r->internalSortKey) {
|
||||
// Replace the current node
|
||||
node->parent = r->parent;
|
||||
if (node->parent) {
|
||||
|
@ -1334,9 +1334,16 @@ addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
|
|||
freeEnvironmentInfo(node);
|
||||
return RC_INTERNAL_ERROR;
|
||||
}
|
||||
} else {
|
||||
// If node has no parent, then it is the root.
|
||||
*root = node;
|
||||
}
|
||||
|
||||
node->next = r->next;
|
||||
node->prev = r->prev;
|
||||
|
||||
debug(L"# replaced %s/%s/%i in tree\n", node->company, node->tag, node->internalSortKey);
|
||||
freeEnvironmentInfo(r);
|
||||
} else {
|
||||
debug(L"# not adding %s/%s/%i to tree\n", node->company, node->tag, node->internalSortKey);
|
||||
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
|
||||
_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;
|
||||
}
|
||||
|
||||
if (_isLegacyVersion(env)) {
|
||||
return _registryReadLegacyEnvironment(search, root, env, fallbackArch);
|
||||
}
|
||||
|
||||
// If pythonw.exe requested, check specific value
|
||||
if (search->windowed) {
|
||||
exitCode = _registryReadString(&env->executablePath, root, L"InstallPath", L"WindowedExecutablePath");
|
||||
|
@ -1425,6 +1530,11 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
|
|||
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");
|
||||
if (exitCode) {
|
||||
return exitCode;
|
||||
|
@ -1435,29 +1545,6 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -1486,7 +1573,7 @@ _registrySearchTags(const SearchInfo *search, EnvironmentInfo **result, HKEY roo
|
|||
freeEnvironmentInfo(env);
|
||||
exitCode = 0;
|
||||
} else if (!exitCode) {
|
||||
exitCode = addEnvironmentInfo(result, env);
|
||||
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||
if (exitCode) {
|
||||
freeEnvironmentInfo(env);
|
||||
if (exitCode == RC_DUPLICATE_ITEM) {
|
||||
|
@ -1574,7 +1661,7 @@ appxSearch(const SearchInfo *search, EnvironmentInfo **result, const wchar_t *pa
|
|||
copyWstr(&env->displayName, buffer);
|
||||
}
|
||||
|
||||
int exitCode = addEnvironmentInfo(result, env);
|
||||
int exitCode = addEnvironmentInfo(result, NULL, env);
|
||||
if (exitCode) {
|
||||
freeEnvironmentInfo(env);
|
||||
if (exitCode == RC_DUPLICATE_ITEM) {
|
||||
|
@ -1612,7 +1699,7 @@ explicitOverrideSearch(const SearchInfo *search, EnvironmentInfo **result)
|
|||
if (exitCode) {
|
||||
goto abort;
|
||||
}
|
||||
exitCode = addEnvironmentInfo(result, env);
|
||||
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||
if (exitCode) {
|
||||
goto abort;
|
||||
}
|
||||
|
@ -1661,7 +1748,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
|
|||
if (exitCode) {
|
||||
goto abort;
|
||||
}
|
||||
exitCode = addEnvironmentInfo(result, env);
|
||||
exitCode = addEnvironmentInfo(result, NULL, env);
|
||||
if (exitCode) {
|
||||
goto abort;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue