Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft.WinGet.DSC improvements (and breaking change) #4795

Merged
merged 14 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ namespace AppInstaller::CLI::Configuration
{
namespace
{
constexpr static std::string_view UnitType_WinGetSources = "WinGetSources"sv;
constexpr static std::string_view UnitType_WinGetSource = "WinGetSource"sv;
constexpr static std::string_view UnitType_WinGetPackage = "WinGetPackage"sv;

constexpr static std::string_view WellKnownSourceName_WinGet = "winget"sv;
constexpr static std::string_view WellKnownSourceName_MSStore = "msstore"sv;

constexpr static std::string_view ValueSetKey_TreatAsArray = "treatAsArray"sv;

constexpr static std::string_view WinGetSourcesValueSetKey_Sources = "sources"sv;
constexpr static std::string_view WinGetSourcesValueSetKey_SourceName = "name"sv;
constexpr static std::string_view WinGetSourcesValueSetKey_SourceType = "type"sv;
constexpr static std::string_view WinGetSourcesValueSetKey_SourceArg = "arg"sv;
constexpr static std::string_view WinGetSourceValueSetKey_Name = "name"sv;
constexpr static std::string_view WinGetSourceValueSetKey_Type = "type"sv;
constexpr static std::string_view WinGetSourceValueSetKey_Arg = "argument"sv;
constexpr static std::string_view WinGetSourceValueSetKey_Ensure = "ensure"sv;
constexpr static std::string_view WinGetSourceValueSetKey_Ensure_Present = "present"sv;

constexpr static std::string_view WinGetPackageValueSetKey_Id = "id"sv;
constexpr static std::string_view WinGetPackageValueSetKey_Version = "version"sv;
Expand All @@ -37,6 +38,7 @@ namespace AppInstaller::CLI::Configuration
std::string Name;
std::string Type;
std::string Arg;
bool Present = true;

bool Empty()
{
Expand Down Expand Up @@ -66,64 +68,30 @@ namespace AppInstaller::CLI::Configuration
return defaultIfFailed;
}

std::vector<WinGetSource> ParseWinGetSourcesFromSettings(const ValueSet& settings)
WinGetSource ParseWinGetSourceFromSettings(const ValueSet& settings)
{
WinGetSource result;

// Iterate through the value set as Powershell variables are case-insensitive.
std::vector<WinGetSource> result;
for (auto const& settingsPair : settings)
{
auto settingsKey = Utility::ConvertToUTF8(settingsPair.Key());
if (Utility::CaseInsensitiveEquals(WinGetSourcesValueSetKey_Sources, settingsKey))
{
auto sources = settingsPair.Value().try_as<ValueSet>();
if (!sources)
{
return {};
}
bool isArray = false;
for (auto const& sourcesPair : sources)
{
if (Utility::CaseInsensitiveEquals(ValueSetKey_TreatAsArray, Utility::ConvertToUTF8(sourcesPair.Key())))
{
isArray = true;
}
else
{
auto source = sourcesPair.Value().try_as<ValueSet>();
if (source)
{
WinGetSource wingetSource;
for (auto const& sourcePair : source)
{
auto sourceKey = Utility::ConvertToUTF8(sourcePair.Key());
if (Utility::CaseInsensitiveEquals(WinGetSourcesValueSetKey_SourceName, sourceKey))
{
wingetSource.Name = GetPropertyValueAsString(sourcePair.Value());
}
else if (Utility::CaseInsensitiveEquals(WinGetSourcesValueSetKey_SourceType, sourceKey))
{
wingetSource.Type = GetPropertyValueAsString(sourcePair.Value());
}
else if (Utility::CaseInsensitiveEquals(WinGetSourcesValueSetKey_SourceArg, sourceKey))
{
wingetSource.Arg = GetPropertyValueAsString(sourcePair.Value());
}
}

if (!wingetSource.Empty())
{
result.emplace_back(std::move(wingetSource));
}
}
}
}

if (!isArray)
{
return {};
}

break;
if (Utility::CaseInsensitiveEquals(WinGetSourceValueSetKey_Name, settingsKey))
{
result.Name = GetPropertyValueAsString(settingsPair.Value());
}
else if (Utility::CaseInsensitiveEquals(WinGetSourceValueSetKey_Type, settingsKey))
{
result.Type = GetPropertyValueAsString(settingsPair.Value());
}
else if (Utility::CaseInsensitiveEquals(WinGetSourceValueSetKey_Arg, settingsKey))
{
result.Arg = GetPropertyValueAsString(settingsPair.Value());
}
else if (Utility::CaseInsensitiveEquals(WinGetSourceValueSetKey_Ensure, settingsKey))
{
result.Present = Utility::CaseInsensitiveEquals(WinGetSourceValueSetKey_Ensure_Present, GetPropertyValueAsString(settingsPair.Value()));
}
}

Expand Down Expand Up @@ -206,56 +174,48 @@ namespace AppInstaller::CLI::Configuration
auto unitType = Utility::ConvertToUTF8(details.UnitType());
auto unitIntent = unit.Intent();

if (Utility::CaseInsensitiveEquals(UnitType_WinGetSources, unitType))
if (Utility::CaseInsensitiveEquals(UnitType_WinGetSource, unitType))
{
auto sources = ParseWinGetSourcesFromSettings(unit.Settings());
if (sources.size() == 0)
{
AICLI_LOG(Config, Warning, << "Failed to parse WinGetSources or empty content.");
context.Reporter.Warn() << Resource::String::WinGetResourceUnitEmptyContent(Utility::LocIndView{ UnitType_WinGetSources }) << std::endl;
foundIssues = true;
}
for (auto const& source : sources)
{
// Validate basic semantics.
if (source.Name.empty())
{
AICLI_LOG(Config, Error, << "WinGetSource unit missing required arg: Name");
context.Reporter.Error() << Resource::String::WinGetResourceUnitMissingRequiredArg(Utility::LocIndView{ UnitType_WinGetSources }, "Name"_liv) << std::endl;
foundIssues = true;
}
if (source.Arg.empty())
{
AICLI_LOG(Config, Error, << "WinGetSource unit missing required arg: Arg");
context.Reporter.Error() << Resource::String::WinGetResourceUnitMissingRequiredArg(Utility::LocIndView{ UnitType_WinGetSources }, "Arg"_liv) << std::endl;
foundIssues = true;
}
auto source = ParseWinGetSourceFromSettings(unit.Settings());

// Validate well known source or process 3rd party source.
if (IsWellKnownSourceName(source.Name))
{
if (!ValidateWellKnownSource(source))
{
AICLI_LOG(Config, Warning, << "WinGetSource conflicts with a well known source. Source: " << source.Name);
context.Reporter.Warn() << Resource::String::WinGetResourceUnitKnownSourceConfliction(Utility::LocIndView{ source.Name }) << std::endl;
foundIssues = true;
}
}
else
{
if (unitIntent == ConfigurationUnitIntent::Assert)
{
AICLI_LOG(Config, Warning, << "Asserting on 3rd party source: " << source.Name);
context.Reporter.Warn() << Resource::String::WinGetResourceUnitThirdPartySourceAssertion(Utility::LocIndView{ source.Name }) << std::endl;
foundIssues = true;
}
else if (unitIntent == ConfigurationUnitIntent::Apply)
{
// Add to dependency source map so it can be validated with later WinGetPackage source
m_dependenciesSourceAndUnitIdMap.emplace(Utility::FoldCase(std::string_view{ source.Name }), Utility::FoldCase(Utility::NormalizedString{ unit.Identifier() }));
}
}
}
// Validate basic semantics.
if (source.Name.empty())
{
AICLI_LOG(Config, Error, << "WinGetSource unit missing required arg: Name");
context.Reporter.Error() << Resource::String::WinGetResourceUnitMissingRequiredArg(Utility::LocIndView{ UnitType_WinGetSource }, "Name"_liv) << std::endl;
foundIssues = true;
}
if (source.Arg.empty() && source.Present)
{
AICLI_LOG(Config, Error, << "WinGetSource unit missing required arg: Argument");
context.Reporter.Error() << Resource::String::WinGetResourceUnitMissingRequiredArg(Utility::LocIndView{ UnitType_WinGetSource }, "Argument"_liv) << std::endl;
foundIssues = true;
}

// Validate well known source or process 3rd party source.
if (IsWellKnownSourceName(source.Name))
{
if (!ValidateWellKnownSource(source))
{
AICLI_LOG(Config, Warning, << "WinGetSource conflicts with a well known source. Source: " << source.Name);
context.Reporter.Warn() << Resource::String::WinGetResourceUnitKnownSourceConfliction(Utility::LocIndView{ source.Name }) << std::endl;
foundIssues = true;
}
}
else
{
if (unitIntent == ConfigurationUnitIntent::Assert)
{
AICLI_LOG(Config, Warning, << "Asserting on 3rd party source: " << source.Name);
context.Reporter.Warn() << Resource::String::WinGetResourceUnitThirdPartySourceAssertion(Utility::LocIndView{ source.Name }) << std::endl;
foundIssues = true;
}
else if (unitIntent == ConfigurationUnitIntent::Apply)
{
// Add to dependency source map so it can be validated with later WinGetPackage source
m_dependenciesSourceAndUnitIdMap.emplace(Utility::FoldCase(std::string_view{ source.Name }), Utility::FoldCase(Utility::NormalizedString{ unit.Identifier() }));
}
}
}
else if (Utility::CaseInsensitiveEquals(UnitType_WinGetPackage, unitType))
{
Expand All @@ -281,8 +241,8 @@ namespace AppInstaller::CLI::Configuration
}
if (package.UseLatest && !package.Version.empty())
{
AICLI_LOG(Config, Error, << "WinGetPackage unit both UseLatest and Version declared. Package: " << package.Id);
context.Reporter.Error() << Resource::String::WinGetResourceUnitBothPackageVersionAndUseLatest(Utility::LocIndView{ package.Id }) << std::endl;
AICLI_LOG(Config, Warning, << "WinGetPackage unit both UseLatest and Version declared. Package: " << package.Id);
context.Reporter.Warn() << Resource::String::WinGetResourceUnitBothPackageVersionAndUseLatest(Utility::LocIndView{ package.Id }) << std::endl;
foundIssues = true;
}
// Validate dependency source is configured.
Expand Down Expand Up @@ -395,4 +355,4 @@ namespace AppInstaller::CLI::Configuration

return !foundIssues;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSource
Arg: "https://localhost:5001/TestKit"
Name: TestSource
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -21,4 +20,3 @@ properties:
id: AppInstallerTest.TestExeInstaller
source: TestSource
version: "1.0.1.0"

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSource
Arg: "https://localhost:5001/TestKit"
Name: TestSource
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -21,4 +20,3 @@ properties:
id: AppInstallerTest.DoesNotExist
source: TestSource
version: "1.0.1.0"

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSource
Arg: "https://localhost:5001/TestKit"
Name: TestSource
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -21,4 +20,3 @@ properties:
id: AppInstallerTest.TestExeInstaller
source: TestSource
version: "101.0.101.0"

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSourceV2
Arg: "https://localhost:5001/TestKit"
Name: TestSourceV2
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -21,4 +20,3 @@ properties:
id: AppInstallerTest.TestExeInstaller
source: TestSourceV2
version: "1.0.1.0"

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSource
Arg: "https://localhost:5001/TestKit"
Name: TestSource
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -21,4 +20,3 @@ properties:
id: AppInstallerTest.TestValidManifest
source: TestSource
version: "1.0.0.0"

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
properties:
configurationVersion: 0.2.0
resources:
- resource: Microsoft.WinGet.DSC/WinGetSources
- resource: Microsoft.WinGet.DSC/WinGetSource
id: configureSource
directives:
description: Add test source
allowPrerelease: true
settings:
Sources:
- Name: TestSource
Arg: "https://localhost:5001/TestKit"
Name: TestSource
Argument: "https://localhost:5001/TestKit"
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: testPackage
dependsOn:
Expand All @@ -22,4 +21,3 @@ properties:
source: TestSource
version: "1.0.1.0"
useLatest: true

Loading
Loading