diff options
author | Steve Dower <steve.dower@microsoft.com> | 2015-07-18 16:28:19 (GMT) |
---|---|---|
committer | Steve Dower <steve.dower@microsoft.com> | 2015-07-18 16:28:19 (GMT) |
commit | 2434aa24e049e54fb6573d7e5126b410c4569037 (patch) | |
tree | 15c5a58dbf864f42a59b400dae25afe3cd076493 | |
parent | a3d03ec6b1191c04fb4073e26069d3282c0b6e72 (diff) | |
download | cpython-2434aa24e049e54fb6573d7e5126b410c4569037.zip cpython-2434aa24e049e54fb6573d7e5126b410c4569037.tar.gz cpython-2434aa24e049e54fb6573d7e5126b410c4569037.tar.bz2 |
Adds support for an unattend.xml file to control the Windows installer options.
-rw-r--r-- | Doc/using/windows.rst | 14 | ||||
-rw-r--r-- | Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 93 |
2 files changed, 106 insertions, 1 deletions
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 53d5f3e..dad827d 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -171,6 +171,20 @@ display a simplified initial page and disallow customization:: recommended for per-user installs when there is also a system-wide installation that included the launcher.) +The options listed above can also be provided in a file named ``unattend.xml`` +alongside the executable. This file specifies a list of options and values. +When a value is provided as an attribute, it will be converted to a number if +possible. Values provided as element text are always left as strings. This +example file sets the same options and the previous example:: + + <Options> + <Option Name="InstallAllUsers" Value="no" /> + <Option Name="Include_launcher" Value="0" /> + <Option Name="Include_test" Value="no" /> + <Option Name="SimpleInstall" Value="yes" /> + <Option Name="SimpleInstallDescription">Just for me, no test suite</Option> + </Options> + .. _install-layout-option: Installing Without Downloading diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp index 2d8f04d..416f2d5 100644 --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -1249,6 +1249,92 @@ private: return hr; } + // + // ParseVariablesFromUnattendXml - reads options from unattend.xml if it + // exists + // + HRESULT ParseVariablesFromUnattendXml() { + HRESULT hr = S_OK; + LPWSTR sczUnattendXmlPath = nullptr; + IXMLDOMDocument *pixdUnattend = nullptr; + IXMLDOMNodeList *pNodes = nullptr; + IXMLDOMNode *pNode = nullptr; + long cNodes; + DWORD dwAttr; + LPWSTR scz = nullptr; + BOOL bValue; + int iValue; + BOOL tryConvert; + BSTR bstrValue = nullptr; + + hr = BalFormatString(L"[WixBundleOriginalSourceFolder]unattend.xml", &sczUnattendXmlPath); + BalExitOnFailure(hr, "Failed to calculate path to unattend.xml"); + + if (!FileExistsEx(sczUnattendXmlPath, &dwAttr)) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_VERBOSE, "Did not find %ls", sczUnattendXmlPath); + hr = S_FALSE; + goto LExit; + } + + hr = XmlLoadDocumentFromFile(sczUnattendXmlPath, &pixdUnattend); + BalExitOnFailure1(hr, "Failed to read %ls", sczUnattendXmlPath); + + // get the list of variables users have overridden + hr = XmlSelectNodes(pixdUnattend, L"/Options/Option", &pNodes); + if (S_FALSE == hr) { + ExitFunction1(hr = S_OK); + } + BalExitOnFailure(hr, "Failed to select option nodes."); + + hr = pNodes->get_length((long*)&cNodes); + BalExitOnFailure(hr, "Failed to get option node count."); + + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Reading settings from %ls", sczUnattendXmlPath); + + for (DWORD i = 0; i < cNodes; ++i) { + hr = XmlNextElement(pNodes, &pNode, nullptr); + BalExitOnFailure(hr, "Failed to get next node."); + + // @Name + hr = XmlGetAttributeEx(pNode, L"Name", &scz); + BalExitOnFailure(hr, "Failed to get @Name."); + + tryConvert = TRUE; + hr = XmlGetAttribute(pNode, L"Value", &bstrValue); + if (FAILED(hr) || !bstrValue || !*bstrValue) { + hr = XmlGetText(pNode, &bstrValue); + tryConvert = FALSE; + } + BalExitOnFailure(hr, "Failed to get @Value."); + + if (tryConvert && + CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"yes", -1)) { + _engine->SetVariableNumeric(scz, 1); + } else if (tryConvert && + CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"no", -1)) { + _engine->SetVariableNumeric(scz, 0); + } else if (tryConvert && ::StrToIntExW(bstrValue, STIF_DEFAULT, &iValue)) { + _engine->SetVariableNumeric(scz, iValue); + } else { + _engine->SetVariableString(scz, bstrValue); + } + + ReleaseNullBSTR(bstrValue); + ReleaseNullStr(scz); + ReleaseNullObject(pNode); + } + + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Finished reading from %ls", sczUnattendXmlPath); + + LExit: + ReleaseObject(pNode); + ReleaseObject(pNodes); + ReleaseObject(pixdUnattend); + ReleaseStr(sczUnattendXmlPath); + + return hr; + } + // // InitializeData - initializes all the package information. @@ -1264,6 +1350,9 @@ private: hr = ParseOverridableVariablesFromXml(pixdManifest); BalExitOnFailure(hr, "Failed to read overridable variables."); + hr = ParseVariablesFromUnattendXml(); + ExitOnFailure(hr, "Failed to read unattend.ini file."); + hr = ProcessCommandLine(&_language); ExitOnFailure(hr, "Unknown commandline parameters."); @@ -1323,7 +1412,9 @@ private: hr = StrAllocString(psczLanguage, &argv[i][0], 0); BalExitOnFailure(hr, "Failed to copy language."); - } + } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"simple", -1)) { + _engine->SetVariableNumeric(L"SimpleInstall", 1); + } } else if (_overridableVariables) { int value; const wchar_t* pwc = wcschr(argv[i], L'='); |