Skip to content

Commit f5b00a2

Browse files
authored
Update configure export --all for recent DSC changes (#6226)
CP #6222 to 1.28 Updates our `ExportAll` test to use `_` instead of `.` in the name of the subdirectory resource as DSC 3.2 is now strict about this. Improves our DSC resource filtering mechanism to target some well-known resources and then exclude all resources that reside in that same location. This will prevent new DSC provided resources from being included by default.
1 parent c25b662 commit f5b00a2

3 files changed

Lines changed: 127 additions & 37 deletions

File tree

src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp

Lines changed: 125 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,29 @@ namespace AppInstaller::CLI::Workflow
101101
return {
102102
L"Microsoft.WinGet/",
103103
L"Microsoft.WinGet.Dev/",
104-
L"Microsoft.DSC.Debug/",
104+
};
105+
};
106+
107+
// Returns unit type prefixes that identify resources known to be shipped with DSC.
108+
// These are used both to exclude the resources themselves and to discover the DSC
109+
// installation location, so that any co-located resources are also excluded.
110+
std::vector<std::wstring_view> DscShippedResourcePrefixes()
111+
{
112+
return {
105113
L"Microsoft.DSC/",
114+
L"Microsoft.DSC.Debug/",
106115
L"Microsoft.DSC.Transitional/",
107-
L"Microsoft.Windows/RebootPending",
108-
L"Microsoft.Windows/Registry",
109-
L"Microsoft.Windows/WMI",
110-
L"Microsoft.Windows/WindowsPowerShell",
111-
L"Microsoft/OSInfo"
116+
L"Microsoft/OSInfo",
112117
};
113-
};
118+
}
119+
120+
// Returns unit type prefixes for DSC-shipped resources that are still allowed to
121+
// appear in the exported configuration. All other DSC-shipped resources are excluded by default.
122+
std::vector<std::wstring_view> DscShippedResourcesAllowList()
123+
{
124+
// Currently empty: all DSC-shipped resources are excluded from export by default.
125+
return {};
126+
}
114127

115128
Logging::Level ConvertLevel(DiagnosticLevel level)
116129
{
@@ -1582,10 +1595,10 @@ namespace AppInstaller::CLI::Workflow
15821595
}
15831596
}
15841597

1585-
std::vector<IConfigurationUnitProcessorDetails> GetAllUnitProcessors(Execution::Context& context)
1598+
std::vector<IConfigurationUnitProcessorDetails3> GetAllUnitProcessors3(Execution::Context& context)
15861599
{
15871600
ConfigurationContext& configContext = context.Get<Data::ConfigurationContext>();
1588-
std::vector<IConfigurationUnitProcessorDetails> result;
1601+
std::vector<IConfigurationUnitProcessorDetails3> result;
15891602

15901603
// Only supported by dsc v3 processor.
15911604
if (ConfigurationRemoting::ProcessorEngine::DSCv3 == ConfigurationRemoting::DetermineProcessorEngine(configContext.Set()))
@@ -1601,7 +1614,11 @@ namespace AppInstaller::CLI::Workflow
16011614
auto cancellationScope = progressScope->Callback().SetCancellationFunction([&]() { findAction.Cancel(); });
16021615
for (auto unitProcessor : findAction.get())
16031616
{
1604-
result.emplace_back(std::move(unitProcessor));
1617+
IConfigurationUnitProcessorDetails3 processor3;
1618+
if (unitProcessor.try_as(processor3))
1619+
{
1620+
result.emplace_back(std::move(processor3));
1621+
}
16051622
}
16061623
}
16071624

@@ -1683,19 +1700,13 @@ namespace AppInstaller::CLI::Workflow
16831700
struct UnitProcessorTree
16841701
{
16851702
private:
1686-
struct SourceAndPackage
1687-
{
1688-
PackageCollection::Source Source;
1689-
PackageCollection::Package Package;
1690-
};
1691-
16921703
struct Node
16931704
{
16941705
// Packages whose installed location is at this node
1695-
std::vector<SourceAndPackage> Packages;
1706+
std::vector<PackageCollection::Package> Packages;
16961707

16971708
// Units whose location is at this node.
1698-
std::vector<IConfigurationUnitProcessorDetails> Units;
1709+
std::vector<IConfigurationUnitProcessorDetails3> Units;
16991710
};
17001711

17011712
Filesystem::PathTree<Node> m_pathTree;
@@ -1707,33 +1718,29 @@ namespace AppInstaller::CLI::Workflow
17071718
}
17081719

17091720
public:
1710-
UnitProcessorTree(std::vector<IConfigurationUnitProcessorDetails>&& unitProcessors)
1721+
UnitProcessorTree(std::vector<IConfigurationUnitProcessorDetails3>&& unitProcessors)
17111722
{
17121723
for (auto&& unit : unitProcessors)
17131724
{
1714-
IConfigurationUnitProcessorDetails3 unitProcessor3;
1715-
if (unit.try_as(unitProcessor3))
1716-
{
1717-
winrt::hstring unitPath = unitProcessor3.Path();
1718-
AICLI_LOG(Config, Verbose, << "Found unit `" << Utility::ConvertToUTF8(unit.UnitType()) << "` at: " << Utility::ConvertToUTF8(unitPath));
1719-
Node& node = FindNodeForFilePath(unitPath);
1720-
node.Units.emplace_back(std::move(unit));
1721-
}
1725+
winrt::hstring unitPath = unit.Path();
1726+
AICLI_LOG(Config, Verbose, << "Found unit `" << Utility::ConvertToUTF8(unit.UnitType()) << "` at: " << Utility::ConvertToUTF8(unitPath));
1727+
Node& node = FindNodeForFilePath(unitPath);
1728+
node.Units.emplace_back(std::move(unit));
17221729
}
17231730
}
17241731

1725-
void PlacePackage(const PackageCollection::Source& source, const PackageCollection::Package& package)
1732+
void PlacePackage(const PackageCollection::Package& package)
17261733
{
17271734
Node* node = m_pathTree.Find(package.InstalledLocation);
17281735
if (node)
17291736
{
1730-
node->Packages.emplace_back(SourceAndPackage{ source, package });
1737+
node->Packages.emplace_back(package);
17311738
}
17321739
}
17331740

1734-
std::vector<IConfigurationUnitProcessorDetails> GetResourcesForPackage(const PackageCollection::Package& package) const
1741+
std::vector<IConfigurationUnitProcessorDetails3> GetResourcesForPackage(const PackageCollection::Package& package) const
17351742
{
1736-
std::vector<IConfigurationUnitProcessorDetails> result;
1743+
std::vector<IConfigurationUnitProcessorDetails3> result;
17371744

17381745
m_pathTree.VisitIf(
17391746
package.InstalledLocation,
@@ -1760,10 +1767,10 @@ namespace AppInstaller::CLI::Workflow
17601767
std::wstring packageUnitType = GetWinGetPackageUnitType(configContext);
17611768

17621769
// This will be later used by per package settings export.
1763-
std::vector<IConfigurationUnitProcessorDetails> unitProcessors;
1770+
std::vector<IConfigurationUnitProcessorDetails3> unitProcessors;
17641771
try
17651772
{
1766-
unitProcessors = GetAllUnitProcessors(context);
1773+
unitProcessors = GetAllUnitProcessors3(context);
17671774
}
17681775
catch (...)
17691776
{
@@ -1776,11 +1783,13 @@ namespace AppInstaller::CLI::Workflow
17761783
// Filter out processors in exclusion list.
17771784
for (auto itr = unitProcessors.begin(); itr != unitProcessors.end(); /* itr incremented in the logic */)
17781785
{
1786+
std::wstring unitType{ itr->UnitType() };
17791787
bool processorRemoved = false;
17801788
for (const auto& exclusionItem : exclusionList)
17811789
{
1782-
if (Utility::CaseInsensitiveStartsWith(itr->UnitType(), exclusionItem))
1790+
if (Utility::CaseInsensitiveStartsWith(unitType, exclusionItem))
17831791
{
1792+
AICLI_LOG(Config, Verbose, << "Filtering excluded resource `" << Utility::ConvertToUTF8(itr->UnitType()) << "` from export");
17841793
itr = unitProcessors.erase(itr);
17851794
processorRemoved = true;
17861795
break;
@@ -1793,14 +1802,95 @@ namespace AppInstaller::CLI::Workflow
17931802
}
17941803
}
17951804

1805+
// Filter out DSC-shipped resources and any resources co-located with them.
1806+
// First pass: find the parent directory of each known DSC resource to identify the DSC
1807+
// installation location(s), handling both packaged and unpackaged (PATH-based) DSC installs.
1808+
// Second pass: remove any resource that either matches a known DSC prefix or resides in one
1809+
// of those locations, unless the resource type appears in DscShippedResourcesAllowList().
1810+
{
1811+
const auto dscPrefixes = DscShippedResourcePrefixes();
1812+
const auto dscAllowList = DscShippedResourcesAllowList();
1813+
1814+
std::set<std::filesystem::path> dscLocations;
1815+
for (const auto& processor : unitProcessors)
1816+
{
1817+
std::wstring unitType{ processor.UnitType() };
1818+
for (const auto& prefix : dscPrefixes)
1819+
{
1820+
if (Utility::CaseInsensitiveStartsWith(unitType, prefix))
1821+
{
1822+
std::filesystem::path location = std::filesystem::weakly_canonical(
1823+
std::filesystem::path{ std::wstring{ processor.Path() } }.parent_path());
1824+
dscLocations.emplace(std::move(location));
1825+
break;
1826+
}
1827+
}
1828+
}
1829+
1830+
for (auto itr = unitProcessors.begin(); itr != unitProcessors.end(); /* itr incremented in the logic */)
1831+
{
1832+
std::wstring unitType{ itr->UnitType() };
1833+
1834+
// Check the allow list first.
1835+
bool inAllowList = false;
1836+
for (const auto& allowedPrefix : dscAllowList)
1837+
{
1838+
if (Utility::CaseInsensitiveStartsWith(unitType, allowedPrefix))
1839+
{
1840+
inAllowList = true;
1841+
break;
1842+
}
1843+
}
1844+
1845+
if (inAllowList)
1846+
{
1847+
++itr;
1848+
continue;
1849+
}
1850+
1851+
// Check if the resource type is a known DSC-shipped prefix.
1852+
bool isDscResource = false;
1853+
for (const auto& prefix : dscPrefixes)
1854+
{
1855+
if (Utility::CaseInsensitiveStartsWith(unitType, prefix))
1856+
{
1857+
isDscResource = true;
1858+
break;
1859+
}
1860+
}
1861+
1862+
// If not matched by prefix, check whether it shares a location with a known DSC resource.
1863+
if (!isDscResource && !dscLocations.empty())
1864+
{
1865+
std::filesystem::path location = std::filesystem::weakly_canonical(
1866+
std::filesystem::path{ std::wstring{ itr->Path() } }.parent_path());
1867+
1868+
if (dscLocations.find(location) != dscLocations.end())
1869+
{
1870+
isDscResource = true;
1871+
}
1872+
}
1873+
1874+
if (isDscResource)
1875+
{
1876+
AICLI_LOG(Config, Verbose, << "Filtering DSC-shipped resource `" << Utility::ConvertToUTF8(itr->UnitType()) << "` from export");
1877+
itr = unitProcessors.erase(itr);
1878+
}
1879+
else
1880+
{
1881+
++itr;
1882+
}
1883+
}
1884+
}
1885+
17961886
// Build a tree of the unit processors and place packages onto it to indicate nearest ownership.
17971887
UnitProcessorTree unitProcessorTree{ std::move(unitProcessors) };
17981888

17991889
for (const auto& source : context.Get<Execution::Data::PackageCollection>().Sources)
18001890
{
18011891
for (const auto& package : source.Packages)
18021892
{
1803-
unitProcessorTree.PlacePackage(source, package);
1893+
unitProcessorTree.PlacePackage(package);
18041894
}
18051895
}
18061896

src/AppInstallerCLIE2ETests/ConfigureExportCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public void ExportAll()
178178
Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_AppInstallerTest.TestPackageExport"));
179179
Assert.True(showResult.StdOut.Contains("data: TestData"));
180180

181-
Assert.True(showResult.StdOut.Contains("AppInstallerTest/TestResource.SubDirectory"));
181+
Assert.True(showResult.StdOut.Contains("AppInstallerTest/TestResource_SubDirectory"));
182182
Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_AppInstallerTest.TestPackageExport"));
183183
Assert.True(showResult.StdOut.Contains("data: TestData"));
184184
}

src/AppInstallerTestExeInstaller/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ void GenerateDSCv3ProviderFiles(const path& installDirectory, const std::wstring
218218

219219
if (!subDirectory.empty())
220220
{
221-
DscResourceJsonContent += '.';
221+
DscResourceJsonContent += '_';
222222
DscResourceJsonContent += subDirectory;
223223
}
224224

0 commit comments

Comments
 (0)