mirror of https://github.com/python/cpython
Adds support for an unattend.xml file to control the Windows installer options.
This commit is contained in:
parent
a3d03ec6b1
commit
2434aa24e0
|
@ -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
|
recommended for per-user installs when there is also a system-wide installation
|
||||||
that included the launcher.)
|
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:
|
.. _install-layout-option:
|
||||||
|
|
||||||
Installing Without Downloading
|
Installing Without Downloading
|
||||||
|
|
|
@ -1249,6 +1249,92 @@ private:
|
||||||
return hr;
|
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.
|
// InitializeData - initializes all the package information.
|
||||||
|
@ -1264,6 +1350,9 @@ private:
|
||||||
hr = ParseOverridableVariablesFromXml(pixdManifest);
|
hr = ParseOverridableVariablesFromXml(pixdManifest);
|
||||||
BalExitOnFailure(hr, "Failed to read overridable variables.");
|
BalExitOnFailure(hr, "Failed to read overridable variables.");
|
||||||
|
|
||||||
|
hr = ParseVariablesFromUnattendXml();
|
||||||
|
ExitOnFailure(hr, "Failed to read unattend.ini file.");
|
||||||
|
|
||||||
hr = ProcessCommandLine(&_language);
|
hr = ProcessCommandLine(&_language);
|
||||||
ExitOnFailure(hr, "Unknown commandline parameters.");
|
ExitOnFailure(hr, "Unknown commandline parameters.");
|
||||||
|
|
||||||
|
@ -1323,7 +1412,9 @@ private:
|
||||||
|
|
||||||
hr = StrAllocString(psczLanguage, &argv[i][0], 0);
|
hr = StrAllocString(psczLanguage, &argv[i][0], 0);
|
||||||
BalExitOnFailure(hr, "Failed to copy language.");
|
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) {
|
} else if (_overridableVariables) {
|
||||||
int value;
|
int value;
|
||||||
const wchar_t* pwc = wcschr(argv[i], L'=');
|
const wchar_t* pwc = wcschr(argv[i], L'=');
|
||||||
|
|
Loading…
Reference in New Issue