]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #24585: Enables build-to-build upgrades that preserve settings.
authorSteve Dower <steve.dower@microsoft.com>
Thu, 9 Jul 2015 03:18:44 +0000 (20:18 -0700)
committerSteve Dower <steve.dower@microsoft.com>
Thu, 9 Jul 2015 03:18:44 +0000 (20:18 -0700)
Rather than using Burn "Persisted" variables we now add registry keys for each added feature. These can be detected by the installer regardless of which version installed them, and we use this for Modify and Upgrade. In particular, Upgrades can't access the Persisted variables, but can find well-known registry keys.
There are also some changes to the bootstrap app to properly handle upgrades.
Finally, a few minor improvements to the Windows build to keep things tidier.

33 files changed:
PCbuild/build.bat
PCbuild/python.props
Tools/msi/build.bat
Tools/msi/bundle/Default.thm
Tools/msi/bundle/Default.wxl
Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
Tools/msi/bundle/bootstrap/pythonba.vcxproj
Tools/msi/bundle/bundle.wxs
Tools/msi/bundle/packagegroups/core.wxs
Tools/msi/bundle/packagegroups/dev.wxs
Tools/msi/bundle/packagegroups/doc.wxs
Tools/msi/bundle/packagegroups/exe.wxs
Tools/msi/bundle/packagegroups/lib.wxs
Tools/msi/bundle/packagegroups/postinstall.wxs
Tools/msi/bundle/packagegroups/tcltk.wxs
Tools/msi/bundle/packagegroups/test.wxs
Tools/msi/bundle/packagegroups/tools.wxs
Tools/msi/common.wxs
Tools/msi/core/core_d.wxs
Tools/msi/core/core_pdb.wxs
Tools/msi/dev/dev.wxs
Tools/msi/doc/doc.wxs
Tools/msi/exe/exe.wxs
Tools/msi/exe/exe_files.wxs
Tools/msi/launcher/launcher_files.wxs
Tools/msi/launcher/launcher_reg.wxs
Tools/msi/lib/lib.wxs
Tools/msi/msi.props
Tools/msi/path/path.wxs
Tools/msi/pip/pip.wxs
Tools/msi/tcltk/tcltk.wxs
Tools/msi/test/test.wxs
Tools/msi/tools/tools.wxs

index 3f8e231df02638a0a19515e4d6173abc77094bd1..17f8686b428bba3e4801266a68475eafe8ab8f01 100644 (file)
@@ -25,16 +25,17 @@ set verbose=/nologo /v:m
 set kill=\r
 \r
 :CheckOpts\r
-if '%1'=='-c' (set conf=%2) & shift & shift & goto CheckOpts\r
-if '%1'=='-p' (set platf=%2) & shift & shift & goto CheckOpts\r
-if '%1'=='-r' (set target=Rebuild) & shift & goto CheckOpts\r
-if '%1'=='-t' (set target=%2) & shift & shift & goto CheckOpts\r
-if '%1'=='-d' (set conf=Debug) & shift & goto CheckOpts\r
-if '%1'=='-e' call "%dir%get_externals.bat" & shift & goto CheckOpts\r
-if '%1'=='-m' (set parallel=/m) & shift & goto CheckOpts\r
-if '%1'=='-M' (set parallel=) & shift & goto CheckOpts\r
-if '%1'=='-v' (set verbose=/v:n) & shift & goto CheckOpts\r
-if '%1'=='-k' (set kill=true) & shift & goto CheckOpts\r
+if '%~1'=='-c' (set conf=%2) & shift & shift & goto CheckOpts\r
+if '%~1'=='-p' (set platf=%2) & shift & shift & goto CheckOpts\r
+if '%~1'=='-r' (set target=Rebuild) & shift & goto CheckOpts\r
+if '%~1'=='-t' (set target=%2) & shift & shift & goto CheckOpts\r
+if '%~1'=='-d' (set conf=Debug) & shift & goto CheckOpts\r
+if '%~1'=='-e' call "%dir%get_externals.bat" & shift & goto CheckOpts\r
+if '%~1'=='-m' (set parallel=/m) & shift & goto CheckOpts\r
+if '%~1'=='-M' (set parallel=) & shift & goto CheckOpts\r
+if '%~1'=='-v' (set verbose=/v:n) & shift & goto CheckOpts\r
+if '%~1'=='-k' (set kill=true) & shift & goto CheckOpts\r
+if '%~1'=='-V' shift & goto Version\r
 \r
 if '%platf%'=='x64' (set vs_platf=x86_amd64)\r
 \r
@@ -50,3 +51,9 @@ rem Passing %1-9 is not the preferred option, but argument parsing in
 rem batch is, shall we say, "lackluster"\r
 echo on\r
 msbuild "%dir%pcbuild.proj" /t:%target% %parallel% %verbose% /p:Configuration=%conf% /p:Platform=%platf% %1 %2 %3 %4 %5 %6 %7 %8 %9\r
+\r
+@goto :eof\r
+\r
+:Version\r
+rem Display the current build version information\r
+msbuild "%dir%python.props" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9\r
index 1431ddcfe7951904f8b8c80cbc0c252c62d31b7a..857b8f8ee7f3454315da9f76b9ae076e14d587cc 100644 (file)
@@ -42,7 +42,9 @@
     
     <!-- Full path of the resulting python.exe binary -->
     <PythonExe Condition="'$(PythonExe)' == ''">$(BuildPath)python$(PyDebugExt).exe</PythonExe>
-
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(OverrideVersion)' == ''">
     <!--
     Read version information from Include\patchlevel.h. The following properties are set:
     
     <ReleaseLevelName Condition="$(_ReleaseLevel) == 'ALPHA'">a$(ReleaseSerial)</ReleaseLevelName>
     <ReleaseLevelName Condition="$(_ReleaseLevel) == 'BETA'">b$(ReleaseSerial)</ReleaseLevelName>
     <ReleaseLevelName Condition="$(_ReleaseLevel) == 'GAMMA'">rc$(ReleaseSerial)</ReleaseLevelName>
+  </PropertyGroup>
+  
+  <PropertyGroup Condition="'$(OverrideVersion)' != ''">
+    <!--
+    Override the version number when building by specifying OverrideVersion.
+    For example:
+    
+        PCBuild\build.bat "/p:OverrideVersion=3.5.2a1"
     
+    Use the -V option to check your version is valid:
+    
+        PCBuild\build.bat -V "/p:OverrideVersion=3.5.2a1"
+          PythonVersionNumber: 3.5.2
+          PythonVersion:       3.5.2a1
+          PythonVersionHex:    0x030502A1
+          Field3Value:         2101
+    
+    Note that this only affects the version numbers embedded in resources and
+    installers, but not sys.version.
+    -->
+    <MajorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[1].Value)</MajorVersionNumber>
+    <MinorVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[2].Value)</MinorVersionNumber>
+    <MicroVersionNumber>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[3].Value)</MicroVersionNumber>
+    <ReleaseLevelName>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[4].Value)</ReleaseLevelName>
+    <_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[5].Value)</_ReleaseLevel>
+    <ReleaseSerial>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[6].Value)</ReleaseSerial>
+    <ReleaseSerial Condition="'$(ReleaseSerial)' == ''">0</ReleaseSerial>
+    <ReleaseLevelNumber>15</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 'a'">10</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 'b'">11</ReleaseLevelNumber>
+    <ReleaseLevelNumber Condition="$(_ReleaseLevel) == 'rc'">12</ReleaseLevelNumber>
+  </PropertyGroup>
+  
+  <PropertyGroup>
     <PythonVersionNumber>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)</PythonVersionNumber>
     <PythonVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)$(ReleaseLevelName)</PythonVersion>
     <PythonVersionHex>$([msbuild]::BitwiseOr(
   <Target Name="ShowVersionInfo">
     <Message Importance="high" Text="PythonVersionNumber: $(PythonVersionNumber)" />
     <Message Importance="high" Text="PythonVersion:       $(PythonVersion)" />
-    <Message Importance="high" Text="$([System.String]::Format(`PythonVersionHex:    0x{0:x}`, $([System.UInt32]::Parse($(PythonVersionHex)))))" />
+    <Message Importance="high" Text="PythonVersionHex:    0x$([System.UInt32]::Parse($(PythonVersionHex)).ToString(`X08`))" />
     <Message Importance="high" Text="Field3Value:         $(Field3Value)" />
   </Target>
 </Project>
index 1dc05c399746858bba3465fddcfa75f10e741c68..c135b63d218f06434e1985916a13becb5b571117 100644 (file)
@@ -8,10 +8,10 @@ set BUILDX64=
 set BUILDDOC=\r
 \r
 :CheckOpts\r
-if "%1" EQU "-h" goto Help\r
-if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts\r
-if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts\r
-if "%1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts\r
+if "%~1" EQU "-h" goto Help\r
+if "%~1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts\r
+if "%~1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts\r
+if "%~1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts\r
 \r
 if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1)\r
 \r
index d5e19699776e91629ef17cb7d56af473a8895806..0c79dd50c02952f95d866f7639267d42a2986800 100644 (file)
 
         <Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallMessage)</Text>
 
-        <Button Name="InstallJustForMeButton" X="175" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallJustForMeButton)</Button>
+        <Button Name="InstallButton" X="175" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
         <Button Name="InstallCustomButton" X="175" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallCustomButton)</Button>
 
         <Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="20" TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
 
         <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
     </Page>
+    <Page Name="Upgrade">
+        <Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.InstallUpgradeHeader)</Text>
+        <Image X="0" Y="0" Width="162" Height="352" ImageFile="SideBar.png"/>
+
+        <Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallUpgradeMessage)</Text>
+
+        <Button Name="InstallUpgradeButton" X="175" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeButton)</Button>
+        <Button Name="InstallUpgradeCustomButton" X="175" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeCustomButton)</Button>
+
+        <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
+    </Page>
     <Page Name="SimpleInstall">
         <Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.InstallHeader)</Text>
         <Image X="0" Y="0" Width="162" Height="352" ImageFile="SideBar.png"/>
index 3ecb2faf8ebfd545e9ffa48e15d93fa3ab538b0a..19ba7eb14b0a6b80079cef0ae3fa7b8321151148 100644 (file)
@@ -21,6 +21,8 @@ Continue?</String>
   <String Id="InstallHeader">Install [WixBundleName]</String>
   <String Id="InstallMessage">Select Install Now to install Python with default settings, or choose Customize to enable or disable features.</String>
   <String Id="InstallVersion">Version [WixBundleVersion]</String>
+  <String Id="InstallUpgradeHeader">Upgrade to [WixBundleName]</String>
+  <String Id="InstallUpgradeMessage">Select Upgrade Now to keep your current settings, or choose Customize to enable or disable features.</String>
   <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
   <String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
   <String Id="HelpHeader">Setup Help</String>
@@ -40,8 +42,8 @@ Continue?</String>
     Logs to a specific file. By default, log files are created in %TEMP%.</String>
   <String Id="InstallLicenseLinkText">[WixBundleName] &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
   <String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and conditions</String>
-  <String Id="InstallJustForMeButton">&amp;Install Now</String>
-  <String Id="InstallJustForMeButtonNote">[DefaultJustForMeTargetDir]
+  <String Id="InstallButton">&amp;Install Now</String>
+  <String Id="InstallButtonNote">[DefaultJustForMeTargetDir]
 
 Includes IDLE, pip and documentation
 Creates shortcuts and file associations</String>
@@ -49,6 +51,13 @@ Creates shortcuts and file associations</String>
   <String Id="InstallCustomButtonNote">Choose location and features</String>
   <String Id="InstallSimpleButton">&amp;Install</String>
   <String Id="InstallSimpleButtonNote">Uses setting preselected by your administrator</String>
+  <String Id="InstallUpgradeButton">&amp;Upgrade Now</String>
+  <String Id="InstallUpgradeButtonNote">[TargetDir]
+
+Replaces your existing installation without changing settings.
+Select Customize to review current options.</String>
+  <String Id="InstallUpgradeCustomButton">C&amp;ustomize installation</String>
+  <String Id="InstallUpgradeCustomButtonNote">Choose location and features</String>
   <String Id="Custom1Header">Optional Features</String>
   <String Id="Custom2Header">Advanced Options</String>
   <String Id="CustomLocationLabel">Customize install location</String>
@@ -107,4 +116,5 @@ Feel free to email &lt;a href="mailto:python-list@python.org"&gt;python-list@pyt
   <String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
   <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
   <String Id="FailureRestartButton">&amp;Restart</String>
+  <String Id="FailureExistingInstall">Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName].</String>
 </WixLocalization>
index 585f66cd5bfa64636d19700bd76d46f3c8cba20a..728355930a4cde8ec2bf53af5c4bb085cb9d8e63 100644 (file)
@@ -47,6 +47,7 @@ enum PAGE {
     PAGE_LOADING,
     PAGE_HELP,
     PAGE_INSTALL,
+    PAGE_UPGRADE,
     PAGE_SIMPLE_INSTALL,
     PAGE_CUSTOM1,
     PAGE_CUSTOM2,
@@ -63,6 +64,7 @@ static LPCWSTR PAGE_NAMES[] = {
     L"Loading",
     L"Help",
     L"Install",
+    L"Upgrade",
     L"SimpleInstall",
     L"Custom1",
     L"Custom2",
@@ -79,10 +81,11 @@ enum CONTROL_ID {
     ID_MINIMIZE_BUTTON,
 
     // Welcome page
-    ID_INSTALL_ALL_USERS_BUTTON,
-    ID_INSTALL_JUST_FOR_ME_BUTTON,
+    ID_INSTALL_BUTTON,
     ID_INSTALL_CUSTOM_BUTTON,
     ID_INSTALL_SIMPLE_BUTTON,
+    ID_INSTALL_UPGRADE_BUTTON,
+    ID_INSTALL_UPGRADE_CUSTOM_BUTTON,
     ID_INSTALL_CANCEL_BUTTON,
     
     // Customize Page
@@ -141,10 +144,11 @@ static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = {
     { ID_CLOSE_BUTTON, L"CloseButton" },
     { ID_MINIMIZE_BUTTON, L"MinimizeButton" },
 
-    { ID_INSTALL_ALL_USERS_BUTTON, L"InstallAllUsersButton" },
-    { ID_INSTALL_JUST_FOR_ME_BUTTON, L"InstallJustForMeButton" },
+    { ID_INSTALL_BUTTON, L"InstallButton" },
     { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" },
     { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" },
+    { ID_INSTALL_UPGRADE_BUTTON, L"InstallUpgradeButton" },
+    { ID_INSTALL_UPGRADE_CUSTOM_BUTTON, L"InstallUpgradeCustomButton" },
     { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" },
 
     { ID_TARGETDIR_EDITBOX, L"TargetDir" },
@@ -191,13 +195,35 @@ static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = {
     { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" },
 };
 
+static struct { LPCWSTR regName; LPCWSTR variableName; } OPTIONAL_FEATURES[] = {
+    { L"core_d", L"Include_debug" },
+    { L"core_pdb", L"Include_symbols" },
+    { L"dev", L"Include_dev" },
+    { L"doc", L"Include_doc" },
+    { L"exe", L"Include_exe" },
+    { L"lib", L"Include_lib" },
+    { L"path", L"PrependPath" },
+    { L"pip", L"Include_pip" },
+    { L"tcltk", L"Include_tcltk" },
+    { L"test", L"Include_test" },
+    { L"tools", L"Include_tools" },
+    { L"Shortcuts", L"Shortcuts" },
+    // Include_launcher and AssociateFiles are handled separately and so do
+    // not need to be included in this list.
+    { nullptr, nullptr }
+};
+
+
+
 class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
     void ShowPage(DWORD newPageId) {
         // Process each control for special handling in the new page.
         ProcessPageControls(ThemeGetPage(_theme, newPageId));
 
         // Enable disable controls per-page.
-        if (_pageIds[PAGE_INSTALL] == newPageId || _pageIds[PAGE_SIMPLE_INSTALL] == newPageId) {
+        if (_pageIds[PAGE_INSTALL] == newPageId ||
+            _pageIds[PAGE_SIMPLE_INSTALL] == newPageId ||
+            _pageIds[PAGE_UPGRADE] == newPageId) {
             InstallPage_Show();
         } else if (_pageIds[PAGE_CUSTOM1] == newPageId) {
             Custom1Page_Show();
@@ -222,7 +248,7 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
         // On the install page set the focus to the install button or
         // the next enabled control if install is disabled
         if (_pageIds[PAGE_INSTALL] == newPageId) {
-            ThemeSetFocus(_theme, ID_INSTALL_ALL_USERS_BUTTON);
+            ThemeSetFocus(_theme, ID_INSTALL_BUTTON);
         } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) {
             ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON);
         }
@@ -234,7 +260,7 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
     void OnCommand(CONTROL_ID id) {
         LPWSTR defaultDir = nullptr;
         LPWSTR targetDir = nullptr;
-        LONGLONG elevated, crtInstalled;
+        LONGLONG elevated, crtInstalled, installAllUsers;
         BOOL checked;
         WCHAR wzPath[MAX_PATH] = { };
         BROWSEINFOW browseInfo = { };
@@ -247,87 +273,42 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
             break;
 
         // Install commands
-        case ID_INSTALL_SIMPLE_BUTTON:
-            hr = BalGetStringVariable(L"TargetDir", &targetDir);
-            if (FAILED(hr) || !targetDir || !*targetDir) {
-                LONGLONG installAll;
-                if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) {
-                    hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir);
-                    BalExitOnFailure(hr, "Failed to get the default all users install directory");
-                } else {
-                    hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir);
-                    BalExitOnFailure(hr, "Failed to get the default per-user install directory");
-                }
-
-                if (!defaultDir || !*defaultDir) {
-                    BalLogError(E_INVALIDARG, "Default install directory is blank");
-                }
-
-                hr = BalFormatString(defaultDir, &targetDir);
-                BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir);
-
-                hr = _engine->SetVariableString(L"TargetDir", targetDir);
-                ReleaseStr(targetDir);
-                BalExitOnFailure(hr, "Failed to set install target directory");
-            } else {
-                ReleaseStr(targetDir);
-            }
-
-            OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
-            break;
-
-        case ID_INSTALL_ALL_USERS_BUTTON:
-            SavePageSettings();
-            
-            hr = _engine->SetVariableNumeric(L"InstallAllUsers", 1);
-            ExitOnFailure(hr, L"Failed to set install scope");
-
-            hr = _engine->SetVariableNumeric(L"CompileAll", 1);
-            ExitOnFailure(hr, L"Failed to set compile all setting");
-
-            hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir);
-            BalExitOnFailure(hr, "Failed to get the default all users install directory");
-
-            if (!defaultDir || !*defaultDir) {
-                BalLogError(E_INVALIDARG, "Default install directory is blank");
-            }
-
-            hr = BalFormatString(defaultDir, &targetDir);
-            BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir);
-
-            hr = _engine->SetVariableString(L"TargetDir", targetDir);
-            ReleaseStr(targetDir);
-            BalExitOnFailure(hr, "Failed to set install target directory");
-
-            OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
-            break;
-
-        case ID_INSTALL_JUST_FOR_ME_BUTTON:
+        case ID_INSTALL_SIMPLE_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_BUTTON: __fallthrough;
+        case ID_INSTALL_BUTTON:
             SavePageSettings();
 
             if (!QueryElevateForCrtInstall()) {
                 break;
             }
 
-            hr = _engine->SetVariableNumeric(L"InstallAllUsers", 0);
-            ExitOnFailure(hr, L"Failed to set install scope");
+            hr = BalGetNumericVariable(L"InstallAllUsers", &installAllUsers);
+            ExitOnFailure(hr, L"Failed to get install scope");
 
-            hr = _engine->SetVariableNumeric(L"CompileAll", 0);
-            ExitOnFailure(hr, L"Failed to unset CompileAll");
+            hr = _engine->SetVariableNumeric(L"CompileAll", installAllUsers);
+            ExitOnFailure(hr, L"Failed to update CompileAll");
 
-            hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir);
-            BalExitOnFailure(hr, "Failed to get the default per-user install directory");
+            hr = BalGetStringVariable(L"TargetDir", &targetDir);
+            if (FAILED(hr) || !targetDir || !targetDir[0]) {
+                ReleaseStr(targetDir);
 
-            if (!defaultDir || !*defaultDir) {
-                BalLogError(E_INVALIDARG, "Default install directory is blank");
-            }
+                hr = BalGetStringVariable(
+                    installAllUsers ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir",
+                    &defaultDir
+                );
+                BalExitOnFailure(hr, "Failed to get the default install directory");
 
-            hr = BalFormatString(defaultDir, &targetDir);
-            BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir);
+                if (!defaultDir || !defaultDir[0]) {
+                    BalLogError(E_INVALIDARG, "Default install directory is blank");
+                }
 
-            hr = _engine->SetVariableString(L"TargetDir", targetDir);
+                hr = BalFormatString(defaultDir, &targetDir);
+                BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir);
+
+                hr = _engine->SetVariableString(L"TargetDir", targetDir);
+                BalExitOnFailure(hr, "Failed to set install target directory");
+            }
             ReleaseStr(targetDir);
-            BalExitOnFailure(hr, "Failed to set install target directory");
 
             OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
             break;
@@ -342,6 +323,7 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
             break;
 
         case ID_INSTALL_CUSTOM_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_CUSTOM_BUTTON: __fallthrough;
         case ID_CUSTOM2_BACK_BUTTON:
             SavePageSettings();
             GoToPage(PAGE_CUSTOM1);
@@ -460,10 +442,11 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
             elevated = 0;
         }
 
-        ThemeControlElevates(_theme, ID_INSTALL_ALL_USERS_BUTTON, !elevated);
 
-        if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) {
-            ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, !elevated);
+        if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll && !elevated) {
+            ThemeControlElevates(_theme, ID_INSTALL_BUTTON, TRUE);
+            ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, TRUE);
+            ThemeControlElevates(_theme, ID_INSTALL_UPGRADE_BUTTON, TRUE);
         }
     }
 
@@ -667,7 +650,34 @@ public: // IBootstrapperApplication
 
         // Remember when our bundle would cause a downgrade.
         if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) {
-            _downgrading = TRUE;
+            _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);
+            }
+        } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) {
+            if (_command.action == BOOTSTRAPPER_ACTION_INSTALL) {
+                LOC_STRING *pLocString = nullptr;
+                if (SUCCEEDED(LocGetString(_wixLoc, L"#(loc.FailureExistingInstall)", &pLocString)) && pLocString) {
+                    BalFormatString(pLocString->wzText, &_failedMessage);
+                } else {
+                    BalFormatString(L"Cannot install [WixBundleName] because it is already installed.", &_failedMessage);
+                }
+                BalLog(
+                    BOOTSTRAPPER_LOG_LEVEL_ERROR,
+                    "Related bundle %ls is preventing install",
+                    wzBundleId
+                );
+                SetState(PYBA_STATE_FAILED, E_WIXSTDBA_CONDITION_FAILED);
+            }
         }
 
         return CheckCanceled() ? IDCANCEL : IDOK;
@@ -1969,7 +1979,7 @@ private:
         BalExitOnFailure(hr, "Failed to update strings");
 
         // If we are going to apply a downgrade, bail.
-        if (_downgrading && BOOTSTRAPPER_ACTION_UNINSTALL < action) {
+        if (_downgradingOtherVersion && BOOTSTRAPPER_ACTION_UNINSTALL < action) {
             if (_suppressDowngradeFailure) {
                 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version of this product is installed but downgrade failure has been suppressed; continuing...");
             } else {
@@ -2354,7 +2364,9 @@ private:
                 if (_installPage == PAGE_LOADING) {
                     switch (_command.action) {
                     case BOOTSTRAPPER_ACTION_INSTALL:
-                        if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) {
+                        if (_upgradingOldVersion) {
+                            _installPage = PAGE_UPGRADE;
+                        } else if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) {
                             _installPage = PAGE_SIMPLE_INSTALL;
                         } else {
                             _installPage = PAGE_INSTALL;
@@ -2608,6 +2620,179 @@ private:
         }
     }
 
+    static bool IsTargetPlatformx64(__in IBootstrapperEngine* pEngine) {
+        WCHAR platform[8];
+        DWORD platformLen = 8;
+
+        if (FAILED(pEngine->GetVariableString(L"TargetPlatform", platform, &platformLen))) {
+            return S_FALSE;
+        }
+
+        return ::CompareStringW(LOCALE_NEUTRAL, 0, platform, -1, L"x64", -1) == CSTR_EQUAL;
+    }
+
+    static HRESULT LoadOptionalFeatureStatesFromKey(
+        __in IBootstrapperEngine* pEngine,
+        __in HKEY hkHive,
+        __in LPCWSTR subkey
+    ) {
+        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);
+        }
+        if (res == ERROR_FILE_NOT_FOUND) {
+            return S_FALSE;
+        }
+        if (res != ERROR_SUCCESS) {
+            return HRESULT_FROM_WIN32(res);
+        }
+
+        for (auto p = OPTIONAL_FEATURES; p->regName; ++p) {
+            res = RegQueryValueExW(hKey, p->regName, nullptr, nullptr, nullptr, nullptr);
+            if (res == ERROR_FILE_NOT_FOUND) {
+                pEngine->SetVariableNumeric(p->variableName, 0);
+            } else if (res == ERROR_SUCCESS) {
+                pEngine->SetVariableNumeric(p->variableName, 1);
+            } else {
+                RegCloseKey(hKey);
+                return HRESULT_FROM_WIN32(res);
+            }
+        }
+
+        RegCloseKey(hKey);
+        return S_OK;
+    }
+
+    static HRESULT LoadTargetDirFromKey(
+        __in IBootstrapperEngine* pEngine,
+        __in HKEY hkHive,
+        __in LPCWSTR subkey
+    ) {
+        HKEY hKey;
+        LRESULT res;
+        DWORD dataType;
+        BYTE buffer[1024];
+        DWORD bufferLen = sizeof(buffer);
+
+        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);
+        }
+        if (res == ERROR_FILE_NOT_FOUND) {
+            return S_FALSE;
+        }
+        if (res != ERROR_SUCCESS) {
+            return HRESULT_FROM_WIN32(res);
+        }
+
+        res = RegQueryValueExW(hKey, nullptr, nullptr, &dataType, buffer, &bufferLen);
+        if (res == ERROR_SUCCESS && dataType == REG_SZ && bufferLen < sizeof(buffer)) {
+            pEngine->SetVariableString(L"TargetDir", reinterpret_cast<wchar_t*>(buffer));
+        }
+        RegCloseKey(hKey);
+        return HRESULT_FROM_WIN32(res);
+    }
+
+    static HRESULT LoadLauncherStateFromKey(
+        __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);
+        }
+
+        if (res == ERROR_FILE_NOT_FOUND) {
+            return S_FALSE;
+        }
+        if (res != ERROR_SUCCESS) {
+            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);
+        }
+
+        res = RegQueryValueExW(hKey, L"AssociateFiles", nullptr, nullptr, nullptr, nullptr);
+        if (res == ERROR_FILE_NOT_FOUND) {
+            pEngine->SetVariableNumeric(L"AssociateFiles", 0);
+        } else if (res == ERROR_SUCCESS) {
+            pEngine->SetVariableNumeric(L"AssociateFiles", 1);
+        }
+
+        RegCloseKey(hKey);
+        return S_OK;
+    }
+
+    static void LoadOptionalFeatureStates(__in IBootstrapperEngine* pEngine) {
+        WCHAR subkeyFmt[256];
+        WCHAR subkey[256];
+        DWORD subkeyLen;
+        HRESULT hr;
+        HKEY hkHive;
+
+        // The launcher installation is separate from the Python install, so we
+        // check its state later. This also checks the file association option.
+
+        // Get the registry key from the bundle, to save having to duplicate it
+        // in multiple places.
+        subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]);
+        hr = pEngine->GetVariableString(L"OptionalFeaturesRegistryKey", subkeyFmt, &subkeyLen);
+        BalExitOnFailure(hr, "Failed to locate registry key");
+        subkeyLen = sizeof(subkey) / sizeof(subkey[0]);
+        hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen);
+        BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt);
+
+        // Check the current user's registry for existing features
+        hkHive = HKEY_CURRENT_USER;
+        hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey);
+        BalExitOnFailure1(hr, "Failed to read from HKCU\\%ls", subkey);
+        if (hr == S_FALSE) {
+            // Now check the local machine registry
+            hkHive = HKEY_LOCAL_MACHINE;
+            hr = LoadOptionalFeatureStatesFromKey(pEngine, hkHive, subkey);
+            BalExitOnFailure1(hr, "Failed to read from HKLM\\%ls", subkey);
+            if (hr == S_OK) {
+                // Found a system-wide install, so enable these settings.
+                pEngine->SetVariableNumeric(L"InstallAllUsers", 1);
+                pEngine->SetVariableNumeric(L"CompileAll", 1);
+            }
+        }
+
+        if (hr == S_OK) {
+            // Cannot change InstallAllUsersState when upgrading. While there's
+            // no good reason to not allow installing a per-user and an all-user
+            // version simultaneously, Burn can't handle the state management
+            // and will need to uninstall the old one. 
+            pEngine->SetVariableString(L"InstallAllUsersState", L"disable");
+
+            // Get the previous install directory. This can be changed by the
+            // user.
+            subkeyLen = sizeof(subkeyFmt) / sizeof(subkeyFmt[0]);
+            hr = pEngine->GetVariableString(L"TargetDirRegistryKey", subkeyFmt, &subkeyLen);
+            BalExitOnFailure(hr, "Failed to locate registry key");
+            subkeyLen = sizeof(subkey) / sizeof(subkey[0]);
+            hr = pEngine->FormatString(subkeyFmt, subkey, &subkeyLen);
+            BalExitOnFailure1(hr, "Failed to format %ls", subkeyFmt);
+            LoadTargetDirFromKey(pEngine, hkHive, subkey);
+        }
+
+    LExit:
+        return;
+    }
 
 public:
     //
@@ -2667,7 +2852,8 @@ public:
         _installPage = PAGE_LOADING;
         _hrFinal = hrHostInitialization;
 
-        _downgrading = FALSE;
+        _downgradingOtherVersion = FALSE;
+        _upgradingOldVersion = FALSE;
         _restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
         _restartRequired = FALSE;
         _allowRestart = FALSE;
@@ -2690,6 +2876,8 @@ public:
 
         _hBAFModule = nullptr;
         _baFunction = nullptr;
+
+        LoadOptionalFeatureStates(pEngine);
     }
 
 
@@ -2748,7 +2936,8 @@ private:
     DWORD _calculatedCacheProgress;
     DWORD _calculatedExecuteProgress;
 
-    BOOL _downgrading;
+    BOOL _downgradingOtherVersion;
+    BOOL _upgradingOldVersion;
     BOOTSTRAPPER_APPLY_RESTART _restartResult;
     BOOL _restartRequired;
     BOOL _allowRestart;
index 5d8337c1349442017b6b17620650d3b072099829..be12957112fa6d8273fe98ddafc575cb20acafcf 100644 (file)
@@ -31,7 +31,7 @@
   <PropertyGroup Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <CharacterSet>Unicode</CharacterSet>
-    <IntDir>$(ProjectDir)..\..\obj\$(Configuration)_Bootstrap\</IntDir>
+    <IntDir>$(PySourcePath)PCBuild\obj\$(Configuration)_$(Platform)_Setup\Bootstrap\</IntDir>
     <OutDir>$(IntDir)</OutDir>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
index 76e87ab6234f33ae7feada3468fa801f6ee378a4..678dac4e872f17df65931b42790b760964bbba5b 100644 (file)
     <Variable Name="ShortVersion" Value="$(var.MajorVersionNumber).$(var.MinorVersionNumber)" />
     <Variable Name="ShortVersionNoDot" Value="$(var.MajorVersionNumber)$(var.MinorVersionNumber)" />
 
-    <Variable Name="InstallAllUsers" Value="0" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="TargetDir" Value="" Persisted="yes" bal:Overridable="yes" />
+    <Variable Name="InstallAllUsers" Value="0" bal:Overridable="yes" />
+    <Variable Name="TargetDir" Value="" bal:Overridable="yes" />
     <?if $(var.Platform)~="x64" ?>
     <Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFiles64Folder]Python [ShortVersion]" bal:Overridable="yes" />
+    <Variable Name="TargetPlatform" Value="x64" />
     <?else ?>
     <Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFilesFolder]Python [ShortVersion]" bal:Overridable="yes" />
+    <Variable Name="TargetPlatform" Value="x86" />
     <?endif ?>
     <Variable Name="DefaultJustForMeTargetDir" Value="[LocalAppDataFolder]Programs\Python\Python[ShortVersionNoDot]$(var.Suffix32)" bal:Overridable="yes" />
+    <Variable Name="OptionalFeaturesRegistryKey" Value="Software\$(var.TestPrefix)Python\PythonCore\[ShortVersion]$(var.Suffix32)\InstalledFeatures" />
+    <Variable Name="TargetDirRegistryKey" Value="Software\$(var.TestPrefix)Python\PythonCore\[ShortVersion]$(var.Suffix32)\InstallPath" />
     
     <!--
     An empty string will use the other defaults based on InstallAllUsers
     <Variable Name="TargetDirState" Value="enabled" />
     <Variable Name="CustomBrowseButtonState" Value="enabled" />
 
-    <Variable Name="Include_core" Value="1" Persisted="yes" />
-    <Variable Name="Include_exe" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_dev" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_lib" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_test" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_doc" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_tools" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_tcltk" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_pip" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_launcher" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_symbols" Value="0" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Include_debug" Value="0" Persisted="yes" bal:Overridable="yes" />
+    <Variable Name="Include_core" Value="1" />
+    <Variable Name="Include_exe" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_dev" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_lib" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_test" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_doc" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_tools" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_tcltk" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_pip" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_launcher" Value="1" bal:Overridable="yes" />
+    <Variable Name="Include_symbols" Value="0" bal:Overridable="yes" />
+    <Variable Name="Include_debug" Value="0" bal:Overridable="yes" />
     
-    <Variable Name="AssociateFiles" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="Shortcuts" Value="1" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="PrependPath" Value="0" Persisted="yes" bal:Overridable="yes" />
-    <Variable Name="CompileAll" Value="0" Persisted="yes" bal:Overridable="yes" />
+    <Variable Name="AssociateFiles" Value="1" bal:Overridable="yes" />
+    <Variable Name="Shortcuts" Value="1" bal:Overridable="yes" />
+    <Variable Name="PrependPath" Value="0" bal:Overridable="yes" />
+    <Variable Name="CompileAll" Value="0" bal:Overridable="yes" />
     
     <Variable Name="SimpleInstall" Value="0" bal:Overridable="yes" />
     
index 9df6b7919422d019f83efdc152597effea0e1e9b..a7895858379d00928042570deb04c81d05f3b408 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip)">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="core_AllUsers_pdb"
                         SourceFile="core_pdb.msi"
@@ -17,6 +18,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="core_AllUsers_d"
                         SourceFile="core_d.msi"
@@ -25,6 +27,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
 
             <MsiPackage Id="core_JustForMe"
@@ -34,6 +37,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip)">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="core_JustForMe_pdb"
                         SourceFile="core_pdb.msi"
@@ -42,6 +46,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="core_JustForMe_d"
                         SourceFile="core_d.msi"
@@ -50,6 +55,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index f2ea29b611a30a965277b068317825bc62acb88e..f7f50250cbe3a869f6325c33b0bbb005ed448661 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_dev">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="dev_AllUsers_d"
                         SourceFile="dev_d.msi"
@@ -17,6 +18,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_dev and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
 
             <MsiPackage Id="dev_JustForMe"
@@ -26,6 +28,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_dev">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="dev_JustForMe_d"
                         SourceFile="dev_d.msi"
@@ -34,6 +37,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_dev and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 7843f44263a3a5851592e2fd1e685e3f731deb8c..2f11e27a925ce1ee0db35f95cfd0c59d89f8713a 100644 (file)
@@ -10,6 +10,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_doc">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             
             <MsiPackage Id="doc_JustForMe"
@@ -20,6 +21,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_doc">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 50346d94a1670b63783e7e63f7e235f7696c6b2a..03d6f6256643beab23e0668ed0252ee59d31ca94 100644 (file)
@@ -10,6 +10,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip)">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="exe_AllUsers_pdb"
                         SourceFile="exe_pdb.msi"
@@ -18,6 +19,7 @@
                         DownloadUrl="$(var.DownloadUrl)"
                         InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="exe_AllUsers_d"
                         SourceFile="exe_d.msi"
@@ -26,6 +28,7 @@
                         DownloadUrl="$(var.DownloadUrl)"
                         InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             
             <MsiPackage Id="exe_JustForMe"
@@ -36,6 +39,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip)">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="exe_JustForMe_pdb"
                         SourceFile="exe_pdb.msi"
@@ -44,6 +48,7 @@
                         DownloadUrl="$(var.DownloadUrl)"
                         InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="exe_JustForMe_d"
                         SourceFile="exe_d.msi"
@@ -52,6 +57,7 @@
                         DownloadUrl="$(var.DownloadUrl)"
                         InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 47a97f16d0f7aa90aa106e8a04eab8f6fef97729..f7c57c8035b2764e67f83c765a97946a7a4631d4 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_lib">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="lib_AllUsers_pdb"
                         SourceFile="lib_pdb.msi"
@@ -17,6 +18,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_lib and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="lib_AllUsers_d"
                         SourceFile="lib_d.msi"
@@ -25,6 +27,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_lib and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
 
             <MsiPackage Id="lib_JustForMe"
@@ -34,6 +37,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_lib">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="lib_JustForMe_pdb"
                         SourceFile="lib_pdb.msi"
@@ -42,6 +46,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_lib and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="lib_JustForMe_d"
                         SourceFile="lib_d.msi"
@@ -50,6 +55,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_lib and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 35978cc7c6f75b04020d12c567856daedddd2b8c..4c50001d2ab33aa6dab8d9c9b8a383d873c01019 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_pip">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="pip_JustForMe"
                         SourceFile="pip.msi"
@@ -17,6 +18,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_pip">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             
             <MsiPackage Id="path_AllUsers"
@@ -26,6 +28,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and PrependPath">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="path_JustForMe"
                         SourceFile="path.msi"
@@ -34,6 +37,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and PrependPath">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             
             <?define CompileAllCommand=-$(var.ShortVersion)$(var.Suffix32) -E -s -Wi "[TargetDir]\Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TargetDir]\Lib"?>
index e0e3958d560a6063fee44ea998da4e9c2beee813..92f41cbc79179e8393bc520e65e29ed16f364c7c 100644 (file)
@@ -10,6 +10,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="InstallAllUsers and Include_tcltk">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="tcltk_AllUsers_pdb"
                         SourceFile="tcltk_pdb.msi"
@@ -19,6 +20,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="InstallAllUsers and Include_tcltk and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="tcltk_AllUsers_d"
                         SourceFile="tcltk_d.msi"
@@ -28,6 +30,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="InstallAllUsers and Include_tcltk and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
 
             <MsiPackage Id="tcltk_JustForMe"
@@ -38,6 +41,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="not InstallAllUsers and Include_tcltk">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="tcltk_JustForMe_pdb"
                         SourceFile="tcltk_pdb.msi"
@@ -47,6 +51,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="not InstallAllUsers and Include_tcltk and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="tcltk_JustForMe_d"
                         SourceFile="tcltk_d.msi"
@@ -56,6 +61,7 @@
                         EnableFeatureSelection="yes"
                         InstallCondition="not InstallAllUsers and Include_tcltk and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index b64e8ff94292a70b669433a2d6dfaff7ac619e5a..b3e0f3e9223a64887086e720b5038e724d6262d5 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_test">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="test_AllUsers_pdb"
                         SourceFile="test_pdb.msi"
@@ -17,6 +18,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_test and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="test_AllUsers_d"
                         SourceFile="test_d.msi"
@@ -25,6 +27,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_test and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
 
             <MsiPackage Id="test_JustForMe"
@@ -34,6 +37,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_test">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="test_JustForMe_pdb"
                         SourceFile="test_pdb.msi"
@@ -42,6 +46,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_test and Include_symbols">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             <MsiPackage Id="test_JustForMe_d"
                         SourceFile="test_d.msi"
@@ -50,6 +55,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_test and Include_debug">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 06af5b588f6df0df814b1027e05c4121a81923f4..c92f27ba0187a18dc86360a7dc81c7eee7d30a7e 100644 (file)
@@ -9,6 +9,7 @@
                         ForcePerMachine="yes"
                         InstallCondition="InstallAllUsers and Include_tools">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
             
             <MsiPackage Id="tools_JustForMe"
@@ -18,6 +19,7 @@
                         ForcePerMachine="no"
                         InstallCondition="not InstallAllUsers and Include_tools">
                 <MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
+                <MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
             </MsiPackage>
         </PackageGroup>
     </Fragment>
index 7529aab0c6c81b04852a403a8e8aa1ea5af0299b..cc39540a2b06f412fc47092890348d0c2ae128a6 100644 (file)
@@ -4,6 +4,15 @@
         <Property Id="REGISTRYKEY" Value="Software\$(var.TestPrefix)Python\PythonCore\$(var.ShortVersion)$(var.Suffix32)" />
     </Fragment>
     
+    <Fragment>
+        <Component Id="OptionalFeature" Guid="*" Directory="InstallDirectory">
+            <Condition>OPTIONALFEATURESREGISTRYKEY</Condition>
+            <RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
+                <RegistryValue Type="string" Name="$(var.OptionalFeatureName)" Value="$(var.Version)" KeyPath="yes" />
+            </RegistryKey>
+        </Component>
+    </Fragment>
+    
     <Fragment>
         <Property Id="UpgradeTable" Value="1" />
         
index 8422117db99b9800ee8f483b5e37a3148506a631..bb35f994be2461084dd3562d5fba2f975b0ecd9f 100644 (file)
@@ -8,6 +8,7 @@
         
         <Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
             <ComponentGroupRef Id="core_dll_d" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>
index c9a558d2c79d8a867fc7f6f2ad0fb791f5f13ee6..ba72d956cdf6067983f78c4d9889d6dccbe84f7f 100644 (file)
@@ -8,6 +8,7 @@
         
         <Feature Id="Symbols" AllowAdvertise="no" Title="!(loc.TitlePdb)" Description="!(loc.DescriptionPdb)">
             <ComponentGroupRef Id="core_symbols" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>
index f8af9aab5cbe3444105186ea8a73caef86162301..a09e139c428bf1478f893189dc37d78c44aebce6 100644 (file)
@@ -13,6 +13,7 @@
 <?ifdef IncludeMinGWLib ?>
             <ComponentGroupRef Id="dev_mingw" />
 <?endif ?>
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>
index 22b0213932458aa37beee820b8f44ceb422587df..bbe30a13e32697cf5dda6e2de4a80d5f9b401a04 100644 (file)
@@ -9,13 +9,16 @@
         
         <Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <ComponentGroupRef Id="doc" Primary="yes" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
         <Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <ComponentGroupRef Id="doc" />
             
             <?ifdef DocFilename ?>
             <Component Id="doc_shortcut" Directory="MenuDir" Guid="*">
-                <RegistryValue Root="HKMU" Key="[REGISTRYKEY]\DocShortcuts" Type="integer" Value="1" KeyPath="yes" />
+                <RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
+                    <RegistryValue Name="$(var.OptionalFeatureName)_shortcut" Type="string" Value="$(var.Version)" KeyPath="yes" />
+                </RegistryKey>
                 <Shortcut Id="python.chm"
                           Target="[#python.chm]"
                           Name="!(loc.ShortcutName)"
index d8b05e0f584eac85231367f4b2003d1d8bf1dfb7..dcbf646da0f17d528946de9ac4946f203e52a790 100644 (file)
@@ -11,6 +11,7 @@
             <ComponentGroupRef Id="exe_python" Primary="yes" />
             <ComponentGroupRef Id="exe_txt" />
             <ComponentGroupRef Id="exe_icons" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
             
         <Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
@@ -23,6 +24,7 @@
                 <RemoveFolder Id="Remove_MenuDir" Directory="MenuDir" On="uninstall" />
                 <RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
                     <RegistryValue Key="InstallPath\InstallGroup" Type="string" Value="!(loc.ProductName)" KeyPath="yes" />
+                    <RegistryValue Key="InstalledFeatures" Name="Shortcuts" Type="string" Value="$(var.Version)" />
                 </RegistryKey>
             </Component>
         </Feature>
index 642237299f3195455b2cefd9ce0bb49a432eeb76..3b5fce446c6b55691f2e5efda728addb1fcbde0f 100644 (file)
@@ -23,6 +23,7 @@
                 
                 <RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
                     <RegistryValue Key="InstallPath" Type="string" Value="[InstallDirectory]" KeyPath="no" />
+                    <RegistryValue Key="InstallPath" Name="ExecutablePath" Type="string" Value="[#python.exe]" KeyPath="no" />
                 </RegistryKey>
             </Component>
             <Component Id="pythonw.exe" Directory="InstallDirectory" Guid="$(var.PythonwExeComponentGuid)">
index 9606dc6dd2c5e933add951bc9a00101dd567c6ac..589dee5654716288a0bd97384f5482efcd2329cd 100644 (file)
@@ -4,6 +4,7 @@
         <ComponentGroup Id="launcher_exe">
             <Component Id="py.exe" Directory="LauncherInstallDirectory" Guid="{B5107402-6958-461B-8B0A-4037D3327160}">
                 <File Id="py.exe" Name="py.exe" Source="py.exe" KeyPath="yes" />
+                <RegistryValue Root="HKMU" Key="Software\Python\PyLauncher" Value="[#py.exe]" Type="string" />
             </Component>
             <Component Id="pyw.exe" Directory="LauncherInstallDirectory" Guid="{8E52B8CD-48BB-4D74-84CD-6238BCD11F20}">
                 <File Id="pyw.exe" Name="pyw.exe" Source="pyw.exe" KeyPath="yes" />
             <Component Id="launcher_path_cu" Directory="LauncherInstallDirectory" Guid="{95AEB930-367C-475C-A17E-A89BFCD4C670}">
                 <Condition>NOT ALLUSERS=1</Condition>
                 
-                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher\InstallDir" Value="[LauncherInstallDirectory]" Type="string" />
+                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher" Name="InstallDir" Value="[LauncherInstallDirectory]" Type="string" />
                 <Environment Id="PATH_CU" Action="set" Name="PATH" Part="first" Value="[LauncherInstallDirectory]" />
             </Component>
             <Component Id="launcher_path_lm" Directory="LauncherInstallDirectory" Guid="{4A41C365-4E27-4D38-A6D1-4A01B4A6500C}">
                 <Condition>ALLUSERS=1</Condition>
-                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher\InstallDir" Value="[LauncherInstallDirectory]" Type="string" />
+                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher" Name="InstallDir" Value="[LauncherInstallDirectory]" Type="string" />
             </Component>
         </ComponentGroup>
     </Fragment>
index 204b4ed261fcffb2630f0ffdfbfbb29b2fef2701..eef71c8d392c708a4112d53d916f6ff12138a7f3 100644 (file)
@@ -3,7 +3,7 @@
     <Fragment>
         <ComponentGroup Id="launcher_reg">
             <Component Id="file_association" Directory="LauncherInstallDirectory" Guid="{5AF84D9A-D820-456B-B230-6E0105A50276}">
-                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher\AssociateFiles" Value="1" Type="integer" />
+                <RegistryValue KeyPath="yes" Root="HKMU" Key="Software\Python\PyLauncher" Name="AssociateFiles" Value="1" Type="integer" />
                 
                 <ProgId Id="$(var.TestPrefix)Python.File" Description="!(loc.PythonFileDescription)" Advertise="no" Icon="py.exe" IconIndex="1">
                     <Extension Id="$(var.FileExtension)" ContentType="text/plain">
index b1aec75a7c774e76d544c837d3899afde364ce19..2b04bcb3049c48df06dae5f7d0298b3303b33136 100644 (file)
@@ -11,6 +11,7 @@
             <ComponentGroupRef Id="lib_py" />
             <ComponentGroupRef Id="lib_files" />
             <ComponentGroupRef Id="lib_extensions" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>
index bd22345ec31704a5844840bf26937856bd4b78c0..1d9f0f0df1deedd827393de0d81c79d138579a87 100644 (file)
@@ -43,7 +43,7 @@
     </ItemGroup>
 
     <PropertyGroup>
-        <IntermediateOutputPath>$(MSBuildThisFileDirectory)\obj\$(Configuration)_$(Platform)\$(OutputName)</IntermediateOutputPath>
+        <IntermediateOutputPath>$(PySourcePath)PCBuild\obj\$(Configuration)_$(Platform)_Setup\$(OutputName)</IntermediateOutputPath>
         <IntermediateOutputPath Condition="'$(OutputSuffix)' != ''">$(IntermediateOutputPath)_$(OutputSuffix)</IntermediateOutputPath>
         <OutputPath Condition="'$(OutputPath)' == ''">$(BuildPath)</OutputPath>
         <OutputPath Condition="!HasTrailingSlash($(OutputPath))">$(OutputPath)\</OutputPath>
@@ -71,6 +71,7 @@
             NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0;
             Bitness=$(Bitness);
             PyDebugExt=$(PyDebugExt);
+            OptionalFeatureName=$(OutputName);
         </DefineConstants>
         <DefineConstants Condition="'$(CRTRedist)' != ''">
             $(DefineConstants);CRTRedist=$(CRTRedist);
         <LinkerBindInputPaths Include="$(CRTRedist)" Condition="'$(CRTRedist)' != ''">
             <BindName>redist</BindName>
         </LinkerBindInputPaths>
-        <LinkerBindInputPaths Include="$(CRTRedist)\$(Platform)" Condition="'$(CRTRedist)' != ''">
-            <BindName>crt</BindName>
-        </LinkerBindInputPaths>
     </ItemGroup>
 
     <Target Name="_ValidateMsiProps" BeforeTargets="PrepareForBuild">
index 7e462e26e9c1880ef674c52d8a50fb2fd181317f..8b37936cc938f2602f47acc72595c50b89dc88a0 100644 (file)
@@ -9,7 +9,9 @@
         <Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <Component Id="PrependPath_CU" Directory="InstallDirectory" Guid="*">
                 <Condition>NOT ALLUSERS=1</Condition>
-                <RegistryValue KeyPath="yes" Root="HKCU" Key="[REGISTRYKEY]\PrependPath" Value="1" Type="integer" />
+                <RegistryKey Root="HKCU" Key="[REGISTRYKEY]">
+                    <RegistryValue KeyPath="yes" Key="InstalledFeatures" Name="$(var.OptionalFeatureName)" Value="$(var.Version)" Type="string" />
+                </RegistryKey>
                 
                 <CreateFolder Directory="Scripts" />
                 <RemoveFolder Id="Remove_Scripts_CU" Directory="Scripts" On="uninstall" />
@@ -19,7 +21,9 @@
             </Component>
             <Component Id="PrependPath_LM" Directory="InstallDirectory" Guid="*">
                 <Condition>ALLUSERS=1</Condition>
-                <RegistryValue KeyPath="yes" Root="HKLM" Key="[REGISTRYKEY]\PrependPath" Value="1" Type="integer" />
+                <RegistryKey Root="HKLM" Key="[REGISTRYKEY]">
+                    <RegistryValue KeyPath="yes" Key="InstalledFeatures" Name="$(var.OptionalFeatureName)" Value="$(var.Version)" Type="string" />
+                </RegistryKey>
                 
                 <CreateFolder Directory="Scripts" />
                 <RemoveFolder Id="Remove_Scripts_LM" Directory="Scripts" On="uninstall" />
index c46a868188838b390b6085d62ae0037009230334..19e9f5fd2088607f2c860ef33e2d10e6b0f8e2fa 100644 (file)
@@ -15,9 +15,7 @@
         <Condition Message="!(loc.NoPython)">PYTHON_EXE</Condition>
         
         <Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
-            <Component Id="pip" Guid="*" Directory="InstallDirectory">
-                <RegistryValue KeyPath="yes" Root="HKMU" Key="[REGISTRYKEY]\EnsurePipRun" Value="1" Type="integer" />
-            </Component>
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
         
         <?if $(var.Platform)~="x64" ?>
index 5def5ed4db7859e1716a5f013f82a8c3a8d38c34..0b83c5cb5c05a7809a50c76ff671b35707077c6f 100644 (file)
@@ -30,6 +30,7 @@
             <Component Id="idle_reg" Directory="InstallDirectory">
                 <RegistryValue KeyPath="yes" Root="HKMU" Key="[REGISTRYKEY]\Idle" Type="string" Value="[#Lib_idlelib_idle.pyw]" />
             </Component>
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
         <Feature Id="AssociateFiles" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <ComponentGroupRef Id="tkinter_lib" />
index de477858eb338785571e8c46b9b6e35b3ac83ca9..f2ed64f07bf281dc4bc36b2f645100a915e1e078 100644 (file)
@@ -10,6 +10,7 @@
         <Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <ComponentGroupRef Id="test_py" />
             <ComponentGroupRef Id="test_extensions" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>
index 366d4c68f30edb41603e7a977ad20d0e29c73246..8f8418a46c2d36864698653522c94cb7695900a8 100644 (file)
@@ -9,6 +9,7 @@
         <Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
             <ComponentGroupRef Id="tools_py" />
             <ComponentGroupRef Id="tools_scripts" />
+            <ComponentRef Id="OptionalFeature" />
         </Feature>
     </Product>
 </Wix>