diff --git a/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj b/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj
index 8a0520f5e1..45b393129c 100644
--- a/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj
+++ b/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj
@@ -43,6 +43,9 @@
False
+
+ False
+
@@ -55,5 +58,6 @@
+
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeSubmissionMismatch.json b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeSubmissionMismatch.json
new file mode 100644
index 0000000000..e9aa1b3dbe
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeSubmissionMismatch.json
@@ -0,0 +1,45 @@
+{
+ "version": "1.0",
+ "metadatas": [
+ {
+ "version": "1.0",
+ "productVersionMin": "1.0",
+ "productVersionMax": "1.0",
+ "metadata": [
+ {
+ "installerHash": "ABCD",
+ "submissionIdentifier": "1",
+ "AppsAndFeaturesEntries": [
+ {
+ "DisplayName": "Name",
+ "Publisher": "Publisher",
+ "DisplayVersion": "1.0",
+ "ProductCode": "{46210E3D-EBB3-43D4-B9BB-48A7DB0F9B93}",
+ "InstallerType": 3
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "1.0",
+ "productVersionMin": "1.0",
+ "productVersionMax": "1.0",
+ "metadata": [
+ {
+ "installerHash": "EFGH",
+ "submissionIdentifier": "2",
+ "AppsAndFeaturesEntries": [
+ {
+ "DisplayName": "Name",
+ "Publisher": "Publisher",
+ "DisplayVersion": "1.0",
+ "ProductCode": "{46210E3D-EBB3-43D4-B9BB-48A7DB0F9B93}",
+ "InstallerType": 3
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeValid.json b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeValid.json
new file mode 100644
index 0000000000..100df54b38
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/MergeValid.json
@@ -0,0 +1,45 @@
+{
+ "version": "1.0",
+ "metadatas": [
+ {
+ "version": "1.0",
+ "productVersionMin": "1.0",
+ "productVersionMax": "1.0",
+ "metadata": [
+ {
+ "installerHash": "ABCD",
+ "submissionIdentifier": "1",
+ "AppsAndFeaturesEntries": [
+ {
+ "DisplayName": "Name",
+ "Publisher": "Publisher",
+ "DisplayVersion": "1.0",
+ "ProductCode": "{46210E3D-EBB3-43D4-B9BB-48A7DB0F9B93}",
+ "InstallerType": 3
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "version": "1.0",
+ "productVersionMin": "1.0",
+ "productVersionMax": "1.0",
+ "metadata": [
+ {
+ "installerHash": "EFGH",
+ "submissionIdentifier": "1",
+ "AppsAndFeaturesEntries": [
+ {
+ "DisplayName": "Name",
+ "Publisher": "Publisher",
+ "DisplayVersion": "1.0",
+ "ProductCode": "{46210E3D-EBB3-43D4-B9BB-48A7DB0F9B93}",
+ "InstallerType": 3
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/Minimal.json b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/Minimal.json
new file mode 100644
index 0000000000..514d164a23
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/InstallerMetadata/Minimal.json
@@ -0,0 +1,15 @@
+{
+ "version": "1.0",
+ "supportedMetadataVersion": "1.0",
+ "submissionData": {
+ "submissionIdentifier": "1"
+ },
+ "packageData": {
+ "installerHash": "ABCD",
+ "DefaultLocale": {
+ "PackageLocale": "en-us",
+ "PackageName": "Name",
+ "Publisher": "Publisher"
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Add.yaml b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Add.yaml
new file mode 100644
index 0000000000..e9fcd7d8fb
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Add.yaml
@@ -0,0 +1,16 @@
+Installers:
+- Architecture: x86
+ InstallerSha256: 0000000000000000000000000000000000000000000000000000000000000000
+ InstallerType: exe
+ InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe
+License: Test
+ManifestType: merged
+ManifestVersion: 1.1.0
+MinimumOSVersion: 10.0.0.0
+PackageIdentifier: AppInstallerTest.WinGetUtilTest
+PackageLocale: en-US
+PackageName: AppInstallerTest
+PackageVersion: 1.0.0.0
+Publisher: AppInstallerTest
+Tags:
+- add
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Update.yaml b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Update.yaml
new file mode 100644
index 0000000000..6c2307d4b0
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Merged/WinGetUtilTest.Update.yaml
@@ -0,0 +1,16 @@
+Installers:
+- Architecture: x86
+ InstallerSha256: 0000000000000000000000000000000000000000000000000000000000000000
+ InstallerType: exe
+ InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe
+License: Test
+ManifestType: merged
+ManifestVersion: 1.1.0
+MinimumOSVersion: 10.0.0.0
+PackageIdentifier: AppInstallerTest.WinGetUtilTest
+PackageLocale: en-US
+PackageName: AppInstallerTest
+PackageVersion: 1.0.0.0
+Publisher: AppInstallerTest
+Tags:
+- update
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.installer.yaml b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.installer.yaml
new file mode 100644
index 0000000000..00a170f956
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.installer.yaml
@@ -0,0 +1,10 @@
+PackageIdentifier: AppInstallerTest.WinGetUtilTest
+PackageVersion: "1.0.0.0"
+MinimumOSVersion: 10.0.0.0
+Installers:
+ - Architecture: x86
+ InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe
+ InstallerType: nullsoft
+ InstallerSha256: 0000000000000000000000000000000000000000000000000000000000000000
+ManifestType: installer
+ManifestVersion: 1.1.0
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.locale.en-US.yaml b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.locale.en-US.yaml
new file mode 100644
index 0000000000..c18ef5894d
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.locale.en-US.yaml
@@ -0,0 +1,9 @@
+PackageIdentifier: AppInstallerTest.WinGetUtilTest
+PackageVersion: "1.0.0.0"
+PackageLocale: en-US
+Publisher: AppInstallerTest
+License: Test
+PackageName: AppInstallerTest
+ShortDescription: WinGetUtilTest
+ManifestType: defaultLocale
+ManifestVersion: 1.1.0
diff --git a/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.yaml b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.yaml
new file mode 100644
index 0000000000..c08fc757ae
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/TestData/WinGetUtil/Manifests/Unmerged/ValidateManifest/WinGetUtilTest.yaml
@@ -0,0 +1,5 @@
+PackageIdentifier: AppInstallerTest.WinGetUtilTest
+PackageVersion: "1.0.0.0"
+DefaultLocale: en-US
+ManifestType: version
+ManifestVersion: 1.1.0
diff --git a/src/AppInstallerCLIE2ETests/TestIndexSetup.cs b/src/AppInstallerCLIE2ETests/TestIndexSetup.cs
index 3964953125..db53f5fc95 100644
--- a/src/AppInstallerCLIE2ETests/TestIndexSetup.cs
+++ b/src/AppInstallerCLIE2ETests/TestIndexSetup.cs
@@ -71,7 +71,7 @@ private static void SetupSourcePackage()
}
// Generate Index.db file using IndexCreationTool.exe
- RunCommand(Path.Combine(indexCreationToolPath, "IndexCreationTool.exe"), $"-d {TestCommon.StaticFileRootPath}", indexDestPath);
+ RunCommand(Path.Combine(indexCreationToolPath, "IndexCreationTool.exe"), $"-d {TestCommon.StaticFileRootPath} -i {ManifestsName}", indexDestPath);
string packageDir = Path.Combine(TestCommon.StaticFileRootPath, PackageName);
string indexPackageDestPath = Path.Combine(TestCommon.StaticFileRootPath, Constants.IndexPackage);
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilCompareVersions.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilCompareVersions.cs
new file mode 100644
index 0000000000..84abc1825b
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilCompareVersions.cs
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using NUnit.Framework;
+
+ public class WinGetUtilCompareVersions
+ {
+ [Test]
+ // V1 = V2
+ [TestCase("1.0.0.0", "1.0.0.0", 0)]
+ [TestCase("1.0.0", "1.0.0.0", 0)]
+ [TestCase("1.0", "1.0.0.0", 0)]
+ [TestCase("1", "1.0.0.0", 0)]
+ // V1 > V2
+ [TestCase("1.0.0.1", "1.0.0.0", 1)]
+ [TestCase("1.0.1.0", "1.0.0.0", 1)]
+ [TestCase("1.1.0.0", "1.0.0.0", 1)]
+ [TestCase("2.0.0.0", "1.0.0.0", 1)]
+ // V1 < V2
+ [TestCase("1.0.0.0", "1.0.0.1", -1)]
+ [TestCase("1.0.0.0", "1.0.1.0", -1)]
+ [TestCase("1.0.0.0", "1.1.0.0", -1)]
+ [TestCase("1.0.0.0", "2.0.0.0", -1)]
+ public void WinGetUtil_CompareVersions(string version1, string version2, int expectedResult)
+ {
+ // Compare versions
+ WinGetUtilWrapper.WinGetCompareVersions(version1, version2, out int result);
+ Assert.AreEqual(expectedResult, result);
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilDownload.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilDownload.cs
new file mode 100644
index 0000000000..d31a6073a1
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilDownload.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using System.IO;
+ using System.Linq;
+ using NUnit.Framework;
+
+ public class WinGetUtilDownload
+ {
+ [Test]
+ public void WinGetUtil_Download()
+ {
+ uint hashSize = 32;
+ byte[] sha256Hash = new byte[hashSize];
+ string installerUrl = @"https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe";
+ string filePath = TestCommon.GetRandomTestFile(".exe");
+
+ // Download
+ WinGetUtilWrapper.WinGetDownload(installerUrl, filePath, sha256Hash, hashSize);
+
+ Assert.True(File.Exists(filePath));
+ Assert.False(sha256Hash.All(byteVal => byteVal == 0));
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilInstallerMetadataCollection.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilInstallerMetadataCollection.cs
new file mode 100644
index 0000000000..d11c11128f
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilInstallerMetadataCollection.cs
@@ -0,0 +1,77 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using Newtonsoft.Json;
+ using NUnit.Framework;
+ using System;
+ using System.IO;
+ using System.Runtime.InteropServices;
+
+ public class WinGetUtilInstallerMetadataCollection
+ {
+ [Test]
+ public void WinGetUtil_BeginCompleteInstallerMetadataCollection()
+ {
+ string logFilePath = TestCommon.GetRandomTestFile(".log");
+ string inputJson = TestCommon.GetTestDataFile(@"WinGetUtil\InstallerMetadata\Minimal.json");
+ string outputFilePath = TestCommon.GetRandomTestFile(".json");
+
+ WinGetUtilWrapper.WinGetBeginInstallerMetadataCollection(
+ inputJson,
+ logFilePath,
+ WinGetUtilWrapper.WinGetBeginInstallerMetadataCollectionOptions.WinGetBeginInstallerMetadataCollectionOption_InputIsFilePath,
+ out IntPtr collectionHandle);
+
+ Assert.AreNotEqual(IntPtr.Zero, collectionHandle);
+ Assert.True(File.Exists(logFilePath));
+
+ WinGetUtilWrapper.WinGetCompleteInstallerMetadataCollection(
+ collectionHandle,
+ outputFilePath,
+ WinGetUtilWrapper.WinGetCompleteInstallerMetadataCollectionOptions.WinGetCompleteInstallerMetadataCollectionOption_None);
+
+ string outputJson = File.ReadAllText(outputFilePath);
+ Assert.IsNotEmpty(JsonConvert.DeserializeObject(outputJson).ToString());
+ }
+
+ [Test]
+ public void WinGetUtil_MergeInstallerMetadata_Success()
+ {
+ string logFilePath = TestCommon.GetRandomTestFile(".log");
+ string inputJsonPath = TestCommon.GetTestDataFile(@"WinGetUtil\InstallerMetadata\MergeValid.json");
+ string inputJson = File.ReadAllText(inputJsonPath);
+
+ WinGetUtilWrapper.WinGetMergeInstallerMetadata(
+ inputJson,
+ out string outputJson,
+ 0,
+ logFilePath,
+ WinGetUtilWrapper.WinGetMergeInstallerMetadataOptions.WinGetMergeInstallerMetadataOptions_None);
+
+ Assert.True(File.Exists(logFilePath));
+ Assert.IsNotEmpty(JsonConvert.DeserializeObject(outputJson).ToString());
+ }
+
+ [Test]
+ public void WinGetUtil_MergeInstallerMetadata_Fail_SubmissionMismatch()
+ {
+ string logFilePath = TestCommon.GetRandomTestFile(".log");
+ string inputJsonPath = TestCommon.GetTestDataFile(@"WinGetUtil\InstallerMetadata\MergeSubmissionMismatch.json");
+ string inputJson = File.ReadAllText(inputJsonPath);
+
+ Assert.Throws(() =>
+ {
+ WinGetUtilWrapper.WinGetMergeInstallerMetadata(
+ inputJson,
+ out string outputJson,
+ 0,
+ logFilePath,
+ WinGetUtilWrapper.WinGetMergeInstallerMetadataOptions.WinGetMergeInstallerMetadataOptions_None);
+ });
+
+ Assert.True(File.Exists(logFilePath));
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilLog.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilLog.cs
new file mode 100644
index 0000000000..635f3a4af4
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilLog.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using System.IO;
+ using NUnit.Framework;
+
+ public class WinGetUtilLog
+ {
+ [Test]
+ public void WinGetUtil_Logging()
+ {
+ string filePath = TestCommon.GetRandomTestFile(".log");
+
+ // Init logging
+ WinGetUtilWrapper.WinGetLoggingInit(filePath);
+ Assert.True(File.Exists(filePath));
+
+ // Terminate logging
+ WinGetUtilWrapper.WinGetLoggingTerm(filePath);
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilManifest.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilManifest.cs
new file mode 100644
index 0000000000..8dee02baaf
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilManifest.cs
@@ -0,0 +1,68 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using System;
+ using System.IO;
+ using NUnit.Framework;
+
+ public class WinGetUtilManifest
+ {
+ private IntPtr indexHandle;
+
+ [SetUp]
+ public void SetUp()
+ {
+ this.indexHandle = IntPtr.Zero;
+ var sqliteFile = TestCommon.GetRandomTestFile(".db");
+ uint majorVersion = 1;
+ uint minorVersion = 2;
+ WinGetUtilWrapper.WinGetSQLiteIndexCreate(sqliteFile, majorVersion, minorVersion, out this.indexHandle); ;
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ WinGetUtilWrapper.WinGetSQLiteIndexClose(this.indexHandle);
+ }
+
+ [Test]
+ [TestCase(WinGetUtilWrapper.CreateManifestOption.NoValidation)]
+ [TestCase(WinGetUtilWrapper.CreateManifestOption.SchemaAndSemanticValidation)]
+ public void WinGetUtil_ValidateManifest_Success(WinGetUtilWrapper.CreateManifestOption createManifestOption)
+ {
+ string manifestsDir = TestCommon.GetTestDataFile(@"WinGetUtil\Manifests\Unmerged\ValidateManifest");
+ string mergedManifestPath = TestCommon.GetRandomTestFile(".yaml");
+
+ // Create manifest
+ WinGetUtilWrapper.WinGetCreateManifest(
+ manifestsDir,
+ out bool succeeded,
+ out IntPtr manifestHandle,
+ out string createFailureMessage,
+ mergedManifestPath,
+ createManifestOption);
+
+ Assert.True(succeeded);
+ Assert.AreNotEqual(IntPtr.Zero, manifestHandle);
+ Assert.IsNull(createFailureMessage);
+ Assert.True(File.Exists(mergedManifestPath));
+
+ // Validate manifest
+ WinGetUtilWrapper.WinGetValidateManifestV3(
+ manifestHandle,
+ indexHandle,
+ out WinGetUtilWrapper.ValidateManifestResultCode resultCode,
+ out string validateFailureMessage,
+ WinGetUtilWrapper.ValidateManifestOptionV2.ArpVersionValidation,
+ WinGetUtilWrapper.ValidateManifestOperationType.Add);
+
+ Assert.AreEqual(WinGetUtilWrapper.ValidateManifestResultCode.Success, resultCode);
+ Assert.IsEmpty(validateFailureMessage);
+
+ // Close manifest
+ WinGetUtilWrapper.WinGetCloseManifest(manifestHandle);
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilSQLiteIndex.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilSQLiteIndex.cs
new file mode 100644
index 0000000000..652d04ad97
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilSQLiteIndex.cs
@@ -0,0 +1,142 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using System;
+ using System.IO;
+ using System.Runtime.InteropServices;
+ using NUnit.Framework;
+
+ public class WinGetUtilSQLiteIndex
+ {
+ private string sqlitePath;
+ private readonly uint majorVersion = 1;
+ private readonly uint minorVersion = 2;
+
+ // Manifest example 1
+ private readonly string addManifestsFile_1 = TestCommon.GetTestDataFile(@"WinGetUtil\Manifests\Merged\WinGetUtilTest.Add.yaml");
+ private readonly string updateManifestsFile_1 = TestCommon.GetTestDataFile(@"WinGetUtil\Manifests\Merged\WinGetUtilTest.Update.yaml");
+ private readonly string relativePath_1 = @"manifests\a\AppInstallerTest\WinGetUtilTest\1.0.0.0\WinGetTest.yaml";
+
+ [SetUp]
+ public void SetUp()
+ {
+ this.sqlitePath = TestCommon.GetRandomTestFile(".sql");
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_AddManifest()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Add manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexAddManifest(indexHandle, addManifestsFile_1, relativePath_1);
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_UpdateManifest_Success()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Add manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexAddManifest(indexHandle, addManifestsFile_1, relativePath_1);
+
+ // Update manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexUpdateManifest(indexHandle, updateManifestsFile_1, relativePath_1, out bool indexModified);
+ Assert.True(indexModified);
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_UpdateManifest_Fail_NotFound()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Update non-existing manifest
+ Assert.Throws(() =>
+ {
+ WinGetUtilWrapper.WinGetSQLiteIndexUpdateManifest(indexHandle, updateManifestsFile_1, relativePath_1, out bool indexModified);
+ });
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_RemoveManifest_Success()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Add manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexAddManifest(indexHandle, addManifestsFile_1, relativePath_1);
+
+ // Remove manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexRemoveManifest(indexHandle, addManifestsFile_1, relativePath_1);
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_RemoveManifest_Fail_NotFound()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Remove non-existing manifest
+ Assert.Throws(() =>
+ {
+ WinGetUtilWrapper.WinGetSQLiteIndexRemoveManifest(indexHandle, addManifestsFile_1, relativePath_1);
+ });
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_OpenClose()
+ {
+ SQLiteIndex((_) =>
+ {
+ // Open
+ WinGetUtilWrapper.WinGetSQLiteIndexOpen(sqlitePath, out IntPtr indexHandle);
+
+ // Add manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexAddManifest(indexHandle, addManifestsFile_1, relativePath_1);
+
+ // Close
+ WinGetUtilWrapper.WinGetSQLiteIndexClose(indexHandle);
+ });
+ }
+
+ [Test]
+ public void WinGetUtil_SQLiteIndex_CheckConsistency()
+ {
+ SQLiteIndex((indexHandle) =>
+ {
+ // Add manifest
+ WinGetUtilWrapper.WinGetSQLiteIndexAddManifest(indexHandle, addManifestsFile_1, relativePath_1);
+
+ // Prepare for packaging
+ WinGetUtilWrapper.WinGetSQLiteIndexPrepareForPackaging(indexHandle);
+
+ // Check consistency
+ WinGetUtilWrapper.WinGetSQLiteIndexCheckConsistency(indexHandle, out bool succeeded);
+ Assert.True(succeeded);
+ });
+ }
+
+ ///
+ /// Create and close an sqlite index file.
+ ///
+ /// Function to execute.
+ private void SQLiteIndex(Action Execute)
+ {
+ // Create
+ WinGetUtilWrapper.WinGetSQLiteIndexCreate(sqlitePath, majorVersion, minorVersion, out IntPtr indexHandle);
+ Assert.True(File.Exists(sqlitePath));
+ Assert.AreNotEqual(IntPtr.Zero, indexHandle);
+
+ // Execute provided function
+ Execute(indexHandle);
+
+ // Close
+ WinGetUtilWrapper.WinGetSQLiteIndexClose(indexHandle);
+ }
+ }
+}
diff --git a/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilWrapper.cs b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilWrapper.cs
new file mode 100644
index 0000000000..a9a42749cf
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/WinGetUtil/WinGetUtilWrapper.cs
@@ -0,0 +1,157 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.WinGetUtil
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Wrapper class for WinGetUtil exports.
+ /// For more details about methods in this class visit WinGetUtil.h file.
+ ///
+ public class WinGetUtilWrapper
+ {
+ private const string DllName = @"WinGetUtil.dll";
+
+ [Flags]
+ public enum CreateManifestOption
+ {
+ NoValidation = 0,
+ SchemaValidation = 0x1,
+ SchemaAndSemanticValidation = 0x2,
+ ReturnErrorOnVerifiedPublisherFields = 0x1000,
+ }
+
+ [Flags]
+ public enum ValidateManifestResultCode
+ {
+ Success = 0,
+ DependenciesValidationFailure = 0x1,
+ ArpVersionValidationFailure = 0x2,
+ InstallerValidationFailure = 0x4,
+ SingleManifestPackageHasDependencies = 0x10000,
+ MultiManifestPackageHasDependencies = 0x20000,
+ MissingManifestDependenciesNode = 0x40000,
+ NoSuitableMinVersionDependency = 0x80000,
+ FoundDependencyLoop = 0x100000,
+ InternalError = 0x1000,
+ }
+
+ [Flags]
+ public enum ValidateManifestOptionV2
+ {
+ None = 0,
+ DependenciesValidation = 0x1,
+ ArpVersionValidation = 0x2,
+ InstallerValidation = 0x4,
+ }
+
+ public enum ValidateManifestOperationType
+ {
+ Add = 0,
+ Update = 1,
+ Delete = 2,
+ }
+
+ public enum WinGetBeginInstallerMetadataCollectionOptions
+ {
+ WinGetBeginInstallerMetadataCollectionOption_None = 0,
+ WinGetBeginInstallerMetadataCollectionOption_InputIsFilePath = 0x1,
+ WinGetBeginInstallerMetadataCollectionOption_InputIsURI = 0x2,
+ };
+
+ public enum WinGetCompleteInstallerMetadataCollectionOptions
+ {
+ WinGetCompleteInstallerMetadataCollectionOption_None = 0,
+ WinGetCompleteInstallerMetadataCollectionOption_Abandon = 0x1,
+ };
+
+ public enum WinGetMergeInstallerMetadataOptions
+ {
+ WinGetMergeInstallerMetadataOptions_None = 0,
+ };
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetCompareVersions(string version1, string version2, [MarshalAs(UnmanagedType.U4)] out int comparisonResult);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetDownload(string url, string filePath, [MarshalAs(UnmanagedType.LPArray)] byte[] sha26Hash, uint sha256HashLength);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetLoggingInit(string logPath);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetLoggingTerm(string logPath);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetCreateManifest(
+ string inputPath,
+ [MarshalAs(UnmanagedType.U1)] out bool succeeded,
+ out IntPtr manifestHandle,
+ [MarshalAs(UnmanagedType.BStr)] out string failureMessage,
+ string mergedManifestPath,
+ CreateManifestOption option);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetCloseManifest(IntPtr manifest);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetValidateManifestV3(
+ IntPtr manifestHandle,
+ IntPtr indexHandle,
+ out ValidateManifestResultCode result,
+ [MarshalAs(UnmanagedType.BStr)] out string failureMessage,
+ ValidateManifestOptionV2 option,
+ ValidateManifestOperationType operationType);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexCreate(string filePath, uint majorVersion, uint minorVersion, out IntPtr index);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexOpen(string filePath, out IntPtr index);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexClose(IntPtr index);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexAddManifest(IntPtr index, string manifestPath, string relativePath);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexUpdateManifest(
+ IntPtr index,
+ string manifestPath,
+ string relativePath,
+ [MarshalAs(UnmanagedType.U1)] out bool indexModified);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexRemoveManifest(IntPtr index, string manifestPath, string relativePath);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexPrepareForPackaging(IntPtr index);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetSQLiteIndexCheckConsistency(IntPtr index, [MarshalAs(UnmanagedType.U1)] out bool succeeded);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetBeginInstallerMetadataCollection(
+ string inputJSON,
+ string logFilePath,
+ WinGetBeginInstallerMetadataCollectionOptions options,
+ out IntPtr collectionHandle);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetCompleteInstallerMetadataCollection(
+ IntPtr collectionHandle,
+ string outputFilePath,
+ WinGetCompleteInstallerMetadataCollectionOptions options);
+
+ [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)]
+ public static extern void WinGetMergeInstallerMetadata(
+ string inputJSON,
+ [MarshalAs(UnmanagedType.BStr)] out string outputJSON,
+ uint maximumOutputSizeInBytes,
+ string logFilePath,
+ WinGetMergeInstallerMetadataOptions options);
+ }
+}
diff --git a/src/IndexCreationTool/Program.cs b/src/IndexCreationTool/Program.cs
index 17b5c86c19..4baef32d0a 100644
--- a/src/IndexCreationTool/Program.cs
+++ b/src/IndexCreationTool/Program.cs
@@ -4,8 +4,10 @@
namespace IndexCreationTool
{
using System;
+ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+ using System.Linq;
class Program
{
@@ -19,12 +21,19 @@ static void Main(string[] args)
string appxManifestPath = string.Empty;
string certPath = string.Empty;
+ // List of directories to include. By default, include all directories.
+ List includeDirList = new() { string.Empty };
+
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-d" && ++i < args.Length)
{
rootDir = args[i];
}
+ else if (args[i] == "-i" && ++i < args.Length)
+ {
+ includeDirList = args[i].Split(",").ToList();
+ }
else if (args[i] == "-m" && ++i < args.Length)
{
appxManifestPath = args[i];
@@ -37,7 +46,7 @@ static void Main(string[] args)
if (string.IsNullOrEmpty(rootDir))
{
- Console.WriteLine("Usage: IndexCreationTool.exe -d [-m [-c ]]");
+ Console.WriteLine("Usage: IndexCreationTool.exe -d [-i ] [-m [-c ]]");
return;
}
@@ -50,9 +59,13 @@ static void Main(string[] args)
using (var indexHelper = WinGetUtilWrapper.Create(IndexName))
{
- foreach (string file in Directory.EnumerateFiles(rootDir, "*.yaml", SearchOption.AllDirectories))
+ foreach (string includeDir in includeDirList)
{
- indexHelper.AddManifest(file, Path.GetRelativePath(rootDir, file));
+ var fullPath = Path.Combine(rootDir, includeDir);
+ foreach (string file in Directory.EnumerateFiles(fullPath, "*.yaml", SearchOption.AllDirectories))
+ {
+ indexHelper.AddManifest(file, Path.GetRelativePath(rootDir, file));
+ }
}
indexHelper.PrepareForPackaging();
}