commit 49c0ddbd9bccb579292ec0da723911ac2310e4a0
parent c82ca612537f6dcecd210985ebbc58eda81b6e54
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Mon, 20 Apr 2020 17:08:53 -0700
Trim individual multi-vals in manifest (#89)
Diffstat:
8 files changed, 125 insertions(+), 7 deletions(-)
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -358,6 +358,9 @@
<CopyFileToFolders Include="TestData\Manifest-Good-Switches.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
+ <CopyFileToFolders Include="TestData\Manifest-Good-Spaces.yaml">
+ <DeploymentContent>true</DeploymentContent>
+ </CopyFileToFolders>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppInstallerCLICore\AppInstallerCLICore.vcxproj">
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -255,5 +255,8 @@
<CopyFileToFolders Include="TestData\InstallerArgTest_Inno_NoSwitches.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
+ <CopyFileToFolders Include="TestData\Manifest-Good-Spaces.yaml">
+ <Filter>TestData</Filter>
+ </CopyFileToFolders>
</ItemGroup>
</Project>
\ No newline at end of file
diff --git a/src/AppInstallerCLITests/Strings.cpp b/src/AppInstallerCLITests/Strings.cpp
@@ -36,3 +36,17 @@ TEST_CASE("NormalizedString", "[strings]")
std::string_view input2 = u8"\xFB01";
REQUIRE(NormalizedString(input2) == u8"fi");
}
+
+TEST_CASE("Trim", "[strings]")
+{
+ std::string str;
+ REQUIRE(Trim(str.assign("")) == "");
+ REQUIRE(Trim(str.assign(" ")) == "");
+ REQUIRE(Trim(str.assign(" \t ")) == "");
+ REQUIRE(Trim(str.assign(" a")) == "a");
+ REQUIRE(Trim(str.assign("bght ")) == "bght");
+ REQUIRE(Trim(str.assign("\tStuff\f")) == "Stuff");
+ REQUIRE(Trim(str.assign("Multiple words")) == "Multiple words");
+ REQUIRE(Trim(str.assign(" Multiple words")) == "Multiple words");
+ REQUIRE(Trim(str.assign("Much after is taken \f\n\r\t\v\v\t\r\n\f ")) == "Much after is taken");
+}
diff --git a/src/AppInstallerCLITests/TestData/Manifest-Good-Spaces.yaml b/src/AppInstallerCLITests/TestData/Manifest-Good-Spaces.yaml
@@ -0,0 +1,53 @@
+Id: microsoft.msixsdk
+Name: " MSIX SDK"
+AppMoniker: "msixsdk"
+Version: 1.7.32
+Publisher: Microsoft
+Channel: release
+Author: Microsoft
+License: MIT License
+LicenseUrl: https://github.com/microsoft/msix-packaging/blob/master/LICENSE
+MinOSVersion: 0.0.0.0
+Description: The MSIX SDK project is an effort to enable developers
+Homepage: https://github.com/microsoft/msix-packaging
+Tags: "msix, appx"
+Commands: "makemsix ,makeappx"
+Protocols: "protocol1,protocol2"
+FileExtensions: "appx,appxbundle,msix,msixbundle"
+# InstallerType and Switches CAN have a "default" value
+# on the root. An installer can override them.
+InstallerType: Zip
+Switches:
+ Custom: /custom
+ SilentWithProgress: /silentwithprogress
+ Silent: /silence
+ Interactive: /interactive
+ Language: /en-us
+ Log: /log=<LOGPATH>
+ InstallLocation: /dir=<INSTALLPATH>
+Installers:
+ - Arch: x86
+ Url: https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx86.zip
+ Sha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82
+ Language: en-US
+ InstallerType: Zip
+ Scope: user
+ Switches:
+ Custom: /c
+ SilentWithProgress: /sp
+ Silent: /s
+ Interactive: /i
+ Language: /en
+ Log: /l=<LOGPATH>
+ InstallLocation: /d=<INSTALLPATH>
+ - Arch: x64
+ Url: https://rubengustorage.blob.core.windows.net/publiccontainer/msixsdkx64.zip
+ Sha256: 69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF0000
+ Language: en-US
+ InstallerType: Zip
+ Scope: user
+Localization:
+ - Language: es-MX
+ Description: El proyecto MSIX SDK es habilita desarrolladores de diferentes
+ Homepage: https://github.com/microsoft/msix-packaging/es-MX
+ LicenseUrl: https://github.com/microsoft/msix-packaging/blob/master/LICENSE-es-MX+
\ No newline at end of file
diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp
@@ -106,6 +106,22 @@ TEST_CASE("ReadGoodManifestAndVerifyContents", "[ManifestValidation]")
REQUIRE(localization1.LicenseUrl == "https://github.com/microsoft/msix-packaging/blob/master/LICENSE-es-MX");
}
+TEST_CASE("ReadGoodManifestWithSpaces", "[ManifestValidation]")
+{
+ Manifest manifest = Manifest::CreateFromPath(TestDataFile("Manifest-Good-Spaces.yaml"));
+
+ REQUIRE(manifest.Id == "microsoft.msixsdk");
+ REQUIRE(manifest.Name == "MSIX SDK");
+ REQUIRE(manifest.AppMoniker == "msixsdk");
+ REQUIRE(manifest.Version == "1.7.32");
+ REQUIRE(manifest.Channel == "release");
+ REQUIRE(manifest.MinOSVersion == "0.0.0.0");
+ REQUIRE(manifest.Tags == MultiValue{ "msix", "appx" });
+ REQUIRE(manifest.Commands == MultiValue{ "makemsix", "makeappx" });
+ REQUIRE(manifest.Protocols == MultiValue{ "protocol1", "protocol2" });
+ REQUIRE(manifest.FileExtensions == MultiValue{ "appx", "appxbundle", "msix", "msixbundle" });
+}
+
void TestManifest(const std::filesystem::path& manifestPath, const std::string& expectedError = {})
{
if (expectedError.empty())
diff --git a/src/AppInstallerCommonCore/AppInstallerStrings.cpp b/src/AppInstallerCommonCore/AppInstallerStrings.cpp
@@ -5,6 +5,13 @@
namespace AppInstaller::Utility
{
+ // Same as std::isspace(char)
+#define AICLI_SPACE_CHARS " \f\n\r\t\v"sv
+
+ using namespace std::string_view_literals;
+ constexpr std::string_view s_SpaceChars = AICLI_SPACE_CHARS;
+ constexpr std::wstring_view s_WideSpaceChars = L"" AICLI_SPACE_CHARS;
+
bool CaseInsensitiveEquals(std::string_view a, std::string_view b)
{
// TODO: When we bring in ICU, do this correctly.
@@ -118,7 +125,7 @@ namespace AppInstaller::Utility
}
std::wstring inputAsWStr(str.data());
- bool nonWhitespaceNotFound = inputAsWStr.find_last_not_of(L" \t\v\f") == std::wstring::npos;
+ bool nonWhitespaceNotFound = inputAsWStr.find_last_not_of(s_WideSpaceChars) == std::wstring::npos;
return nonWhitespaceNotFound;
}
@@ -136,6 +143,23 @@ namespace AppInstaller::Utility
return result;
}
+ std::string& Trim(std::string& str)
+ {
+ size_t begin = str.find_first_not_of(s_SpaceChars);
+ size_t end = str.find_last_not_of(s_SpaceChars);
+
+ if (begin == std::string_view::npos || end == std::string_view::npos)
+ {
+ str.clear();
+ }
+ else
+ {
+ str = str.substr(begin, (end - begin) + 1);
+ }
+
+ return str;
+ }
+
std::string ReadEntireStream(std::istream& stream)
{
std::streampos currentPos = stream.tellg();
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerStrings.h b/src/AppInstallerCommonCore/Public/AppInstallerStrings.h
@@ -86,6 +86,9 @@ namespace AppInstaller::Utility
// Returns a value indicating whether a replacement occurred.
bool FindAndReplace(std::string& inputStr, std::string_view token, std::string_view value);
+ // Removes whitespace from the beginning and end of the string.
+ std::string& Trim(std::string& str);
+
// Reads the entire stream into a string.
std::string ReadEntireStream(std::istream& stream);
}
diff --git a/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp b/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp
@@ -25,6 +25,7 @@ namespace AppInstaller::Manifest
}
std::string splitVal = input.substr(currentPos, splitPos - currentPos);
+ Utility::Trim(splitVal);
if (!splitVal.empty())
{
result.emplace_back(std::move(splitVal));
@@ -44,16 +45,16 @@ namespace AppInstaller::Manifest
const std::vector<ManifestFieldInfo> FieldInfos =
{
- { "Id", [this](const YAML::Node& value) { Id = value.as<std::string>(); }, true, "^[\\S]+\\.[\\S]+$" },
- { "Name", [this](const YAML::Node& value) { Name = value.as<std::string>(); }, true },
- { "Version", [this](const YAML::Node& value) { Version = value.as<std::string>(); }, true,
+ { "Id", [this](const YAML::Node& value) { Id = value.as<std::string>(); Utility::Trim(Id); }, true, "^[\\S]+\\.[\\S]+$" },
+ { "Name", [this](const YAML::Node& value) { Name = value.as<std::string>(); Utility::Trim(Name); }, true },
+ { "Version", [this](const YAML::Node& value) { Version = value.as<std::string>(); Utility::Trim(Version); }, true,
"^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){0,3}$" },
{ "Publisher", [this](const YAML::Node& value) { Publisher = value.as<std::string>(); }, true },
- { "AppMoniker", [this](const YAML::Node& value) { AppMoniker = value.as<std::string>(); } },
- { "Channel", [this](const YAML::Node& value) { Channel = value.as<std::string>(); } },
+ { "AppMoniker", [this](const YAML::Node& value) { AppMoniker = value.as<std::string>(); Utility::Trim(AppMoniker); } },
+ { "Channel", [this](const YAML::Node& value) { Channel = value.as<std::string>(); Utility::Trim(Channel); } },
{ "Author", [this](const YAML::Node& value) { Author = value.as<std::string>(); } },
{ "License", [this](const YAML::Node& value) { License = value.as<std::string>(); } },
- { "MinOSVersion", [this](const YAML::Node& value) { MinOSVersion = value.as<std::string>(); }, false,
+ { "MinOSVersion", [this](const YAML::Node& value) { MinOSVersion = value.as<std::string>(); Utility::Trim(MinOSVersion); }, false,
"^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){0,3}$" },
{ "Tags", [this](const YAML::Node& value) { Tags = SplitMultiValueField(value.as<std::string>()); } },
{ "Commands", [this](const YAML::Node& value) { Commands = SplitMultiValueField(value.as<std::string>()); } },