winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit b4d8c969230e2ec8079dbb870523eacbf0925938
parent 6cd7b8693a35a1725e22e737d7811c04edcc3a2e
Author: Ruben Guerrero <rubengu@microsoft.com>
Date:   Wed, 10 Jan 2024 09:23:10 -0800

Update WinGetUtilInterop project (#4045)

This PR fulfills my lifelong dream of updating the `WinGetUtilInterop`
to include most of the APIs from `WinGetUtil`. Internally we have a
project with all this code, so I just copy them here with some minor
changes. Because of that, some of them are not included. The idea would
be that any new APIs added into WinGetUtil should have their
corresponding C# interop implementation in the same PR.

APIs included:
- WinGetLoggingInit
- WinGetLoggingTerm
- WinGetSQLiteIndexCreate
- WinGetSQLiteIndexOpen
- WinGetSQLiteIndexClose
- WinGetSQLiteIndexAddManifest
- WinGetSQLiteIndexUpdateManifest
- WinGetSQLiteIndexRemoveManifest
- WinGetSQLiteIndexPrepareForPackaging
- WinGetSQLiteIndexCheckConsistency
- WinGetCreateManifest
- WinGetCloseManifest
- WinGetValidateManifestV3
- WinGetDownload
- WinGetCompareVersions
- WinGetBeginInstallerMetadataCollection
- WinGetCompleteInstallerMetadataCollection

Missing ones:
- WinGetValidateManifest
- WinGetValidateManifestV2
- WinGetValidateManifestDependencies
- WinGetMergeInstallerMetadata

In that project we just have SQLite tests, so I port them too. I also
added the same stylecops convention so you will see some header changes.

Diffstat:
Mazure-pipelines.yml | 13+++++++++++--
Msrc/AppInstallerCLI.sln | 31+++++++++++++------------------
Msrc/WinGetSourceCreator/WinGetLocalSource.cs | 4++--
Asrc/WinGetUtilInterop.UnitTests/APIUnitTests/SQLiteIndexUnitTests.cs | 337+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/WinGetUtilInterop.UnitTests/Common/DisplayTestMethodNameAttribute.cs | 6+++---
Msrc/WinGetUtilInterop.UnitTests/ManifestUnitTest/ManifestEqualityUnitTests.cs | 6+++---
Msrc/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs | 8++++----
Asrc/WinGetUtilInterop.UnitTests/TestCollateral/PackageTest.yaml | 18++++++++++++++++++
Asrc/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewName.yaml | 18++++++++++++++++++
Asrc/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewVersion.yaml | 18++++++++++++++++++
Msrc/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj | 22++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetFactory.cs | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetInstallerMetadata.cs | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetLogging.cs | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetManifest.cs | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetSQLiteIndex.cs | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Api/WinGetUtilities.cs | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Common/Constants.cs | 19+++++++++++++++++++
Asrc/WinGetUtilInterop/Common/CreateManifestResult.cs | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Common/Enums.cs | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Common/ManifestValidationResult.cs | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Exceptions/WinGetDownloadException.cs | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Exceptions/WinGetInstallerMetadataException.cs | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Exceptions/WinGetLoggingException.cs | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Exceptions/WinGetManifestException.cs | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Exceptions/WinGetSQLiteIndexException.cs | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/WinGetUtilInterop/Exceptions/WinGetUtilIndexException.cs | 48------------------------------------------------
Dsrc/WinGetUtilInterop/Helpers/WinGetUtilIndex.cs | 278-------------------------------------------------------------------------------
Dsrc/WinGetUtilInterop/Helpers/WinGetUtilWrapperManifest.cs | 77-----------------------------------------------------------------------------
Asrc/WinGetUtilInterop/Interfaces/IWinGetFactory.cs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Interfaces/IWinGetInstallerMetadata.cs | 22++++++++++++++++++++++
Asrc/WinGetUtilInterop/Interfaces/IWinGetLogging.cs | 17+++++++++++++++++
Asrc/WinGetUtilInterop/Interfaces/IWinGetManifest.cs | 29+++++++++++++++++++++++++++++
Asrc/WinGetUtilInterop/Interfaces/IWinGetSQLiteIndex.cs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/WinGetUtilInterop/Interfaces/IWinGetUtilIndex.cs | 52----------------------------------------------------
Asrc/WinGetUtilInterop/Interfaces/IWinGetUtilities.cs | 32++++++++++++++++++++++++++++++++
Msrc/WinGetUtilInterop/Manifest/Preview/InstallerSwitches.cs | 7+++----
Msrc/WinGetUtilInterop/Manifest/Preview/Manifest.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/Preview/ManifestInstaller.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/Preview/ManifestLocalization.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/InstallerArpEntry.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/InstallerDependency.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/InstallerExpectedReturnCode.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/InstallerInstallationMetadata.cs | 11++++++-----
Msrc/WinGetUtilInterop/Manifest/V1/InstallerMarkets.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/InstallerNestedInstallerFile.cs | 13+++++++++----
Msrc/WinGetUtilInterop/Manifest/V1/InstallerPackageDependency.cs | 8+++-----
Msrc/WinGetUtilInterop/Manifest/V1/InstallerSwitches.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/Manifest.cs | 10++++------
Msrc/WinGetUtilInterop/Manifest/V1/ManifestDocumentation.cs | 14++++++--------
Msrc/WinGetUtilInterop/Manifest/V1/ManifestIcon.cs | 15+++++++--------
Msrc/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs | 11+++++------
Msrc/WinGetUtilInterop/Manifest/V1/ManifestInstallerFile.cs | 12++++--------
Msrc/WinGetUtilInterop/Manifest/V1/ManifestLocalization.cs | 6+++---
Msrc/WinGetUtilInterop/Manifest/V1/MinManifestInfo.cs | 7+++----
Msrc/WinGetUtilInterop/Manifest/V1/PackageAgreement.cs | 6+++---
Msrc/WinGetUtilInterop/WinGetUtilInterop.csproj | 8++++++--
57 files changed, 2072 insertions(+), 577 deletions(-)

diff --git a/azure-pipelines.yml b/azure-pipelines.yml @@ -291,12 +291,21 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Files: WinGetUtilInterop.UnitTests' inputs: - SourceFolder: '$(Build.SourcesDirectory)\src\WinGetUtilInterop.UnitTests\bin\$(BuildConfiguration)\net6.0' + SourceFolder: '$(Build.SourcesDirectory)\src\WinGetUtilInterop.UnitTests\bin\$(buildPlatform)\$(BuildConfiguration)\net6.0' TargetFolder: '$(Build.ArtifactStagingDirectory)\WinGetUtilInterop.UnitTests\' CleanTargetFolder: true OverWrite: true condition: succeededOrFailed() + - task: CopyFiles@2 + displayName: 'Copy WinGetUtil to WinGetUtilInterop.UnitTests folder' + inputs: + Contents: | + $(buildOutDir)\WinGetUtil\WinGetUtil.dll + TargetFolder: '$(Build.ArtifactStagingDirectory)\WinGetUtilInterop.UnitTests\' + flattenFolders: true + condition: succeededOrFailed() + - task: VSTest@2 displayName: 'Run tests: WinGetUtilInterop.UnitTests' inputs: @@ -304,7 +313,7 @@ jobs: testAssemblyVer2: 'WinGetUtilInterop.UnitTests.dll' searchFolder: '$(Build.ArtifactStagingDirectory)\WinGetUtilInterop.UnitTests' codeCoverageEnabled: true - platform: 'Any CPU' + platform: '$(buildPlatform)' configuration: '$(BuildConfiguration)' condition: succeededOrFailed() diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln @@ -769,34 +769,29 @@ Global {846FB88B-BF1B-4F33-9883-E589CEC99739}.TestRelease|x64.ActiveCfg = Release|Any CPU {846FB88B-BF1B-4F33-9883-E589CEC99739}.TestRelease|x86.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|ARM64.Build.0 = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x64.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x64.Build.0 = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x86.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x86.Build.0 = Debug|Any CPU + {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x64.ActiveCfg = Debug|x64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x64.Build.0 = Debug|x64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x86.ActiveCfg = Debug|x86 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Debug|x86.Build.0 = Debug|x86 {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|Any CPU.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|ARM64.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|ARM64.Build.0 = Debug|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|x64.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|x64.Build.0 = Debug|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|x86.ActiveCfg = Debug|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Fuzzing|x86.Build.0 = Debug|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.PowerShell|Any CPU.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.PowerShell|ARM64.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.PowerShell|x64.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.PowerShell|x86.ActiveCfg = Release|Any CPU {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|ARM64.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|ARM64.Build.0 = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x64.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x64.Build.0 = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x86.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x86.Build.0 = Release|Any CPU + {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|ARM64.ActiveCfg = Release|ARM64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x64.ActiveCfg = Release|x64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x64.Build.0 = Release|x64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x86.ActiveCfg = Release|x86 + {68808357-902B-406C-8C19-E8E26A69DE8A}.Release|x86.Build.0 = Release|x86 {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|Any CPU.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|ARM64.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x64.ActiveCfg = Release|Any CPU - {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x86.ActiveCfg = Release|Any CPU + {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|ARM64.ActiveCfg = Release|ARM64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x64.ActiveCfg = Release|x64 + {68808357-902B-406C-8C19-E8E26A69DE8A}.TestRelease|x86.ActiveCfg = Release|x86 {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|Any CPU.ActiveCfg = Debug|x64 {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM64.ActiveCfg = Debug|ARM64 {2046B5AF-666D-4CE8-8D3E-C32C57908A56}.Debug|ARM64.Build.0 = Debug|ARM64 diff --git a/src/WinGetSourceCreator/WinGetLocalSource.cs b/src/WinGetSourceCreator/WinGetLocalSource.cs @@ -6,7 +6,7 @@ namespace Microsoft.WinGetSourceCreator using global::WinGetSourceCreator.Model; using System.Text.Json.Serialization; using System.Text.Json; - using WinGetUtilInterop.Helpers; + using Microsoft.WinGetUtil.Api; public class WinGetLocalSource { @@ -113,7 +113,7 @@ namespace Microsoft.WinGetSourceCreator public string CreateIndex(string indexName) { string fullPath = Path.Combine(this.workingDirectory, indexName); - using var indexHelper = WinGetUtilIndex.CreateLatestVersion(fullPath); + using var indexHelper = new WinGetFactory().SQLiteIndexCreateLatestVersion(fullPath); Queue<string> filesQueue = new(Directory.EnumerateFiles(this.workingDirectory, "*.yaml", SearchOption.AllDirectories)); while (filesQueue.Count > 0) diff --git a/src/WinGetUtilInterop.UnitTests/APIUnitTests/SQLiteIndexUnitTests.cs b/src/WinGetUtilInterop.UnitTests/APIUnitTests/SQLiteIndexUnitTests.cs @@ -0,0 +1,337 @@ +// ----------------------------------------------------------------------------- +// <copyright file="SQLiteIndexUnitTests.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace WinGetUtilInterop.UnitTests.APIUnitTests +{ + using System; + using System.IO; + using System.Reflection; + using Microsoft.WinGetUtil.Api; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + using Microsoft.WinGetUtil.UnitTests.Common.Logging; + using Xunit; + using Xunit.Abstractions; + + /// <summary> + /// SQLite Index tests. + /// </summary> + public class SQLiteIndexUnitTests + { + private const string Index = "Index"; + private const string IndexLogFile = "index_log.txt"; + private const string IndexFileName = "index.db"; + + private const string PackageTest = "PackageTest.yaml"; + private const string PackageTestNewName = "PackageTestNewName.yaml"; + private const string PackageTestNewVersion = "PackageTestNewVersion.yaml"; + private const string PackageTestRelativePath = @"manifests\t\Test\Test\1.0\Test.Test.yaml"; + + private readonly string indexTestFilePath; + private readonly string indexTestLogFile; + private readonly string indexTestOutputPath; + private readonly string indexTestDataPath; + + private ITestOutputHelper log; + + /// <summary> + /// Initializes a new instance of the <see cref="SQLiteIndexUnitTests"/> class. + /// </summary> + /// <param name="log">Output Helper.</param> + public SQLiteIndexUnitTests(ITestOutputHelper log) + { + this.log = log; + + var assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + this.indexTestDataPath = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "TestCollateral"); + + this.indexTestOutputPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString(), "WinGetUtilIndexTests"); + Directory.CreateDirectory(this.indexTestOutputPath); + + this.indexTestFilePath = Path.Combine(this.indexTestOutputPath, IndexFileName); + this.indexTestLogFile = Path.Combine(this.indexTestOutputPath, IndexLogFile); + + if (File.Exists(this.indexTestFilePath)) + { + File.Delete(this.indexTestFilePath); + } + + if (File.Exists(this.indexTestLogFile)) + { + File.Delete(this.indexTestLogFile); + } + } + + /// <summary> + /// Verify opening a existing index file succeeds. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void OpenIndex() + { + this.CreateIndexHelperForIndexTest((wrapper) => true); + this.OpenIndexHelper((wrapper) => true); + } + + /// <summary> + /// Verify opening a fake file fails. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void OpenIndexFileDontExist() + { + // Verify fails with non existent file. + var exception = Assert.Throws<WinGetSQLiteIndexException>( + () => + { + var factory = new WinGetFactory(); + using var log = factory.LoggingInit(this.indexTestLogFile); + using var wrapper = factory.SQLiteIndexOpen("fakeFile.db"); + }); + Assert.NotNull(exception.InnerException); + Assert.True(exception.InnerException is System.Runtime.InteropServices.COMException); + Assert.Equal(-2018574322, exception.InnerException.HResult); + File.Delete(this.indexTestLogFile); + + // Verify fails with not an index file. + string textFile = Path.Combine(this.indexTestOutputPath, "text.txt"); + File.WriteAllText(textFile, "This is a text file."); + Assert.True(File.Exists(textFile), "File created correctly."); + var exception2 = Assert.Throws<WinGetSQLiteIndexException>( + () => + { + var factory = new WinGetFactory(); + using var log = factory.LoggingInit(this.indexTestLogFile); + using var wrapper = factory.SQLiteIndexOpen(textFile); + }); + Assert.NotNull(exception2.InnerException); + Assert.True(exception2.InnerException is System.Runtime.InteropServices.COMException); + Assert.Equal("File opened that is not a database file (0x87AF001A)", exception2.InnerException.Message); + File.Delete(textFile); + } + + /// <summary> + /// Verifies adding a manifest to the index succeeds. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void AddManifest() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string testManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(testManifest, PackageTestRelativePath); + return true; + }); + } + + /// <summary> + /// Verify that adding an already existing manifest fails. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void AddManifestAlreadyExists() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string testManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(testManifest, PackageTestRelativePath); + + // Add manifest again. + var exception = Assert.Throws<WinGetSQLiteIndexException>( + () => + { + wrapper.AddManifest(testManifest, PackageTestRelativePath); + }); + Assert.NotNull(exception.InnerException); + Assert.True(exception.InnerException is System.Runtime.InteropServices.COMException); + Assert.Equal(-2147024713, exception.InnerException.HResult); + + return true; + }); + } + + /// <summary> + /// Verify that updating a manifest with different name. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void UpdateManifest() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string addManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(addManifest, PackageTestRelativePath); + + // Update manifest. name is different, should return true. + string updateManifest = Path.Combine(this.indexTestDataPath, PackageTestNewName); + Assert.True(wrapper.UpdateManifest(updateManifest, PackageTestRelativePath)); + + return true; + }); + } + + /// <summary> + /// Verify that updating a manifest in the index with the exact same information succeeds. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void UpdateManifestNoChanges() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string addManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(addManifest, PackageTestRelativePath); + + // Update manifest. Same file, should succeed but return false. + Assert.False(wrapper.UpdateManifest(addManifest, PackageTestRelativePath)); + + return true; + }); + } + + /// <summary> + /// Verify that updating a manifest that doesn't exists fails. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void UpdateManifestNonExistant() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Update manifest that doesn't exists + string updateManifest = Path.Combine(this.indexTestDataPath, PackageTest); + var exception = Assert.Throws<WinGetSQLiteIndexException>( + () => + { + wrapper.UpdateManifest(updateManifest, PackageTestRelativePath); + }); + Assert.NotNull(exception.InnerException); + Assert.True(exception.InnerException is System.Runtime.InteropServices.COMException); + Assert.Equal(-2147023728, exception.InnerException.HResult); + + return true; + }); + } + + /// <summary> + /// Verify that updating an existing manifest in the index, but another version. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void UpdateManifestDifferentVersion() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string addManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(addManifest, PackageTestRelativePath); + + // Update manifest. Version is different. + string updateManifest = Path.Combine(this.indexTestDataPath, PackageTestNewVersion); + var exception = Assert.Throws<WinGetSQLiteIndexException>( + () => + { + wrapper.UpdateManifest(updateManifest, PackageTestRelativePath); + }); + Assert.NotNull(exception.InnerException); + Assert.True(exception.InnerException is System.Runtime.InteropServices.COMException); + Assert.Equal(-2147023728, exception.InnerException.HResult); + + return true; + }); + } + + /// <summary> + /// Verify that removing a manifest in the index succeeds. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void RemoveManifest() + { + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string addManifest = Path.Combine(this.indexTestDataPath, PackageTest); + wrapper.AddManifest(addManifest, PackageTestRelativePath); + + // Remove manifest. + wrapper.RemoveManifest(addManifest, PackageTestRelativePath); + + return true; + }); + } + + /// <summary> + /// Verify that trying to delete a manifest that doesn't exists fails. + /// </summary> + [Fact] + [DisplayTestMethodName] + public void RemoveManifestNonExistant() + { + // create index, add manifest, delete. + this.CreateIndexHelperForIndexTest((wrapper) => + { + // Add manifest. + string addManifest = Path.Combine(this.indexTestDataPath, PackageTest); + + // Remove manifest. + Assert.Throws<WinGetSQLiteIndexException>( + () => + { + wrapper.RemoveManifest(addManifest, PackageTestRelativePath); + }); + + return true; + }); + } + + private void CreateIndexHelperForIndexTest(Func<IWinGetSQLiteIndex, bool> lambda) + { + if (File.Exists(this.indexTestLogFile)) + { + File.Delete(this.indexTestLogFile); + } + + if (File.Exists(this.indexTestFilePath)) + { + File.Delete(this.indexTestFilePath); + } + + // Create index. + var factory = new WinGetFactory(); + using var log = factory.LoggingInit(this.indexTestLogFile); + using var wrapper = factory.SQLiteIndexCreateLatestVersion(this.indexTestFilePath); + Assert.True(lambda(wrapper), "Expression passed"); + + Assert.True(File.Exists(this.indexTestLogFile)); + Assert.True(File.Exists(this.indexTestFilePath)); + } + + private void OpenIndexHelper(Func<IWinGetSQLiteIndex, bool> lambda) + { + Assert.True(File.Exists(this.indexTestFilePath)); + if (File.Exists(this.indexTestLogFile)) + { + File.Delete(this.indexTestLogFile); + } + + // Open index. + var factory = new WinGetFactory(); + using var log = factory.LoggingInit(this.indexTestLogFile); + using var wrapper = factory.SQLiteIndexOpen(this.indexTestFilePath); + Assert.True(lambda(wrapper), "Expression passed"); + + Assert.True(File.Exists(this.indexTestLogFile)); + } + } +} diff --git a/src/WinGetUtilInterop.UnitTests/Common/DisplayTestMethodNameAttribute.cs b/src/WinGetUtilInterop.UnitTests/Common/DisplayTestMethodNameAttribute.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="DisplayTestMethodNameAttribute.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.UnitTests.Common.Logging { diff --git a/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/ManifestEqualityUnitTests.cs b/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/ManifestEqualityUnitTests.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestEqualityUnitTests.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.UnitTests.ManifestUnitTest { diff --git a/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs b/src/WinGetUtilInterop.UnitTests/ManifestUnitTest/V1ManifestReadTest.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="V1ManifestReadTest.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.UnitTests.ManifestUnitTest { @@ -55,7 +55,7 @@ namespace Microsoft.WinGetUtil.UnitTests.ManifestUnitTest Manifest v160manifest = Manifest.CreateManifestFromPath( Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestCollateral", ManifestStrings.V160ManifestMerged)); - + this.ValidateManifestFields(v160manifest, TestManifestVersion.V160); } diff --git a/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTest.yaml b/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTest.yaml @@ -0,0 +1,18 @@ +PackageIdentifier: Test.Test +PackageVersion: 1.0 +PackageName: Test +Publisher: Test +PackageUrl: https://test.com +License: Test. +LicenseUrl: https://test.com +ShortDescription: A test +Installers: +- Architecture: x64 + InstallerUrl: https://test.com/installer.exe + InstallerType: exe + InstallerSwitches: + Silent: /silent + InstallerSha256: 00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF +PackageLocale: en-US +ManifestType: singleton +ManifestVersion: 1.0.0 diff --git a/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewName.yaml b/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewName.yaml @@ -0,0 +1,18 @@ +PackageIdentifier: Test.Test +PackageVersion: 1.0 +PackageName: NewName +Publisher: Test +PackageUrl: https://test.com +License: Test. +LicenseUrl: https://test.com +ShortDescription: A test +Installers: +- Architecture: x64 + InstallerUrl: https://test.com/installer.exe + InstallerType: exe + InstallerSwitches: + Silent: /silent + InstallerSha256: 00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF +PackageLocale: en-US +ManifestType: singleton +ManifestVersion: 1.0.0 diff --git a/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewVersion.yaml b/src/WinGetUtilInterop.UnitTests/TestCollateral/PackageTestNewVersion.yaml @@ -0,0 +1,18 @@ +PackageIdentifier: Test.Test +PackageVersion: 2.0 +PackageName: Test +Publisher: Test +PackageUrl: https://test.com +License: Test. +LicenseUrl: https://test.com +ShortDescription: A test +Installers: +- Architecture: x64 + InstallerUrl: https://test.com/installer.exe + InstallerType: exe + InstallerSwitches: + Silent: /silent + InstallerSha256: 00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF +PackageLocale: en-US +ManifestType: singleton +ManifestVersion: 1.0.0 diff --git a/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj b/src/WinGetUtilInterop.UnitTests/WinGetUtilInterop.UnitTests.csproj @@ -2,6 +2,7 @@ <PropertyGroup> <TargetFramework>net6.0</TargetFramework> + <Platforms>x64;x86</Platforms> </PropertyGroup> <ItemGroup> @@ -14,10 +15,22 @@ <PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" /> <PackageReference Include="coverlet.collector" Version="1.2.0" /> + <PackageReference Include="StyleCop.Analyzers" Version="1.1.118"> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <AdditionalFiles Include="..\stylecop.json" Link="stylecop.json" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\WinGetUtilInterop\WinGetUtilInterop.csproj" /> + <ProjectReference Include="..\WinGetUtil\WinGetUtil.vcxproj" > + <OutputItemType>Content</OutputItemType> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + <ReferenceOutputAssembly>True</ReferenceOutputAssembly> + </ProjectReference> </ItemGroup> <ItemGroup> @@ -30,6 +43,15 @@ <None Update="TestCollateral\DifferentId.yaml"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> + <None Update="TestCollateral\PackageTestNewName.yaml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Update="TestCollateral\PackageTestNewVersion.yaml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Update="TestCollateral\PackageTest.yaml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> <None Update="TestCollateral\OneInstaller.yaml"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> diff --git a/src/WinGetUtilInterop/Api/WinGetFactory.cs b/src/WinGetUtilInterop/Api/WinGetFactory.cs @@ -0,0 +1,208 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetFactory.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Factory methods. + /// </summary> + public sealed class WinGetFactory : IWinGetFactory + { + private const uint IndexLatestVersion = unchecked((uint)-1); + + /// <inheritdoc/> + public IWinGetSQLiteIndex SQLiteIndexCreate(string indexFile, uint majorVersion, uint minorVersion) + { + try + { + WinGetSQLiteIndexCreate( + indexFile, + majorVersion, + minorVersion, + out IntPtr index); + return new WinGetSQLiteIndex(index); + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public IWinGetSQLiteIndex SQLiteIndexCreateLatestVersion(string indexFile) + { + return this.SQLiteIndexCreate(indexFile, IndexLatestVersion, IndexLatestVersion); + } + + /// <inheritdoc/> + public IWinGetSQLiteIndex SQLiteIndexOpen(string indexFile) + { + try + { + WinGetSQLiteIndexOpen(indexFile, out IntPtr index); + return new WinGetSQLiteIndex(index); + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public IWinGetLogging LoggingInit(string indexLogFile) + { + try + { + WinGetLoggingInit(indexLogFile); + return new WinGetLogging(indexLogFile); + } + catch (Exception e) + { + throw new WinGetLoggingException(e); + } + } + + /// <inheritdoc/> + public CreateManifestResult CreateManifest(string manifestPath, string mergedManifestPath, WinGetCreateManifestOption option) + { + try + { + bool succeeded = false; + IntPtr manifestHandle = IntPtr.Zero; + string failureOrWarningMessage = null; + WinGetCreateManifest( + manifestPath, + out succeeded, + out manifestHandle, + out failureOrWarningMessage, + mergedManifestPath, + option); + + // WinGetUtil uses exceptions for passing warning messages. When a warning is detected, + // WinGetUtil will throw so a manifest handle will not be returned, in this case, we try + // to create the manifest handle without any validation. + if (succeeded && manifestHandle == IntPtr.Zero) + { + WinGetCreateManifest( + manifestPath, + out succeeded, + out manifestHandle, + out string failureNotExpected, + null, + WinGetCreateManifestOption.NoValidation); + } + + return new CreateManifestResult(succeeded, failureOrWarningMessage, succeeded ? new WinGetManifest(manifestHandle) : null); + } + catch (Exception e) + { + throw new WinGetManifestException(e); + } + } + + /// <summary> + /// Begins the installer metadata collection process. + /// </summary> + /// <param name="input">input.</param> + /// <param name="logFilePath">Log file path.</param> + /// <param name="options">An enum of type <see cref="WinGetBeginInstallerMetadataCollectionOptions"/>.</param> + /// <param name="outputFilePath">Metadata output file path.</param> + /// <returns>IWinGetInstallerMetadata with the handle to the installer metadata collection.</returns> + public IWinGetInstallerMetadata BeginInstallerMetadataCollection( + string input, + string logFilePath, + WinGetBeginInstallerMetadataCollectionOptions options, + string outputFilePath) + { + try + { + IntPtr collectionHandle = IntPtr.Zero; + WinGetBeginInstallerMetadataCollection( + input, + logFilePath, + options, + out collectionHandle); + + return new WinGetInstallerMetadata(collectionHandle, outputFilePath); + } + catch (Exception e) + { + throw new WinGetInstallerMetadataException(e); + } + } + + /// <summary> + /// Creates a new index file at filePath with the given version. + /// </summary> + /// <param name="filePath">File path to create index.</param> + /// <param name="majorVersion">Major version.</param> + /// <param name="minorVersion">Minor version.</param> + /// <param name="index">Out handle of the index.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexCreate(string filePath, uint majorVersion, uint minorVersion, out IntPtr index); + + /// <summary> + /// Opens an existing index at filePath. + /// </summary> + /// <param name="filePath">File path of index.</param> + /// <param name="index">Out handle of the index.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexOpen(string filePath, out IntPtr index); + + /// <summary> + /// Initializes the logging infrastructure. + /// </summary> + /// <param name="logPath">Log path.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetLoggingInit(string logPath); + + /// <summary> + /// Creates a manifest with schema or semantic validation if needed. + /// </summary> + /// <param name="inputPath">Path of manifest.</param> + /// <param name="succeeded">If create manifest succeeded.</param> + /// <param name="manifestHandle">Out bool is validation succeeded.</param> + /// <param name="failureMessage">Out string failure message, if any.</param> + /// <param name="mergedManifestPath">Path to merged manifest file. Empty means no merged manifest needed.</param> + /// <param name="option">Validate manifest option.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetCreateManifest( + string inputPath, + [MarshalAs(UnmanagedType.U1)] out bool succeeded, + out IntPtr manifestHandle, + [MarshalAs(UnmanagedType.BStr)] out string failureMessage, + string mergedManifestPath, + WinGetCreateManifestOption option); + + /// <summary> + /// Begins the installer metadata collection process. By default, inputJSON is expected to be a JSON string. + /// See the WinGetBeginInstallerMetadataCollectionOptions for more options. + /// logFilePath optionally specifies where to write the log file for the collection operation. + /// The collectionHandle is owned by the caller and must be passed to WinGetCompleteInstallerMetadataCollection to free it. + /// </summary> + /// <param name="inputJSON">Input Json.</param> + /// <param name="logFilePath">Log file path.</param> + /// <param name="options">An enum of type <see cref="WinGetBeginInstallerMetadataCollectionOptions"/>.</param> + /// <param name="collectionHandle">Collection handle.</param> + /// <returns>Metadata Collection handle.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetBeginInstallerMetadataCollection( + string inputJSON, + string logFilePath, + WinGetBeginInstallerMetadataCollectionOptions options, + out IntPtr collectionHandle); + } +} diff --git a/src/WinGetUtilInterop/Api/WinGetInstallerMetadata.cs b/src/WinGetUtilInterop/Api/WinGetInstallerMetadata.cs @@ -0,0 +1,96 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetInstallerMetadata.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Wrapper for WinGetInstallerMetadata operations. + /// </summary> + public sealed class WinGetInstallerMetadata : IWinGetInstallerMetadata + { + private readonly string outputFilePath; + private IntPtr collectionHandle; + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetInstallerMetadata"/> class. + /// </summary> + /// <param name="collectionHandle">Collection handle.</param> + /// <param name="outputFilePath">Output file path.</param> + internal WinGetInstallerMetadata(IntPtr collectionHandle, string outputFilePath) + { + this.collectionHandle = collectionHandle; + this.outputFilePath = outputFilePath; + } + + /// <inheritdoc /> + public void Complete(bool abandon = false) + { + try + { + this.CompleteInternal(abandon ? + WinGetCompleteInstallerMetadataCollectionOptions.WinGetCompleteInstallerMetadataCollectionOption_Abandon : + WinGetCompleteInstallerMetadataCollectionOptions.WinGetCompleteInstallerMetadataCollectionOption_None); + this.collectionHandle = IntPtr.Zero; + } + catch (Exception e) + { + throw new WinGetInstallerMetadataException(e); + } + } + + /// <summary> + /// Dispose method. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Dispose method to free the manifest handle. + /// </summary> + /// <param name="disposing">Bool value indicating if Dispose is being run.</param> + public void Dispose(bool disposing) + { + if (disposing) + { + this.Complete(true); + } + } + + /// <summary> + /// Completes the installer metadata collection process, Always frees the collectionHandle. + /// WinGetCompleteInstallerMetadataCollection must be called exactly once for each call to WinGetBeginInstallerMetadataCollection. + /// </summary> + /// <param name="collectionHandle">Collection Handle.</param> + /// <param name="outputFilePath">Metadata output file path.</param> + /// <param name="options">An enum of type <see cref="WinGetBeginInstallerMetadataCollectionOptions"/>.</param> + /// <returns>Metadata collection handle.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetCompleteInstallerMetadataCollection( + IntPtr collectionHandle, + string outputFilePath, + WinGetCompleteInstallerMetadataCollectionOptions options); + + private void CompleteInternal(WinGetCompleteInstallerMetadataCollectionOptions options) + { + if (this.collectionHandle != IntPtr.Zero) + { + WinGetCompleteInstallerMetadataCollection( + this.collectionHandle, + this.outputFilePath, + options); + } + } + } +} diff --git a/src/WinGetUtilInterop/Api/WinGetLogging.cs b/src/WinGetUtilInterop/Api/WinGetLogging.cs @@ -0,0 +1,68 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetLogging.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.IO; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Wrapper class around WinGetUtil log native implementation. + /// For dll entry points are defined here: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + public sealed class WinGetLogging : IWinGetLogging + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetLogging"/> class. + /// </summary> + /// <param name="logFile">Open index file. Must be closed at dispose.</param> + internal WinGetLogging(string logFile) + { + this.LogFile = logFile; + } + + /// <summary> + /// Gets log file. + /// </summary> + public string LogFile { get; private set; } + + /// <summary> + /// Dispose method. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Dispose method to dispose the Git desktop process runner. + /// </summary> + /// <param name="disposing">Bool value indicating if Dispose is being run.</param> + public void Dispose(bool disposing) + { + if (disposing) + { + if (File.Exists(this.LogFile)) + { + WinGetLoggingTerm(this.LogFile); + } + } + } + + //// <summary> + //// Closes the index log file. + //// </summary> + //// <param name="logPath">Log path to close. Null for all.</param> + //// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetLoggingTerm(string logPath); + } +} diff --git a/src/WinGetUtilInterop/Api/WinGetManifest.cs b/src/WinGetUtilInterop/Api/WinGetManifest.cs @@ -0,0 +1,110 @@ +// ----------------------------------------------------------------------- +// <copyright file="WinGetManifest.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Wrapper class around WinGetUtil manifest native implementation. + /// For dll entry points are defined here: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + public sealed class WinGetManifest : IWinGetManifest + { + private readonly IntPtr manifestHandle; + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetManifest"/> class. + /// </summary> + /// <param name="manifestHandle">Handle of the manifest.</param> + /// <param name="loggingContext">Logging Context.</param> + internal WinGetManifest(IntPtr manifestHandle) + { + this.manifestHandle = manifestHandle; + } + + /// <inheritdoc/> + public ManifestValidationResult ValidateManifestV3( + IntPtr indexHandle, + WinGetValidateManifestOptionV2 option, + WinGetValidateManifestOperationType operationType) + { + try + { + WinGetValidateManifestV3( + this.manifestHandle, + indexHandle, + out WinGetValidateManifestResult result, + out string failureOrWarningMessage, + option, + operationType); + + return new ManifestValidationResult(result == WinGetValidateManifestResult.Success, failureOrWarningMessage, result); + } + catch (Exception e) + { + throw new WinGetManifestException(e); + } + } + + /// <summary> + /// Dispose method. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Dispose method to free the manifest handle. + /// </summary> + /// <param name="disposing">Bool value indicating if Dispose is being run.</param> + public void Dispose(bool disposing) + { + if (disposing) + { + if (this.manifestHandle != IntPtr.Zero) + { + WinGetCloseManifest(this.manifestHandle); + } + } + } + + /// <summary> + /// Closes the manifest handle. + /// </summary> + /// <param name="manifest">Handle of the manifest.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetCloseManifest(IntPtr manifest); + + /// <summary> + /// Validates a given manifest. Returns an enum for validation result and + /// a string representing validation errors if validation failed. + /// </summary> + /// <param name="manifestHandle">Handle of the manifest.</param> + /// <param name="indexHandle">Handle of the index.</param> + /// <param name="result">Out validation result.</param> + /// <param name="failureMessage">Out string failure message, if any.</param> + /// <param name="option">Validate manifest option.</param> + /// <param name="operationType">Validate manifest operation type.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetValidateManifestV3( + IntPtr manifestHandle, + IntPtr indexHandle, + out WinGetValidateManifestResult result, + [MarshalAs(UnmanagedType.BStr)] out string failureMessage, + WinGetValidateManifestOptionV2 option, + WinGetValidateManifestOperationType operationType); + } +} diff --git a/src/WinGetUtilInterop/Api/WinGetSQLiteIndex.cs b/src/WinGetUtilInterop/Api/WinGetSQLiteIndex.cs @@ -0,0 +1,200 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetSQLiteIndex.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Wrapper class for SQLite index operations. + /// </summary> + public sealed class WinGetSQLiteIndex : IWinGetSQLiteIndex + { + private readonly IntPtr indexHandle; + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetSQLiteIndex"/> class. + /// </summary> + /// <param name="indexHandle">Handle of the index.</param> + internal WinGetSQLiteIndex(IntPtr indexHandle) + { + this.indexHandle = indexHandle; + } + + /// <inheritdoc/> + public void AddManifest(string manifestPath, string relativePath) + { + try + { + WinGetSQLiteIndexAddManifest(this.indexHandle, manifestPath, relativePath); + return; + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public bool UpdateManifest(string manifestPath, string relativePath) + { + try + { + // For now, modifying a manifest implies that the file didn't got moved in the repository. So only + // contents of the file are modified. However, in the future we might support moving which requires + // oldManifestPath, oldRelativePath, newManifestPath and oldManifestPath. + WinGetSQLiteIndexUpdateManifest( + this.indexHandle, + manifestPath, + relativePath, + out bool indexModified); + return indexModified; + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public void RemoveManifest(string manifestPath, string relativePath) + { + try + { + WinGetSQLiteIndexRemoveManifest(this.indexHandle, manifestPath, relativePath); + return; + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public void PrepareForPackaging() + { + try + { + WinGetSQLiteIndexPrepareForPackaging(this.indexHandle); + return; + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public bool IsIndexConsistent() + { + try + { + WinGetSQLiteIndexCheckConsistency(this.indexHandle, out bool indexModified); + return indexModified; + } + catch (Exception e) + { + throw new WinGetSQLiteIndexException(e); + } + } + + /// <inheritdoc/> + public IntPtr GetIndexHandle() + { + return this.indexHandle; + } + + /// <summary> + /// Dispose method. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Dispose method to free the sqlite index handle. + /// </summary> + /// <param name="disposing">Bool value indicating if Dispose is being run.</param> + public void Dispose(bool disposing) + { + if (disposing) + { + if (this.indexHandle != IntPtr.Zero) + { + WinGetSQLiteIndexClose(this.indexHandle); + } + } + } + + /// <summary> + /// Closes the index. + /// </summary> + /// <param name="index">Handle of the index.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexClose(IntPtr index); + + /// <summary> + /// Adds the manifest at the repository relative path to the index. + /// If the function succeeds, the manifest has been added. + /// </summary> + /// <param name="index">Handle of the index.</param> + /// <param name="manifestPath">Manifest to add.</param> + /// <param name="relativePath">Path of the manifest in the container.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexAddManifest(IntPtr index, string manifestPath, string relativePath); + + /// <summary> + /// Updates the manifest at the repository relative path in the index. + /// The out value indicates whether the index was modified by the function. + /// </summary> + /// <param name="index">Handle of the index.</param> + /// <param name="manifestPath">Old manifest path.</param> + /// <param name="relativePath">Old relative path in the container.</param> + /// <param name="indexModified">Out bool if the index is modified.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexUpdateManifest( + IntPtr index, + string manifestPath, + string relativePath, + [MarshalAs(UnmanagedType.U1)] out bool indexModified); + + /// <summary> + /// Removes the manifest at the repository relative path from the index. + /// </summary> + /// <param name="index">Index handle.</param> + /// <param name="manifestPath">Manifest path to remove.</param> + /// <param name="relativePath">Relative path in the container.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexRemoveManifest(IntPtr index, string manifestPath, string relativePath); + + /// <summary> + /// Removes data that is no longer needed for an index that is to be published. + /// </summary> + /// <param name="index">Index handle.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexPrepareForPackaging(IntPtr index); + + /// <summary> + /// Checks the index for consistency, ensuring that at a minimum all referenced rows actually exist. + /// </summary> + /// <param name="index">Index handle.</param> + /// <param name="succeeded">Does the consistency check succeeded.</param> + /// <returns>HRESULT.</returns> + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetSQLiteIndexCheckConsistency(IntPtr index, [MarshalAs(UnmanagedType.U1)] out bool succeeded); + } +} diff --git a/src/WinGetUtilInterop/Api/WinGetUtilities.cs b/src/WinGetUtilInterop/Api/WinGetUtilities.cs @@ -0,0 +1,63 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetUtilities.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Api +{ + using System; + using System.Runtime.InteropServices; + using Microsoft.WinGetUtil.Common; + using Microsoft.WinGetUtil.Exceptions; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Download wrapper. + /// </summary> + public sealed class WinGetUtilities : IWinGetUtilities + { + /// <inheritdoc/> + public string Download(string url, string filePath, bool enableLogging = false, string logFilePath = null) + { + IWinGetLogging log = null; + if (enableLogging) + { + if (string.IsNullOrWhiteSpace(logFilePath)) + { + throw new ArgumentNullException($"Download logging is enabled and log file path `{logFilePath}` is not provided."); + } + + log = new WinGetFactory().LoggingInit(logFilePath); + } + + try + { + byte[] sha256Hash = new byte[32]; + WinGetDownload(url, filePath, sha256Hash, (uint)sha256Hash.Length); + return BitConverter.ToString(sha256Hash).Replace("-", string.Empty); + } + catch (Exception e) + { + throw new WinGetDownloadException(e); + } + finally + { + log?.Dispose(); + } + } + + /// <inheritdoc/> + public int CompareVersions(string version1, string version2) + { + WinGetCompareVersions(version1, version2, out int result); + return result; + } + + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetDownload(string url, string filePath, [MarshalAs(UnmanagedType.LPArray)] byte[] sha26Hash, uint sha256HashLength); + + [DllImport(Constants.DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr WinGetCompareVersions(string version1, string version2, [MarshalAs(UnmanagedType.U4)] out int comparisonResult); + } +} diff --git a/src/WinGetUtilInterop/Common/Constants.cs b/src/WinGetUtilInterop/Common/Constants.cs @@ -0,0 +1,19 @@ +// ----------------------------------------------------------------------------- +// <copyright file="Constants.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Common +{ + /// <summary> + /// Constants. + /// </summary> + public static class Constants + { + /// <summary> + /// Dll name. + /// </summary> + public const string DllName = "WinGetUtil.dll"; + } +} diff --git a/src/WinGetUtilInterop/Common/CreateManifestResult.cs b/src/WinGetUtilInterop/Common/CreateManifestResult.cs @@ -0,0 +1,69 @@ +// ----------------------------------------------------------------------------- +// <copyright file="CreateManifestResult.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Common +{ + using System; + using Microsoft.WinGetUtil.Interfaces; + + /// <summary> + /// Class representing create manifest result. + /// </summary> + public class CreateManifestResult : IDisposable + { + /// <summary> + /// Initializes a new instance of the <see cref="CreateManifestResult"/> class. + /// </summary> + /// <param name="isValid">Is manifest valid.</param> + /// <param name="message">Warning or failure validation message.</param> + /// <param name="manifestHandle">Created manifest handle if succeeded.</param> + public CreateManifestResult(bool isValid, string message, IWinGetManifest manifestHandle) + { + this.IsValid = isValid; + this.Message = message; + this.ManifestHandle = manifestHandle; + } + + /// <summary> + /// Gets a value indicating whether the manifest is valid. + /// </summary> + public bool IsValid { get; } = false; + + /// <summary> + /// Gets warning or failure validation message. + /// </summary> + public string Message { get; } = null; + + /// <summary> + /// Gets created manifest handle if succeeded. + /// </summary> + public IWinGetManifest ManifestHandle { get; } = null; + + /// <summary> + /// Dispose method. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Dispose method to free the manifest handle. + /// </summary> + /// <param name="disposing">Bool value indicating if Dispose is being run.</param> + public void Dispose(bool disposing) + { + if (disposing) + { + if (this.ManifestHandle != null) + { + this.ManifestHandle.Dispose(); + } + } + } + } +} diff --git a/src/WinGetUtilInterop/Common/Enums.cs b/src/WinGetUtilInterop/Common/Enums.cs @@ -0,0 +1,197 @@ +// ----------------------------------------------------------------------------- +// <copyright file="Enums.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Common +{ + using System; + + /// <summary> + /// Options for creating a manifest for validation. + /// Must be in sync with WinGetCreateManifestOption at: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + [Flags] + public enum WinGetCreateManifestOption + { + /// <summary> + /// Just create the manifest without any validation + /// </summary> + NoValidation = 0, + + /// <summary> + /// Only validate against json schema + /// </summary> + SchemaValidation = 0x1, + + /// <summary> + /// Validate against schema and also perform semantic validation + /// </summary> + SchemaAndSemanticValidation = 0x2, + + // Below options are additional validation behaviors if needed + + /// <summary> + /// Return error on manifest fields that require verified publishers, used during semantic validation + /// </summary> + ReturnErrorOnVerifiedPublisherFields = 0x1000, + } + + /// <summary> + /// Options for validating a manifest. + /// Must be in sync with WinGetValidateManifestOptionV2 at: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + [Flags] + public enum WinGetValidateManifestOptionV2 + { + /// <summary> + /// No validation, caller will get E_INVALIDARG + /// </summary> + None = 0, + + /// <summary> + /// Dependencies validation against index + /// </summary> + DependenciesValidation = 0x1, + + /// <summary> + /// Arp version validation against index + /// </summary> + ArpVersionValidation = 0x2, + + /// <summary> + /// Installer validation + /// </summary> + InstallerValidation = 0x4, + } + + /// <summary> + /// Operation type for validating a manifest. + /// Must be in sync with WinGetValidateManifestOperationType at: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + public enum WinGetValidateManifestOperationType + { + /// <summary> + /// Add + /// </summary> + OperationTypeAdd = 0, + + /// <summary> + /// Update + /// </summary> + OperationTypeUpdate = 1, + + /// <summary> + /// Delete + /// </summary> + OperationTypeDelete = 2, + } + + /// <summary> + /// Manifest validation result. + /// Must be in sync with WinGetValidateManifestResult at: + /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. + /// </summary> + [Flags] + public enum WinGetValidateManifestResult + { + /// <summary> + /// Manifest validation success. + /// </summary> + Success = 0, + + // Each validation step should have an enum for corresponding failure. + + /// <summary> + /// Dependencies validation failure. + /// </summary> + DependenciesValidationFailure = 0x1, + + /// <summary> + /// Arp version validation failure. + /// </summary> + ArpVersionValidationFailure = 0x2, + + /// <summary> + /// Installer validation failure. + /// </summary> + InstallerValidationFailure = 0x4, + + // Dependencies validation result. + + /// <summary> + /// Single Manifest package has dependencies. + /// </summary> + SingleManifestPackageHasDependencies = 0x10000, + + /// <summary> + /// Multi manifest package has dependencies. + /// </summary> + MultiManifestPackageHasDependencies = 0x20000, + + /// <summary> + /// Missing manifest dependencies node. + /// </summary> + MissingManifestDependenciesNode = 0x40000, + + /// <summary> + /// No Suitable min version found for manifest. + /// </summary> + NoSuitableMinVersionDependency = 0x80000, + + /// <summary> + /// Validation encountered a loop during dependencies validation. + /// </summary> + FoundDependencyLoop = 0x100000, + + // Internal error meaning validation does not complete as desired. + + /// <summary> + /// Manifest validation internal error. + /// </summary> + InternalError = 0x1000, + } + + /// <summary> + /// Option flags for WinGetBeginInstallerMetadataCollection. + /// </summary> + [Flags] + public enum WinGetBeginInstallerMetadataCollectionOptions + { + /// <summary> + /// None. + /// </summary> + WinGetBeginInstallerMetadataCollectionOption_None = 0, + + /// <summary> + /// The inputJSON is a local file path, not a JSON string. + /// </summary> + WinGetBeginInstallerMetadataCollectionOption_InputIsFilePath = 0x1, + + /// <summary> + /// The inputJSON is a remote URI, not a JSON string. + /// </summary> + WinGetBeginInstallerMetadataCollectionOption_InputIsURI = 0x2, + } + + /// <summary> + /// Option flags for WinGetCompleteInstallerMetadataCollection. + /// </summary> + [Flags] + public enum WinGetCompleteInstallerMetadataCollectionOptions + { + /// <summary> + /// Metadata collection option none. + /// </summary> + WinGetCompleteInstallerMetadataCollectionOption_None = 0, + + /// <summary> + /// Complete will simply free the collection handle without doing any additional work. + /// </summary> + WinGetCompleteInstallerMetadataCollectionOption_Abandon = 0x1, + } +} diff --git a/src/WinGetUtilInterop/Common/ManifestValidationResult.cs b/src/WinGetUtilInterop/Common/ManifestValidationResult.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ManifestValidationResult.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Common +{ + /// <summary> + /// Manifest validation result. + /// </summary> + public class ManifestValidationResult + { + /// <summary> + /// Initializes a new instance of the <see cref="ManifestValidationResult"/> class. + /// </summary> + /// <param name="isValid">A value indicating whether manifest is valid.</param> + /// <param name="message">Error message.</param> + /// <param name="resultCode">Result code.</param> + public ManifestValidationResult(bool isValid, string message, WinGetValidateManifestResult resultCode) + { + this.IsValid = isValid; + this.Message = message; + this.ResultCode = resultCode; + } + + /// <summary> + /// Gets a value indicating whether manifest is valid. + /// </summary> + public bool IsValid { get; private set; } + + /// <summary> + /// Gets the message associated with the validation. + /// </summary> + public string Message { get; private set; } + + /// <summary> + /// Gets the result code associate with the validation. + /// </summary> + public WinGetValidateManifestResult ResultCode { get; private set; } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetDownloadException.cs b/src/WinGetUtilInterop/Exceptions/WinGetDownloadException.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetDownloadException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Exceptions +{ + using System; + + /// <summary> + /// Exception for download operations. + /// </summary> + public class WinGetDownloadException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetDownloadException"/> class. + /// </summary> + public WinGetDownloadException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetDownloadException"/> class. + /// </summary> + /// <param name="message">Message.</param> + public WinGetDownloadException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetDownloadException"/> class. + /// </summary> + /// <param name="inner">Inner exception.</param> + public WinGetDownloadException(Exception inner) + : base(string.Empty, inner) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetDownloadException"/> class. + /// </summary> + /// <param name="message">Message.</param> + /// <param name="inner">Inner exception.</param> + public WinGetDownloadException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetInstallerMetadataException.cs b/src/WinGetUtilInterop/Exceptions/WinGetInstallerMetadataException.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetInstallerMetadataException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Exceptions +{ + using System; + + /// <summary> + /// Exception for installer metadata operations. + /// </summary> + public class WinGetInstallerMetadataException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetInstallerMetadataException"/> class. + /// </summary> + public WinGetInstallerMetadataException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetInstallerMetadataException"/> class. + /// </summary> + /// <param name="message">Message.</param> + public WinGetInstallerMetadataException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetInstallerMetadataException"/> class. + /// </summary> + /// <param name="inner">Inner exception.</param> + public WinGetInstallerMetadataException(Exception inner) + : base(string.Empty, inner) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetInstallerMetadataException"/> class. + /// </summary> + /// <param name="message">Message.</param> + /// <param name="inner">Inner exception.</param> + public WinGetInstallerMetadataException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetLoggingException.cs b/src/WinGetUtilInterop/Exceptions/WinGetLoggingException.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetLoggingException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Exceptions +{ + using System; + + /// <summary> + /// Exception for logging operations. + /// </summary> + public class WinGetLoggingException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetLoggingException"/> class. + /// </summary> + public WinGetLoggingException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetLoggingException"/> class. + /// </summary> + /// <param name="message">Message.</param> + public WinGetLoggingException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetLoggingException"/> class. + /// </summary> + /// <param name="inner">Inner exception.</param> + public WinGetLoggingException(Exception inner) + : base(string.Empty, inner) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetLoggingException"/> class. + /// </summary> + /// <param name="message">Message.</param> + /// <param name="inner">Inner exception.</param> + public WinGetLoggingException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetManifestException.cs b/src/WinGetUtilInterop/Exceptions/WinGetManifestException.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetManifestException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Exceptions +{ + using System; + + /// <summary> + /// Exception for manifest operations. + /// </summary> + public class WinGetManifestException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetManifestException"/> class. + /// </summary> + public WinGetManifestException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetManifestException"/> class. + /// </summary> + /// <param name="message">Message.</param> + public WinGetManifestException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetManifestException"/> class. + /// </summary> + /// <param name="inner">Inner exception.</param> + public WinGetManifestException(Exception inner) + : base(string.Empty, inner) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetManifestException"/> class. + /// </summary> + /// <param name="message">Message.</param> + /// <param name="inner">Inner exception.</param> + public WinGetManifestException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetSQLiteIndexException.cs b/src/WinGetUtilInterop/Exceptions/WinGetSQLiteIndexException.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="WinGetSQLiteIndexException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Exceptions +{ + using System; + + /// <summary> + /// Exception for SQLite index operations. + /// </summary> + public class WinGetSQLiteIndexException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="WinGetSQLiteIndexException"/> class. + /// </summary> + public WinGetSQLiteIndexException() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetSQLiteIndexException"/> class. + /// </summary> + /// <param name="message">Message.</param> + public WinGetSQLiteIndexException(string message) + : base(message) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetSQLiteIndexException"/> class. + /// </summary> + /// <param name="inner">Inner exception.</param> + public WinGetSQLiteIndexException(Exception inner) + : base(string.Empty, inner) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="WinGetSQLiteIndexException"/> class. + /// </summary> + /// <param name="message">Message.</param> + /// <param name="inner">Inner exception.</param> + public WinGetSQLiteIndexException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/WinGetUtilInterop/Exceptions/WinGetUtilIndexException.cs b/src/WinGetUtilInterop/Exceptions/WinGetUtilIndexException.cs @@ -1,48 +0,0 @@ -// ----------------------------------------------------------------------- -// <copyright file="WinGetUtilSQLiteIndexException.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. -// </copyright> -// ----------------------------------------------------------------------- - -namespace WinGetUtilInterop.Exceptions -{ - using System; - - public class WinGetUtilIndexException : Exception - { - /// <summary> - /// Initializes a new instance of the <see cref="WinGetUtilIndexException"/> class. - /// </summary> - public WinGetUtilIndexException() - { - } - - /// <summary> - /// Initializes a new instance of the <see cref="WinGetUtilIndexException"/> class. - /// </summary> - /// <param name="message">Message.</param> - public WinGetUtilIndexException(string message) - : base(message) - { - } - - /// <summary> - /// Initializes a new instance of the <see cref="WinGetUtilIndexException"/> class. - /// </summary> - /// <param name="inner">Inner exception.</param> - public WinGetUtilIndexException(Exception inner) - : base(string.Empty, inner) - { - } - - /// <summary> - /// Initializes a new instance of the <see cref="WinGetUtilIndexException"/> class. - /// </summary> - /// <param name="message">Message.</param> - /// <param name="inner">Inner exception.</param> - public WinGetUtilIndexException(string message, Exception inner) - : base(message, inner) - { - } - } -} diff --git a/src/WinGetUtilInterop/Helpers/WinGetUtilIndex.cs b/src/WinGetUtilInterop/Helpers/WinGetUtilIndex.cs @@ -1,278 +0,0 @@ -// ----------------------------------------------------------------------- -// <copyright file="WinGetUtilWrapperSQLiteIndex.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. -// </copyright> -// ----------------------------------------------------------------------- - -namespace WinGetUtilInterop.Helpers -{ - using System; - using System.Runtime.InteropServices; - using Microsoft.WinGetUtil.Interfaces; - using WinGetUtilInterop.Exceptions; - - public class WinGetUtilIndex : IWinGetUtilIndex - { - private const string WinGetUtilDll = "WinGetUtil.dll"; - private const uint IndexLatestVersion = unchecked((uint)-1); - - /// <summary> - /// WinGet Index latest version. - /// </summary> - public const uint WinGetIndexLatestVersion = unchecked((uint)-1); - - private readonly IntPtr indexHandle; - - /// <summary> - /// Initializes a new instance of the <see cref="WinGetUtilIndex"/> class. - /// </summary> - /// <param name="indexHandle">Handle of the index.</param> - /// <param name="loggingContext">Logging Context.</param> - private WinGetUtilIndex(IntPtr indexHandle) - { - this.indexHandle = indexHandle; - } - - /// <summary> - /// Creates a new index file in the specified path. - /// </summary> - /// <param name="indexFile">Index file to create.</param> - /// <param name="majorVersion">Major version.</param> - /// <param name="minorVersion">Minor version.</param> - /// <param name="loggingContext">Logging Context.</param> - /// <returns>Instance of IWinGetUtilSQLiteIndex.</returns> - public static IWinGetUtilIndex Create(string indexFile, uint majorVersion, uint minorVersion) - { - try - { - WinGetSQLiteIndexCreate( - indexFile, - majorVersion, - minorVersion, - out IntPtr index); - return new WinGetUtilIndex(index); - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <summary> - /// Creates a new index file in the specified path. - /// </summary> - /// <param name="indexFile">Index file to create.</param> - /// <returns>Instance of IWinGetUtilSQLiteIndex.</returns> - public static IWinGetUtilIndex CreateLatestVersion(string indexFile) - { - return Create(indexFile, IndexLatestVersion, IndexLatestVersion); - } - - /// <summary> - /// Open the index file. - /// </summary> - /// <param name="indexFile">Index file to open.</param> - /// <returns>Instance of IWinGetUtilSQLiteIndex.</returns> - public static IWinGetUtilIndex Open(string indexFile) - { - try - { - WinGetSQLiteIndexOpen(indexFile, out IntPtr index); - return new WinGetUtilIndex(index); - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public void AddManifest(string manifestPath, string relativePath) - { - try - { - WinGetSQLiteIndexAddManifest(this.indexHandle, manifestPath, relativePath); - return; - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public bool UpdateManifest(string manifestPath, string relativePath) - { - try - { - // For now, modifying a manifest implies that the file didn't got moved in the repository. So only - // contents of the file are modified. However, in the future we might support moving which requires - // oldManifestPath, oldRelativePath, newManifestPath and oldManifestPath. - WinGetSQLiteIndexUpdateManifest( - this.indexHandle, - manifestPath, - relativePath, - out bool indexModified); - return indexModified; - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public void RemoveManifest(string manifestPath, string relativePath) - { - try - { - WinGetSQLiteIndexRemoveManifest(this.indexHandle, manifestPath, relativePath); - return; - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public void PrepareForPackaging() - { - try - { - WinGetSQLiteIndexPrepareForPackaging(this.indexHandle); - return; - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public bool IsIndexConsistent() - { - try - { - WinGetSQLiteIndexCheckConsistency(this.indexHandle, out bool indexModified); - return indexModified; - } - catch (Exception e) - { - throw new WinGetUtilIndexException(e); - } - } - - /// <inheritdoc/> - public IntPtr GetIndexHandle() - { - return this.indexHandle; - } - - /// <summary> - /// Dispose method. - /// </summary> - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Dispose method to free the sqlite index handle. - /// </summary> - /// <param name="disposing">Bool value indicating if Dispose is being run.</param> - public void Dispose(bool disposing) - { - if (disposing) - { - if (this.indexHandle != null) - { - WinGetSQLiteIndexClose(this.indexHandle); - } - } - } - - /// <summary> - /// Creates a new index file at filePath with the given version. - /// </summary> - /// <param name="filePath">File path to create index.</param> - /// <param name="majorVersion">Major version.</param> - /// <param name="minorVersion">Minor version.</param> - /// <param name="index">Out handle of the index.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexCreate(string filePath, uint majorVersion, uint minorVersion, out IntPtr index); - - /// <summary> - /// Opens an existing index at filePath. - /// </summary> - /// <param name="filePath">File path of index.</param> - /// <param name="index">Out handle of the index.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexOpen(string filePath, out IntPtr index); - - /// <summary> - /// Closes the index. - /// </summary> - /// <param name="index">Handle of the index.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexClose(IntPtr index); - - /// <summary> - /// Adds the manifest at the repository relative path to the index. - /// If the function succeeds, the manifest has been added. - /// </summary> - /// <param name="index">Handle of the index.</param> - /// <param name="manifestPath">Manifest to add.</param> - /// <param name="relativePath">Path of the manifest in the container.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexAddManifest(IntPtr index, string manifestPath, string relativePath); - - /// <summary> - /// Updates the manifest at the repository relative path in the index. - /// The out value indicates whether the index was modified by the function. - /// </summary> - /// <param name="index">Handle of the index.</param> - /// <param name="manifestPath">Old manifest path.</param> - /// <param name="relativePath">Old relative path in the container.</param> - /// <param name="indexModified">Out bool if the index is modified.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexUpdateManifest( - IntPtr index, - string manifestPath, - string relativePath, - [MarshalAs(UnmanagedType.U1)] out bool indexModified); - - /// <summary> - /// Removes the manifest at the repository relative path from the index. - /// </summary> - /// <param name="index">Index handle.</param> - /// <param name="manifestPath">Manifest path to remove.</param> - /// <param name="relativePath">Relative path in the container.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexRemoveManifest(IntPtr index, string manifestPath, string relativePath); - - /// <summary> - /// Removes data that is no longer needed for an index that is to be published. - /// </summary> - /// <param name="index">Index handle.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexPrepareForPackaging(IntPtr index); - - /// <summary> - /// Checks the index for consistency, ensuring that at a minimum all referenced rows actually exist. - /// </summary> - /// <param name="index">Index handle.</param> - /// <param name="succeeded">Does the consistency check succeeded.</param> - /// <returns>HRESULT.</returns> - [DllImport(WinGetUtilDll, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetSQLiteIndexCheckConsistency(IntPtr index, [MarshalAs(UnmanagedType.U1)] out bool succeeded); - } -} diff --git a/src/WinGetUtilInterop/Helpers/WinGetUtilWrapperManifest.cs b/src/WinGetUtilInterop/Helpers/WinGetUtilWrapperManifest.cs @@ -1,77 +0,0 @@ -// ----------------------------------------------------------------------- -// <copyright file="WinGetUtilWrapperManifest.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------- - -namespace Microsoft.WinGetUtil.Helpers -{ - using System; - using System.Runtime.InteropServices; - - /// <summary> - /// Wrapper class around WinGetUtil manifest native implementation. - /// For dll entry points are defined here: - /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. - /// </summary> - public sealed class WinGetUtilWrapperManifest - { - /// <summary> - /// The error from the installer. - /// Must be in sync with WinGetValidateManifestOption at: - /// https://github.com/microsoft/winget-cli/blob/master/src/WinGetUtil/WinGetUtil.h. - /// </summary> - public enum ValidateManifestOption - { - /// <summary> - /// Default validation behavior. - /// </summary> - Default, - - /// <summary> - /// Schema validation only. - /// </summary> - SchemaValidationOnly, - } - - /// <summary> - /// Validates the manifest is compliant. - /// </summary> - /// <param name="manifestPath">Manifest path.</param> - /// <param name="mergedManifestPath">Merged manifest output path.</param> - /// <param name="option">Desired validate manifest option.</param> - /// <returns>Message from manifest validation.</returns> - public static (bool isValid, string message) ValidateManifest( - string manifestPath, - string mergedManifestPath = null, - ValidateManifestOption option = ValidateManifestOption.Default) - { - WinGetValidateManifestV2( - manifestPath, - out bool succeeded, - out string failureOrWarningMessage, - mergedManifestPath, - option); - - return (succeeded, failureOrWarningMessage); - } - - /// <summary> - /// Validates a given manifest. Returns a bool for validation result and - /// a string representing validation errors if validation failed. - /// </summary> - /// <param name="manifestPath">Path to manifest file.</param> - /// <param name="succeeded">Out bool is validation succeeded.</param> - /// <param name="failureMessage">Out string failure message, if any.</param> - /// <param name="mergedManifestPath">Path to merged manifest file. Empty means no merged manifest needed.</param> - /// <param name="option">Validate manifest option.</param> - /// <returns>HRESULT.</returns> - [DllImport("WinGetUtil.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] - private static extern IntPtr WinGetValidateManifestV2( - string manifestPath, - [MarshalAs(UnmanagedType.U1)] out bool succeeded, - [MarshalAs(UnmanagedType.BStr)] out string failureMessage, - string mergedManifestPath, - ValidateManifestOption option); - } -} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetFactory.cs b/src/WinGetUtilInterop/Interfaces/IWinGetFactory.cs @@ -0,0 +1,55 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetFactory.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + using Microsoft.WinGetUtil.Common; + + /// <summary> + /// Factory methods. + /// </summary> + public interface IWinGetFactory + { + /// <summary> + /// Creates a new index file in the specified path. + /// </summary> + /// <param name="indexFile">Index file to create.</param> + /// <param name="majorVersion">Major version.</param> + /// <param name="minorVersion">Minor version.</param> + /// <returns>Instance of IWinGetSQLiteIndex.</returns> + IWinGetSQLiteIndex SQLiteIndexCreate(string indexFile, uint majorVersion, uint minorVersion); + + /// <summary> + /// Creates a new index file in the specified path. + /// </summary> + /// <param name="indexFile">Index file to create.</param> + /// <returns>Instance of IWinGetSQLiteIndex.</returns> + IWinGetSQLiteIndex SQLiteIndexCreateLatestVersion(string indexFile); + + /// <summary> + /// Open the index file. + /// </summary> + /// <param name="indexFile">Index file to open.</param> + /// <returns>Instance of IWinGetSQLiteIndex.</returns> + IWinGetSQLiteIndex SQLiteIndexOpen(string indexFile); + + /// <summary> + /// Initializes logging. + /// </summary> + /// <param name="logFile">Log index file.</param> + /// <returns>Instance of IWinGetLogging.</returns> + IWinGetLogging LoggingInit(string logFile); + + /// <summary> + /// Validates the manifest is compliant and creates a manifest handle if succeeded. + /// </summary> + /// <param name="manifestPath">Manifest path.</param> + /// <param name="mergedManifestPath">Merged manifest output path.</param> + /// <param name="option">Desired validate manifest option.</param> + /// <returns>The <see cref="CreateManifestResult"/> class.</returns> + CreateManifestResult CreateManifest(string manifestPath, string mergedManifestPath, WinGetCreateManifestOption option); + } +} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetInstallerMetadata.cs b/src/WinGetUtilInterop/Interfaces/IWinGetInstallerMetadata.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetInstallerMetadata.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + using System; + + /// <summary> + /// Interface for installer metadata collection. + /// </summary> + public interface IWinGetInstallerMetadata : IDisposable + { + /// <summary> + /// Completes the installer metadata collection process. + /// </summary> + /// <param name="abandon">True to abandon the operation.</param> + void Complete(bool abandon = false); + } +} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetLogging.cs b/src/WinGetUtilInterop/Interfaces/IWinGetLogging.cs @@ -0,0 +1,17 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetLogging.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + using System; + + /// <summary> + /// Logger interface. + /// </summary> + public interface IWinGetLogging : IDisposable + { + } +} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetManifest.cs b/src/WinGetUtilInterop/Interfaces/IWinGetManifest.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetManifest.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + using System; + using Microsoft.WinGetUtil.Common; + + /// <summary> + /// Interface for Wrapper class around WinGetUtil index modifier native implementation. + /// </summary> + public interface IWinGetManifest : IDisposable + { + /// <summary> + /// Validate the manifest. + /// </summary> + /// <param name="indexHandle">The index handle.</param> + /// <param name="option">Manifest validation option.</param> + /// <param name="operationType">Manifest validation operation type.</param> + /// <returns>Result and message from manifest validation.</returns> + ManifestValidationResult ValidateManifestV3( + IntPtr indexHandle, + WinGetValidateManifestOptionV2 option, + WinGetValidateManifestOperationType operationType); + } +} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetSQLiteIndex.cs b/src/WinGetUtilInterop/Interfaces/IWinGetSQLiteIndex.cs @@ -0,0 +1,55 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetSQLiteIndex.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + using System; + + /// <summary> + /// Interface for index operations. + /// </summary> + public interface IWinGetSQLiteIndex : IDisposable + { + /// <summary> + /// Adds manifest to index. + /// </summary> + /// <param name="manifestPath">Manifest to add.</param> + /// <param name="relativePath">Path of the manifest in the repository.</param> + void AddManifest(string manifestPath, string relativePath); + + /// <summary> + /// Updates manifest in the index. + /// </summary> + /// <param name="manifestPath">Path to manifest to modify.</param> + /// <param name="relativePath">Path of the manifest in the repository.</param> + /// <returns>True if index was modified.</returns> + bool UpdateManifest(string manifestPath, string relativePath); + + /// <summary> + /// Delete manifest from index. + /// </summary> + /// <param name="manifestPath">Path to manifest to modify.</param> + /// <param name="relativePath">Path of the manifest in the repository.</param> + void RemoveManifest(string manifestPath, string relativePath); + + /// <summary> + /// Wrapper for WinGetSQLiteIndexPrepareForPackaging. + /// </summary> + void PrepareForPackaging(); + + /// <summary> + /// Checks the index for consistency, ensuring that at a minimum all referenced rows actually exist. + /// </summary> + /// <returns>Is index consistent.</returns> + bool IsIndexConsistent(); + + /// <summary> + /// Gets the managed index handle. It is used in additional manifest validation that requires an index. + /// </summary> + /// <returns>The managed index handle.</returns> + IntPtr GetIndexHandle(); + } +} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetUtilIndex.cs b/src/WinGetUtilInterop/Interfaces/IWinGetUtilIndex.cs @@ -1,52 +0,0 @@ -// ----------------------------------------------------------------------- -// <copyright file="WinGetUtilWrapperManifest.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------- - -namespace Microsoft.WinGetUtil.Interfaces -{ - using System; - - public interface IWinGetUtilIndex : IDisposable - { - /// <summary> - /// Adds manifest to index. - /// </summary> - /// <param name="manifestPath">Manifest to add.</param> - /// <param name="relativePath">Path of the manifest in the repository.</param> - void AddManifest(string manifestPath, string relativePath); - - /// <summary> - /// Updates manifest in the index. - /// </summary> - /// <param name="manifestPath">Path to manifest to modify.</param> - /// <param name="relativePath">Path of the manifest in the repository.</param> - /// <returns>True if index was modified.</returns> - bool UpdateManifest(string manifestPath, string relativePath); - - /// <summary> - /// Delete manifest from index. - /// </summary> - /// <param name="manifestPath">Path to manifest to modify.</param> - /// <param name="relativePath">Path of the manifest in the repository.</param> - void RemoveManifest(string manifestPath, string relativePath); - - /// <summary> - /// Wrapper for WinGetSQLiteIndexPrepareForPackaging. - /// </summary> - void PrepareForPackaging(); - - /// <summary> - /// Checks the index for consistency, ensuring that at a minimum all referenced rows actually exist. - /// </summary> - /// <returns>Is index consistent.</returns> - bool IsIndexConsistent(); - - /// <summary> - /// Gets the managed index handle. It is used in additional manifest validation that requires an index. - /// </summary> - /// <returns>The managed index handle.</returns> - IntPtr GetIndexHandle(); - } -} diff --git a/src/WinGetUtilInterop/Interfaces/IWinGetUtilities.cs b/src/WinGetUtilInterop/Interfaces/IWinGetUtilities.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IWinGetUtilities.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGetUtil.Interfaces +{ + /// <summary> + /// Winget Util utilities interface. + /// </summary> + public interface IWinGetUtilities + { + /// <summary> + /// Download a file from URL. + /// </summary> + /// <param name="url">Installer url.</param> + /// <param name="filePath">Destination file path.</param> + /// <param name="enableLogging">Enable logging.</param> + /// <param name="logFilePath">Log file path.</param> + /// <returns>SHA256 of the installer.</returns> + string Download(string url, string filePath, bool enableLogging = false, string logFilePath = null); + + /// <summary> + /// Compare two version. + /// </summary> + /// <param name="version1">Version 1.</param> + /// <param name="version2">Version 2.</param> + /// <returns>Integer value indicating the comparison result.</returns> + int CompareVersions(string version1, string version2); + } +} diff --git a/src/WinGetUtilInterop/Manifest/Preview/InstallerSwitches.cs b/src/WinGetUtilInterop/Manifest/Preview/InstallerSwitches.cs @@ -1,13 +1,12 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerSwitches.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.Preview { using System; - using System.Runtime.CompilerServices; /// <summary> /// Class that contains different types of installer switches like Default, Silent and Verbose. diff --git a/src/WinGetUtilInterop/Manifest/Preview/Manifest.cs b/src/WinGetUtilInterop/Manifest/Preview/Manifest.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="Manifest.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.Preview { diff --git a/src/WinGetUtilInterop/Manifest/Preview/ManifestInstaller.cs b/src/WinGetUtilInterop/Manifest/Preview/ManifestInstaller.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestInstaller.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.Preview { diff --git a/src/WinGetUtilInterop/Manifest/Preview/ManifestLocalization.cs b/src/WinGetUtilInterop/Manifest/Preview/ManifestLocalization.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestLocalization.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.Preview { diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerArpEntry.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerArpEntry.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerArpEntry.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerDependency.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerDependency.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerDependency.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerExpectedReturnCode.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerExpectedReturnCode.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerExpectedReturnCode.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerInstallationMetadata.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerInstallationMetadata.cs @@ -1,15 +1,16 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerInstallationMetadata.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; using System.Collections.Generic; - using System.Text; + /// <summary> + /// Installation metadata. + /// </summary> public class InstallerInstallationMetadata { /// <summary> diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerMarkets.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerMarkets.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerMarkets.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerNestedInstallerFile.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerNestedInstallerFile.cs @@ -1,9 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Text; +// ----------------------------------------------------------------------------- +// <copyright file="InstallerNestedInstallerFile.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { + /// <summary> + /// Installer nested installer file. + /// </summary> public class InstallerNestedInstallerFile { /// <summary> @@ -12,7 +17,7 @@ namespace Microsoft.WinGetUtil.Models.V1 public string RelativeFilePath { get; set; } /// <summary> - /// Gets or set portable command alias. + /// Gets or sets portable command alias. /// </summary> public string PortableCommandAlias { get; set; } } diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerPackageDependency.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerPackageDependency.cs @@ -1,13 +1,11 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerPackageDependency.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; - /// <summary> /// Class that contains package dependency from same source. /// </summary> diff --git a/src/WinGetUtilInterop/Manifest/V1/InstallerSwitches.cs b/src/WinGetUtilInterop/Manifest/V1/InstallerSwitches.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="InstallerSwitches.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/Manifest.cs b/src/WinGetUtilInterop/Manifest/V1/Manifest.cs @@ -1,15 +1,13 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="Manifest.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; using System.Collections.Generic; using System.IO; - using System.Linq; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -137,7 +135,7 @@ namespace Microsoft.WinGetUtil.Models.V1 /// Gets or sets the release notes in default locale. /// </summary> public string ReleaseNotes { get; set; } - + /// <summary> /// Gets or sets the manifest documentation. /// </summary> diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestDocumentation.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestDocumentation.cs @@ -1,15 +1,14 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestDocumentation.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; - using System.Collections.Generic; - using System.Text; - + /// <summary> + /// Manifest documentation. + /// </summary> public class ManifestDocumentation { /// <summary> @@ -21,6 +20,5 @@ namespace Microsoft.WinGetUtil.Models.V1 /// Gets or sets the document url. /// </summary> public string DocumentUrl { get; set; } - } } diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestIcon.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestIcon.cs @@ -1,15 +1,14 @@ -// ----------------------------------------------------------------------- -// <copyright file="ManifestDocumentation.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------------- +// <copyright file="ManifestIcon.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; - using System.Collections.Generic; - using System.Text; - + /// <summary> + /// Icon information. + /// </summary> public class ManifestIcon { /// <summary> diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestInstaller.cs @@ -1,12 +1,11 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestInstaller.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; using System.Collections.Generic; using YamlDotNet.Serialization; @@ -256,9 +255,9 @@ namespace Microsoft.WinGetUtil.Models.V1 (this.InstallerLocale == other.InstallerLocale) && (this.Scope == other.Scope) && (this.InstallerType == other.InstallerType) && - (this.Switches == other.Switches) && + (this.Switches == other.Switches) && (this.InstallationMetadata == other.InstallationMetadata) && - (this.NestedInstallerType == other.NestedInstallerType) && + (this.NestedInstallerType == other.NestedInstallerType) && (this.NestedInstallerFiles == other.NestedInstallerFiles) && (this.DisplayInstallWarnings == other.DisplayInstallWarnings); } diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestInstallerFile.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestInstallerFile.cs @@ -1,15 +1,11 @@ -// ----------------------------------------------------------------------- -// <copyright file="ManifestInstallationMetadata.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------------- +// <copyright file="ManifestInstallerFile.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; - using System.Collections.Generic; - using System.Text; - /// <summary> /// Represents an installer file. /// </summary> diff --git a/src/WinGetUtilInterop/Manifest/V1/ManifestLocalization.cs b/src/WinGetUtilInterop/Manifest/V1/ManifestLocalization.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="ManifestLocalization.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/Manifest/V1/MinManifestInfo.cs b/src/WinGetUtilInterop/Manifest/V1/MinManifestInfo.cs @@ -1,12 +1,11 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="MinManifestInfo.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { - using System; using System.IO; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; diff --git a/src/WinGetUtilInterop/Manifest/V1/PackageAgreement.cs b/src/WinGetUtilInterop/Manifest/V1/PackageAgreement.cs @@ -1,8 +1,8 @@ -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="PackageAgreement.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> -// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------------- namespace Microsoft.WinGetUtil.Models.V1 { diff --git a/src/WinGetUtilInterop/WinGetUtilInterop.csproj b/src/WinGetUtilInterop/WinGetUtilInterop.csproj @@ -1,14 +1,18 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFramework>netstandard2.0</TargetFramework> + <TargetFramework>netstandard2.1</TargetFramework> + <RootNamespace>Microsoft.WinGetUtil</RootNamespace> </PropertyGroup> <ItemGroup> - <Folder Include="Manifest\" /> + <AdditionalFiles Include="..\stylecop.json" Link="stylecop.json" /> </ItemGroup> <ItemGroup> <PackageReference Include="YamlDotNet" Version="8.1.2" /> + <PackageReference Include="StyleCop.Analyzers" Version="1.1.118"> + <PrivateAssets>all</PrivateAssets> + </PackageReference> </ItemGroup> </Project>