Skip to content

Commit

Permalink
platform filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
yao-msft committed May 3, 2024
1 parent c675339 commit 6c5f61a
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 44 deletions.
4 changes: 4 additions & 0 deletions src/AppInstallerCLICore/Argument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ namespace AppInstaller::CLI
// Download command
case Execution::Args::Type::DownloadDirectory:
return { type, "download-directory"_liv, 'd', ArgTypeCategory::None };
case Execution::Args::Type::Platform:
return { type, "platform"_liv, ArgTypeCategory::None };
case Execution::Args::Type::SkipMicrosoftStorePackageLicense:
return { type, "skip-microsoft-store-package-license"_liv, "skip-license"_liv, ArgTypeCategory::None };

Expand Down Expand Up @@ -396,6 +398,8 @@ namespace AppInstaller::CLI
return Argument{ type, Resource::String::DownloadDirectoryArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, false };
case Args::Type::SkipMicrosoftStorePackageLicense:
return Argument{ type, Resource::String::SkipMicrosoftStorePackageLicenseArgumentDescription, ArgumentType::Flag, Argument::Visibility::Help, false };
case Args::Type::Platform:
return Argument{ type, Resource::String::PlatformArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, false };
case Args::Type::InstallerType:
return Argument{ type, Resource::String::InstallerTypeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help, false };
case Args::Type::ResumeId:
Expand Down
20 changes: 17 additions & 3 deletions src/AppInstallerCLICore/Commands/DownloadCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#include "Workflows/InstallFlow.h"
#include "Workflows/PromptFlow.h"
#include "Resources.h"
#include <AppInstallerRuntime.h>
#include <AppInstallerRuntime.h>
#include <winget/ManifestCommon.h>

namespace AppInstaller::CLI
{
Expand Down Expand Up @@ -38,7 +39,8 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::AuthenticationAccount),
Argument::ForType(Args::Type::AcceptPackageAgreements),
Argument::ForType(Args::Type::AcceptSourceAgreements),
Argument::ForType(Args::Type::SkipMicrosoftStorePackageLicense),
Argument::ForType(Args::Type::SkipMicrosoftStorePackageLicense),
Argument::ForType(Args::Type::Platform),
};
}

Expand All @@ -59,7 +61,19 @@ namespace AppInstaller::CLI

void DownloadCommand::ValidateArgumentsInternal(Args& execArgs) const
{
Argument::ValidateCommonArguments(execArgs);
Argument::ValidateCommonArguments(execArgs);

if (execArgs.Contains(Execution::Args::Type::Platform))
{
Manifest::PlatformEnum selectedPlatform = Manifest::ConvertToPlatformEnumForMSStoreDownload(std::string(execArgs.GetArg(Execution::Args::Type::Platform)));
if (selectedPlatform == Manifest::PlatformEnum::Unknown)
{
auto validOptions = Utility::Join(", "_liv, std::vector<Utility::LocIndString>{
"Windows.Universal"_lis, "Windows.Desktop"_lis, "Windows.IoT"_lis, "Windows.Team"_lis, "Windows.Holographic"_lis
});
throw CommandException(Resource::String::InvalidArgumentValueError(Argument::ForType(Execution::Args::Type::Platform).Name(), validOptions));
}
}
}

void DownloadCommand::ExecuteInternal(Context& context) const
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/ExecutionArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace AppInstaller::CLI::Execution
// Download Command
DownloadDirectory,
SkipMicrosoftStorePackageLicense,
Platform,

// Setting Command
AdminSettingEnable,
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(PinResetUseForceArg);
WINGET_DEFINE_RESOURCE_STRINGID(PinType);
WINGET_DEFINE_RESOURCE_STRINGID(PinVersion);
WINGET_DEFINE_RESOURCE_STRINGID(PlatformArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(PoliciesPolicy);
WINGET_DEFINE_RESOURCE_STRINGID(PortableAliasAdded);
WINGET_DEFINE_RESOURCE_STRINGID(PortableHashMismatchOverridden);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,17 +280,22 @@ namespace AppInstaller::CLI::Workflow
const auto& installer = context.Get<Execution::Data::Installer>().value();

Utility::Architecture requiredArchitecture = Utility::Architecture::Unknown;
Manifest::PlatformEnum requiredPlatform = Manifest::PlatformEnum::Unknown;
std::string requiredLocale;
if (context.Args.Contains(Execution::Args::Type::InstallArchitecture))
{
requiredArchitecture = Utility::ConvertToArchitectureEnum(context.Args.GetArg(Execution::Args::Type::InstallArchitecture));
}
if (context.Args.Contains(Execution::Args::Type::Platform))
{
requiredPlatform = Manifest::ConvertToPlatformEnumForMSStoreDownload(context.Args.GetArg(Execution::Args::Type::Platform));
}
if (context.Args.Contains(Execution::Args::Type::Locale))
{
requiredLocale = context.Args.GetArg(Execution::Args::Type::Locale);
}

MSStoreDownloadContext downloadContext{ installer.ProductId, requiredArchitecture, requiredLocale, GetAuthenticationArguments(context) };
MSStoreDownloadContext downloadContext{ installer.ProductId, requiredArchitecture, requiredPlatform, requiredLocale, GetAuthenticationArguments(context) };

MSStoreDownloadInfo downloadInfo;
try
Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2950,4 +2950,7 @@ Please specify one of them using the --source option to proceed.</value>
<data name="SkipMicrosoftStorePackageLicenseArgumentDescription" xml:space="preserve">
<value>Skips retrieving Microsoft Store package offline license. Retrieving Microsoft Store package license requires administrator account in a Microsoft Entra Id tenant</value>
</data>
<data name="PlatformArgumentDescription" xml:space="preserve">
<value>Select the target platform</value>
</data>
</root>
70 changes: 39 additions & 31 deletions src/AppInstallerCommonCore/MSStoreDownload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,24 +588,33 @@ namespace AppInstaller::MSStore
#ifndef WINGET_DISABLE_FOR_FUZZING
namespace SfsClientDetails
{
enum class TargetPlatform
{
Universal,
Desktop,
IoT,
Analog,
Ppi,
};

const std::string SupportedFileTypes[] = { ".msix", ".msixbundle", ".appx", ".appxbundle" };
const std::vector<std::pair<std::string, TargetPlatform>> SupportedPlatforms =

Manifest::PlatformEnum ConvertFromSfsPlatform(std::string_view applicability)
{
{ "Universal", TargetPlatform::Universal },
{ "Desktop", TargetPlatform::Desktop },
{ "IoT", TargetPlatform::IoT },
{ "Analog", TargetPlatform::Analog },
{ "Ppi", TargetPlatform::Ppi },
};
if (Utility::CaseInsensitiveStartsWith(applicability, "universal"))
{
return Manifest::PlatformEnum::Universal;
}
else if (Utility::CaseInsensitiveStartsWith(applicability, "desktop"))
{
return Manifest::PlatformEnum::Desktop;
}
else if (Utility::CaseInsensitiveStartsWith(applicability, "iot"))

Check failure on line 603 in src/AppInstallerCommonCore/MSStoreDownload.cpp

View workflow job for this annotation

GitHub Actions / Check Spelling

`iot` is not a recognized word. (unrecognized-spelling)
{
return Manifest::PlatformEnum::IoT;
}
else if (Utility::CaseInsensitiveStartsWith(applicability, "analog"))
{
return Manifest::PlatformEnum::Holographic;
}
else if (Utility::CaseInsensitiveStartsWith(applicability, "ppi"))
{
return Manifest::PlatformEnum::Team;
}

return Manifest::PlatformEnum::Unknown;
}

Utility::Architecture ConvertFromSfsArchitecture(SFS::Architecture sfsArchitecture)
{
Expand All @@ -626,26 +635,24 @@ namespace AppInstaller::MSStore
return Utility::Architecture::Unknown;
}

std::vector<TargetPlatform> GetSfsPackageFileSupportedPlatforms(const SFS::AppFile& appFile)
std::vector<Manifest::PlatformEnum> GetSfsPackageFileSupportedPlatforms(const SFS::AppFile& appFile, Manifest::PlatformEnum requiredPlatform)
{
std::vector<TargetPlatform> supportedPlatforms;
std::vector<Manifest::PlatformEnum> supportedPlatforms;

for (auto const& applicability : appFile.GetApplicabilityDetails().GetPlatformApplicabilityForPackage())
{
for (auto const& platformPair : SupportedPlatforms)
auto platform = ConvertFromSfsPlatform(applicability);
if (platform != Manifest::PlatformEnum::Unknown &&
(platform == requiredPlatform || requiredPlatform == Manifest::PlatformEnum::Unknown))
{
if (Utility::CaseInsensitiveStartsWith(applicability, platformPair.first))
{
supportedPlatforms.emplace_back(platformPair.second);
break;
}
supportedPlatforms.emplace_back(platform);
}
}

return supportedPlatforms;
}

std::vector<Utility::Architecture> GetSfsPackageFileSupportedArchitectures(const SFS::AppFile& appFile, Utility::Architecture architecture)
std::vector<Utility::Architecture> GetSfsPackageFileSupportedArchitectures(const SFS::AppFile& appFile, Utility::Architecture requiredArchitecture)
{
std::vector<Utility::Architecture> supportedArchitectures;

Expand All @@ -657,8 +664,8 @@ namespace AppInstaller::MSStore
continue;
}

if (architecture == Utility::Architecture::Unknown || // No required architecture
convertedArchitecture == architecture)
if (requiredArchitecture == Utility::Architecture::Unknown || // No required architecture
convertedArchitecture == requiredArchitecture)
{
supportedArchitectures.emplace_back(convertedArchitecture);
}
Expand Down Expand Up @@ -740,9 +747,10 @@ namespace AppInstaller::MSStore

std::vector<MSStoreDownloadFile> PopulateSfsAppFileToMSStoreDownloadFileVector(
const std::vector<SFS::AppFile>& appFiles,
Utility::Architecture architecture = Utility::Architecture::Unknown)
Utility::Architecture requiredArchitecture = Utility::Architecture::Unknown,
Manifest::PlatformEnum requiredPlatform = Manifest::PlatformEnum::Unknown)
{
using PlatformAndArchitectureKey = std::pair<TargetPlatform, Utility::Architecture>;
using PlatformAndArchitectureKey = std::pair<Manifest::PlatformEnum, Utility::Architecture>;

// Since the server may return multiple versions of the same package, we'll use ths map to record the one with latest version
// for each Platform|Architecture pair.
Expand All @@ -751,13 +759,13 @@ namespace AppInstaller::MSStore
for (auto const& appFile : appFiles)
{
// Filter out unsupported packages
auto supportedPlatforms = GetSfsPackageFileSupportedPlatforms(appFile);
auto supportedPlatforms = GetSfsPackageFileSupportedPlatforms(appFile, requiredPlatform);
if (supportedPlatforms.empty())
{
AICLI_LOG(Core, Info, << "Package skipped due to unsupported platforms. FileId:" << appFile.GetFileId());
continue;
}
auto supportedArchitectures = GetSfsPackageFileSupportedArchitectures(appFile, architecture);
auto supportedArchitectures = GetSfsPackageFileSupportedArchitectures(appFile, requiredArchitecture);
if (supportedArchitectures.empty())
{
AICLI_LOG(Core, Info, << "Package skipped due to unsupported architecture. FileId:" << appFile.GetFileId());
Expand Down
42 changes: 35 additions & 7 deletions src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,48 @@ namespace AppInstaller::Manifest
return result;
}

PlatformEnum ConvertToPlatformEnum(const std::string& in)
PlatformEnum ConvertToPlatformEnum(std::string_view in)
{
PlatformEnum result = PlatformEnum::Unknown;
std::string inStrLower = Utility::ToLower(in);

if (Utility::CaseInsensitiveEquals(in, "windows.desktop"))
if (inStrLower == "windows.desktop")
{
result = PlatformEnum::Desktop;
return PlatformEnum::Desktop;
}
else if (Utility::CaseInsensitiveEquals(in, "windows.universal"))
else if (inStrLower == "windows.universal")
{
result = PlatformEnum::Universal;
return PlatformEnum::Universal;
}

return result;
return PlatformEnum::Unknown;
}

PlatformEnum ConvertToPlatformEnumForMSStoreDownload(std::string_view in)
{
std::string inStrLower = Utility::ToLower(in);

if (inStrLower == "windows.desktop")
{
return PlatformEnum::Desktop;
}
else if (inStrLower == "windows.universal")
{
return PlatformEnum::Universal;
}
else if (inStrLower == "windows.iot")
{
return PlatformEnum::IoT;
}
else if (inStrLower == "windows.team")
{
return PlatformEnum::Team;
}
else if (inStrLower == "windows.holographic")
{
return PlatformEnum::Holographic;
}

return PlatformEnum::Unknown;
}

ElevationRequirementEnum ConvertToElevationRequirementEnum(const std::string& in)
Expand Down
8 changes: 7 additions & 1 deletion src/AppInstallerCommonCore/Public/winget/MSStoreDownload.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <AppInstallerArchitecture.h>
#include <AppInstallerVersions.h>
#include "winget/Authentication.h"
#include "winget/ManifestCommon.h"

#include <string>
#include <optional>
Expand All @@ -30,7 +31,12 @@ namespace AppInstaller::MSStore

struct MSStoreDownloadContext
{
MSStoreDownloadContext(std::string productId, AppInstaller::Utility::Architecture architecture, std::string locale, AppInstaller::Authentication::AuthenticationArguments authArgs);
MSStoreDownloadContext(
std::string productId,
AppInstaller::Utility::Architecture architecture,
AppInstaller::Manifest::PlatformEnum platform,
std::string locale,
AppInstaller::Authentication::AuthenticationArguments authArgs);

// Calls display catalog API and sfs-client to get download info.
MSStoreDownloadInfo GetDownloadInfo();
Expand Down
7 changes: 6 additions & 1 deletion src/AppInstallerCommonCore/Public/winget/ManifestCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ namespace AppInstaller::Manifest
Unknown,
Universal,
Desktop,
IoT,
Team,
Holographic,
};

enum class ElevationRequirementEnum
Expand Down Expand Up @@ -365,6 +368,8 @@ namespace AppInstaller::Manifest

PlatformEnum ConvertToPlatformEnum(const std::string& in);

PlatformEnum ConvertToPlatformEnumForMSStoreDownload(std::string_view in);

ElevationRequirementEnum ConvertToElevationRequirementEnum(const std::string& in);

UnsupportedArgumentEnum ConvertToUnsupportedArgumentEnum(const std::string& in);
Expand Down Expand Up @@ -451,4 +456,4 @@ namespace AppInstaller::Manifest

// Get a list of default return codes for known installer types
std::map<DWORD, ExpectedReturnCodeEnum> GetDefaultKnownReturnCodes(InstallerTypeEnum installerType);
}
}

1 comment on commit 6c5f61a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@check-spelling-bot Report

🔴 Please review

See the 📜action log for details.

Unrecognized words (8)

deduping
IENT
iot
overrided
RESTAPI
SFSCl
sfsclient
storeapps

Previously acknowledged words that are now absent ata bitspace EPester epth hrow issuetitle mapview Mta oop PFM STARTUPINFOW testdata visualstudiocode :arrow_right:
To accept ✔️ these unrecognized words as correct and remove the previously acknowledged and now absent words, run the following commands

... in a clone of the git@github.com:yao-msft/winget-cli.git repository
on the msstoredownload branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.21/apply.pl' |
perl - 'https://github.com/yao-msft/winget-cli/actions/runs/8933111271/attempts/1'
Available 📚 dictionaries could cover words not in the 📘 dictionary

This includes both expected items (541) from .github/actions/spelling/expect.txt and unrecognized words (8)

Dictionary Entries Covers
cspell:win32/src/win32.txt 53509 20
cspell:python/src/python/python-lib.txt 3873 4
cspell:python/src/python/python.txt 453 2
cspell:python/src/common/extra.txt 741 2
cspell:php/php.txt 2597 2
cspell:npm/npm.txt 288 2
cspell:django/django.txt 859 2
cspell:csharp/csharp.txt 19 2
cspell:sql/src/tsql.txt 455 1
cspell:scala/scala.txt 833 1

Consider adding them using (in .github/workflows/spelling3.yml):

      with:
        extra_dictionaries:
          cspell:win32/src/win32.txt
          cspell:python/src/python/python-lib.txt
          cspell:python/src/python/python.txt
          cspell:python/src/common/extra.txt
          cspell:php/php.txt
          cspell:npm/npm.txt
          cspell:django/django.txt
          cspell:csharp/csharp.txt
          cspell:sql/src/tsql.txt
          cspell:scala/scala.txt

To stop checking additional dictionaries, add:

      with:
        check_extra_dictionaries: ''
Warnings (1)

See the 📜action log for details.

ℹ️ Warnings Count
ℹ️ unexpected-line-ending 1

See ℹ️ Event descriptions for more information.

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.