cpython (merge 3.5 -> default): Merge from 3.5 (including all NEWS entries)
https://hg.python.org/cpython/rev/7dcc03b344b5 changeset: 99415:7dcc03b344b5 parent: 99412:1ff29b57628e parent: 99414:8537ec50c254 user: Steve Dower <steve.dower@microsoft.com> date: Wed Dec 02 09:19:07 2015 -0800 summary: Merge from 3.5 (including all NEWS entries) files: Misc/NEWS | 260 +++++++++- Tools/msi/bundle/Default.thm | 2 +- Tools/msi/bundle/Default.wxl | 4 +- Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 223 ++++--- Tools/msi/bundle/bundle.wxs | 4 +- Tools/msi/bundle/packagegroups/launcher.wxs | 4 +- 6 files changed, 389 insertions(+), 108 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -476,21 +476,84 @@ `python3 -m venv`. +What's New in Python 3.5.1 final? +================================= + +Release date: 2015-12-06 + +Core and Builtins +----------------- + +Library +------- + +Windows +------- + +- Issue #25715: Python 3.5.1 installer shows wrong upgrade path and incorrect + logic for launcher detection. + What's New in Python 3.5.1 release candidate 1? =============================================== -Release date: TBA +Release date: 2015-11-22 Core and Builtins ----------------- +- Issue #25630: Fix a possible segfault during argument parsing in functions + that accept filesystem paths. + +- Issue #23564: Fixed a partially broken sanity check in the _posixsubprocess + internals regarding how fds_to_pass were passed to the child. The bug had + no actual impact as subprocess.py already avoided it. + +- Issue #25388: Fixed tokenizer crash when processing undecodable source code + with a null byte. + +- Issue #25462: The hash of the key now is calculated only once in most + operations in C implementation of OrderedDict. + +- Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now + rejects builtin types with not defined __new__. + +- Issue #25555: Fix parser and AST: fill lineno and col_offset of "arg" node + when compiling AST from Python objects. + - Issue #24802: Avoid buffer overreads when int(), float(), compile(), exec() and eval() are passed bytes-like objects. These objects are not necessarily terminated by a null byte, but the functions assumed they were. +- Issue #24726: Fixed a crash and leaking NULL in repr() of OrderedDict that + was mutated by direct calls of dict methods. + +- Issue #25449: Iterating OrderedDict with keys with unstable hash now raises + KeyError in C implementations as well as in Python implementation. + +- Issue #25395: Fixed crash when highly nested OrderedDict structures were + garbage collected. + +- Issue #25274: sys.setrecursionlimit() now raises a RecursionError if the new + recursion limit is too low depending at the current recursion depth. Modify + also the "lower-water mark" formula to make it monotonic. This mark is used + to decide when the overflowed flag of the thread state is reset. + - Issue #24402: Fix input() to prompt to the redirected stdout when sys.stdout.fileno() fails. +- Issue #24806: Prevent builtin types that are not allowed to be subclassed from + being subclassed through multiple inheritance. + +- Issue #24848: Fixed a number of bugs in UTF-7 decoding of misformed data. + +- Issue #25280: Import trace messages emitted in verbose (-v) mode are no + longer formatted twice. + +- Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the + getrandom() function instead of the getentropy() function. The getentropy() + function is blocking to generate very good quality entropy, os.urandom() + doesn't need such high-quality entropy. + - Issue #25182: The stdprinter (used as sys.stderr before the io module is imported at startup) now uses the backslashreplace error handler. @@ -514,6 +577,12 @@ - Issue #25583: Avoid incorrect errors raised by os.makedirs(exist_ok=True) when the OS gives priority to errors such as EACCES over EEXIST. +- Issue #25593: Change semantics of EventLoop.stop() in asyncio. + +- Issue #6973: When we know a subprocess.Popen process has died, do + not allow the send_signal(), terminate(), or kill() methods to do + anything as they could potentially signal a different process. + - Issue #25590: In the Readline completer, only call getattr() once per attribute. @@ -521,6 +590,71 @@ by wrapping a memoryview. This was a regression made in 3.5a1. Based on patch by Eryksun. +- Issue #25584: Added "escape" to the __all__ list in the glob module. + +- Issue #25584: Fixed recursive glob() with patterns starting with '\*\*'. + +- Issue #25446: Fix regression in smtplib's AUTH LOGIN support. + +- Issue #18010: Fix the pydoc web server's module search function to handle + exceptions from importing packages. + +- Issue #25554: Got rid of circular references in regular expression parsing. + +- Issue #25510: fileinput.FileInput.readline() now returns b'' instead of '' + at the end if the FileInput was opened with binary mode. + Patch by Ryosuke Ito. + +- Issue #25503: Fixed inspect.getdoc() for inherited docstrings of properties. + Original patch by John Mark Vandenberg. + +- Issue #25515: Always use os.urandom as a source of randomness in uuid.uuid4. + +- Issue #21827: Fixed textwrap.dedent() for the case when largest common + whitespace is a substring of smallest leading whitespace. + Based on patch by Robert Li. + +- Issue #25447: The lru_cache() wrapper objects now can be copied and pickled + (by returning the original object unchanged). + +- Issue #25390: typing: Don't crash on Union[str, Pattern]. + +- Issue #25441: asyncio: Raise error from drain() when socket is closed. + +- Issue #25410: Cleaned up and fixed minor bugs in C implementation of + OrderedDict. + +- Issue #25411: Improved Unicode support in SMTPHandler through better use of + the email package. Thanks to user simon04 for the patch. + +- Issue #25407: Remove mentions of the formatter module being removed in + Python 3.6. + +- Issue #25406: Fixed a bug in C implementation of OrderedDict.move_to_end() + that caused segmentation fault or hang in iterating after moving several + items to the start of ordered dict. + +- Issue #25364: zipfile now works in threads disabled builds. + +- Issue #25328: smtpd's SMTPChannel now correctly raises a ValueError if both + decode_data and enable_SMTPUTF8 are set to true. + +- Issue #25316: distutils raises OSError instead of DistutilsPlatformError + when MSVC is not installed. + +- Issue #25380: Fixed protocol for the STACK_GLOBAL opcode in + pickletools.opcodes. + +- Issue #23972: Updates asyncio datagram create method allowing reuseport + and reuseaddr socket options to be set prior to binding the socket. + Mirroring the existing asyncio create_server method the reuseaddr option + for datagram sockets defaults to True if the O/S is 'posix' (except if the + platform is Cygwin). Patch by Chris Laws. + +- Issue #25304: Add asyncio.run_coroutine_threadsafe(). This lets you + submit a coroutine to a loop from another thread, returning a + concurrent.futures.Future. By Vincent Michel. + - Issue #25232: Fix CGIRequestHandler to split the query from the URL at the first question mark (?) rather than the last. Patch from Xiang Zhang. @@ -548,6 +682,9 @@ - Issue #25233: Rewrite the guts of asyncio.Queue and asyncio.Semaphore to be more understandable and correct. +- Issue #25203: Failed readline.set_completer_delims() no longer left the + module in inconsistent state. + - Issue #23600: Default implementation of tzinfo.fromutc() was returning wrong results in some cases. @@ -621,6 +758,19 @@ - Issue #24881: Fixed setting binary mode in Python implementation of FileIO on Windows and Cygwin. Patch from Akira Li. +- Issue #25578: Fix (another) memory leak in SSLSocket.getpeercer(). + +- Issue #25530: Disable the vulnerable SSLv3 protocol by default when creating + ssl.SSLContext. + +- Issue #25569: Fix memory leak in SSLSocket.getpeercert(). + +- Issue #25471: Sockets returned from accept() shouldn't appear to be + nonblocking. + +- Issue #25319: When threading.Event is reinitialized, the underlying condition + should use a regular lock rather than a recursive lock. + - Issue #21112: Fix regression in unittest.expectedFailure on subclasses. Patch from Berker Peksag. @@ -642,8 +792,104 @@ - Issue #23572: Fixed functools.singledispatch on classes with falsy metaclasses. Patch by Ethan Furman. -- Issue #12006: Add ISO 8601 year, week, and day directives (%G, %V, %u) to - strptime. +- asyncio: ensure_future() now accepts awaitable objects. + +IDLE +---- + +- Issue 15348: Stop the debugger engine (normally in a user process) + before closing the debugger window (running in the IDLE process). + This prevents the RuntimeErrors that were being caught and ignored. + +- Issue #24455: Prevent IDLE from hanging when a) closing the shell while the + debugger is active (15347); b) closing the debugger with the [X] button + (15348); and c) activating the debugger when already active (24455). + The patch by Mark Roseman does this by making two changes. + 1. Suspend and resume the gui.interaction method with the tcl vwait + mechanism intended for this purpose (instead of root.mainloop & .quit). + 2. In gui.run, allow any existing interaction to terminate first. + +- Change 'The program' to 'Your program' in an IDLE 'kill program?' message + to make it clearer that the program referred to is the currently running + user program, not IDLE itself. + +- Issue #24750: Improve the appearance of the IDLE editor window status bar. + Patch by Mark Roseman. + +- Issue #25313: Change the handling of new built-in text color themes to better + address the compatibility problem introduced by the addition of IDLE Dark. + Consistently use the revised idleConf.CurrentTheme everywhere in idlelib. + +- Issue #24782: Extension configuration is now a tab in the IDLE Preferences + dialog rather than a separate dialog. The former tabs are now a sorted + list. Patch by Mark Roseman. + +- Issue #22726: Re-activate the config dialog help button with some content + about the other buttons and the new IDLE Dark theme. + +- Issue #24820: IDLE now has an 'IDLE Dark' built-in text color theme. + It is more or less IDLE Classic inverted, with a cobalt blue background. + Strings, comments, keywords, ... are still green, red, orange, ... . + To use it with IDLEs released before November 2015, hit the + 'Save as New Custom Theme' button and enter a new name, + such as 'Custom Dark'. The custom theme will work with any IDLE + release, and can be modified. + +- Issue #25224: README.txt is now an idlelib index for IDLE developers and + curious users. The previous user content is now in the IDLE doc chapter. + 'IDLE' now means 'Integrated Development and Learning Environment'. + +- Issue #24820: Users can now set breakpoint colors in + Settings -> Custom Highlighting. Original patch by Mark Roseman. + +- Issue #24972: Inactive selection background now matches active selection + background, as configured by users, on all systems. Found items are now + always highlighted on Windows. Initial patch by Mark Roseman. + +- Issue #24570: Idle: make calltip and completion boxes appear on Macs + affected by a tk regression. Initial patch by Mark Roseman. + +- Issue #24988: Idle ScrolledList context menus (used in debugger) + now work on Mac Aqua. Patch by Mark Roseman. + +- Issue #24801: Make right-click for context menu work on Mac Aqua. + Patch by Mark Roseman. + +- Issue #25173: Associate tkinter messageboxes with a specific widget. + For Mac OSX, make them a 'sheet'. Patch by Mark Roseman. + +- Issue #25198: Enhance the initial html viewer now used for Idle Help. + * Properly indent fixed-pitch text (patch by Mark Roseman). + * Give code snippet a very Sphinx-like light blueish-gray background. + * Re-use initial width and height set by users for shell and editor. + * When the Table of Contents (TOC) menu is used, put the section header + at the top of the screen. + +- Issue #25225: Condense and rewrite Idle doc section on text colors. + +- Issue #21995: Explain some differences between IDLE and console Python. + +- Issue #22820: Explain need for *print* when running file from Idle editor. + +- Issue #25224: Doc: augment Idle feature list and no-subprocess section. + +- Issue #25219: Update doc for Idle command line options. + Some were missing and notes were not correct. + +- Issue #24861: Most of idlelib is private and subject to change. + Use idleib.idle.* to start Idle. See idlelib.__init__.__doc__. + +- Issue #25199: Idle: add synchronization comments for future maintainers. + +- Issue #16893: Replace help.txt with help.html for Idle doc display. + The new idlelib/help.html is rstripped Doc/build/html/library/idle.html. + It looks better than help.txt and will better document Idle as released. + The tkinter html viewer that works for this file was written by Mark Roseman. + The now unused EditorWindow.HelpDialog class and helt.txt file are deprecated. + +- Issue #24199: Deprecate unused idlelib.idlever with possible removal in 3.6. + +- Issue #24790: Remove extraneous code (which also create 2 & 3 conflicts). Documentation ------------- @@ -670,6 +916,8 @@ Tests ----- +- Issue #25449: Added tests for OrderedDict subclasses. + - Issue #25099: Make test_compileall not fail when an entry on sys.path cannot be written to (commonly seen in administrative installs on Windows). @@ -689,7 +937,6 @@ - Issue #24986: It is now possible to build Python on Windows without errors when external libraries are not available. - Windows ------- @@ -728,6 +975,11 @@ - Issue #25022: Removed very outdated PC/example_nt/ directory. +Tools/Demos +----------- + +- Issue #25440: Fix output of python-config --extension-suffix. + What's New in Python 3.5.0 final? ================================= diff --git a/Tools/msi/bundle/Default.thm b/Tools/msi/bundle/Default.thm --- a/Tools/msi/bundle/Default.thm +++ b/Tools/msi/bundle/Default.thm @@ -66,7 +66,7 @@ <Checkbox Name="Include_launcher" X="185" Y="251" Width="100" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_launcherLabel)</Checkbox> <Checkbox Name="CustomInstallLauncherAllUsers" X="285" Y="251" Width="-11" Height="24" TabStop="yes" FontId="3">#(loc.InstallLauncherAllUsersLabel)</Checkbox> - <Text X="205" Y="276" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_launcherHelpLabel)</Text> + <Text Name="Include_launcherHelp" X="205" Y="276" Width="-11" Height="24" TabStop="no" FontId="5"></Text> <Button Name="Custom1BackButton" X="185" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button> <Button Name="CustomNextButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomNextButton)</Button> diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl --- a/Tools/msi/bundle/Default.wxl +++ b/Tools/msi/bundle/Default.wxl @@ -76,7 +76,9 @@ <String Id="Include_testLabel">Python &test suite</String> <String Id="Include_testHelpLabel">Installs the standard library test suite.</String> <String Id="Include_launcherLabel">py &launcher</String> - <String Id="Include_launcherHelpLabel">Installs the global 'py' launcher to make it easier to start Python.</String> + <String Id="Include_launcherHelp">Installs the global 'py' launcher to make it easier to start Python.</String> + <String Id="Include_launcherRemove">Use Programs and Features to remove the 'py' launcher.</String> + <String Id="Include_launcherUpgrade">Upgrades the global 'py' launcher from the previous version.</String> <String Id="AssociateFilesLabel">Associate &files with Python (requires the py launcher)</String> <String Id="ShortcutsLabel">Create shortcuts for installed applications</String> diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -94,6 +94,7 @@ ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, + ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, ID_CUSTOM_COMPILE_ALL_CHECKBOX, ID_CUSTOM_BROWSE_BUTTON, ID_CUSTOM_BROWSE_BUTTON_LABEL, @@ -158,6 +159,7 @@ { ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, L"AssociateFiles" }, { ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, L"InstallAllUsers" }, { ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, L"CustomInstallLauncherAllUsers" }, + { ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, L"Include_launcherHelp" }, { ID_CUSTOM_COMPILE_ALL_CHECKBOX, L"CompileAll" }, { ID_CUSTOM_BROWSE_BUTTON, L"CustomBrowseButton" }, { ID_CUSTOM_BROWSE_BUTTON_LABEL, L"CustomBrowseButtonLabel" }, @@ -454,6 +456,20 @@ ThemeSendControlMessage(_theme, ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, BM_SETCHECK, installLauncherAllUsers ? BST_CHECKED : BST_UNCHECKED, 0); + + LOC_STRING *pLocString = nullptr; + LPCWSTR locKey = L"#(loc.Include_launcherHelp)"; + LONGLONG detectedLauncher; + + if (SUCCEEDED(BalGetNumericVariable(L"DetectedLauncher", &detectedLauncher)) && detectedLauncher) { + locKey = L"#(loc.Include_launcherRemove)"; + } else if (SUCCEEDED(BalGetNumericVariable(L"DetectedOldLauncher", &detectedLauncher)) && detectedLauncher) { + locKey = L"#(loc.Include_launcherUpgrade)"; + } + + if (SUCCEEDED(LocGetString(_wixLoc, locKey, &pLocString)) && pLocString) { + ThemeSetTextControl(_theme, ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, pLocString->wzText); + } } void Custom2Page_Show() { @@ -641,6 +657,29 @@ return nResult; } + virtual STDMETHODIMP_(int) OnDetectRelatedMsiPackage( + __in_z LPCWSTR wzPackageId, + __in_z LPCWSTR /*wzProductCode*/, + __in BOOL fPerMachine, + __in DWORD64 /*dw64Version*/, + __in BOOTSTRAPPER_RELATED_OPERATION operation + ) { + if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation && + (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_AllUsers", -1) || + CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_JustForMe", -1))) { + auto hr = LoadAssociateFilesStateFromKey(_engine, fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER); + if (hr == S_OK) { + _engine->SetVariableNumeric(L"AssociateFiles", 1); + } else if (FAILED(hr)) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load AssociateFiles state: error code 0x%08X", hr); + } + + _engine->SetVariableNumeric(L"Include_launcher", 1); + _engine->SetVariableNumeric(L"DetectedOldLauncher", 1); + _engine->SetVariableNumeric(L"InstallLauncherAllUsers", fPerMachine ? 1 : 0); + } + return CheckCanceled() ? IDCANCEL : IDNOACTION; + } virtual STDMETHODIMP_(int) OnDetectRelatedBundle( __in LPCWSTR wzBundleId, @@ -656,24 +695,8 @@ if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) { _downgradingOtherVersion = TRUE; } else if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation) { - _upgradingOldVersion = TRUE; - - // Assume we don't want the launcher or file associations, and if - // they have already been installed then loading the state will - // reactivate these settings. - _engine->SetVariableNumeric(L"Include_launcher", 0); - _engine->SetVariableNumeric(L"AssociateFiles", 0); - auto hr = LoadLauncherStateFromKey(_engine, HKEY_CURRENT_USER); - if (hr == S_FALSE) { - hr = LoadLauncherStateFromKey(_engine, HKEY_LOCAL_MACHINE); - } - if (FAILED(hr)) { - BalLog( - BOOTSTRAPPER_LOG_LEVEL_ERROR, - "Failed to load launcher state: error code 0x%08X", - hr - ); - } + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Detected previous version - planning upgrade"); + _upgrading = TRUE; LoadOptionalFeatureStates(_engine); } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) { @@ -699,9 +722,42 @@ virtual STDMETHODIMP_(void) OnDetectPackageComplete( __in LPCWSTR wzPackageId, - __in HRESULT /*hrStatus*/, + __in HRESULT hrStatus, __in BOOTSTRAPPER_PACKAGE_STATE state - ) { } + ) { + if (FAILED(hrStatus)) { + return; + } + + BOOL detectedLauncher = FALSE; + HKEY hkey = HKEY_LOCAL_MACHINE; + if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_AllUsers", -1)) { + if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) { + detectedLauncher = TRUE; + _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 1); + } + } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_JustForMe", -1)) { + if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) { + detectedLauncher = TRUE; + _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 0); + } + } + + if (detectedLauncher) { + /* When we detect the current version of the launcher. */ + _engine->SetVariableNumeric(L"Include_launcher", 1); + _engine->SetVariableNumeric(L"DetectedLauncher", 1); + _engine->SetVariableString(L"Include_launcherState", L"disable"); + _engine->SetVariableString(L"InstallLauncherAllUsersState", L"disable"); + + auto hr = LoadAssociateFilesStateFromKey(_engine, hkey); + if (hr == S_OK) { + _engine->SetVariableNumeric(L"AssociateFiles", 1); + } else if (FAILED(hr)) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load AssociateFiles state: error code 0x%08X", hr); + } + } + } virtual STDMETHODIMP_(void) OnDetectComplete(__in HRESULT hrStatus) { @@ -716,32 +772,7 @@ if (SUCCEEDED(hrStatus)) { // Ensure the default path has been set - LONGLONG installAll; - LPWSTR targetDir = nullptr; - LPWSTR defaultTargetDir = nullptr; - - hrStatus = BalGetStringVariable(L"TargetDir", &targetDir); - if (FAILED(hrStatus) || !targetDir || !targetDir[0]) { - ReleaseStr(targetDir); - targetDir = nullptr; - - if (FAILED(BalGetNumericVariable(L"InstallAllUsers", &installAll))) { - installAll = 0; - } - - hrStatus = BalGetStringVariable( - installAll ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir", - &defaultTargetDir - ); - - if (SUCCEEDED(hrStatus) && defaultTargetDir) { - if (defaultTargetDir[0] && SUCCEEDED(BalFormatString(defaultTargetDir, &targetDir))) { - hrStatus = _engine->SetVariableString(L"TargetDir", targetDir); - ReleaseStr(targetDir); - } - ReleaseStr(defaultTargetDir); - } - } + hrStatus = EnsureTargetDir(); } SetState(PYBA_STATE_DETECTED, hrStatus); @@ -1396,9 +1427,14 @@ hr = LoadBootstrapperBAFunctions(); BalExitOnFailure(hr, "Failed to load bootstrapper functions."); + hr = UpdateUIStrings(_command.action); BalExitOnFailure(hr, "Failed to load UI strings."); + if (_command.action == BOOTSTRAPPER_ACTION_MODIFY) { + LoadOptionalFeatureStates(_engine); + } + GetBundleFileVersion(); // don't fail if we couldn't get the version info; best-effort only LExit: @@ -1906,27 +1942,6 @@ for (DWORD i = 0; i < _theme->cControls; ++i) { THEME_CONTROL* pControl = _theme->rgControls + i; LPWSTR text = nullptr; - LPWSTR name = nullptr; - LOC_STRING *locText = nullptr; - - // If a command link has a note, then add it. - if ((pControl->dwStyle & BS_TYPEMASK) == BS_COMMANDLINK || - (pControl->dwStyle & BS_TYPEMASK) == BS_DEFCOMMANDLINK) { - hr = StrAllocFormatted(&name, L"#(loc.%lsNote)", pControl->sczName); - if (SUCCEEDED(hr)) { - hr = LocGetString(_wixLoc, name, &locText); - ReleaseStr(name); - if (SUCCEEDED(hr) && locText && locText->wzText && locText->wzText[0]) { - hr = BalFormatString(locText->wzText, &text); - if (SUCCEEDED(hr) && text && text[0]) { - ThemeSendControlMessage(_theme, pControl->wId, BCM_SETNOTE, 0, (LPARAM)text); - ReleaseStr(text); - text = nullptr; - } - } - } - hr = S_OK; - } if (!pControl->wPageId && pControl->sczText && *pControl->sczText) { HRESULT hrFormat; @@ -2048,6 +2063,7 @@ return; } + HRESULT UpdateUIStrings(__in BOOTSTRAPPER_ACTION action) { HRESULT hr = S_OK; LPCWSTR likeInstalling = nullptr; @@ -2270,6 +2286,30 @@ StrFree(controlState); } StrFree(controlName); + controlName = nullptr; + + + // If a command link has a note, then add it. + if ((pControl->dwStyle & BS_TYPEMASK) == BS_COMMANDLINK || + (pControl->dwStyle & BS_TYPEMASK) == BS_DEFCOMMANDLINK) { + hr = StrAllocFormatted(&controlName, L"#(loc.%lsNote)", pControl->sczName); + if (SUCCEEDED(hr)) { + LOC_STRING *locText = nullptr; + hr = LocGetString(_wixLoc, controlName, &locText); + if (SUCCEEDED(hr) && locText && locText->wzText && locText->wzText[0]) { + LPWSTR text = nullptr; + hr = BalFormatString(locText->wzText, &text); + if (SUCCEEDED(hr) && text && text[0]) { + ThemeSendControlMessage(_theme, pControl->wId, BCM_SETNOTE, 0, (LPARAM)text); + ReleaseStr(text); + text = nullptr; + } + } + ReleaseStr(controlName); + controlName = nullptr; + } + hr = S_OK; + } } ThemeControlEnable(_theme, pControl->wId, enableControl); @@ -2515,9 +2555,8 @@ if (_installPage == PAGE_LOADING) { switch (_command.action) { case BOOTSTRAPPER_ACTION_INSTALL: - if (_upgradingOldVersion) { + if (_upgrading) { _installPage = PAGE_UPGRADE; - _upgrading = TRUE; } else if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { _installPage = PAGE_SIMPLE_INSTALL; } else { @@ -2560,11 +2599,9 @@ static BAL_CONDITION WILL_ELEVATE_CONDITION = { L"not WixBundleElevated and (" /*Elevate when installing for all users*/ - L"InstallAllUsers or" + L"InstallAllUsers or " /*Elevate when installing the launcher for all users and it was not detected*/ - L"(InstallLauncherAllUsers and Include_launcher and not DetectedLauncher) or" - /*Elevate when the launcher was installed for all users and it is being removed*/ - L"(DetectedLauncher and DetectedLauncherAllUsers and not Include_launcher)" + L"(Include_launcher and InstallLauncherAllUsers and not DetectedLauncher)" L")", L"" }; @@ -2867,19 +2904,16 @@ return HRESULT_FROM_WIN32(res); } - static HRESULT LoadLauncherStateFromKey( + static HRESULT LoadAssociateFilesStateFromKey( __in IBootstrapperEngine* pEngine, __in HKEY hkHive ) { const LPCWSTR subkey = L"Software\\Python\\PyLauncher"; HKEY hKey; LRESULT res; - - if (IsTargetPlatformx64(pEngine)) { - res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - } else { - res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); - } + HRESULT hr; + + res = RegOpenKeyExW(hkHive, subkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); if (res == ERROR_FILE_NOT_FOUND) { return S_FALSE; @@ -2888,26 +2922,17 @@ return HRESULT_FROM_WIN32(res); } - res = RegQueryValueExW(hKey, nullptr, nullptr, nullptr, nullptr, nullptr); - if (res == ERROR_FILE_NOT_FOUND) { - pEngine->SetVariableNumeric(L"Include_launcher", 0); - } else if (res == ERROR_SUCCESS) { - pEngine->SetVariableNumeric(L"Include_launcher", 1); - pEngine->SetVariableNumeric(L"DetectedLauncher", 1); - pEngine->SetVariableNumeric(L"InstallLauncherAllUsers", (hkHive == HKEY_LOCAL_MACHINE) ? 1 : 0); - pEngine->SetVariableNumeric(L"DetectedLauncherAllUsers", (hkHive == HKEY_LOCAL_MACHINE) ? 1 : 0); - pEngine->SetVariableString(L"InstallLauncherAllUsersState", L"disable"); - } - res = RegQueryValueExW(hKey, L"AssociateFiles", nullptr, nullptr, nullptr, nullptr); if (res == ERROR_FILE_NOT_FOUND) { - pEngine->SetVariableNumeric(L"AssociateFiles", 0); + hr = S_FALSE; } else if (res == ERROR_SUCCESS) { - pEngine->SetVariableNumeric(L"AssociateFiles", 1); + hr = S_OK; + } else { + hr = HRESULT_FROM_WIN32(res); } RegCloseKey(hKey); - return S_OK; + return hr; } static void LoadOptionalFeatureStates(__in IBootstrapperEngine* pEngine) { @@ -2918,7 +2943,11 @@ HKEY hkHive; // The launcher installation is separate from the Python install, so we - // check its state later. This also checks the file association option. + // check its state later. For now, assume we don't want the launcher or + // file associations, and if they have already been installed then + // loading the state will reactivate these settings. + pEngine->SetVariableNumeric(L"Include_launcher", 0); + pEngine->SetVariableNumeric(L"AssociateFiles", 0); // Get the registry key from the bundle, to save having to duplicate it // in multiple places. @@ -3089,7 +3118,6 @@ _hrFinal = hrHostInitialization; _downgradingOtherVersion = FALSE; - _upgradingOldVersion = FALSE; _restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE; _restartRequired = FALSE; _allowRestart = FALSE; @@ -3113,8 +3141,6 @@ _hBAFModule = nullptr; _baFunction = nullptr; - - EnsureTargetDir(); } @@ -3174,7 +3200,6 @@ DWORD _calculatedExecuteProgress; BOOL _downgradingOtherVersion; - BOOL _upgradingOldVersion; BOOTSTRAPPER_APPLY_RESTART _restartResult; BOOL _restartRequired; BOOL _allowRestart; diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs --- a/Tools/msi/bundle/bundle.wxs +++ b/Tools/msi/bundle/bundle.wxs @@ -51,7 +51,7 @@ --> <Variable Name="DefaultCustomTargetDir" Value="" bal:Overridable="yes" /> - <Variable Name="InstallAllUsersState" Value="enabled" /> + <Variable Name="InstallAllUsersState" Value="enabled" bal:Overridable="yes" /> <?if "$(var.PyTestExt)"="" ?> <Variable Name="InstallLauncherAllUsersState" Value="enabled" bal:Overridable="yes" /> <?else ?> @@ -72,6 +72,7 @@ <Variable Name="Include_pip" Value="1" bal:Overridable="yes" /> <?if "$(var.PyTestExt)"="" ?> <Variable Name="Include_launcher" Value="1" bal:Overridable="yes" /> + <Variable Name="Include_launcherState" Value="enabled" bal:Overridable="yes" /> <?else ?> <Variable Name="Include_launcher" Value="0" /> <Variable Name="Include_launcherState" Value="disable" /> @@ -81,6 +82,7 @@ <Variable Name="LauncherOnly" Value="0" bal:Overridable="yes" /> <Variable Name="DetectedLauncher" Value="0" /> + <Variable Name="DetectedOldLauncher" Value="0" /> <Variable Name="AssociateFiles" Value="1" bal:Overridable="yes" /> <Variable Name="Shortcuts" Value="1" bal:Overridable="yes" /> diff --git a/Tools/msi/bundle/packagegroups/launcher.wxs b/Tools/msi/bundle/packagegroups/launcher.wxs --- a/Tools/msi/bundle/packagegroups/launcher.wxs +++ b/Tools/msi/bundle/packagegroups/launcher.wxs @@ -11,7 +11,7 @@ EnableFeatureSelection="yes" Permanent="yes" Visible="yes" - InstallCondition="(InstallAllUsers or InstallLauncherAllUsers) and Include_launcher" /> + InstallCondition="(InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" /> <MsiPackage Id="launcher_JustForMe" SourceFile="launcher.msi" @@ -21,7 +21,7 @@ EnableFeatureSelection="yes" Permanent="yes" Visible="yes" - InstallCondition="not (InstallAllUsers or InstallLauncherAllUsers) and Include_launcher" /> + InstallCondition="not (InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" /> </PackageGroup> </Fragment> </Wix> \ No newline at end of file -- Repository URL: https://hg.python.org/cpython
participants (1)
-
steve.dower