From 12b92e0575a9f8c17f7871eaa56b636060306240 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Thu, 3 Aug 2023 10:43:41 +0200 Subject: [PATCH] Use file scoped namespaces --- src/Cupboard.Core/Catalog.cs | 15 +- src/Cupboard.Core/CatalogContext.cs | 37 +- src/Cupboard.Core/ErrorOptions.cs | 11 +- .../Extensions/FileSystemExtensions.cs | 23 +- .../Extensions/ICupboardLoggerExtensions.cs | 99 ++-- .../Extensions/IEnumerableExtensions.cs | 13 +- .../Extensions/IWindowsRegistryExtensions.cs | 45 +- .../Extensions/PathExtensions.cs | 27 +- .../Extensions/ResourceExtensions.cs | 39 +- .../Extensions/ResourceStateExtensions.cs | 29 +- src/Cupboard.Core/Fact.cs | 163 +++--- src/Cupboard.Core/FactCollection.cs | 93 ++- src/Cupboard.Core/ICupboardLogger.cs | 15 +- src/Cupboard.Core/IEnvironmentRefresher.cs | 9 +- src/Cupboard.Core/IExecutionContext.cs | 27 +- src/Cupboard.Core/IFactBuilder.cs | 9 +- src/Cupboard.Core/IFactProvider.cs | 9 +- src/Cupboard.Core/IHasPackageName.cs | 9 +- src/Cupboard.Core/IHasPackageState.cs | 9 +- src/Cupboard.Core/IO/Chmod.cs | 145 +++-- src/Cupboard.Core/IO/ChmodClass.cs | 13 +- src/Cupboard.Core/IO/ChmodFormatter.cs | 73 ++- src/Cupboard.Core/IO/ChmodFormatting.cs | 11 +- src/Cupboard.Core/IO/ChmodParser.cs | 87 ++- src/Cupboard.Core/IO/ICupboardEnvironment.cs | 9 +- src/Cupboard.Core/IO/ICupboardFileSystem.cs | 7 +- src/Cupboard.Core/IO/IProcessRunner.cs | 9 +- src/Cupboard.Core/IO/IWindowsRegistry.cs | 19 +- src/Cupboard.Core/IO/IWindowsRegistryKey.cs | 25 +- .../IO/Obsolete/RegistryKeyPath.cs | 159 +++-- .../IO/Obsolete/RegistryKeyRoot.cs | 23 +- .../IO/Obsolete/RegistryKeyValueKind.cs | 25 +- src/Cupboard.Core/IO/Permissions.cs | 19 +- src/Cupboard.Core/IO/ProcessRunnerResult.cs | 23 +- src/Cupboard.Core/IO/RegistryHive.cs | 21 +- src/Cupboard.Core/IO/RegistryPath.cs | 163 +++--- src/Cupboard.Core/IO/RegistryValueKind.cs | 23 +- src/Cupboard.Core/IO/SpecialMode.cs | 19 +- src/Cupboard.Core/IRebootDetector.cs | 9 +- src/Cupboard.Core/IReportSubscriber.cs | 9 +- src/Cupboard.Core/IResourceBuilder.cs | 15 +- src/Cupboard.Core/IResourceIdentity.cs | 11 +- src/Cupboard.Core/IResourceProvider.cs | 17 +- src/Cupboard.Core/ISecurityPrincipal.cs | 9 +- src/Cupboard.Core/LogLevel.cs | 57 +- src/Cupboard.Core/Manifest.cs | 9 +- src/Cupboard.Core/ManifestContext.cs | 77 ++- src/Cupboard.Core/OSArchitecture.cs | 17 +- src/Cupboard.Core/OSPlatform.cs | 17 +- .../PackageInstallerOperation.cs | 13 +- src/Cupboard.Core/PackageInstallerProvider.cs | 227 ++++---- src/Cupboard.Core/PackageInstallerResult.cs | 13 +- src/Cupboard.Core/PackageState.cs | 11 +- src/Cupboard.Core/RebootOptions.cs | 11 +- src/Cupboard.Core/Report.cs | 57 +- src/Cupboard.Core/ReportItem.cs | 27 +- src/Cupboard.Core/Resource.cs | 23 +- src/Cupboard.Core/ResourceBuilder.cs | 79 ++- src/Cupboard.Core/ResourceProvider.cs | 61 +- src/Cupboard.Core/ResourceState.cs | 21 +- src/Cupboard.Core/ServiceModule.cs | 9 +- src/Cupboard.Core/Verbosity.cs | 17 +- .../Chocolatey/ChocolateyPackage.cs | 29 +- .../Chocolatey/ChocolateyPackageExtensions.cs | 59 +- .../Chocolatey/ChocolateyPackageProvider.cs | 159 +++-- .../Features/WindowsFeature.cs | 17 +- .../Features/WindowsFeatureExtensions.cs | 19 +- .../Features/WindowsFeatureProvider.cs | 165 +++--- .../Features/WindowsFeatureState.cs | 11 +- .../Registry/Obsolete/RegistryKey.cs | 23 +- .../Obsolete/RegistryKeyExtensions.cs | 45 +- .../Registry/Obsolete/RegistryKeyProvider.cs | 215 ++++--- .../Registry/RegistryKeyState.cs | 11 +- .../Registry/RegistryValue.cs | 23 +- .../Registry/RegistryValueExtensions.cs | 59 +- .../Registry/RegistryValueProvider.cs | 229 ++++---- .../WindowsFacts.cs | 13 +- .../WindowsModule.cs | 27 +- .../WindowsResourceProvider.cs | 25 +- .../Winget/WingetPackage.cs | 35 +- .../Winget/WingetPackageExtensions.cs | 51 +- .../Winget/WingetPackageProvider.cs | 113 ++-- src/Cupboard.Providers.Windows/WmiFacts.cs | 63 +- src/Cupboard.Providers/ArgumentFacts.cs | 51 +- src/Cupboard.Providers/Directory/Directory.cs | 21 +- .../Directory/DirectoryExtensions.cs | 27 +- .../Directory/DirectoryProvider.cs | 143 +++-- .../Directory/DirectoryState.cs | 11 +- src/Cupboard.Providers/Download/Download.cs | 23 +- .../Download/DownloadExtensions.cs | 63 +- .../Download/DownloadProvider.cs | 167 +++--- src/Cupboard.Providers/EnvironmentFacts.cs | 61 +- src/Cupboard.Providers/Exec/Exec.cs | 21 +- src/Cupboard.Providers/Exec/ExecExtensions.cs | 33 +- src/Cupboard.Providers/Exec/ExecProvider.cs | 91 ++- src/Cupboard.Providers/File/File.cs | 23 +- src/Cupboard.Providers/File/FileExtensions.cs | 53 +- src/Cupboard.Providers/File/FileProvider.cs | 235 ++++---- src/Cupboard.Providers/File/FileState.cs | 11 +- src/Cupboard.Providers/MachineFacts.cs | 87 ++- .../MachineFactsExtensions.cs | 123 ++-- .../PowerShell/PowerShell.cs | 21 +- .../PowerShell/PowerShellFlavor.cs | 11 +- .../PowerShell/PowerShellProvider.cs | 213 ++++--- .../PowerShell/PowerShellScriptExtensions.cs | 43 +- src/Cupboard.Providers/ResourcesModule.cs | 31 +- .../VSCode/VSCodeExtension.cs | 19 +- .../VSCode/VSCodeExtensionExtensions.cs | 19 +- .../VSCode/VSCodeExtensionProvider.cs | 107 ++-- src/Cupboard.Testing/CupboardFixture.cs | 173 +++--- .../Extensions/CupboardFixtureExtensions.cs | 83 ++- .../Extensions/ReportExtensions.cs | 25 +- .../Fakes/FakeCupboardEnvironment.cs | 117 ++-- .../Fakes/FakeCupboardFileSystem.cs | 81 ++- .../Fakes/FakeEnvironmentRefresher.cs | 9 +- src/Cupboard.Testing/Fakes/FakeFactBuilder.cs | 23 +- src/Cupboard.Testing/Fakes/FakeLogger.cs | 103 ++-- .../Fakes/FakeProcessRunner.cs | 99 ++-- .../Fakes/FakeRebootDetector.cs | 15 +- .../Fakes/FakeReportSubscriber.cs | 15 +- .../Fakes/FakeSecurityPrincipal.cs | 15 +- .../Fakes/FakeWindowsRegistry.cs | 35 +- .../Fakes/FakeWindowsRegistryKey.cs | 99 ++-- src/Cupboard.Testing/LambdaCatalog.cs | 23 +- .../Fixtures/FakeProcessRunnerFixture.cs | 23 +- src/Cupboard.Tests/Properties/WindowsFact.cs | 25 +- .../Unit/FactCollectionTests.cs | 149 +++-- .../Unit/IO/ChmodParserTests.cs | 55 +- src/Cupboard.Tests/Unit/IO/ChmodTests.cs | 157 +++-- .../Unit/IO/RegistryKeyTests.cs | 111 ++-- .../Unit/ManifestContextTests.cs | 107 ++-- .../Unit/Providers/ChocolateyProviderTests.cs | 545 +++++++++--------- .../Unit/Providers/FileProviderTests.cs | 127 ++-- .../Unit/Providers/PowerShellProviderTests.cs | 279 +++++---- .../Providers/VSCodeExtensionProviderTests.cs | 387 +++++++------ .../Unit/Providers/WingetProviderTests.cs | 171 +++--- src/Cupboard/Cli/FactCommand.cs | 69 ++- .../Infrastructure/DirectoryPathConverter.cs | 25 +- .../Cli/Infrastructure/FilePathConverter.cs | 25 +- .../Cli/Infrastructure/TypeRegistrar.cs | 47 +- .../Cli/Infrastructure/TypeResolver.cs | 27 +- .../Cli/Infrastructure/VerbosityConverter.cs | 67 ++- src/Cupboard/Cli/RunCommand.cs | 303 +++++----- src/Cupboard/ColorPalette.cs | 59 +- src/Cupboard/CupboardHost.cs | 53 +- src/Cupboard/CupboardHostBuilder.cs | 149 +++-- src/Cupboard/CupboardLogger.cs | 125 ++-- src/Cupboard/EnvironmentRefresher.cs | 69 ++- src/Cupboard/ExecutionAction.cs | 13 +- src/Cupboard/ExecutionEngine.cs | 237 ++++---- src/Cupboard/ExecutionPlan.cs | 41 +- src/Cupboard/ExecutionPlanBuilder.cs | 123 ++-- src/Cupboard/ExecutionPlanItem.cs | 23 +- .../Extensions/IAnsiConsoleExtensions.cs | 15 +- .../RegistryKeyValueKindExtensions.cs | 35 +- .../Extensions/RegistryValueKindExtensions.cs | 33 +- .../Extensions/ServiceCollectionExtensions.cs | 105 ++-- src/Cupboard/FactBuilder.cs | 33 +- src/Cupboard/IExecutionController.cs | 75 ++- src/Cupboard/IO/CupboardEnvironment.cs | 63 +- src/Cupboard/IO/CupboardFileSystem.cs | 19 +- src/Cupboard/IO/ProcessRunner.cs | 87 ++- src/Cupboard/IO/WindowsRegistry.cs | 21 +- src/Cupboard/IO/WindowsRegistryKey.cs | 91 ++- src/Cupboard/IStatusUpdater.cs | 41 +- src/Cupboard/RebootDetector.cs | 119 ++-- src/Cupboard/ReportRenderer.cs | 191 +++--- src/Cupboard/ResourceComparer.cs | 55 +- src/Cupboard/ResourceGraph.cs | 131 +++-- src/Cupboard/ResourceGraphBuilder.cs | 95 ++- src/Cupboard/ResourceGraphEdge.cs | 19 +- src/Cupboard/ResourceGraphWalker.cs | 143 +++-- src/Cupboard/ResourceIdentity.cs | 39 +- src/Cupboard/ResourceProviderRepository.cs | 37 +- src/Cupboard/SecurityPrincipal.cs | 17 +- src/Cupboard/WindowsCatalog.cs | 11 +- src/Sandbox/Facts/RustFactProvider.cs | 29 +- src/Sandbox/Manifests/Chocolatey.cs | 50 +- src/Sandbox/Manifests/ChocolateyPackages.cs | 17 +- src/Sandbox/Manifests/Rust.cs | 69 ++- src/Sandbox/Manifests/VSCode.cs | 61 +- src/Sandbox/Manifests/WindowsSettings.cs | 99 ++-- src/Sandbox/Manifests/WingetPackages.cs | 15 +- src/Sandbox/Program.cs | 27 +- 184 files changed, 5817 insertions(+), 6000 deletions(-) diff --git a/src/Cupboard.Core/Catalog.cs b/src/Cupboard.Core/Catalog.cs index e652f5f..70dfde2 100644 --- a/src/Cupboard.Core/Catalog.cs +++ b/src/Cupboard.Core/Catalog.cs @@ -1,12 +1,11 @@ -namespace Cupboard +namespace Cupboard; + +public abstract class Catalog { - public abstract class Catalog + public virtual bool CanRun(FactCollection facts) { - public virtual bool CanRun(FactCollection facts) - { - return true; - } - - public abstract void Execute(CatalogContext context); + return true; } + + public abstract void Execute(CatalogContext context); } diff --git a/src/Cupboard.Core/CatalogContext.cs b/src/Cupboard.Core/CatalogContext.cs index 0b0cce0..12c10db 100644 --- a/src/Cupboard.Core/CatalogContext.cs +++ b/src/Cupboard.Core/CatalogContext.cs @@ -1,29 +1,28 @@ using System; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public sealed class CatalogContext { - public sealed class CatalogContext - { - private readonly HashSet _manifests; + private readonly HashSet _manifests; - public FactCollection Facts { get; } + public FactCollection Facts { get; } - public CatalogContext(FactCollection facts) - { - Facts = facts ?? throw new ArgumentNullException(nameof(facts)); - _manifests = new HashSet(); - } + public CatalogContext(FactCollection facts) + { + Facts = facts ?? throw new ArgumentNullException(nameof(facts)); + _manifests = new HashSet(); + } - public void UseManifest() - where TManifest : Manifest - { - _manifests.Add(typeof(TManifest)); - } + public void UseManifest() + where TManifest : Manifest + { + _manifests.Add(typeof(TManifest)); + } - public IEnumerable GetManifests() - { - return _manifests; - } + public IEnumerable GetManifests() + { + return _manifests; } } diff --git a/src/Cupboard.Core/ErrorOptions.cs b/src/Cupboard.Core/ErrorOptions.cs index 7e18ae7..69b1c12 100644 --- a/src/Cupboard.Core/ErrorOptions.cs +++ b/src/Cupboard.Core/ErrorOptions.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum ErrorOptions { - public enum ErrorOptions - { - IgnoreErrors = 0, - Abort = 1, - } + IgnoreErrors = 0, + Abort = 1, } diff --git a/src/Cupboard.Core/Extensions/FileSystemExtensions.cs b/src/Cupboard.Core/Extensions/FileSystemExtensions.cs index 97c4283..78038e2 100644 --- a/src/Cupboard.Core/Extensions/FileSystemExtensions.cs +++ b/src/Cupboard.Core/Extensions/FileSystemExtensions.cs @@ -1,20 +1,19 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class FileSystemExtensions { - public static class FileSystemExtensions + public static bool CreateSymbolicLinkSafe(this IFileProvider fileProvider, FilePath source, FilePath destination) { - public static bool CreateSymbolicLinkSafe(this IFileProvider fileProvider, FilePath source, FilePath destination) + try + { + fileProvider.CreateSymbolicLink(source, destination); + return true; + } + catch { - try - { - fileProvider.CreateSymbolicLink(source, destination); - return true; - } - catch - { - return false; - } + return false; } } } diff --git a/src/Cupboard.Core/Extensions/ICupboardLoggerExtensions.cs b/src/Cupboard.Core/Extensions/ICupboardLoggerExtensions.cs index 6f73332..4c4ecad 100644 --- a/src/Cupboard.Core/Extensions/ICupboardLoggerExtensions.cs +++ b/src/Cupboard.Core/Extensions/ICupboardLoggerExtensions.cs @@ -1,65 +1,64 @@ -namespace Cupboard +namespace Cupboard; + +public static class ICupboardLoggerExtensions { - public static class ICupboardLoggerExtensions + public static void Fatal(this ICupboardLogger logger, string markup) { - public static void Fatal(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Quiet, LogLevel.Fatal, markup); - } + logger?.Log(Verbosity.Quiet, LogLevel.Fatal, markup); + } - public static void Error(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Quiet, LogLevel.Error, markup); - } + public static void Error(this ICupboardLogger logger, string markup) + { + logger?.Log(Verbosity.Quiet, LogLevel.Error, markup); + } - public static void Warning(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Minimal, LogLevel.Warning, markup); - } + public static void Warning(this ICupboardLogger logger, string markup) + { + logger?.Log(Verbosity.Minimal, LogLevel.Warning, markup); + } - public static void Information(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Normal, LogLevel.Information, markup); - } + public static void Information(this ICupboardLogger logger, string markup) + { + logger?.Log(Verbosity.Normal, LogLevel.Information, markup); + } - public static void Verbose(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Verbose, LogLevel.Verbose, markup); - } + public static void Verbose(this ICupboardLogger logger, string markup) + { + logger?.Log(Verbosity.Verbose, LogLevel.Verbose, markup); + } - public static void Debug(this ICupboardLogger logger, string markup) - { - logger?.Log(Verbosity.Diagnostic, LogLevel.Debug, markup); - } + public static void Debug(this ICupboardLogger logger, string markup) + { + logger?.Log(Verbosity.Diagnostic, LogLevel.Debug, markup); + } - public static void Fatal(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Quiet, LogLevel.Fatal, title, markup); - } + public static void Fatal(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Quiet, LogLevel.Fatal, title, markup); + } - public static void Error(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Quiet, LogLevel.Error, title, markup); - } + public static void Error(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Quiet, LogLevel.Error, title, markup); + } - public static void Warning(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Minimal, LogLevel.Warning, title, markup); - } + public static void Warning(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Minimal, LogLevel.Warning, title, markup); + } - public static void Information(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Normal, LogLevel.Information, title, markup); - } + public static void Information(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Normal, LogLevel.Information, title, markup); + } - public static void Verbose(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Verbose, LogLevel.Verbose, title, markup); - } + public static void Verbose(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Verbose, LogLevel.Verbose, title, markup); + } - public static void Debug(this ICupboardLogger logger, string title, string markup) - { - logger?.Log(Verbosity.Diagnostic, LogLevel.Debug, title, markup); - } + public static void Debug(this ICupboardLogger logger, string title, string markup) + { + logger?.Log(Verbosity.Diagnostic, LogLevel.Debug, title, markup); } } diff --git a/src/Cupboard.Core/Extensions/IEnumerableExtensions.cs b/src/Cupboard.Core/Extensions/IEnumerableExtensions.cs index e498cab..2cdaa1e 100644 --- a/src/Cupboard.Core/Extensions/IEnumerableExtensions.cs +++ b/src/Cupboard.Core/Extensions/IEnumerableExtensions.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public static class IEnumerableExtensions { - public static class IEnumerableExtensions + public static IReadOnlyList ToReadOnlyList(this IEnumerable source) { - public static IReadOnlyList ToReadOnlyList(this IEnumerable source) - { - return source as IReadOnlyList - ?? new List(source ?? Array.Empty()); - } + return source as IReadOnlyList + ?? new List(source ?? Array.Empty()); } } diff --git a/src/Cupboard.Core/Extensions/IWindowsRegistryExtensions.cs b/src/Cupboard.Core/Extensions/IWindowsRegistryExtensions.cs index 6e0e370..e6bee99 100644 --- a/src/Cupboard.Core/Extensions/IWindowsRegistryExtensions.cs +++ b/src/Cupboard.Core/Extensions/IWindowsRegistryExtensions.cs @@ -1,33 +1,32 @@ using System; -namespace Cupboard +namespace Cupboard; + +public static class IWindowsRegistryExtensions { - public static class IWindowsRegistryExtensions + public static IWindowsRegistryKey? GetKey(this IWindowsRegistry registry, RegistryPath path, bool writable) { - public static IWindowsRegistryKey? GetKey(this IWindowsRegistry registry, RegistryPath path, bool writable) + if (registry is null) { - if (registry is null) - { - throw new ArgumentNullException(nameof(registry)); - } + throw new ArgumentNullException(nameof(registry)); + } - if (path is null) - { - throw new ArgumentNullException(nameof(path)); - } + if (path is null) + { + throw new ArgumentNullException(nameof(path)); + } - var root = path.Hive switch - { - RegistryHive.ClassesRoot => registry.ClassesRoot, - RegistryHive.CurrentUser => registry.CurrentUser, - RegistryHive.LocalMachine => registry.LocalMachine, - RegistryHive.Users => registry.Users, - RegistryHive.CurrentConfig => registry.CurrentConfig, - RegistryHive.PerformanceData => registry.PerformanceData, - _ => throw new InvalidOperationException("Unknown registry root"), - }; + var root = path.Hive switch + { + RegistryHive.ClassesRoot => registry.ClassesRoot, + RegistryHive.CurrentUser => registry.CurrentUser, + RegistryHive.LocalMachine => registry.LocalMachine, + RegistryHive.Users => registry.Users, + RegistryHive.CurrentConfig => registry.CurrentConfig, + RegistryHive.PerformanceData => registry.PerformanceData, + _ => throw new InvalidOperationException("Unknown registry root"), + }; - return root.OpenSubKey(path.SubKey, writable); - } + return root.OpenSubKey(path.SubKey, writable); } } diff --git a/src/Cupboard.Core/Extensions/PathExtensions.cs b/src/Cupboard.Core/Extensions/PathExtensions.cs index 3cdc785..a070a78 100644 --- a/src/Cupboard.Core/Extensions/PathExtensions.cs +++ b/src/Cupboard.Core/Extensions/PathExtensions.cs @@ -3,24 +3,23 @@ using Mono.Unix; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class PathExtensions { - public static class PathExtensions + public static void SetPermissions(this Path path, Chmod chmod) { - public static void SetPermissions(this Path path, Chmod chmod) + if (path is null) { - if (path is null) - { - throw new ArgumentNullException(nameof(path)); - } - - if (RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) - { - return; - } + throw new ArgumentNullException(nameof(path)); + } - var info = UnixFileSystemInfo.GetFileSystemEntry(path.FullPath); - info.FileAccessPermissions = chmod.ToFileAccessPermissions(); + if (RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) + { + return; } + + var info = UnixFileSystemInfo.GetFileSystemEntry(path.FullPath); + info.FileAccessPermissions = chmod.ToFileAccessPermissions(); } } diff --git a/src/Cupboard.Core/Extensions/ResourceExtensions.cs b/src/Cupboard.Core/Extensions/ResourceExtensions.cs index 06c0bb6..54bcb95 100644 --- a/src/Cupboard.Core/Extensions/ResourceExtensions.cs +++ b/src/Cupboard.Core/Extensions/ResourceExtensions.cs @@ -1,26 +1,25 @@ -namespace Cupboard +namespace Cupboard; + +public static class ResourceExtensions { - public static class ResourceExtensions + public static IResourceBuilder OnError(this IResourceBuilder builder, ErrorOptions options) + where T : Resource { - public static IResourceBuilder OnError(this IResourceBuilder builder, ErrorOptions options) - where T : Resource - { - builder.Configure(res => res.Error = options); - return builder; - } + builder.Configure(res => res.Error = options); + return builder; + } - public static IResourceBuilder OnReboot(this IResourceBuilder builder, RebootOptions options) - where T : Resource - { - builder.Configure(res => res.Reboot = options); - return builder; - } + public static IResourceBuilder OnReboot(this IResourceBuilder builder, RebootOptions options) + where T : Resource + { + builder.Configure(res => res.Reboot = options); + return builder; + } - public static IResourceBuilder RequireAdministrator(this IResourceBuilder builder) - where T : Resource - { - builder.Configure(res => res.RequireAdministrator = true); - return builder; - } + public static IResourceBuilder RequireAdministrator(this IResourceBuilder builder) + where T : Resource + { + builder.Configure(res => res.RequireAdministrator = true); + return builder; } } diff --git a/src/Cupboard.Core/Extensions/ResourceStateExtensions.cs b/src/Cupboard.Core/Extensions/ResourceStateExtensions.cs index 84013ab..587fdbd 100644 --- a/src/Cupboard.Core/Extensions/ResourceStateExtensions.cs +++ b/src/Cupboard.Core/Extensions/ResourceStateExtensions.cs @@ -1,22 +1,21 @@ using System; -namespace Cupboard +namespace Cupboard; + +public static class ResourceStateExtensions { - public static class ResourceStateExtensions + public static bool IsError(this ResourceState state) { - public static bool IsError(this ResourceState state) + return state switch { - return state switch - { - ResourceState.Unknown => true, - ResourceState.Changed => false, - ResourceState.Unchanged => false, - ResourceState.Error => true, - ResourceState.Skipped => false, - ResourceState.ManuallySkipped => false, - ResourceState.Executed => false, - _ => throw new InvalidOperationException($"Unknown resource state '{state}'"), - }; - } + ResourceState.Unknown => true, + ResourceState.Changed => false, + ResourceState.Unchanged => false, + ResourceState.Error => true, + ResourceState.Skipped => false, + ResourceState.ManuallySkipped => false, + ResourceState.Executed => false, + _ => throw new InvalidOperationException($"Unknown resource state '{state}'"), + }; } } diff --git a/src/Cupboard.Core/Fact.cs b/src/Cupboard.Core/Fact.cs index 7c411c7..497bc6e 100644 --- a/src/Cupboard.Core/Fact.cs +++ b/src/Cupboard.Core/Fact.cs @@ -1,115 +1,114 @@ using System; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public sealed class Fact { - public sealed class Fact - { - private static Fact DefaultFact { get; } = new Fact(null, string.Empty); + private static Fact DefaultFact { get; } = new Fact(null, string.Empty); + + public string Name { get; } + public string FullName { get; } + public object? Value { get; internal set; } + public Fact this[string key] => GetChild(key); - public string Name { get; } - public string FullName { get; } - public object? Value { get; internal set; } - public Fact this[string key] => GetChild(key); + internal Fact? Parent { get; } + internal Dictionary Children { get; } - internal Fact? Parent { get; } - internal Dictionary Children { get; } + internal Fact(Fact? parent, string id, object? value = null) + { + Parent = parent; + Name = id ?? throw new ArgumentNullException(nameof(id)); + Value = value; + Children = new Dictionary(StringComparer.OrdinalIgnoreCase); + FullName = GetFullName(); + } - internal Fact(Fact? parent, string id, object? value = null) + public T? As(T? defaultValue = default) + where T : notnull + { + if (Value is T result) { - Parent = parent; - Name = id ?? throw new ArgumentNullException(nameof(id)); - Value = value; - Children = new Dictionary(StringComparer.OrdinalIgnoreCase); - FullName = GetFullName(); + return result; } - public T? As(T? defaultValue = default) - where T : notnull + return defaultValue; + } + + private string GetFullName() + { + var stack = new Stack(); + var current = this; + while (current != null) { - if (Value is T result) + if (!string.IsNullOrWhiteSpace(current.Name)) { - return result; + stack.Push(current.Name); } - return defaultValue; + current = current.Parent; } - private string GetFullName() + return string.Join(".", stack); + } + + private Fact GetChild(string key) + { + var parts = key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length > 1) { - var stack = new Stack(); - var current = this; - while (current != null) + // Get full path + var queue = new Queue(key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)); + var root = this; + while (queue.Count > 0) { - if (!string.IsNullOrWhiteSpace(current.Name)) + var current = queue.Dequeue(); + if (root.Children.TryGetValue(current, out var node)) { - stack.Push(current.Name); + root = node; } - - current = current.Parent; - } - - return string.Join(".", stack); - } - - private Fact GetChild(string key) - { - var parts = key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length > 1) - { - // Get full path - var queue = new Queue(key.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)); - var root = this; - while (queue.Count > 0) + else { - var current = queue.Dequeue(); - if (root.Children.TryGetValue(current, out var node)) - { - root = node; - } - else - { - return DefaultFact; - } + return DefaultFact; } - - return root; - } - else - { - Children.TryGetValue(key, out var fact); - return fact ?? DefaultFact; } - } - public static implicit operator string(Fact fact) - { - return fact.Value as string ?? string.Empty; + return root; } - - public static implicit operator int(Fact fact) + else { - return fact.Value is int value ? value : 0; + Children.TryGetValue(key, out var fact); + return fact ?? DefaultFact; } + } - public static implicit operator decimal(Fact fact) - { - return fact.Value is decimal value ? value : 0M; - } + public static implicit operator string(Fact fact) + { + return fact.Value as string ?? string.Empty; + } - public static implicit operator double(Fact fact) - { - return fact.Value is double value ? value : 0D; - } + public static implicit operator int(Fact fact) + { + return fact.Value is int value ? value : 0; + } - public static implicit operator float(Fact fact) - { - return fact.Value is float value ? value : 0F; - } + public static implicit operator decimal(Fact fact) + { + return fact.Value is decimal value ? value : 0M; + } - public static implicit operator bool(Fact fact) - { - return fact.Value is bool value && value; - } + public static implicit operator double(Fact fact) + { + return fact.Value is double value ? value : 0D; + } + + public static implicit operator float(Fact fact) + { + return fact.Value is float value ? value : 0F; + } + + public static implicit operator bool(Fact fact) + { + return fact.Value is bool value && value; } } diff --git a/src/Cupboard.Core/FactCollection.cs b/src/Cupboard.Core/FactCollection.cs index 428c26f..71a42c6 100644 --- a/src/Cupboard.Core/FactCollection.cs +++ b/src/Cupboard.Core/FactCollection.cs @@ -1,71 +1,70 @@ using System.Collections; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public sealed class FactCollection : IEnumerable { - public sealed class FactCollection : IEnumerable - { - private readonly Fact _root; + private readonly Fact _root; - public Fact this[string key] => _root[key]; + public Fact this[string key] => _root[key]; - public FactCollection() - { - _root = new Fact(null, string.Empty, null); - } + public FactCollection() + { + _root = new Fact(null, string.Empty, null); + } + + public void Add(string key, object value) + { + var root = _root; - public void Add(string key, object value) + var queue = new Queue(key.Split('.')); + while (queue.Count > 0) { - var root = _root; + var current = queue.Dequeue(); - var queue = new Queue(key.Split('.')); - while (queue.Count > 0) + if (!root.Children.TryGetValue(current, out var node)) { - var current = queue.Dequeue(); - - if (!root.Children.TryGetValue(current, out var node)) - { - node = queue.Count == 0 - ? new Fact(root, current, value) - : new Fact(root, current); + node = queue.Count == 0 + ? new Fact(root, current, value) + : new Fact(root, current); - root.Children.Add(current, node); - } - else + root.Children.Add(current, node); + } + else + { + if (queue.Count == 0) { - if (queue.Count == 0) - { - // Overwrite the value - node.Value = value; - } + // Overwrite the value + node.Value = value; } - - root = node; } + + root = node; } + } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() + { + var stack = new Stack(); + stack.Push(_root); + while (stack.Count > 0) { - var stack = new Stack(); - stack.Push(_root); - while (stack.Count > 0) + var current = stack.Pop(); + if (current.Value != null) { - var current = stack.Pop(); - if (current.Value != null) - { - yield return current; - } + yield return current; + } - foreach (var (_, child) in current.Children) - { - stack.Push(child); - } + foreach (var (_, child) in current.Children) + { + stack.Push(child); } } + } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); } } diff --git a/src/Cupboard.Core/ICupboardLogger.cs b/src/Cupboard.Core/ICupboardLogger.cs index bff65dc..b6ad83e 100644 --- a/src/Cupboard.Core/ICupboardLogger.cs +++ b/src/Cupboard.Core/ICupboardLogger.cs @@ -1,11 +1,10 @@ -namespace Cupboard +namespace Cupboard; + +public interface ICupboardLogger { - public interface ICupboardLogger - { - Verbosity Verbosity { get; } + Verbosity Verbosity { get; } - void SetVerbosity(Verbosity verbosity); - void Log(Verbosity verbosity, LogLevel level, string text); - void Log(Verbosity verbosity, LogLevel level, string title, string text); - } + void SetVerbosity(Verbosity verbosity); + void Log(Verbosity verbosity, LogLevel level, string text); + void Log(Verbosity verbosity, LogLevel level, string title, string text); } diff --git a/src/Cupboard.Core/IEnvironmentRefresher.cs b/src/Cupboard.Core/IEnvironmentRefresher.cs index 9e42fef..2eb7401 100644 --- a/src/Cupboard.Core/IEnvironmentRefresher.cs +++ b/src/Cupboard.Core/IEnvironmentRefresher.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface IEnvironmentRefresher { - public interface IEnvironmentRefresher - { - void Refresh(); - } + void Refresh(); } diff --git a/src/Cupboard.Core/IExecutionContext.cs b/src/Cupboard.Core/IExecutionContext.cs index be23018..485c576 100644 --- a/src/Cupboard.Core/IExecutionContext.cs +++ b/src/Cupboard.Core/IExecutionContext.cs @@ -1,21 +1,20 @@ using System; -namespace Cupboard +namespace Cupboard; + +public interface IExecutionContext { - public interface IExecutionContext - { - FactCollection Facts { get; } - bool DryRun { get; } - } + FactCollection Facts { get; } + bool DryRun { get; } +} - public sealed class ExecutionContext : IExecutionContext - { - public FactCollection Facts { get; } - public bool DryRun { get; init; } = false; +public sealed class ExecutionContext : IExecutionContext +{ + public FactCollection Facts { get; } + public bool DryRun { get; init; } = false; - public ExecutionContext(FactCollection facts) - { - Facts = facts ?? throw new ArgumentNullException(nameof(facts)); - } + public ExecutionContext(FactCollection facts) + { + Facts = facts ?? throw new ArgumentNullException(nameof(facts)); } } diff --git a/src/Cupboard.Core/IFactBuilder.cs b/src/Cupboard.Core/IFactBuilder.cs index ece625b..0c95aef 100644 --- a/src/Cupboard.Core/IFactBuilder.cs +++ b/src/Cupboard.Core/IFactBuilder.cs @@ -1,9 +1,8 @@ using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +public interface IFactBuilder { - public interface IFactBuilder - { - FactCollection Build(IRemainingArguments args); - } + FactCollection Build(IRemainingArguments args); } diff --git a/src/Cupboard.Core/IFactProvider.cs b/src/Cupboard.Core/IFactProvider.cs index ee6d66b..56e9ab7 100644 --- a/src/Cupboard.Core/IFactProvider.cs +++ b/src/Cupboard.Core/IFactProvider.cs @@ -1,10 +1,9 @@ using System.Collections.Generic; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +public interface IFactProvider { - public interface IFactProvider - { - IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args); - } + IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args); } diff --git a/src/Cupboard.Core/IHasPackageName.cs b/src/Cupboard.Core/IHasPackageName.cs index 369bc98..10a6a81 100644 --- a/src/Cupboard.Core/IHasPackageName.cs +++ b/src/Cupboard.Core/IHasPackageName.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface IHasPackageName { - public interface IHasPackageName - { - string Package { get; } - } + string Package { get; } } diff --git a/src/Cupboard.Core/IHasPackageState.cs b/src/Cupboard.Core/IHasPackageState.cs index 296a6f6..5153921 100644 --- a/src/Cupboard.Core/IHasPackageState.cs +++ b/src/Cupboard.Core/IHasPackageState.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface IHasPackageState { - public interface IHasPackageState - { - PackageState Ensure { get; } - } + PackageState Ensure { get; } } diff --git a/src/Cupboard.Core/IO/Chmod.cs b/src/Cupboard.Core/IO/Chmod.cs index 5e0cb4b..a0a67f3 100644 --- a/src/Cupboard.Core/IO/Chmod.cs +++ b/src/Cupboard.Core/IO/Chmod.cs @@ -3,97 +3,96 @@ using Cupboard.Internal; using Mono.Unix; -namespace Cupboard +namespace Cupboard; + +public sealed class Chmod { - public sealed class Chmod - { - private static readonly Dictionary, Dictionary> _lookup; + private static readonly Dictionary, Dictionary> _lookup; - public SpecialMode Mode { get; } - public Permissions Owner { get; } - public Permissions Group { get; } - public Permissions Other { get; } + public SpecialMode Mode { get; } + public Permissions Owner { get; } + public Permissions Group { get; } + public Permissions Other { get; } - static Chmod() + static Chmod() + { + _lookup = new Dictionary, Dictionary> { - _lookup = new Dictionary, Dictionary> + [c => c.Owner] = new Dictionary { - [c => c.Owner] = new Dictionary - { - { Permissions.Read, FileAccessPermissions.UserRead }, - { Permissions.Write, FileAccessPermissions.UserWrite }, - { Permissions.Execute, FileAccessPermissions.UserExecute }, - }, - [c => c.Group] = new Dictionary - { - { Permissions.Read, FileAccessPermissions.GroupRead }, - { Permissions.Write, FileAccessPermissions.GroupWrite }, - { Permissions.Execute, FileAccessPermissions.GroupExecute }, - }, - [c => c.Other] = new Dictionary - { - { Permissions.Read, FileAccessPermissions.OtherRead }, - { Permissions.Write, FileAccessPermissions.OtherWrite }, - { Permissions.Execute, FileAccessPermissions.OtherExecute }, - }, - }; - } + { Permissions.Read, FileAccessPermissions.UserRead }, + { Permissions.Write, FileAccessPermissions.UserWrite }, + { Permissions.Execute, FileAccessPermissions.UserExecute }, + }, + [c => c.Group] = new Dictionary + { + { Permissions.Read, FileAccessPermissions.GroupRead }, + { Permissions.Write, FileAccessPermissions.GroupWrite }, + { Permissions.Execute, FileAccessPermissions.GroupExecute }, + }, + [c => c.Other] = new Dictionary + { + { Permissions.Read, FileAccessPermissions.OtherRead }, + { Permissions.Write, FileAccessPermissions.OtherWrite }, + { Permissions.Execute, FileAccessPermissions.OtherExecute }, + }, + }; + } - public Chmod(Permissions owner, Permissions group, Permissions other) - : this(SpecialMode.None, owner, group, other) - { - } + public Chmod(Permissions owner, Permissions group, Permissions other) + : this(SpecialMode.None, owner, group, other) + { + } - public Chmod(SpecialMode mode, Permissions owner, Permissions group, Permissions other) - { - Mode = mode; - Owner = owner; - Group = group; - Other = other; - } + public Chmod(SpecialMode mode, Permissions owner, Permissions group, Permissions other) + { + Mode = mode; + Owner = owner; + Group = group; + Other = other; + } - public static Chmod Parse(string pattern) - { - return ChmodParser.Parse(pattern); - } + public static Chmod Parse(string pattern) + { + return ChmodParser.Parse(pattern); + } - public Permissions GetPermissions(ChmodClass @class) + public Permissions GetPermissions(ChmodClass @class) + { + return @class switch { - return @class switch - { - ChmodClass.Owner => Owner, - ChmodClass.Group => Group, - ChmodClass.Other => Other, - _ => throw new NotSupportedException("Invalid chmod reference."), - }; - } + ChmodClass.Owner => Owner, + ChmodClass.Group => Group, + ChmodClass.Other => Other, + _ => throw new NotSupportedException("Invalid chmod reference."), + }; + } - public FileAccessPermissions ToFileAccessPermissions() + public FileAccessPermissions ToFileAccessPermissions() + { + var permissions = default(FileAccessPermissions); + foreach (var map in _lookup) { - var permissions = default(FileAccessPermissions); - foreach (var map in _lookup) + var permission = map.Key(this); + foreach (var p in map.Value) { - var permission = map.Key(this); - foreach (var p in map.Value) + if (permission.HasFlag(p.Key)) { - if (permission.HasFlag(p.Key)) - { - permissions |= p.Value; - } + permissions |= p.Value; } } - - return permissions; } - public string ToString(ChmodFormatting formatting) - { - return ChmodFormatter.Format(this, formatting); - } + return permissions; + } - public override string ToString() - { - return ChmodFormatter.Format(this, ChmodFormatting.Numeric); - } + public string ToString(ChmodFormatting formatting) + { + return ChmodFormatter.Format(this, formatting); + } + + public override string ToString() + { + return ChmodFormatter.Format(this, ChmodFormatting.Numeric); } } diff --git a/src/Cupboard.Core/IO/ChmodClass.cs b/src/Cupboard.Core/IO/ChmodClass.cs index 61c07a3..4780bcc 100644 --- a/src/Cupboard.Core/IO/ChmodClass.cs +++ b/src/Cupboard.Core/IO/ChmodClass.cs @@ -1,9 +1,8 @@ -namespace Cupboard +namespace Cupboard; + +public enum ChmodClass { - public enum ChmodClass - { - Owner = 0, - Group = 1, - Other = 2, - } + Owner = 0, + Group = 1, + Other = 2, } diff --git a/src/Cupboard.Core/IO/ChmodFormatter.cs b/src/Cupboard.Core/IO/ChmodFormatter.cs index a786490..370bc39 100644 --- a/src/Cupboard.Core/IO/ChmodFormatter.cs +++ b/src/Cupboard.Core/IO/ChmodFormatter.cs @@ -1,52 +1,51 @@ using System; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal static class ChmodFormatter { - internal static class ChmodFormatter + public static string Format(Chmod chmod, ChmodFormatting formatting) { - public static string Format(Chmod chmod, ChmodFormatting formatting) + return formatting switch { - return formatting switch - { - ChmodFormatting.Numeric => FormatNumeric(chmod), - ChmodFormatting.Symbolic => FormatVerbose(chmod), - _ => throw new NotSupportedException("Formatting option is not supported."), - }; - } + ChmodFormatting.Numeric => FormatNumeric(chmod), + ChmodFormatting.Symbolic => FormatVerbose(chmod), + _ => throw new NotSupportedException("Formatting option is not supported."), + }; + } + + private static string FormatNumeric(Chmod chmod) + { + return string.Concat( + ((int)chmod.Mode).ToString(), + Format(chmod.Owner, ChmodFormatting.Numeric), + Format(chmod.Group, ChmodFormatting.Numeric), + Format(chmod.Other, ChmodFormatting.Numeric)); + } - private static string FormatNumeric(Chmod chmod) + private static string FormatVerbose(Chmod chmod) + { + return string.Concat( + Format(chmod.Owner, ChmodFormatting.Symbolic), + Format(chmod.Group, ChmodFormatting.Symbolic), + Format(chmod.Other, ChmodFormatting.Symbolic)); + } + + private static string Format(Permissions permissions, ChmodFormatting formatting) + { + if (formatting == ChmodFormatting.Numeric) { - return string.Concat( - ((int)chmod.Mode).ToString(), - Format(chmod.Owner, ChmodFormatting.Numeric), - Format(chmod.Group, ChmodFormatting.Numeric), - Format(chmod.Other, ChmodFormatting.Numeric)); + return ((int)permissions).ToString(); } - private static string FormatVerbose(Chmod chmod) + if (formatting == ChmodFormatting.Symbolic) { return string.Concat( - Format(chmod.Owner, ChmodFormatting.Symbolic), - Format(chmod.Group, ChmodFormatting.Symbolic), - Format(chmod.Other, ChmodFormatting.Symbolic)); + (permissions & Permissions.Read) == Permissions.Read ? "r" : "-", + (permissions & Permissions.Write) == Permissions.Write ? "w" : "-", + (permissions & Permissions.Execute) == Permissions.Execute ? "x" : "-"); } - private static string Format(Permissions permissions, ChmodFormatting formatting) - { - if (formatting == ChmodFormatting.Numeric) - { - return ((int)permissions).ToString(); - } - - if (formatting == ChmodFormatting.Symbolic) - { - return string.Concat( - (permissions & Permissions.Read) == Permissions.Read ? "r" : "-", - (permissions & Permissions.Write) == Permissions.Write ? "w" : "-", - (permissions & Permissions.Execute) == Permissions.Execute ? "x" : "-"); - } - - throw new NotSupportedException("Formatting option is not supported."); - } + throw new NotSupportedException("Formatting option is not supported."); } } diff --git a/src/Cupboard.Core/IO/ChmodFormatting.cs b/src/Cupboard.Core/IO/ChmodFormatting.cs index 955aab1..a7bfa45 100644 --- a/src/Cupboard.Core/IO/ChmodFormatting.cs +++ b/src/Cupboard.Core/IO/ChmodFormatting.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum ChmodFormatting { - public enum ChmodFormatting - { - Numeric = 0, - Symbolic = 1, - } + Numeric = 0, + Symbolic = 1, } diff --git a/src/Cupboard.Core/IO/ChmodParser.cs b/src/Cupboard.Core/IO/ChmodParser.cs index 3772450..8e7d9bd 100644 --- a/src/Cupboard.Core/IO/ChmodParser.cs +++ b/src/Cupboard.Core/IO/ChmodParser.cs @@ -1,62 +1,61 @@ using System; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public static class ChmodParser { - public static class ChmodParser + public static Chmod Parse(string pattern) { - public static Chmod Parse(string pattern) + if (pattern == null) { - if (pattern == null) - { - throw new ArgumentNullException(nameof(pattern)); - } - - if (pattern.Length != 3 && pattern.Length != 4) - { - throw new ArgumentException("Invalid pattern.", nameof(pattern)); - } - - var mode = SpecialMode.None; - if (pattern.Length == 4) - { - mode = ParseSpecialMode(pattern[0]); - pattern = pattern.Substring(1, 3); - } - - var queue = new Queue(new[] { ChmodClass.Owner, ChmodClass.Group, ChmodClass.Other }); - var map = new Dictionary - { - { ChmodClass.Owner, Permissions.None }, - { ChmodClass.Group, Permissions.None }, - { ChmodClass.Other, Permissions.None }, - }; + throw new ArgumentNullException(nameof(pattern)); + } - foreach (var token in pattern) - { - var current = queue.Dequeue(); - if (char.IsNumber(token)) - { - var n = int.Parse(token.ToString()); - map[current] = (Permissions)n; - } - } + if (pattern.Length != 3 && pattern.Length != 4) + { + throw new ArgumentException("Invalid pattern.", nameof(pattern)); + } - return new Chmod( - mode, - map[ChmodClass.Owner], - map[ChmodClass.Group], - map[ChmodClass.Other]); + var mode = SpecialMode.None; + if (pattern.Length == 4) + { + mode = ParseSpecialMode(pattern[0]); + pattern = pattern.Substring(1, 3); } - private static SpecialMode ParseSpecialMode(char token) + var queue = new Queue(new[] { ChmodClass.Owner, ChmodClass.Group, ChmodClass.Other }); + var map = new Dictionary + { + { ChmodClass.Owner, Permissions.None }, + { ChmodClass.Group, Permissions.None }, + { ChmodClass.Other, Permissions.None }, + }; + + foreach (var token in pattern) { + var current = queue.Dequeue(); if (char.IsNumber(token)) { - return (SpecialMode)int.Parse(token.ToString()); + var n = int.Parse(token.ToString()); + map[current] = (Permissions)n; } + } + + return new Chmod( + mode, + map[ChmodClass.Owner], + map[ChmodClass.Group], + map[ChmodClass.Other]); + } - return SpecialMode.None; + private static SpecialMode ParseSpecialMode(char token) + { + if (char.IsNumber(token)) + { + return (SpecialMode)int.Parse(token.ToString()); } + + return SpecialMode.None; } } diff --git a/src/Cupboard.Core/IO/ICupboardEnvironment.cs b/src/Cupboard.Core/IO/ICupboardEnvironment.cs index 1a18beb..4c210d0 100644 --- a/src/Cupboard.Core/IO/ICupboardEnvironment.cs +++ b/src/Cupboard.Core/IO/ICupboardEnvironment.cs @@ -1,9 +1,8 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public interface ICupboardEnvironment : IEnvironment { - public interface ICupboardEnvironment : IEnvironment - { - FilePath GetTempFilePath(); - } + FilePath GetTempFilePath(); } diff --git a/src/Cupboard.Core/IO/ICupboardFileSystem.cs b/src/Cupboard.Core/IO/ICupboardFileSystem.cs index 31e0d7f..2e930fd 100644 --- a/src/Cupboard.Core/IO/ICupboardFileSystem.cs +++ b/src/Cupboard.Core/IO/ICupboardFileSystem.cs @@ -1,8 +1,7 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public interface ICupboardFileSystem : IFileSystem { - public interface ICupboardFileSystem : IFileSystem - { - } } diff --git a/src/Cupboard.Core/IO/IProcessRunner.cs b/src/Cupboard.Core/IO/IProcessRunner.cs index 834c1be..ac12f48 100644 --- a/src/Cupboard.Core/IO/IProcessRunner.cs +++ b/src/Cupboard.Core/IO/IProcessRunner.cs @@ -1,10 +1,9 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public interface IProcessRunner { - public interface IProcessRunner - { - Task Run(string file, string arguments, Func? filter = null, bool supressOutput = false); - } + Task Run(string file, string arguments, Func? filter = null, bool supressOutput = false); } diff --git a/src/Cupboard.Core/IO/IWindowsRegistry.cs b/src/Cupboard.Core/IO/IWindowsRegistry.cs index d8eb356..f219e46 100644 --- a/src/Cupboard.Core/IO/IWindowsRegistry.cs +++ b/src/Cupboard.Core/IO/IWindowsRegistry.cs @@ -1,12 +1,11 @@ -namespace Cupboard +namespace Cupboard; + +public interface IWindowsRegistry { - public interface IWindowsRegistry - { - IWindowsRegistryKey ClassesRoot { get; } - IWindowsRegistryKey CurrentConfig { get; } - IWindowsRegistryKey CurrentUser { get; } - IWindowsRegistryKey LocalMachine { get; } - IWindowsRegistryKey PerformanceData { get; } - IWindowsRegistryKey Users { get; } - } + IWindowsRegistryKey ClassesRoot { get; } + IWindowsRegistryKey CurrentConfig { get; } + IWindowsRegistryKey CurrentUser { get; } + IWindowsRegistryKey LocalMachine { get; } + IWindowsRegistryKey PerformanceData { get; } + IWindowsRegistryKey Users { get; } } diff --git a/src/Cupboard.Core/IO/IWindowsRegistryKey.cs b/src/Cupboard.Core/IO/IWindowsRegistryKey.cs index b32341b..3dc31cf 100644 --- a/src/Cupboard.Core/IO/IWindowsRegistryKey.cs +++ b/src/Cupboard.Core/IO/IWindowsRegistryKey.cs @@ -1,21 +1,20 @@ using System; -namespace Cupboard +namespace Cupboard; + +public interface IWindowsRegistryKey { - public interface IWindowsRegistryKey - { - IWindowsRegistryKey? OpenSubKey(string name, bool writable); - IWindowsRegistryKey? CreateSubKey(string name, bool writable); + IWindowsRegistryKey? OpenSubKey(string name, bool writable); + IWindowsRegistryKey? CreateSubKey(string name, bool writable); - int GetValueCount(); + int GetValueCount(); - bool ValueExists(string name); - object? GetValue(string name); - void DeleteValue(string name); + bool ValueExists(string name); + object? GetValue(string name); + void DeleteValue(string name); - [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] - void SetValue(string name, object value, RegistryKeyValueKind kind); + [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] + void SetValue(string name, object value, RegistryKeyValueKind kind); - void SetValue(string name, object value, RegistryValueKind kind); - } + void SetValue(string name, object value, RegistryValueKind kind); } diff --git a/src/Cupboard.Core/IO/Obsolete/RegistryKeyPath.cs b/src/Cupboard.Core/IO/Obsolete/RegistryKeyPath.cs index 75e3f4e..b027340 100644 --- a/src/Cupboard.Core/IO/Obsolete/RegistryKeyPath.cs +++ b/src/Cupboard.Core/IO/Obsolete/RegistryKeyPath.cs @@ -2,105 +2,104 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use RegistryPath instead")] +public sealed class RegistryKeyPath { - [Obsolete("Please use RegistryPath instead")] - public sealed class RegistryKeyPath - { - private static readonly Dictionary _rootSubstitutions; - private static readonly Dictionary _roots; + private static readonly Dictionary _rootSubstitutions; + private static readonly Dictionary _roots; - public RegistryKeyRoot Root { get; set; } - public string Path { get; set; } - public string SubKey { get; } - public string Value { get; } - public IReadOnlyList Segments { get; } + public RegistryKeyRoot Root { get; set; } + public string Path { get; set; } + public string SubKey { get; } + public string Value { get; } + public IReadOnlyList Segments { get; } - public bool IsValid { get; } + public bool IsValid { get; } - static RegistryKeyPath() + static RegistryKeyPath() + { + _rootSubstitutions = new Dictionary(StringComparer.OrdinalIgnoreCase) { - _rootSubstitutions = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "HKCR", "HKEY_CLASSES_ROOT" }, - { "HKCU", "HKEY_CURRENT_USER" }, - { "HKLM", "HKEY_LOCAL_MACHINE" }, - { "HKU", "HKEY_USERS" }, - { "HKPD", "HKEY_PERFORMANCE_DATA" }, - { "HKCC", "HKEY_CURRENT_CONFIG" }, - { "HKCR:", "HKEY_CLASSES_ROOT" }, - { "HKCU:", "HKEY_CURRENT_USER" }, - { "HKLM:", "HKEY_LOCAL_MACHINE" }, - { "HKU:", "HKEY_USERS" }, - { "HKPD:", "HKEY_PERFORMANCE_DATA" }, - { "HKCC:", "HKEY_CURRENT_CONFIG" }, - }; - - _roots = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "HKEY_CLASSES_ROOT", RegistryKeyRoot.ClassesRoot }, - { "HKEY_CURRENT_CONFIG", RegistryKeyRoot.CurrentConfig }, - { "HKEY_CURRENT_USER", RegistryKeyRoot.CurrentUser }, - { "HKEY_LOCAL_MACHINE", RegistryKeyRoot.LocalMachine }, - { "HKEY_PERFORMANCE_DATA", RegistryKeyRoot.PerformanceData }, - { "HKEY_USERS", RegistryKeyRoot.Users }, - }; - } + { "HKCR", "HKEY_CLASSES_ROOT" }, + { "HKCU", "HKEY_CURRENT_USER" }, + { "HKLM", "HKEY_LOCAL_MACHINE" }, + { "HKU", "HKEY_USERS" }, + { "HKPD", "HKEY_PERFORMANCE_DATA" }, + { "HKCC", "HKEY_CURRENT_CONFIG" }, + { "HKCR:", "HKEY_CLASSES_ROOT" }, + { "HKCU:", "HKEY_CURRENT_USER" }, + { "HKLM:", "HKEY_LOCAL_MACHINE" }, + { "HKU:", "HKEY_USERS" }, + { "HKPD:", "HKEY_PERFORMANCE_DATA" }, + { "HKCC:", "HKEY_CURRENT_CONFIG" }, + }; - public RegistryKeyPath(string path) + _roots = new Dictionary(StringComparer.OrdinalIgnoreCase) { - path ??= string.Empty; - var key = path.Replace("/", "\\"); - - Path = string.Empty; - Segments = new List(key.Split('\\')); + { "HKEY_CLASSES_ROOT", RegistryKeyRoot.ClassesRoot }, + { "HKEY_CURRENT_CONFIG", RegistryKeyRoot.CurrentConfig }, + { "HKEY_CURRENT_USER", RegistryKeyRoot.CurrentUser }, + { "HKEY_LOCAL_MACHINE", RegistryKeyRoot.LocalMachine }, + { "HKEY_PERFORMANCE_DATA", RegistryKeyRoot.PerformanceData }, + { "HKEY_USERS", RegistryKeyRoot.Users }, + }; + } - if (Segments.Count > 0) - { - Root = GetRoot(Segments[0]); - Segments = Segments.Skip(1).ToList(); - Path = string.Join("\\", Segments); - } + public RegistryKeyPath(string path) + { + path ??= string.Empty; + var key = path.Replace("/", "\\"); - SubKey = string.Join("\\", Segments.Take(Segments.Count - 1)); - Value = Segments.LastOrDefault() ?? string.Empty; + Path = string.Empty; + Segments = new List(key.Split('\\')); - IsValid = Segments.Count > 1 - && Root != RegistryKeyRoot.Unknown - && !string.IsNullOrWhiteSpace(Path); + if (Segments.Count > 0) + { + Root = GetRoot(Segments[0]); + Segments = Segments.Skip(1).ToList(); + Path = string.Join("\\", Segments); } - private static RegistryKeyRoot GetRoot(string rootName) - { - if (_rootSubstitutions.ContainsKey(rootName)) - { - rootName = _rootSubstitutions[rootName]; - } + SubKey = string.Join("\\", Segments.Take(Segments.Count - 1)); + Value = Segments.LastOrDefault() ?? string.Empty; - if (!_roots.TryGetValue(rootName, out var r)) - { - return RegistryKeyRoot.Unknown; - } + IsValid = Segments.Count > 1 + && Root != RegistryKeyRoot.Unknown + && !string.IsNullOrWhiteSpace(Path); + } - return r; + private static RegistryKeyRoot GetRoot(string rootName) + { + if (_rootSubstitutions.ContainsKey(rootName)) + { + rootName = _rootSubstitutions[rootName]; } - private string? GetRootName() + if (!_roots.TryGetValue(rootName, out var r)) { - return Root switch - { - RegistryKeyRoot.ClassesRoot => "HKEY_CLASSES_ROOT", - RegistryKeyRoot.CurrentUser => "HKEY_CURRENT_USER", - RegistryKeyRoot.LocalMachine => "HKEY_LOCAL_MACHINE", - RegistryKeyRoot.Users => "HKEY_USERS", - RegistryKeyRoot.CurrentConfig => "HKEY_CURRENT_CONFIG", - _ => null, - }; + return RegistryKeyRoot.Unknown; } - public override string ToString() + return r; + } + + private string? GetRootName() + { + return Root switch { - return string.Concat(GetRootName(), "\\", Path); - } + RegistryKeyRoot.ClassesRoot => "HKEY_CLASSES_ROOT", + RegistryKeyRoot.CurrentUser => "HKEY_CURRENT_USER", + RegistryKeyRoot.LocalMachine => "HKEY_LOCAL_MACHINE", + RegistryKeyRoot.Users => "HKEY_USERS", + RegistryKeyRoot.CurrentConfig => "HKEY_CURRENT_CONFIG", + _ => null, + }; + } + + public override string ToString() + { + return string.Concat(GetRootName(), "\\", Path); } } diff --git a/src/Cupboard.Core/IO/Obsolete/RegistryKeyRoot.cs b/src/Cupboard.Core/IO/Obsolete/RegistryKeyRoot.cs index 08a2efa..3b7bd9b 100644 --- a/src/Cupboard.Core/IO/Obsolete/RegistryKeyRoot.cs +++ b/src/Cupboard.Core/IO/Obsolete/RegistryKeyRoot.cs @@ -1,16 +1,15 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use RegistryRoot instead")] +public enum RegistryKeyRoot { - [Obsolete("Please use RegistryRoot instead")] - public enum RegistryKeyRoot - { - Unknown = 0, - ClassesRoot = 1, - CurrentUser = 2, - LocalMachine = 3, - Users = 4, - CurrentConfig = 5, - PerformanceData = 6, - } + Unknown = 0, + ClassesRoot = 1, + CurrentUser = 2, + LocalMachine = 3, + Users = 4, + CurrentConfig = 5, + PerformanceData = 6, } diff --git a/src/Cupboard.Core/IO/Obsolete/RegistryKeyValueKind.cs b/src/Cupboard.Core/IO/Obsolete/RegistryKeyValueKind.cs index c5dc09b..e1d0c69 100644 --- a/src/Cupboard.Core/IO/Obsolete/RegistryKeyValueKind.cs +++ b/src/Cupboard.Core/IO/Obsolete/RegistryKeyValueKind.cs @@ -1,17 +1,16 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use RegistryValueKind instead")] +public enum RegistryKeyValueKind { - [Obsolete("Please use RegistryValueKind instead")] - public enum RegistryKeyValueKind - { - None = -1, - Unknown = 0, - String = 1, - ExpandString = 2, - Binary = 3, - DWord = 4, - MultiString = 7, - QWord = 11, - } + None = -1, + Unknown = 0, + String = 1, + ExpandString = 2, + Binary = 3, + DWord = 4, + MultiString = 7, + QWord = 11, } diff --git a/src/Cupboard.Core/IO/Permissions.cs b/src/Cupboard.Core/IO/Permissions.cs index bee6c26..4adcef4 100644 --- a/src/Cupboard.Core/IO/Permissions.cs +++ b/src/Cupboard.Core/IO/Permissions.cs @@ -1,14 +1,13 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Flags] +public enum Permissions { - [Flags] - public enum Permissions - { - None = 0, - Execute = 1, - Write = 2, - Read = 4, - All = Read | Write | Execute, - } + None = 0, + Execute = 1, + Write = 2, + Read = 4, + All = Read | Write | Execute, } diff --git a/src/Cupboard.Core/IO/ProcessRunnerResult.cs b/src/Cupboard.Core/IO/ProcessRunnerResult.cs index f5e5221..8e1188a 100644 --- a/src/Cupboard.Core/IO/ProcessRunnerResult.cs +++ b/src/Cupboard.Core/IO/ProcessRunnerResult.cs @@ -1,16 +1,15 @@ -namespace Cupboard +namespace Cupboard; + +public sealed class ProcessRunnerResult { - public sealed class ProcessRunnerResult - { - public int ExitCode { get; } - public string StandardOut { get; } - public string StandardError { get; } + public int ExitCode { get; } + public string StandardOut { get; } + public string StandardError { get; } - public ProcessRunnerResult(int exitCode, string? standardOut = null, string? standardError = null) - { - ExitCode = exitCode; - StandardOut = standardOut ?? string.Empty; - StandardError = standardError ?? string.Empty; - } + public ProcessRunnerResult(int exitCode, string? standardOut = null, string? standardError = null) + { + ExitCode = exitCode; + StandardOut = standardOut ?? string.Empty; + StandardError = standardError ?? string.Empty; } } diff --git a/src/Cupboard.Core/IO/RegistryHive.cs b/src/Cupboard.Core/IO/RegistryHive.cs index 5769efe..decd338 100644 --- a/src/Cupboard.Core/IO/RegistryHive.cs +++ b/src/Cupboard.Core/IO/RegistryHive.cs @@ -1,13 +1,12 @@ -namespace Cupboard +namespace Cupboard; + +public enum RegistryHive { - public enum RegistryHive - { - Unknown = 0, - ClassesRoot = 1, - CurrentUser = 2, - LocalMachine = 3, - Users = 4, - CurrentConfig = 5, - PerformanceData = 6, - } + Unknown = 0, + ClassesRoot = 1, + CurrentUser = 2, + LocalMachine = 3, + Users = 4, + CurrentConfig = 5, + PerformanceData = 6, } diff --git a/src/Cupboard.Core/IO/RegistryPath.cs b/src/Cupboard.Core/IO/RegistryPath.cs index 0760c4a..efa2fb4 100644 --- a/src/Cupboard.Core/IO/RegistryPath.cs +++ b/src/Cupboard.Core/IO/RegistryPath.cs @@ -2,107 +2,106 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard +namespace Cupboard; + +public sealed class RegistryPath { - public sealed class RegistryPath - { - private static readonly Dictionary _rootSubstitutions; - private static readonly Dictionary _roots; + private static readonly Dictionary _rootSubstitutions; + private static readonly Dictionary _roots; - public RegistryHive Hive { get; set; } - public string Path { get; set; } - public string SubKey { get; } - public IReadOnlyList Segments { get; } + public RegistryHive Hive { get; set; } + public string Path { get; set; } + public string SubKey { get; } + public IReadOnlyList Segments { get; } - public bool IsValid { get; } + public bool IsValid { get; } - static RegistryPath() + static RegistryPath() + { + _rootSubstitutions = new Dictionary(StringComparer.OrdinalIgnoreCase) { - _rootSubstitutions = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "HKCR", "HKEY_CLASSES_ROOT" }, - { "HKCU", "HKEY_CURRENT_USER" }, - { "HKLM", "HKEY_LOCAL_MACHINE" }, - { "HKU", "HKEY_USERS" }, - { "HKPD", "HKEY_PERFORMANCE_DATA" }, - { "HKCC", "HKEY_CURRENT_CONFIG" }, - { "HKCR:", "HKEY_CLASSES_ROOT" }, - { "HKCU:", "HKEY_CURRENT_USER" }, - { "HKLM:", "HKEY_LOCAL_MACHINE" }, - { "HKU:", "HKEY_USERS" }, - { "HKPD:", "HKEY_PERFORMANCE_DATA" }, - { "HKCC:", "HKEY_CURRENT_CONFIG" }, - }; - - _roots = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "HKEY_CLASSES_ROOT", RegistryHive.ClassesRoot }, - { "HKEY_CURRENT_CONFIG", RegistryHive.CurrentConfig }, - { "HKEY_CURRENT_USER", RegistryHive.CurrentUser }, - { "HKEY_LOCAL_MACHINE", RegistryHive.LocalMachine }, - { "HKEY_PERFORMANCE_DATA", RegistryHive.PerformanceData }, - { "HKEY_USERS", RegistryHive.Users }, - }; - } - - public RegistryPath(string path) + { "HKCR", "HKEY_CLASSES_ROOT" }, + { "HKCU", "HKEY_CURRENT_USER" }, + { "HKLM", "HKEY_LOCAL_MACHINE" }, + { "HKU", "HKEY_USERS" }, + { "HKPD", "HKEY_PERFORMANCE_DATA" }, + { "HKCC", "HKEY_CURRENT_CONFIG" }, + { "HKCR:", "HKEY_CLASSES_ROOT" }, + { "HKCU:", "HKEY_CURRENT_USER" }, + { "HKLM:", "HKEY_LOCAL_MACHINE" }, + { "HKU:", "HKEY_USERS" }, + { "HKPD:", "HKEY_PERFORMANCE_DATA" }, + { "HKCC:", "HKEY_CURRENT_CONFIG" }, + }; + + _roots = new Dictionary(StringComparer.OrdinalIgnoreCase) { - path ??= string.Empty; - var key = path.Replace("/", "\\"); - - Path = string.Empty; - Segments = new List(key.Split('\\')); - - if (Segments.Count > 0) - { - Hive = GetRoot(Segments[0]); - Segments = Segments.Skip(1).ToList(); - Path = string.Join("\\", Segments); - } + { "HKEY_CLASSES_ROOT", RegistryHive.ClassesRoot }, + { "HKEY_CURRENT_CONFIG", RegistryHive.CurrentConfig }, + { "HKEY_CURRENT_USER", RegistryHive.CurrentUser }, + { "HKEY_LOCAL_MACHINE", RegistryHive.LocalMachine }, + { "HKEY_PERFORMANCE_DATA", RegistryHive.PerformanceData }, + { "HKEY_USERS", RegistryHive.Users }, + }; + } - SubKey = string.Join("\\", Segments.Take(Segments.Count)); + public RegistryPath(string path) + { + path ??= string.Empty; + var key = path.Replace("/", "\\"); - IsValid = Segments.Count > 1 - && Hive != RegistryHive.Unknown - && !string.IsNullOrWhiteSpace(Path); - } + Path = string.Empty; + Segments = new List(key.Split('\\')); - private static RegistryHive GetRoot(string rootName) + if (Segments.Count > 0) { - if (_rootSubstitutions.ContainsKey(rootName)) - { - rootName = _rootSubstitutions[rootName]; - } + Hive = GetRoot(Segments[0]); + Segments = Segments.Skip(1).ToList(); + Path = string.Join("\\", Segments); + } - if (!_roots.TryGetValue(rootName, out var r)) - { - return RegistryHive.Unknown; - } + SubKey = string.Join("\\", Segments.Take(Segments.Count)); - return r; - } + IsValid = Segments.Count > 1 + && Hive != RegistryHive.Unknown + && !string.IsNullOrWhiteSpace(Path); + } - private string? GetRootName() + private static RegistryHive GetRoot(string rootName) + { + if (_rootSubstitutions.ContainsKey(rootName)) { - return Hive switch - { - RegistryHive.ClassesRoot => "HKEY_CLASSES_ROOT", - RegistryHive.CurrentUser => "HKEY_CURRENT_USER", - RegistryHive.LocalMachine => "HKEY_LOCAL_MACHINE", - RegistryHive.Users => "HKEY_USERS", - RegistryHive.CurrentConfig => "HKEY_CURRENT_CONFIG", - _ => null, - }; + rootName = _rootSubstitutions[rootName]; } - public static implicit operator RegistryPath(string path) + if (!_roots.TryGetValue(rootName, out var r)) { - return new RegistryPath(path); + return RegistryHive.Unknown; } - public override string ToString() + return r; + } + + private string? GetRootName() + { + return Hive switch { - return string.Concat(GetRootName(), "\\", Path); - } + RegistryHive.ClassesRoot => "HKEY_CLASSES_ROOT", + RegistryHive.CurrentUser => "HKEY_CURRENT_USER", + RegistryHive.LocalMachine => "HKEY_LOCAL_MACHINE", + RegistryHive.Users => "HKEY_USERS", + RegistryHive.CurrentConfig => "HKEY_CURRENT_CONFIG", + _ => null, + }; + } + + public static implicit operator RegistryPath(string path) + { + return new RegistryPath(path); + } + + public override string ToString() + { + return string.Concat(GetRootName(), "\\", Path); } } diff --git a/src/Cupboard.Core/IO/RegistryValueKind.cs b/src/Cupboard.Core/IO/RegistryValueKind.cs index abeaf29..b98eb02 100644 --- a/src/Cupboard.Core/IO/RegistryValueKind.cs +++ b/src/Cupboard.Core/IO/RegistryValueKind.cs @@ -1,14 +1,13 @@ -namespace Cupboard +namespace Cupboard; + +public enum RegistryValueKind { - public enum RegistryValueKind - { - None = -1, - Unknown = 0, - String = 1, - ExpandString = 2, - Binary = 3, - DWord = 4, - MultiString = 7, - QWord = 11, - } + None = -1, + Unknown = 0, + String = 1, + ExpandString = 2, + Binary = 3, + DWord = 4, + MultiString = 7, + QWord = 11, } diff --git a/src/Cupboard.Core/IO/SpecialMode.cs b/src/Cupboard.Core/IO/SpecialMode.cs index 636dfa4..4ee8941 100644 --- a/src/Cupboard.Core/IO/SpecialMode.cs +++ b/src/Cupboard.Core/IO/SpecialMode.cs @@ -1,14 +1,13 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Flags] +public enum SpecialMode { - [Flags] - public enum SpecialMode - { - None = 0, - Sticky = 1, - Setgid = 1 << 1, - Setuid = 1 << 2, - All = Sticky | Setgid | Setuid, - } + None = 0, + Sticky = 1, + Setgid = 1 << 1, + Setuid = 1 << 2, + All = Sticky | Setgid | Setuid, } diff --git a/src/Cupboard.Core/IRebootDetector.cs b/src/Cupboard.Core/IRebootDetector.cs index 0cf75cd..1bac215 100644 --- a/src/Cupboard.Core/IRebootDetector.cs +++ b/src/Cupboard.Core/IRebootDetector.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface IRebootDetector { - public interface IRebootDetector - { - bool HasPendingReboot(); - } + bool HasPendingReboot(); } diff --git a/src/Cupboard.Core/IReportSubscriber.cs b/src/Cupboard.Core/IReportSubscriber.cs index c14a2cb..829aa29 100644 --- a/src/Cupboard.Core/IReportSubscriber.cs +++ b/src/Cupboard.Core/IReportSubscriber.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface IReportSubscriber { - public interface IReportSubscriber - { - void Notify(Report report); - } + void Notify(Report report); } diff --git a/src/Cupboard.Core/IResourceBuilder.cs b/src/Cupboard.Core/IResourceBuilder.cs index 8c87221..8b18b5f 100644 --- a/src/Cupboard.Core/IResourceBuilder.cs +++ b/src/Cupboard.Core/IResourceBuilder.cs @@ -1,12 +1,11 @@ using System; -namespace Cupboard +namespace Cupboard; + +public interface IResourceBuilder + where TResource : Resource { - public interface IResourceBuilder - where TResource : Resource - { - IResourceBuilder Before(string name); - IResourceBuilder After(string name); - IResourceBuilder Configure(Action action); - } + IResourceBuilder Before(string name); + IResourceBuilder After(string name); + IResourceBuilder Configure(Action action); } diff --git a/src/Cupboard.Core/IResourceIdentity.cs b/src/Cupboard.Core/IResourceIdentity.cs index 188cb3c..5d30d0c 100644 --- a/src/Cupboard.Core/IResourceIdentity.cs +++ b/src/Cupboard.Core/IResourceIdentity.cs @@ -1,11 +1,10 @@ using System; -namespace Cupboard +namespace Cupboard; + +public interface IResourceIdentity { - public interface IResourceIdentity - { - Type ResourceType { get; } + Type ResourceType { get; } - string Name { get; } - } + string Name { get; } } diff --git a/src/Cupboard.Core/IResourceProvider.cs b/src/Cupboard.Core/IResourceProvider.cs index 21921bc..e85bc73 100644 --- a/src/Cupboard.Core/IResourceProvider.cs +++ b/src/Cupboard.Core/IResourceProvider.cs @@ -1,16 +1,15 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public interface IResourceProvider { - public interface IResourceProvider - { - Type ResourceType { get; } + Type ResourceType { get; } - Resource Create(string name); + Resource Create(string name); - bool RequireAdministrator(FactCollection facts); - bool CanRun(FactCollection facts); - Task RunAsync(IExecutionContext context, Resource resource); - } + bool RequireAdministrator(FactCollection facts); + bool CanRun(FactCollection facts); + Task RunAsync(IExecutionContext context, Resource resource); } diff --git a/src/Cupboard.Core/ISecurityPrincipal.cs b/src/Cupboard.Core/ISecurityPrincipal.cs index 4a8f025..c821b2c 100644 --- a/src/Cupboard.Core/ISecurityPrincipal.cs +++ b/src/Cupboard.Core/ISecurityPrincipal.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public interface ISecurityPrincipal { - public interface ISecurityPrincipal - { - bool IsAdministrator(); - } + bool IsAdministrator(); } diff --git a/src/Cupboard.Core/LogLevel.cs b/src/Cupboard.Core/LogLevel.cs index da53b95..db7ff84 100644 --- a/src/Cupboard.Core/LogLevel.cs +++ b/src/Cupboard.Core/LogLevel.cs @@ -1,36 +1,35 @@ -namespace Cupboard +namespace Cupboard; + +public enum LogLevel { - public enum LogLevel - { - /// - /// Severe errors that cause premature termination. - /// - Fatal, + /// + /// Severe errors that cause premature termination. + /// + Fatal, - /// - /// Other runtime errors or unexpected conditions. - /// - Error, + /// + /// Other runtime errors or unexpected conditions. + /// + Error, - /// - /// Use of deprecated APIs, poor use of API, 'almost' errors, other runtime - /// situations that are undesirable or unexpected, but not necessarily "wrong". - /// - Warning, + /// + /// Use of deprecated APIs, poor use of API, 'almost' errors, other runtime + /// situations that are undesirable or unexpected, but not necessarily "wrong". + /// + Warning, - /// - /// Interesting runtime events. - /// - Information, + /// + /// Interesting runtime events. + /// + Information, - /// - /// Detailed information on the flow through the system. - /// - Verbose, + /// + /// Detailed information on the flow through the system. + /// + Verbose, - /// - /// Most detailed information. - /// - Debug, - } + /// + /// Most detailed information. + /// + Debug, } diff --git a/src/Cupboard.Core/Manifest.cs b/src/Cupboard.Core/Manifest.cs index e0c4e52..1311e8a 100644 --- a/src/Cupboard.Core/Manifest.cs +++ b/src/Cupboard.Core/Manifest.cs @@ -1,7 +1,6 @@ -namespace Cupboard +namespace Cupboard; + +public abstract class Manifest { - public abstract class Manifest - { - public abstract void Execute(ManifestContext context); - } + public abstract void Execute(ManifestContext context); } diff --git a/src/Cupboard.Core/ManifestContext.cs b/src/Cupboard.Core/ManifestContext.cs index 4e29a31..d11ded0 100644 --- a/src/Cupboard.Core/ManifestContext.cs +++ b/src/Cupboard.Core/ManifestContext.cs @@ -3,55 +3,54 @@ using System.Linq; using System.Reflection; -namespace Cupboard +namespace Cupboard; + +public sealed class ManifestContext { - public sealed class ManifestContext - { - private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.Instance; + private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.Instance; - public FactCollection Facts { get; } + public FactCollection Facts { get; } - public List Builders { get; } + public List Builders { get; } - public ManifestContext(FactCollection facts) - { - Facts = facts ?? throw new ArgumentNullException(nameof(facts)); - Builders = new List(); - } + public ManifestContext(FactCollection facts) + { + Facts = facts ?? throw new ArgumentNullException(nameof(facts)); + Builders = new List(); + } - public void Resources(IEnumerable resources, Action>? config = null) - where TResource : Resource - { - // Get all public instance properties of the resource - // that are both readable and writable. - var properties = typeof(TResource) - .GetProperties(Bindings) - .Where(p => p.CanRead && p.CanWrite); + public void Resources(IEnumerable resources, Action>? config = null) + where TResource : Resource + { + // Get all public instance properties of the resource + // that are both readable and writable. + var properties = typeof(TResource) + .GetProperties(Bindings) + .Where(p => p.CanRead && p.CanWrite); - foreach (var resource in resources) + foreach (var resource in resources) + { + var builder = new ResourceBuilder(resource.Name); + builder.Configure(c => { - var builder = new ResourceBuilder(resource.Name); - builder.Configure(c => + // Shallow clone of the resource + foreach (var property in properties) { - // Shallow clone of the resource - foreach (var property in properties) - { - var value = property.GetValue(resource); - property.SetValue(c, value); - } - }); - - config?.Invoke(builder); - Builders.Add(builder); - } - } + var value = property.GetValue(resource); + property.SetValue(c, value); + } + }); - public IResourceBuilder Resource(string name) - where TResource : Resource - { - var builder = new ResourceBuilder(name); + config?.Invoke(builder); Builders.Add(builder); - return builder; } } + + public IResourceBuilder Resource(string name) + where TResource : Resource + { + var builder = new ResourceBuilder(name); + Builders.Add(builder); + return builder; + } } diff --git a/src/Cupboard.Core/OSArchitecture.cs b/src/Cupboard.Core/OSArchitecture.cs index b21fd8f..85c7a46 100644 --- a/src/Cupboard.Core/OSArchitecture.cs +++ b/src/Cupboard.Core/OSArchitecture.cs @@ -1,11 +1,10 @@ -namespace Cupboard +namespace Cupboard; + +public enum OSArchitecture { - public enum OSArchitecture - { - Unknown, - X86, - X64, - ARM, - ARM64, - } + Unknown, + X86, + X64, + ARM, + ARM64, } diff --git a/src/Cupboard.Core/OSPlatform.cs b/src/Cupboard.Core/OSPlatform.cs index 22630de..5e172fd 100644 --- a/src/Cupboard.Core/OSPlatform.cs +++ b/src/Cupboard.Core/OSPlatform.cs @@ -1,11 +1,10 @@ -namespace Cupboard +namespace Cupboard; + +public enum OSPlatform { - public enum OSPlatform - { - Unknown, - Windows, - Linux, - MacOS, - FreeBSD, - } + Unknown, + Windows, + Linux, + MacOS, + FreeBSD, } diff --git a/src/Cupboard.Core/PackageInstallerOperation.cs b/src/Cupboard.Core/PackageInstallerOperation.cs index 8c24345..3affdc9 100644 --- a/src/Cupboard.Core/PackageInstallerOperation.cs +++ b/src/Cupboard.Core/PackageInstallerOperation.cs @@ -1,9 +1,8 @@ -namespace Cupboard +namespace Cupboard; + +public enum PackageInstallerOperation { - public enum PackageInstallerOperation - { - RetriveState = 0, - Install = 1, - Uninstall = 2, - } + RetriveState = 0, + Install = 1, + Uninstall = 2, } diff --git a/src/Cupboard.Core/PackageInstallerProvider.cs b/src/Cupboard.Core/PackageInstallerProvider.cs index b5e38b8..3588e08 100644 --- a/src/Cupboard.Core/PackageInstallerProvider.cs +++ b/src/Cupboard.Core/PackageInstallerProvider.cs @@ -1,165 +1,164 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public abstract class PackageInstallerProvider : AsyncResourceProvider + where T : Resource, IHasPackageState, IHasPackageName { - public abstract class PackageInstallerProvider : AsyncResourceProvider - where T : Resource, IHasPackageState, IHasPackageName + private readonly ICupboardLogger _logger; + private readonly IEnvironmentRefresher _refresher; + private string? _cachedOutput; + + protected virtual bool ShouldRefresh => true; + protected virtual bool ShouldCache => false; + protected abstract string Name { get; } + protected virtual string Kind { get; } = "package"; + + protected PackageInstallerProvider( + ICupboardLogger logger, + IEnvironmentRefresher refresher) { - private readonly ICupboardLogger _logger; - private readonly IEnvironmentRefresher _refresher; - private string? _cachedOutput; - - protected virtual bool ShouldRefresh => true; - protected virtual bool ShouldCache => false; - protected abstract string Name { get; } - protected virtual string Kind { get; } = "package"; - - protected PackageInstallerProvider( - ICupboardLogger logger, - IEnvironmentRefresher refresher) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _refresher = refresher; - } + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _refresher = refresher; + } - protected abstract Task GetPackageState(T resource); - protected abstract bool IsPackageInstalled(T resource, string output); + protected abstract Task GetPackageState(T resource); + protected abstract bool IsPackageInstalled(T resource, string output); - protected abstract Task InstallPackage(T resource); - protected abstract Task UninstallPackage(T resource); + protected abstract Task InstallPackage(T resource); + protected abstract Task UninstallPackage(T resource); - protected virtual bool IsError(PackageInstallerOperation operation, ProcessRunnerResult result) + protected virtual bool IsError(PackageInstallerOperation operation, ProcessRunnerResult result) + { + return result.ExitCode != 0; + } + + public override async Task RunAsync(IExecutionContext context, T resource) + { + var state = await CheckIfInstalled(resource).ConfigureAwait(false); + if (state == PackageInstallerResult.Error) { - return result.ExitCode != 0; + return ResourceState.Error; } - public override async Task RunAsync(IExecutionContext context, T resource) + if (resource.Ensure == PackageState.Installed) { - var state = await CheckIfInstalled(resource).ConfigureAwait(false); - if (state == PackageInstallerResult.Error) - { - return ResourceState.Error; - } - - if (resource.Ensure == PackageState.Installed) + if (state == PackageInstallerResult.Missing) { - if (state == PackageInstallerResult.Missing) + if (context.DryRun) { - if (context.DryRun) - { - return ResourceState.Changed; - } - - // Install package - return await Install(resource).ConfigureAwait(false); + return ResourceState.Changed; } - _logger.Debug($"The {Name} {Kind} [yellow]{resource.Package}[/] is already installed"); + // Install package + return await Install(resource).ConfigureAwait(false); } - else + + _logger.Debug($"The {Name} {Kind} [yellow]{resource.Package}[/] is already installed"); + } + else + { + if (state == PackageInstallerResult.Exists) { - if (state == PackageInstallerResult.Exists) + if (context.DryRun) { - if (context.DryRun) - { - return ResourceState.Changed; - } - - // Uninstall package - return await Uninstall(resource).ConfigureAwait(false); + return ResourceState.Changed; } - _logger.Debug($"The {Name} {Kind} [yellow]{resource.Package}[/] is already uninstalled"); + // Uninstall package + return await Uninstall(resource).ConfigureAwait(false); } - return ResourceState.Unchanged; + _logger.Debug($"The {Name} {Kind} [yellow]{resource.Package}[/] is already uninstalled"); } - private async Task CheckIfInstalled(T resource) - { - if (ShouldCache && _cachedOutput is not null) - { - return IsPackageInstalled(resource, _cachedOutput) - ? PackageInstallerResult.Exists - : PackageInstallerResult.Missing; - } - - var result = await GetPackageState(resource).ConfigureAwait(false); - if (IsError(PackageInstallerOperation.RetriveState, result)) - { - _logger.Error($"An error occured while retrieving {Name} state"); - return PackageInstallerResult.Error; - } - - if (ShouldCache) - { - _cachedOutput = result.StandardOut; - } + return ResourceState.Unchanged; + } - return IsPackageInstalled(resource, result.StandardOut) + private async Task CheckIfInstalled(T resource) + { + if (ShouldCache && _cachedOutput is not null) + { + return IsPackageInstalled(resource, _cachedOutput) ? PackageInstallerResult.Exists : PackageInstallerResult.Missing; } - private async Task Install(T resource) + var result = await GetPackageState(resource).ConfigureAwait(false); + if (IsError(PackageInstallerOperation.RetriveState, result)) { - _logger.Debug($"Installing {Name} {Kind} [yellow]{resource.Package}[/]"); - - // Install package - var result = await InstallPackage(resource).ConfigureAwait(false); - _cachedOutput = null; + _logger.Error($"An error occured while retrieving {Name} state"); + return PackageInstallerResult.Error; + } - if (IsError(PackageInstallerOperation.Install, result)) - { - _logger.Error($"An error occured while installing {Name} package"); - return ResourceState.Error; - } + if (ShouldCache) + { + _cachedOutput = result.StandardOut; + } - var state = await CheckIfInstalled(resource).ConfigureAwait(false); - if (state == PackageInstallerResult.Exists) - { - _logger.Information($"The {Name} {Kind} [yellow]{resource.Package}[/] was installed"); + return IsPackageInstalled(resource, result.StandardOut) + ? PackageInstallerResult.Exists + : PackageInstallerResult.Missing; + } - if (ShouldRefresh) - { - _refresher.Refresh(); - } + private async Task Install(T resource) + { + _logger.Debug($"Installing {Name} {Kind} [yellow]{resource.Package}[/]"); - return ResourceState.Changed; - } + // Install package + var result = await InstallPackage(resource).ConfigureAwait(false); + _cachedOutput = null; + if (IsError(PackageInstallerOperation.Install, result)) + { + _logger.Error($"An error occured while installing {Name} package"); return ResourceState.Error; } - private async Task Uninstall(T resource) + var state = await CheckIfInstalled(resource).ConfigureAwait(false); + if (state == PackageInstallerResult.Exists) { - _logger.Debug($"Uninstalling {Name} {Kind} [yellow]{resource.Package}[/]"); - - // Uninstall package - var result = await UninstallPackage(resource).ConfigureAwait(false); - _cachedOutput = null; + _logger.Information($"The {Name} {Kind} [yellow]{resource.Package}[/] was installed"); - if (IsError(PackageInstallerOperation.Uninstall, result)) + if (ShouldRefresh) { - _logger.Error($"An error occured while uninstalling {Name} package"); - return ResourceState.Error; + _refresher.Refresh(); } - var state = await CheckIfInstalled(resource).ConfigureAwait(false); - if (state == PackageInstallerResult.Missing) - { - _logger.Information($"The {Name} {Kind} [yellow]{resource.Package}[/] was uninstalled"); + return ResourceState.Changed; + } - if (ShouldRefresh) - { - _refresher.Refresh(); - } + return ResourceState.Error; + } - return ResourceState.Changed; - } + private async Task Uninstall(T resource) + { + _logger.Debug($"Uninstalling {Name} {Kind} [yellow]{resource.Package}[/]"); + // Uninstall package + var result = await UninstallPackage(resource).ConfigureAwait(false); + _cachedOutput = null; + + if (IsError(PackageInstallerOperation.Uninstall, result)) + { + _logger.Error($"An error occured while uninstalling {Name} package"); return ResourceState.Error; } + + var state = await CheckIfInstalled(resource).ConfigureAwait(false); + if (state == PackageInstallerResult.Missing) + { + _logger.Information($"The {Name} {Kind} [yellow]{resource.Package}[/] was uninstalled"); + + if (ShouldRefresh) + { + _refresher.Refresh(); + } + + return ResourceState.Changed; + } + + return ResourceState.Error; } } diff --git a/src/Cupboard.Core/PackageInstallerResult.cs b/src/Cupboard.Core/PackageInstallerResult.cs index 348be53..539b890 100644 --- a/src/Cupboard.Core/PackageInstallerResult.cs +++ b/src/Cupboard.Core/PackageInstallerResult.cs @@ -1,9 +1,8 @@ -namespace Cupboard +namespace Cupboard; + +public enum PackageInstallerResult { - public enum PackageInstallerResult - { - Exists = 0, - Missing = 1, - Error = 2, - } + Exists = 0, + Missing = 1, + Error = 2, } diff --git a/src/Cupboard.Core/PackageState.cs b/src/Cupboard.Core/PackageState.cs index 5fafb20..a48d867 100644 --- a/src/Cupboard.Core/PackageState.cs +++ b/src/Cupboard.Core/PackageState.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum PackageState { - public enum PackageState - { - Installed = 1, - Uninstalled = 2, - } + Installed = 1, + Uninstalled = 2, } diff --git a/src/Cupboard.Core/RebootOptions.cs b/src/Cupboard.Core/RebootOptions.cs index 2e287df..3be8d75 100644 --- a/src/Cupboard.Core/RebootOptions.cs +++ b/src/Cupboard.Core/RebootOptions.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum RebootOptions { - public enum RebootOptions - { - IgnorePendingReboot = 0, - Reboot = 1, - } + IgnorePendingReboot = 0, + Reboot = 1, } diff --git a/src/Cupboard.Core/Report.cs b/src/Cupboard.Core/Report.cs index bb41f7d..9e9ac82 100644 --- a/src/Cupboard.Core/Report.cs +++ b/src/Cupboard.Core/Report.cs @@ -3,40 +3,39 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard +namespace Cupboard; + +public sealed class Report : IEnumerable { - public sealed class Report : IEnumerable - { - public IReadOnlyList Items { get; } - public FactCollection Facts { get; } - public bool RequiresAdministrator { get; } - public bool DryRun { get; } - public bool PendingReboot { get; } + public IReadOnlyList Items { get; } + public FactCollection Facts { get; } + public bool RequiresAdministrator { get; } + public bool DryRun { get; } + public bool PendingReboot { get; } - public int Count => Items.Count; - public bool Successful { get; } + public int Count => Items.Count; + public bool Successful { get; } - public Report(IEnumerable items, FactCollection facts, bool requiresAdministrator, bool dryRun, bool pendingReboot) - { - Items = items.ToReadOnlyList(); - Facts = facts ?? throw new ArgumentNullException(nameof(facts)); - RequiresAdministrator = requiresAdministrator; - DryRun = dryRun; - PendingReboot = pendingReboot; + public Report(IEnumerable items, FactCollection facts, bool requiresAdministrator, bool dryRun, bool pendingReboot) + { + Items = items.ToReadOnlyList(); + Facts = facts ?? throw new ArgumentNullException(nameof(facts)); + RequiresAdministrator = requiresAdministrator; + DryRun = dryRun; + PendingReboot = pendingReboot; - // Exclude Unknown states if this is a dry run - var temp = DryRun ? Items.Where(x => x.State != ResourceState.Unknown) : Items; - Successful = temp.All(x => !x.State.IsError()); - } + // Exclude Unknown states if this is a dry run + var temp = DryRun ? Items.Where(x => x.State != ResourceState.Unknown) : Items; + Successful = temp.All(x => !x.State.IsError()); + } - public IEnumerator GetEnumerator() - { - return Items.GetEnumerator(); - } + public IEnumerator GetEnumerator() + { + return Items.GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); } } diff --git a/src/Cupboard.Core/ReportItem.cs b/src/Cupboard.Core/ReportItem.cs index 45a9007..d0e8a9c 100644 --- a/src/Cupboard.Core/ReportItem.cs +++ b/src/Cupboard.Core/ReportItem.cs @@ -1,18 +1,17 @@ -namespace Cupboard +namespace Cupboard; + +public sealed class ReportItem { - public sealed class ReportItem - { - public Resource Resource { get; } - public IResourceProvider Provider { get; } - public ResourceState State { get; } - public bool RequireAdministrator { get; } + public Resource Resource { get; } + public IResourceProvider Provider { get; } + public ResourceState State { get; } + public bool RequireAdministrator { get; } - public ReportItem(IResourceProvider provider, Resource resource, ResourceState state, bool requireAdministrator) - { - Provider = provider; - Resource = resource; - State = state; - RequireAdministrator = requireAdministrator; - } + public ReportItem(IResourceProvider provider, Resource resource, ResourceState state, bool requireAdministrator) + { + Provider = provider; + Resource = resource; + State = state; + RequireAdministrator = requireAdministrator; } } diff --git a/src/Cupboard.Core/Resource.cs b/src/Cupboard.Core/Resource.cs index cc09989..2d9b5e9 100644 --- a/src/Cupboard.Core/Resource.cs +++ b/src/Cupboard.Core/Resource.cs @@ -1,20 +1,19 @@ using System; -namespace Cupboard +namespace Cupboard; + +public abstract class Resource : IResourceIdentity { - public abstract class Resource : IResourceIdentity - { - public Type ResourceType => GetType(); + public Type ResourceType => GetType(); - public string Name { get; } - public bool RequireAdministrator { get; set; } + public string Name { get; } + public bool RequireAdministrator { get; set; } - public ErrorOptions Error { get; set; } = ErrorOptions.Abort; - public RebootOptions Reboot { get; set; } = RebootOptions.Reboot; + public ErrorOptions Error { get; set; } = ErrorOptions.Abort; + public RebootOptions Reboot { get; set; } = RebootOptions.Reboot; - protected Resource(string name) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); - } + protected Resource(string name) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); } } diff --git a/src/Cupboard.Core/ResourceBuilder.cs b/src/Cupboard.Core/ResourceBuilder.cs index 446078c..8cfd7ba 100644 --- a/src/Cupboard.Core/ResourceBuilder.cs +++ b/src/Cupboard.Core/ResourceBuilder.cs @@ -1,54 +1,53 @@ using System; using System.Collections.Generic; -namespace Cupboard +namespace Cupboard; + +public abstract class ResourceBuilder { - public abstract class ResourceBuilder - { - public string Name { get; } + public string Name { get; } + + public Type Type { get; set; } + + public List> RunBefore { get; } - public Type Type { get; set; } + public List> RunAfter { get; } - public List> RunBefore { get; } + public List> Configurations { get; } + + protected ResourceBuilder(string name, Type type) + { + Name = name; + Type = type; + RunBefore = new List>(); + RunAfter = new List>(); + Configurations = new List>(); + } +} - public List> RunAfter { get; } +public sealed class ResourceBuilder : ResourceBuilder, IResourceBuilder + where TResource : Resource +{ + public ResourceBuilder(string name) + : base(name, typeof(TResource)) + { + } - public List> Configurations { get; } + public IResourceBuilder Before(string name) + { + RunBefore.Add(Tuple.Create(typeof(TOther), name)); + return this; + } - protected ResourceBuilder(string name, Type type) - { - Name = name; - Type = type; - RunBefore = new List>(); - RunAfter = new List>(); - Configurations = new List>(); - } + public IResourceBuilder After(string name) + { + RunAfter.Add(Tuple.Create(typeof(TOther), name)); + return this; } - public sealed class ResourceBuilder : ResourceBuilder, IResourceBuilder - where TResource : Resource + public IResourceBuilder Configure(Action action) { - public ResourceBuilder(string name) - : base(name, typeof(TResource)) - { - } - - public IResourceBuilder Before(string name) - { - RunBefore.Add(Tuple.Create(typeof(TOther), name)); - return this; - } - - public IResourceBuilder After(string name) - { - RunAfter.Add(Tuple.Create(typeof(TOther), name)); - return this; - } - - public IResourceBuilder Configure(Action action) - { - Configurations.Add(resource => action((TResource)resource)); - return this; - } + Configurations.Add(resource => action((TResource)resource)); + return this; } } diff --git a/src/Cupboard.Core/ResourceProvider.cs b/src/Cupboard.Core/ResourceProvider.cs index 5332eba..191bce7 100644 --- a/src/Cupboard.Core/ResourceProvider.cs +++ b/src/Cupboard.Core/ResourceProvider.cs @@ -1,46 +1,45 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public abstract class ResourceProvider : AsyncResourceProvider + where TResource : Resource { - public abstract class ResourceProvider : AsyncResourceProvider - where TResource : Resource - { - public abstract ResourceState Run(IExecutionContext context, TResource resource); + public abstract ResourceState Run(IExecutionContext context, TResource resource); - public sealed override Task RunAsync(IExecutionContext context, TResource resource) - { - return Task.FromResult(Run(context, resource)); - } + public sealed override Task RunAsync(IExecutionContext context, TResource resource) + { + return Task.FromResult(Run(context, resource)); } +} - public abstract class AsyncResourceProvider : IResourceProvider - where TResource : Resource - { - public Type ResourceType => typeof(TResource); +public abstract class AsyncResourceProvider : IResourceProvider + where TResource : Resource +{ + public Type ResourceType => typeof(TResource); - public virtual bool RequireAdministrator(FactCollection facts) - { - return false; - } + public virtual bool RequireAdministrator(FactCollection facts) + { + return false; + } - public virtual bool CanRun(FactCollection facts) - { - return true; - } + public virtual bool CanRun(FactCollection facts) + { + return true; + } - public abstract TResource Create(string name); + public abstract TResource Create(string name); - public abstract Task RunAsync(IExecutionContext context, TResource resource); + public abstract Task RunAsync(IExecutionContext context, TResource resource); - Task IResourceProvider.RunAsync(IExecutionContext context, Resource resource) - { - return RunAsync(context, (TResource)resource); - } + Task IResourceProvider.RunAsync(IExecutionContext context, Resource resource) + { + return RunAsync(context, (TResource)resource); + } - Resource IResourceProvider.Create(string name) - { - return Create(name); - } + Resource IResourceProvider.Create(string name) + { + return Create(name); } } diff --git a/src/Cupboard.Core/ResourceState.cs b/src/Cupboard.Core/ResourceState.cs index 6b22292..a856720 100644 --- a/src/Cupboard.Core/ResourceState.cs +++ b/src/Cupboard.Core/ResourceState.cs @@ -1,13 +1,12 @@ -namespace Cupboard +namespace Cupboard; + +public enum ResourceState { - public enum ResourceState - { - Unknown = 0, - Changed, - Unchanged, - Executed, - Skipped, - ManuallySkipped, - Error, - } + Unknown = 0, + Changed, + Unchanged, + Executed, + Skipped, + ManuallySkipped, + Error, } diff --git a/src/Cupboard.Core/ServiceModule.cs b/src/Cupboard.Core/ServiceModule.cs index ecd7205..6d8b503 100644 --- a/src/Cupboard.Core/ServiceModule.cs +++ b/src/Cupboard.Core/ServiceModule.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.DependencyInjection; -namespace Cupboard +namespace Cupboard; + +public abstract class ServiceModule { - public abstract class ServiceModule - { - public abstract void Configure(IServiceCollection services); - } + public abstract void Configure(IServiceCollection services); } diff --git a/src/Cupboard.Core/Verbosity.cs b/src/Cupboard.Core/Verbosity.cs index d85f24e..39855d7 100644 --- a/src/Cupboard.Core/Verbosity.cs +++ b/src/Cupboard.Core/Verbosity.cs @@ -1,11 +1,10 @@ -namespace Cupboard +namespace Cupboard; + +public enum Verbosity { - public enum Verbosity - { - Quiet = 0, - Minimal, - Normal, - Verbose, - Diagnostic, - } + Quiet = 0, + Minimal, + Normal, + Verbose, + Diagnostic, } diff --git a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackage.cs b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackage.cs index 1cf8ba7..749b168 100644 --- a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackage.cs +++ b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackage.cs @@ -1,21 +1,20 @@ using System; -namespace Cupboard +namespace Cupboard; + +public sealed class ChocolateyPackage : Resource, IHasPackageState, IHasPackageName { - public sealed class ChocolateyPackage : Resource, IHasPackageState, IHasPackageName - { - public string Package { get; set; } - public PackageState Ensure { get; set; } - public bool PreRelease { get; set; } - public bool IgnoreChecksum { get; set; } - public bool AllowDowngrade { get; set; } - public string? PackageParameters { get; set; } - public string? PackageVersion { get; set; } + public string Package { get; set; } + public PackageState Ensure { get; set; } + public bool PreRelease { get; set; } + public bool IgnoreChecksum { get; set; } + public bool AllowDowngrade { get; set; } + public string? PackageParameters { get; set; } + public string? PackageVersion { get; set; } - public ChocolateyPackage(string name) - : base(name) - { - Package = name ?? throw new ArgumentNullException(nameof(name)); - } + public ChocolateyPackage(string name) + : base(name) + { + Package = name ?? throw new ArgumentNullException(nameof(name)); } } diff --git a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageExtensions.cs b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageExtensions.cs index f675b5d..8587631 100644 --- a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageExtensions.cs +++ b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageExtensions.cs @@ -1,40 +1,39 @@ -namespace Cupboard +namespace Cupboard; + +public static class ChocolateyPackageExtensions { - public static class ChocolateyPackageExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) - { - return builder.Configure(pkg => pkg.Ensure = state); - } + return builder.Configure(pkg => pkg.Ensure = state); + } - public static IResourceBuilder Package(this IResourceBuilder builder, string package) - { - return builder.Configure(pkg => pkg.Package = package); - } + public static IResourceBuilder Package(this IResourceBuilder builder, string package) + { + return builder.Configure(pkg => pkg.Package = package); + } - public static IResourceBuilder IncludePreRelease(this IResourceBuilder builder) - { - return builder.Configure(pkg => pkg.PreRelease = true); - } + public static IResourceBuilder IncludePreRelease(this IResourceBuilder builder) + { + return builder.Configure(pkg => pkg.PreRelease = true); + } - public static IResourceBuilder IgnoreChecksum(this IResourceBuilder builder) - { - return builder.Configure(pkg => pkg.IgnoreChecksum = true); - } + public static IResourceBuilder IgnoreChecksum(this IResourceBuilder builder) + { + return builder.Configure(pkg => pkg.IgnoreChecksum = true); + } - public static IResourceBuilder PackageParameters(this IResourceBuilder builder, string packageParameters) - { - return builder.Configure(pkg => pkg.PackageParameters = packageParameters); - } + public static IResourceBuilder PackageParameters(this IResourceBuilder builder, string packageParameters) + { + return builder.Configure(pkg => pkg.PackageParameters = packageParameters); + } - public static IResourceBuilder UseVersion(this IResourceBuilder builder, string version) - { - return builder.Configure(pkg => pkg.PackageVersion = version); - } + public static IResourceBuilder UseVersion(this IResourceBuilder builder, string version) + { + return builder.Configure(pkg => pkg.PackageVersion = version); + } - public static IResourceBuilder AllowDowngrade(this IResourceBuilder builder) - { - return builder.Configure(pkg => pkg.AllowDowngrade = true); - } + public static IResourceBuilder AllowDowngrade(this IResourceBuilder builder) + { + return builder.Configure(pkg => pkg.AllowDowngrade = true); } } diff --git a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageProvider.cs b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageProvider.cs index 754ba83..d3f3565 100644 --- a/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageProvider.cs +++ b/src/Cupboard.Providers.Windows/Chocolatey/ChocolateyPackageProvider.cs @@ -1,106 +1,105 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public sealed class ChocolateyPackageProvider : PackageInstallerProvider { - public sealed class ChocolateyPackageProvider : PackageInstallerProvider + private readonly IProcessRunner _runner; + + protected override string Name { get; } = "Chocolatey"; + + public ChocolateyPackageProvider( + IProcessRunner runner, + ICupboardLogger logger, + IEnvironmentRefresher refresher) + : base(logger, refresher) + { + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + } + + public override ChocolateyPackage Create(string name) + { + return new ChocolateyPackage(name) + { + Package = name, + }; + } + + protected override bool IsPackageInstalled(ChocolateyPackage resource, string output) { - private readonly IProcessRunner _runner; + var outputSpan = output.AsSpan(); + var containsPackage = outputSpan.Contains(resource.Package.AsSpan(), StringComparison.OrdinalIgnoreCase); + if (string.IsNullOrEmpty(resource.PackageVersion)) + { + return containsPackage; + } + + if (!containsPackage) + { + return false; + } - protected override string Name { get; } = "Chocolatey"; + var indexOfPipe = outputSpan.IndexOf('|'); + if (indexOfPipe == -1) + { + return false; + } - public ChocolateyPackageProvider( - IProcessRunner runner, - ICupboardLogger logger, - IEnvironmentRefresher refresher) - : base(logger, refresher) + var indexOfPipePlusOne = indexOfPipe + 1; + var indexOfNewLine = outputSpan.IndexOfAny('\r', '\n'); + if (indexOfNewLine == -1) { - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + indexOfNewLine = outputSpan.Length; } - public override ChocolateyPackage Create(string name) + var versionSpan = outputSpan[indexOfPipePlusOne..indexOfNewLine]; + return Version.TryParse(versionSpan, out var currentPackageVersion) + && Version.TryParse(resource.PackageVersion.AsSpan(), out var packageVersion) + && ((resource.AllowDowngrade is true && currentPackageVersion == packageVersion) + || (resource.AllowDowngrade is false && currentPackageVersion >= packageVersion)); + } + + protected override async Task GetPackageState(ChocolateyPackage resource) + { + var arguments = $"list --limit-output --local-only --exact {resource.Package}"; + return await _runner.Run("choco", arguments, supressOutput: true).ConfigureAwait(false); + } + + protected override async Task InstallPackage(ChocolateyPackage resource) + { + var arguments = $"install {resource.Package} -y"; + + if (resource.PreRelease) { - return new ChocolateyPackage(name) - { - Package = name, - }; + arguments += " --pre"; } - protected override bool IsPackageInstalled(ChocolateyPackage resource, string output) + if (resource.IgnoreChecksum) { - var outputSpan = output.AsSpan(); - var containsPackage = outputSpan.Contains(resource.Package.AsSpan(), StringComparison.OrdinalIgnoreCase); - if (string.IsNullOrEmpty(resource.PackageVersion)) - { - return containsPackage; - } - - if (!containsPackage) - { - return false; - } - - var indexOfPipe = outputSpan.IndexOf('|'); - if (indexOfPipe == -1) - { - return false; - } - - var indexOfPipePlusOne = indexOfPipe + 1; - var indexOfNewLine = outputSpan.IndexOfAny('\r', '\n'); - if (indexOfNewLine == -1) - { - indexOfNewLine = outputSpan.Length; - } - - var versionSpan = outputSpan[indexOfPipePlusOne..indexOfNewLine]; - return Version.TryParse(versionSpan, out var currentPackageVersion) - && Version.TryParse(resource.PackageVersion.AsSpan(), out var packageVersion) - && ((resource.AllowDowngrade is true && currentPackageVersion == packageVersion) - || (resource.AllowDowngrade is false && currentPackageVersion >= packageVersion)); + arguments += " --ignore-checksum"; } - protected override async Task GetPackageState(ChocolateyPackage resource) + if (resource.AllowDowngrade) { - var arguments = $"list --limit-output --local-only --exact {resource.Package}"; - return await _runner.Run("choco", arguments, supressOutput: true).ConfigureAwait(false); + arguments += " --allow-downgrade"; } - protected override async Task InstallPackage(ChocolateyPackage resource) + if (!string.IsNullOrWhiteSpace(resource.PackageVersion)) { - var arguments = $"install {resource.Package} -y"; - - if (resource.PreRelease) - { - arguments += " --pre"; - } - - if (resource.IgnoreChecksum) - { - arguments += " --ignore-checksum"; - } - - if (resource.AllowDowngrade) - { - arguments += " --allow-downgrade"; - } - - if (!string.IsNullOrWhiteSpace(resource.PackageVersion)) - { - arguments += $" --version {resource.PackageVersion}"; - } - - if (!string.IsNullOrWhiteSpace(resource.PackageParameters)) - { - arguments += $" --package-parameters=\"{resource.PackageParameters}\""; - } - - return await _runner.Run("choco", arguments, t => !t.StartsWith("Progress:")).ConfigureAwait(false); + arguments += $" --version {resource.PackageVersion}"; } - protected override async Task UninstallPackage(ChocolateyPackage resource) + if (!string.IsNullOrWhiteSpace(resource.PackageParameters)) { - return await _runner.Run("choco", $"uninstall {resource.Package}").ConfigureAwait(false); + arguments += $" --package-parameters=\"{resource.PackageParameters}\""; } + + return await _runner.Run("choco", arguments, t => !t.StartsWith("Progress:")).ConfigureAwait(false); + } + + protected override async Task UninstallPackage(ChocolateyPackage resource) + { + return await _runner.Run("choco", $"uninstall {resource.Package}").ConfigureAwait(false); } } diff --git a/src/Cupboard.Providers.Windows/Features/WindowsFeature.cs b/src/Cupboard.Providers.Windows/Features/WindowsFeature.cs index 47e685a..f9b1504 100644 --- a/src/Cupboard.Providers.Windows/Features/WindowsFeature.cs +++ b/src/Cupboard.Providers.Windows/Features/WindowsFeature.cs @@ -1,13 +1,12 @@ -namespace Cupboard +namespace Cupboard; + +public sealed class WindowsFeature : Resource { - public sealed class WindowsFeature : Resource - { - public string? FeatureName { get; set; } - public WindowsFeatureState Ensure { get; set; } = WindowsFeatureState.Enabled; + public string? FeatureName { get; set; } + public WindowsFeatureState Ensure { get; set; } = WindowsFeatureState.Enabled; - public WindowsFeature(string name) - : base(name) - { - } + public WindowsFeature(string name) + : base(name) + { } } diff --git a/src/Cupboard.Providers.Windows/Features/WindowsFeatureExtensions.cs b/src/Cupboard.Providers.Windows/Features/WindowsFeatureExtensions.cs index 4c2084d..9b1fed2 100644 --- a/src/Cupboard.Providers.Windows/Features/WindowsFeatureExtensions.cs +++ b/src/Cupboard.Providers.Windows/Features/WindowsFeatureExtensions.cs @@ -1,15 +1,14 @@ -namespace Cupboard +namespace Cupboard; + +public static class WindowsFeatureExtensions { - public static class WindowsFeatureExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, WindowsFeatureState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, WindowsFeatureState state) - { - return builder.Configure(file => file.Ensure = state); - } + return builder.Configure(file => file.Ensure = state); + } - public static IResourceBuilder FeatureName(this IResourceBuilder builder, string name) - { - return builder.Configure(file => file.FeatureName = name); - } + public static IResourceBuilder FeatureName(this IResourceBuilder builder, string name) + { + return builder.Configure(file => file.FeatureName = name); } } diff --git a/src/Cupboard.Providers.Windows/Features/WindowsFeatureProvider.cs b/src/Cupboard.Providers.Windows/Features/WindowsFeatureProvider.cs index c58d108..30bbde0 100644 --- a/src/Cupboard.Providers.Windows/Features/WindowsFeatureProvider.cs +++ b/src/Cupboard.Providers.Windows/Features/WindowsFeatureProvider.cs @@ -1,118 +1,117 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public sealed class WindowsFeatureProvider : AsyncWindowsResourceProvider { - public sealed class WindowsFeatureProvider : AsyncWindowsResourceProvider + private readonly IProcessRunner _runner; + private readonly IEnvironmentRefresher _refresher; + private readonly ICupboardLogger _logger; + + private enum WindowsFeatureStatus { - private readonly IProcessRunner _runner; - private readonly IEnvironmentRefresher _refresher; - private readonly ICupboardLogger _logger; + Enabled, + Disabled, + Error, + } - private enum WindowsFeatureStatus - { - Enabled, - Disabled, - Error, - } + public WindowsFeatureProvider( + IProcessRunner runner, + IEnvironmentRefresher refresher, + ICupboardLogger logger) + { + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public WindowsFeatureProvider( - IProcessRunner runner, - IEnvironmentRefresher refresher, - ICupboardLogger logger) + public override WindowsFeature Create(string name) + { + return new WindowsFeature(name) { - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); - _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + FeatureName = name, + }; + } - public override WindowsFeature Create(string name) + public override bool RequireAdministrator(FactCollection facts) + { + return true; + } + + public override async Task RunAsync(IExecutionContext context, WindowsFeature resource) + { + var feature = resource.FeatureName; + if (string.IsNullOrWhiteSpace(feature)) { - return new WindowsFeature(name) - { - FeatureName = name, - }; + _logger.Error($"Windows feature '{resource.Name}' does not have a feature name"); + return ResourceState.Error; } - public override bool RequireAdministrator(FactCollection facts) + var status = await IsFeatureEnabled(feature).ConfigureAwait(false); + if (status == WindowsFeatureStatus.Error) { - return true; + _logger.Error($"Could not retrieve state of Windows feature [yellow]{feature}[/]"); + return ResourceState.Error; } - public override async Task RunAsync(IExecutionContext context, WindowsFeature resource) + if (resource.Ensure == WindowsFeatureState.Enabled) { - var feature = resource.FeatureName; - if (string.IsNullOrWhiteSpace(feature)) + if (status == WindowsFeatureStatus.Enabled) { - _logger.Error($"Windows feature '{resource.Name}' does not have a feature name"); - return ResourceState.Error; + _logger.Debug($"The Windows feature [yellow]{feature}[/] is already enabled"); + return ResourceState.Unchanged; } - var status = await IsFeatureEnabled(feature).ConfigureAwait(false); - if (status == WindowsFeatureStatus.Error) + var result = await _runner.Run("dism.exe", $"/online /enable-feature /featurename:{feature}").ConfigureAwait(false); + if (result.ExitCode != 0) { - _logger.Error($"Could not retrieve state of Windows feature [yellow]{feature}[/]"); + _logger.Error($"An error occured when enabling Windows feature [yellow]{feature}[/]"); return ResourceState.Error; } - if (resource.Ensure == WindowsFeatureState.Enabled) - { - if (status == WindowsFeatureStatus.Enabled) - { - _logger.Debug($"The Windows feature [yellow]{feature}[/] is already enabled"); - return ResourceState.Unchanged; - } - - var result = await _runner.Run("dism.exe", $"/online /enable-feature /featurename:{feature}").ConfigureAwait(false); - if (result.ExitCode != 0) - { - _logger.Error($"An error occured when enabling Windows feature [yellow]{feature}[/]"); - return ResourceState.Error; - } - - _refresher.Refresh(); - _logger.Verbose($"Enabled Windows feature [yellow]{feature}[/]"); - - return ResourceState.Changed; - } - else if (resource.Ensure == WindowsFeatureState.Enabled) - { - if (status == WindowsFeatureStatus.Disabled) - { - _logger.Debug($"The Windows feature [yellow]{feature}[/] is already disabled"); - return ResourceState.Unchanged; - } - - var result = await _runner.Run("dism.exe", $"/online /disable-feature /featurename:{feature}").ConfigureAwait(false); - if (result.ExitCode != 0) - { - _logger.Error($"An error occured when disabling Windows feature [yellow]{feature}[/]"); - return ResourceState.Error; - } - - _refresher.Refresh(); - _logger.Verbose($"Disabled Windows feature [yellow]{feature}[/]"); - - return ResourceState.Changed; - } + _refresher.Refresh(); + _logger.Verbose($"Enabled Windows feature [yellow]{feature}[/]"); - return ResourceState.Error; + return ResourceState.Changed; } - - private async Task IsFeatureEnabled(string feature) + else if (resource.Ensure == WindowsFeatureState.Enabled) { - var result = await _runner.Run("dism.exe", $"/online /Get-FeatureInfo /FeatureName:{feature}").ConfigureAwait(false); - if (result.ExitCode != 0) + if (status == WindowsFeatureStatus.Disabled) { - return WindowsFeatureStatus.Error; + _logger.Debug($"The Windows feature [yellow]{feature}[/] is already disabled"); + return ResourceState.Unchanged; } - if (result.StandardOut.Contains("State : Enabled", StringComparison.OrdinalIgnoreCase)) + var result = await _runner.Run("dism.exe", $"/online /disable-feature /featurename:{feature}").ConfigureAwait(false); + if (result.ExitCode != 0) { - return WindowsFeatureStatus.Enabled; + _logger.Error($"An error occured when disabling Windows feature [yellow]{feature}[/]"); + return ResourceState.Error; } - return WindowsFeatureStatus.Disabled; + _refresher.Refresh(); + _logger.Verbose($"Disabled Windows feature [yellow]{feature}[/]"); + + return ResourceState.Changed; } + + return ResourceState.Error; + } + + private async Task IsFeatureEnabled(string feature) + { + var result = await _runner.Run("dism.exe", $"/online /Get-FeatureInfo /FeatureName:{feature}").ConfigureAwait(false); + if (result.ExitCode != 0) + { + return WindowsFeatureStatus.Error; + } + + if (result.StandardOut.Contains("State : Enabled", StringComparison.OrdinalIgnoreCase)) + { + return WindowsFeatureStatus.Enabled; + } + + return WindowsFeatureStatus.Disabled; } } diff --git a/src/Cupboard.Providers.Windows/Features/WindowsFeatureState.cs b/src/Cupboard.Providers.Windows/Features/WindowsFeatureState.cs index ea269d0..c269777 100644 --- a/src/Cupboard.Providers.Windows/Features/WindowsFeatureState.cs +++ b/src/Cupboard.Providers.Windows/Features/WindowsFeatureState.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum WindowsFeatureState { - public enum WindowsFeatureState - { - Enabled = 0, - Disabled, - } + Enabled = 0, + Disabled, } diff --git a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKey.cs b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKey.cs index 50250b0..c92960a 100644 --- a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKey.cs +++ b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKey.cs @@ -1,18 +1,17 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use the RegistryValue resource")] +public sealed class RegistryKey : Resource { - [Obsolete("Please use the RegistryValue resource")] - public sealed class RegistryKey : Resource - { - public RegistryKeyPath? Path { get; set; } - public object? Value { get; set; } - public RegistryKeyValueKind ValueKind { get; set; } = RegistryKeyValueKind.Unknown; - public RegistryKeyState State { get; set; } = RegistryKeyState.Exist; + public RegistryKeyPath? Path { get; set; } + public object? Value { get; set; } + public RegistryKeyValueKind ValueKind { get; set; } = RegistryKeyValueKind.Unknown; + public RegistryKeyState State { get; set; } = RegistryKeyState.Exist; - public RegistryKey(string name) - : base(name) - { - } + public RegistryKey(string name) + : base(name) + { } } diff --git a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyExtensions.cs b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyExtensions.cs index 0d73b27..8cee2ce 100644 --- a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyExtensions.cs +++ b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyExtensions.cs @@ -1,33 +1,32 @@ using System; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use the RegistryValue resource instead")] +public static class RegistryKeyExtensions { - [Obsolete("Please use the RegistryValue resource instead")] - public static class RegistryKeyExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, RegistryKeyState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, RegistryKeyState state) - { - return builder.Configure(reg => reg.State = state); - } + return builder.Configure(reg => reg.State = state); + } - public static IResourceBuilder Path(this IResourceBuilder builder, string path) - { - return builder.Configure(reg => reg.Path = new RegistryKeyPath(path)); - } + public static IResourceBuilder Path(this IResourceBuilder builder, string path) + { + return builder.Configure(reg => reg.Path = new RegistryKeyPath(path)); + } - public static IResourceBuilder Value(this IResourceBuilder builder, object value) - { - return builder.Configure(reg => reg.Value = value); - } + public static IResourceBuilder Value(this IResourceBuilder builder, object value) + { + return builder.Configure(reg => reg.Value = value); + } - public static IResourceBuilder Value(this IResourceBuilder builder, object value, RegistryKeyValueKind kind) + public static IResourceBuilder Value(this IResourceBuilder builder, object value, RegistryKeyValueKind kind) + { + return builder.Configure(reg => { - return builder.Configure(reg => - { - reg.State = RegistryKeyState.Exist; - reg.Value = value; - reg.ValueKind = kind; - }); - } + reg.State = RegistryKeyState.Exist; + reg.Value = value; + reg.ValueKind = kind; + }); } } diff --git a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyProvider.cs b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyProvider.cs index 085aeac..239b2be 100644 --- a/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyProvider.cs +++ b/src/Cupboard.Providers.Windows/Registry/Obsolete/RegistryKeyProvider.cs @@ -1,159 +1,158 @@ using System; using System.Runtime.InteropServices; -namespace Cupboard +namespace Cupboard; + +[Obsolete("Please use the RegistryValue resource instead")] +public sealed class RegistryKeyProvider : WindowsResourceProvider { - [Obsolete("Please use the RegistryValue resource instead")] - public sealed class RegistryKeyProvider : WindowsResourceProvider + private readonly IWindowsRegistry _registry; + private readonly ICupboardLogger _logger; + + public RegistryKeyProvider(IWindowsRegistry registry, ICupboardLogger logger) + { + _registry = registry ?? throw new ArgumentNullException(nameof(registry)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + public override RegistryKey Create(string name) { - private readonly IWindowsRegistry _registry; - private readonly ICupboardLogger _logger; + return new RegistryKey(name); + } + + public override bool RequireAdministrator(FactCollection facts) + { + return true; + } - public RegistryKeyProvider(IWindowsRegistry registry, ICupboardLogger logger) + public override ResourceState Run(IExecutionContext context, RegistryKey resource) + { + if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { - _registry = registry ?? throw new ArgumentNullException(nameof(registry)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _logger.Error("Cannot manipulate registry keys on non-Windows OS"); + return ResourceState.Error; } - public override RegistryKey Create(string name) + if (resource.Path == null) { - return new RegistryKey(name); + _logger.Error($"The registry key for resource '{resource.Name}' has not been set"); + return ResourceState.Error; } - public override bool RequireAdministrator(FactCollection facts) + if (!resource.Path.IsValid) { - return true; + _logger.Error($"The registry key for resource '{resource.Name}' is invalid"); + return ResourceState.Error; } - public override ResourceState Run(IExecutionContext context, RegistryKey resource) + if (resource.State == RegistryKeyState.Exist) { - if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) - { - _logger.Error("Cannot manipulate registry keys on non-Windows OS"); - return ResourceState.Error; - } - - if (resource.Path == null) + if (resource.Value == null) { - _logger.Error($"The registry key for resource '{resource.Name}' has not been set"); + _logger.Error($"The registry key value for resource '{resource.Name}' has not been set"); return ResourceState.Error; } - if (!resource.Path.IsValid) + var root = GetRegistryKey(resource.Path); + if (root == null) { - _logger.Error($"The registry key for resource '{resource.Name}' is invalid"); + _logger.Error($"The registry key for resource '{resource.Name}' could not be found"); return ResourceState.Error; } - if (resource.State == RegistryKeyState.Exist) + var key = root.OpenSubKey(resource.Path.SubKey, true); + if (key == null) { - if (resource.Value == null) - { - _logger.Error($"The registry key value for resource '{resource.Name}' has not been set"); - return ResourceState.Error; - } - - var root = GetRegistryKey(resource.Path); - if (root == null) + if (context.DryRun) { - _logger.Error($"The registry key for resource '{resource.Name}' could not be found"); - return ResourceState.Error; + return ResourceState.Changed; } - var key = root.OpenSubKey(resource.Path.SubKey, true); + _logger.Debug("Trying to create registry key"); + key = root.CreateSubKey(resource.Path.SubKey, true); if (key == null) { - if (context.DryRun) - { - return ResourceState.Changed; - } - - _logger.Debug("Trying to create registry key"); - key = root.CreateSubKey(resource.Path.SubKey, true); - if (key == null) - { - _logger.Error("Could not create the registry key"); - return ResourceState.Error; - } - } - - var value = key.GetValue(resource.Path.Value); - if (value != null) - { - // TODO 2021-07-11: This is good enough for now, but should be properly implemented - if (value.ToString()?.Equals(resource.Value.ToString(), StringComparison.Ordinal) ?? false) - { - _logger.Debug("The registry key already has the expected value"); - return ResourceState.Unchanged; - } - } - - if (!context.DryRun) - { - _logger.Information("Updating registry key"); - key.SetValue(resource.Path.Value, resource.Value, resource.ValueKind); - } - - return ResourceState.Changed; - } - else - { - var root = GetRegistryKey(resource.Path); - if (root == null) - { - _logger.Error("The registry key for resource could not be found"); + _logger.Error("Could not create the registry key"); return ResourceState.Error; } + } - var key = root.OpenSubKey(resource.Path.SubKey, true); - if (key == null) + var value = key.GetValue(resource.Path.Value); + if (value != null) + { + // TODO 2021-07-11: This is good enough for now, but should be properly implemented + if (value.ToString()?.Equals(resource.Value.ToString(), StringComparison.Ordinal) ?? false) { - _logger.Debug("The registry key does not exist"); + _logger.Debug("The registry key already has the expected value"); return ResourceState.Unchanged; } + } - var value = key.GetValue(resource.Path.Value); - if (value == null) - { - _logger.Debug("The registry key value does not exist"); - return ResourceState.Unchanged; - } + if (!context.DryRun) + { + _logger.Information("Updating registry key"); + key.SetValue(resource.Path.Value, resource.Value, resource.ValueKind); + } - if (context.DryRun) - { - return ResourceState.Changed; - } + return ResourceState.Changed; + } + else + { + var root = GetRegistryKey(resource.Path); + if (root == null) + { + _logger.Error("The registry key for resource could not be found"); + return ResourceState.Error; + } - _logger.Information("Deleting registry key value"); - return DeleteRegistryKeyValue(key, resource.Path); + var key = root.OpenSubKey(resource.Path.SubKey, true); + if (key == null) + { + _logger.Debug("The registry key does not exist"); + return ResourceState.Unchanged; } - } - private ResourceState DeleteRegistryKeyValue(IWindowsRegistryKey key, RegistryKeyPath path) - { - try + var value = key.GetValue(resource.Path.Value); + if (value == null) { - key.DeleteValue(path.Value); - return ResourceState.Changed; + _logger.Debug("The registry key value does not exist"); + return ResourceState.Unchanged; } - catch (Exception ex) + + if (context.DryRun) { - _logger.Error($"Could not delete registry key. {ex.Message}"); - return ResourceState.Error; + return ResourceState.Changed; } + + _logger.Information("Deleting registry key value"); + return DeleteRegistryKeyValue(key, resource.Path); } + } - private IWindowsRegistryKey? GetRegistryKey(RegistryKeyPath path) + private ResourceState DeleteRegistryKeyValue(IWindowsRegistryKey key, RegistryKeyPath path) + { + try { - return path.Root switch - { - RegistryKeyRoot.ClassesRoot => _registry.ClassesRoot, - RegistryKeyRoot.CurrentUser => _registry.CurrentUser, - RegistryKeyRoot.LocalMachine => _registry.LocalMachine, - RegistryKeyRoot.Users => _registry.Users, - RegistryKeyRoot.CurrentConfig => _registry.CurrentConfig, - _ => null, - }; + key.DeleteValue(path.Value); + return ResourceState.Changed; + } + catch (Exception ex) + { + _logger.Error($"Could not delete registry key. {ex.Message}"); + return ResourceState.Error; } } + + private IWindowsRegistryKey? GetRegistryKey(RegistryKeyPath path) + { + return path.Root switch + { + RegistryKeyRoot.ClassesRoot => _registry.ClassesRoot, + RegistryKeyRoot.CurrentUser => _registry.CurrentUser, + RegistryKeyRoot.LocalMachine => _registry.LocalMachine, + RegistryKeyRoot.Users => _registry.Users, + RegistryKeyRoot.CurrentConfig => _registry.CurrentConfig, + _ => null, + }; + } } diff --git a/src/Cupboard.Providers.Windows/Registry/RegistryKeyState.cs b/src/Cupboard.Providers.Windows/Registry/RegistryKeyState.cs index c1f8664..618498d 100644 --- a/src/Cupboard.Providers.Windows/Registry/RegistryKeyState.cs +++ b/src/Cupboard.Providers.Windows/Registry/RegistryKeyState.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum RegistryKeyState { - public enum RegistryKeyState - { - Exist = 0, - DoNotExist = 1, - } + Exist = 0, + DoNotExist = 1, } diff --git a/src/Cupboard.Providers.Windows/Registry/RegistryValue.cs b/src/Cupboard.Providers.Windows/Registry/RegistryValue.cs index f574e49..0339fad 100644 --- a/src/Cupboard.Providers.Windows/Registry/RegistryValue.cs +++ b/src/Cupboard.Providers.Windows/Registry/RegistryValue.cs @@ -1,16 +1,15 @@ -namespace Cupboard +namespace Cupboard; + +public sealed class RegistryValue : Resource { - public sealed class RegistryValue : Resource - { - public RegistryPath? Path { get; set; } - public string? Value { get; set; } - public object? Data { get; set; } - public RegistryValueKind ValueKind { get; set; } = RegistryValueKind.Unknown; - public RegistryKeyState State { get; set; } = RegistryKeyState.Exist; + public RegistryPath? Path { get; set; } + public string? Value { get; set; } + public object? Data { get; set; } + public RegistryValueKind ValueKind { get; set; } = RegistryValueKind.Unknown; + public RegistryKeyState State { get; set; } = RegistryKeyState.Exist; - public RegistryValue(string name) - : base(name) - { - } + public RegistryValue(string name) + : base(name) + { } } diff --git a/src/Cupboard.Providers.Windows/Registry/RegistryValueExtensions.cs b/src/Cupboard.Providers.Windows/Registry/RegistryValueExtensions.cs index 9bde58d..779da94 100644 --- a/src/Cupboard.Providers.Windows/Registry/RegistryValueExtensions.cs +++ b/src/Cupboard.Providers.Windows/Registry/RegistryValueExtensions.cs @@ -1,40 +1,39 @@ -namespace Cupboard +namespace Cupboard; + +public static class RegistryValueExtensions { - public static class RegistryValueExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, RegistryKeyState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, RegistryKeyState state) - { - return builder.Configure(reg => reg.State = state); - } + return builder.Configure(reg => reg.State = state); + } - public static IResourceBuilder Path(this IResourceBuilder builder, string path) - { - return builder.Configure(reg => reg.Path = new RegistryPath(path)); - } + public static IResourceBuilder Path(this IResourceBuilder builder, string path) + { + return builder.Configure(reg => reg.Path = new RegistryPath(path)); + } - public static IResourceBuilder Value(this IResourceBuilder builder, string value) - { - return builder.Configure(reg => reg.Value = value); - } + public static IResourceBuilder Value(this IResourceBuilder builder, string value) + { + return builder.Configure(reg => reg.Value = value); + } - public static IResourceBuilder Data(this IResourceBuilder builder, string data) - { - return builder.Configure(reg => reg.Data = data); - } + public static IResourceBuilder Data(this IResourceBuilder builder, string data) + { + return builder.Configure(reg => reg.Data = data); + } - public static IResourceBuilder Data(this IResourceBuilder builder, object data) - { - return builder.Configure(reg => reg.Data = data); - } + public static IResourceBuilder Data(this IResourceBuilder builder, object data) + { + return builder.Configure(reg => reg.Data = data); + } - public static IResourceBuilder Data(this IResourceBuilder builder, object data, RegistryValueKind kind) + public static IResourceBuilder Data(this IResourceBuilder builder, object data, RegistryValueKind kind) + { + return builder.Configure(reg => { - return builder.Configure(reg => - { - reg.State = RegistryKeyState.Exist; - reg.Data = data; - reg.ValueKind = kind; - }); - } + reg.State = RegistryKeyState.Exist; + reg.Data = data; + reg.ValueKind = kind; + }); } } diff --git a/src/Cupboard.Providers.Windows/Registry/RegistryValueProvider.cs b/src/Cupboard.Providers.Windows/Registry/RegistryValueProvider.cs index 8674d47..a38cd8e 100644 --- a/src/Cupboard.Providers.Windows/Registry/RegistryValueProvider.cs +++ b/src/Cupboard.Providers.Windows/Registry/RegistryValueProvider.cs @@ -1,167 +1,166 @@ using System; using System.Runtime.InteropServices; -namespace Cupboard +namespace Cupboard; + +public sealed class RegistryValueProvider : WindowsResourceProvider { - public sealed class RegistryValueProvider : WindowsResourceProvider + private readonly IWindowsRegistry _registry; + private readonly ICupboardLogger _logger; + + public RegistryValueProvider(IWindowsRegistry registry, ICupboardLogger logger) { - private readonly IWindowsRegistry _registry; - private readonly ICupboardLogger _logger; + _registry = registry ?? throw new ArgumentNullException(nameof(registry)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public RegistryValueProvider(IWindowsRegistry registry, ICupboardLogger logger) + public override RegistryValue Create(string name) + { + return new RegistryValue(name) { - _registry = registry ?? throw new ArgumentNullException(nameof(registry)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + Value = name, + }; + } - public override RegistryValue Create(string name) + public override bool RequireAdministrator(FactCollection facts) + { + return true; + } + + public override ResourceState Run(IExecutionContext context, RegistryValue resource) + { + if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { - return new RegistryValue(name) - { - Value = name, - }; + _logger.Error("Cannot manipulate registry keys on non-Windows OS"); + return ResourceState.Error; } - public override bool RequireAdministrator(FactCollection facts) + if (resource.Path == null) { - return true; + _logger.Error($"The registry path for resource '{resource.Name}' has not been set"); + return ResourceState.Error; } - public override ResourceState Run(IExecutionContext context, RegistryValue resource) + if (!resource.Path.IsValid) { - if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) - { - _logger.Error("Cannot manipulate registry keys on non-Windows OS"); - return ResourceState.Error; - } + _logger.Error($"The registry path for resource '{resource.Name}' is invalid"); + return ResourceState.Error; + } - if (resource.Path == null) - { - _logger.Error($"The registry path for resource '{resource.Name}' has not been set"); - return ResourceState.Error; - } + if (string.IsNullOrWhiteSpace(resource.Value)) + { + _logger.Error($"The registry value for resource '{resource.Name}' has not been set"); + return ResourceState.Error; + } - if (!resource.Path.IsValid) + if (resource.State == RegistryKeyState.Exist) + { + if (resource.Data == null) { - _logger.Error($"The registry path for resource '{resource.Name}' is invalid"); + _logger.Error($"The registry key value for resource '{resource.Name}' has not been set"); return ResourceState.Error; } - if (string.IsNullOrWhiteSpace(resource.Value)) + var root = GetRegistryKey(resource.Path); + if (root == null) { - _logger.Error($"The registry value for resource '{resource.Name}' has not been set"); + _logger.Error($"The registry key for resource '{resource.Name}' could not be found"); return ResourceState.Error; } - if (resource.State == RegistryKeyState.Exist) + var key = root.OpenSubKey(resource.Path.SubKey, true); + if (key == null) { - if (resource.Data == null) - { - _logger.Error($"The registry key value for resource '{resource.Name}' has not been set"); - return ResourceState.Error; - } - - var root = GetRegistryKey(resource.Path); - if (root == null) + if (context.DryRun) { - _logger.Error($"The registry key for resource '{resource.Name}' could not be found"); - return ResourceState.Error; + return ResourceState.Changed; } - var key = root.OpenSubKey(resource.Path.SubKey, true); + _logger.Debug("Trying to create registry key"); + key = root.CreateSubKey(resource.Path.SubKey, true); if (key == null) { - if (context.DryRun) - { - return ResourceState.Changed; - } - - _logger.Debug("Trying to create registry key"); - key = root.CreateSubKey(resource.Path.SubKey, true); - if (key == null) - { - _logger.Error("Could not create the registry key"); - return ResourceState.Error; - } - } - - var value = key.GetValue(resource.Value); - if (value != null) - { - // TODO 2021-07-11: This is good enough for now, but should be properly implemented - if (value.ToString()?.Equals(resource.Data.ToString(), StringComparison.Ordinal) ?? false) - { - _logger.Debug("The registry key already has the expected value"); - return ResourceState.Unchanged; - } - } - - if (!context.DryRun) - { - _logger.Information("Updating registry key"); - key.SetValue(resource.Value, resource.Data, resource.ValueKind); - } - - return ResourceState.Changed; - } - else - { - var root = GetRegistryKey(resource.Path); - if (root == null) - { - _logger.Error("The registry key for resource could not be found"); + _logger.Error("Could not create the registry key"); return ResourceState.Error; } + } - var key = root.OpenSubKey(resource.Path.SubKey, true); - if (key == null) + var value = key.GetValue(resource.Value); + if (value != null) + { + // TODO 2021-07-11: This is good enough for now, but should be properly implemented + if (value.ToString()?.Equals(resource.Data.ToString(), StringComparison.Ordinal) ?? false) { - _logger.Debug("The registry key does not exist"); + _logger.Debug("The registry key already has the expected value"); return ResourceState.Unchanged; } + } - var value = key.GetValue(resource.Value); - if (value == null) - { - _logger.Debug("The registry key value does not exist"); - return ResourceState.Unchanged; - } + if (!context.DryRun) + { + _logger.Information("Updating registry key"); + key.SetValue(resource.Value, resource.Data, resource.ValueKind); + } - if (context.DryRun) - { - return ResourceState.Changed; - } + return ResourceState.Changed; + } + else + { + var root = GetRegistryKey(resource.Path); + if (root == null) + { + _logger.Error("The registry key for resource could not be found"); + return ResourceState.Error; + } - _logger.Information("Deleting registry key value"); - return DeleteRegistryKeyValue(key, resource.Value); + var key = root.OpenSubKey(resource.Path.SubKey, true); + if (key == null) + { + _logger.Debug("The registry key does not exist"); + return ResourceState.Unchanged; } - } - private ResourceState DeleteRegistryKeyValue(IWindowsRegistryKey key, string value) - { - try + var value = key.GetValue(resource.Value); + if (value == null) { - key.DeleteValue(value); - return ResourceState.Changed; + _logger.Debug("The registry key value does not exist"); + return ResourceState.Unchanged; } - catch (Exception ex) + + if (context.DryRun) { - _logger.Error($"Could not delete registry key. {ex.Message}"); - return ResourceState.Error; + return ResourceState.Changed; } + + _logger.Information("Deleting registry key value"); + return DeleteRegistryKeyValue(key, resource.Value); } + } - private IWindowsRegistryKey? GetRegistryKey(RegistryPath path) + private ResourceState DeleteRegistryKeyValue(IWindowsRegistryKey key, string value) + { + try { - return path.Hive switch - { - RegistryHive.ClassesRoot => _registry.ClassesRoot, - RegistryHive.CurrentUser => _registry.CurrentUser, - RegistryHive.LocalMachine => _registry.LocalMachine, - RegistryHive.Users => _registry.Users, - RegistryHive.CurrentConfig => _registry.CurrentConfig, - _ => null, - }; + key.DeleteValue(value); + return ResourceState.Changed; + } + catch (Exception ex) + { + _logger.Error($"Could not delete registry key. {ex.Message}"); + return ResourceState.Error; } } + + private IWindowsRegistryKey? GetRegistryKey(RegistryPath path) + { + return path.Hive switch + { + RegistryHive.ClassesRoot => _registry.ClassesRoot, + RegistryHive.CurrentUser => _registry.CurrentUser, + RegistryHive.LocalMachine => _registry.LocalMachine, + RegistryHive.Users => _registry.Users, + RegistryHive.CurrentConfig => _registry.CurrentConfig, + _ => null, + }; + } } diff --git a/src/Cupboard.Providers.Windows/WindowsFacts.cs b/src/Cupboard.Providers.Windows/WindowsFacts.cs index 22702cd..1ccff5f 100644 --- a/src/Cupboard.Providers.Windows/WindowsFacts.cs +++ b/src/Cupboard.Providers.Windows/WindowsFacts.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +internal sealed class WindowsFacts : IFactProvider { - internal sealed class WindowsFacts : IFactProvider + public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) { - public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) - { - var isSandboxUser = Environment.UserName.Equals("WDAGUtilityAccount", StringComparison.OrdinalIgnoreCase); - yield return ("windows.sandbox", isSandboxUser); - } + var isSandboxUser = Environment.UserName.Equals("WDAGUtilityAccount", StringComparison.OrdinalIgnoreCase); + yield return ("windows.sandbox", isSandboxUser); } } diff --git a/src/Cupboard.Providers.Windows/WindowsModule.cs b/src/Cupboard.Providers.Windows/WindowsModule.cs index 9d6893b..29f5e42 100644 --- a/src/Cupboard.Providers.Windows/WindowsModule.cs +++ b/src/Cupboard.Providers.Windows/WindowsModule.cs @@ -1,24 +1,23 @@ using Microsoft.Extensions.DependencyInjection; -namespace Cupboard +namespace Cupboard; + +public sealed class WindowsModule : ServiceModule { - public sealed class WindowsModule : ServiceModule + public override void Configure(IServiceCollection services) { - public override void Configure(IServiceCollection services) - { - // Resources - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + // Resources + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); #pragma warning disable CS0618 // Type or member is obsolete - services.AddSingleton(); + services.AddSingleton(); #pragma warning restore CS0618 // Type or member is obsolete - // Facts - services.AddSingleton(); - services.AddSingleton(); - } + // Facts + services.AddSingleton(); + services.AddSingleton(); } } diff --git a/src/Cupboard.Providers.Windows/WindowsResourceProvider.cs b/src/Cupboard.Providers.Windows/WindowsResourceProvider.cs index 9291ca0..7b7638e 100644 --- a/src/Cupboard.Providers.Windows/WindowsResourceProvider.cs +++ b/src/Cupboard.Providers.Windows/WindowsResourceProvider.cs @@ -1,20 +1,19 @@ -namespace Cupboard +namespace Cupboard; + +public abstract class WindowsResourceProvider : ResourceProvider + where TResource : Resource { - public abstract class WindowsResourceProvider : ResourceProvider - where TResource : Resource + public override bool CanRun(FactCollection facts) { - public override bool CanRun(FactCollection facts) - { - return facts.IsWindows(); - } + return facts.IsWindows(); } +} - public abstract class AsyncWindowsResourceProvider : AsyncResourceProvider - where TResource : Resource +public abstract class AsyncWindowsResourceProvider : AsyncResourceProvider + where TResource : Resource +{ + public override bool CanRun(FactCollection facts) { - public override bool CanRun(FactCollection facts) - { - return facts.IsWindows(); - } + return facts.IsWindows(); } } diff --git a/src/Cupboard.Providers.Windows/Winget/WingetPackage.cs b/src/Cupboard.Providers.Windows/Winget/WingetPackage.cs index 07dfb54..d68ba20 100644 --- a/src/Cupboard.Providers.Windows/Winget/WingetPackage.cs +++ b/src/Cupboard.Providers.Windows/Winget/WingetPackage.cs @@ -1,24 +1,23 @@ using System; -namespace Cupboard +namespace Cupboard; + +public sealed class WingetPackage : Resource, IHasPackageName, IHasPackageState { - public sealed class WingetPackage : Resource, IHasPackageName, IHasPackageState - { - /// - /// Gets or sets the id of the package. - /// This is the id of the package listed by the source. As an example the id for the git cli in the winget source is "Git.Git". - /// - public string Package { get; set; } - public PackageState Ensure { get; set; } - public bool Force { get; set; } - public string? PackageVersion { get; set; } - public string? Override { get; set; } - public string? Source { get; set; } + /// + /// Gets or sets the id of the package. + /// This is the id of the package listed by the source. As an example the id for the git cli in the winget source is "Git.Git". + /// + public string Package { get; set; } + public PackageState Ensure { get; set; } + public bool Force { get; set; } + public string? PackageVersion { get; set; } + public string? Override { get; set; } + public string? Source { get; set; } - public WingetPackage(string name) - : base(name) - { - Package = name ?? throw new ArgumentNullException(nameof(name)); - } + public WingetPackage(string name) + : base(name) + { + Package = name ?? throw new ArgumentNullException(nameof(name)); } } diff --git a/src/Cupboard.Providers.Windows/Winget/WingetPackageExtensions.cs b/src/Cupboard.Providers.Windows/Winget/WingetPackageExtensions.cs index 643efe3..5ad5e28 100644 --- a/src/Cupboard.Providers.Windows/Winget/WingetPackageExtensions.cs +++ b/src/Cupboard.Providers.Windows/Winget/WingetPackageExtensions.cs @@ -1,35 +1,34 @@ -namespace Cupboard +namespace Cupboard; + +public static class WingetPackageExtensions { - public static class WingetPackageExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) - { - return builder.Configure(pkg => pkg.Ensure = state); - } + return builder.Configure(pkg => pkg.Ensure = state); + } - public static IResourceBuilder Package(this IResourceBuilder builder, string package) - { - return builder.Configure(pkg => pkg.Package = package); - } + public static IResourceBuilder Package(this IResourceBuilder builder, string package) + { + return builder.Configure(pkg => pkg.Package = package); + } - public static IResourceBuilder Force(this IResourceBuilder builder, bool force) - { - return builder.Configure(pkg => pkg.Force = force); - } + public static IResourceBuilder Force(this IResourceBuilder builder, bool force) + { + return builder.Configure(pkg => pkg.Force = force); + } - public static IResourceBuilder PackageVersion(this IResourceBuilder builder, string version) - { - return builder.Configure(pkg => pkg.PackageVersion = version); - } + public static IResourceBuilder PackageVersion(this IResourceBuilder builder, string version) + { + return builder.Configure(pkg => pkg.PackageVersion = version); + } - public static IResourceBuilder Override(this IResourceBuilder builder, string packageOverride) - { - return builder.Configure(pkg => pkg.Override = packageOverride); - } + public static IResourceBuilder Override(this IResourceBuilder builder, string packageOverride) + { + return builder.Configure(pkg => pkg.Override = packageOverride); + } - public static IResourceBuilder Source(this IResourceBuilder builder, string source) - { - return builder.Configure(pkg => pkg.Source = source); - } + public static IResourceBuilder Source(this IResourceBuilder builder, string source) + { + return builder.Configure(pkg => pkg.Source = source); } } diff --git a/src/Cupboard.Providers.Windows/Winget/WingetPackageProvider.cs b/src/Cupboard.Providers.Windows/Winget/WingetPackageProvider.cs index 18aa6f0..e7d4fd2 100644 --- a/src/Cupboard.Providers.Windows/Winget/WingetPackageProvider.cs +++ b/src/Cupboard.Providers.Windows/Winget/WingetPackageProvider.cs @@ -1,82 +1,81 @@ using System; using System.Threading.Tasks; -namespace Cupboard +namespace Cupboard; + +public sealed class WingetPackageProvider : PackageInstallerProvider { - public sealed class WingetPackageProvider : PackageInstallerProvider - { - private readonly IProcessRunner _runner; + private readonly IProcessRunner _runner; - protected override string Name { get; } = "Winget"; + protected override string Name { get; } = "Winget"; - public WingetPackageProvider( - IProcessRunner runner, - ICupboardLogger logger, - IEnvironmentRefresher refresher) - : base(logger, refresher) - { - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); - } + public WingetPackageProvider( + IProcessRunner runner, + ICupboardLogger logger, + IEnvironmentRefresher refresher) + : base(logger, refresher) + { + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + } - public override WingetPackage Create(string name) + public override WingetPackage Create(string name) + { + return new WingetPackage(name) { - return new WingetPackage(name) - { - Package = name, - }; - } + Package = name, + }; + } + + protected override bool IsPackageInstalled(WingetPackage resource, string output) + { + return output.Contains(resource.Package, StringComparison.OrdinalIgnoreCase); + } + + protected override async Task GetPackageState(WingetPackage resource) + { + var arguments = $"list --source winget --id {resource.Package}"; + return await _runner.Run("winget", arguments, supressOutput: true).ConfigureAwait(false); + } - protected override bool IsPackageInstalled(WingetPackage resource, string output) + protected override bool IsError(PackageInstallerOperation operation, ProcessRunnerResult result) + { + if (operation == PackageInstallerOperation.RetriveState) { - return output.Contains(resource.Package, StringComparison.OrdinalIgnoreCase); + return result.ExitCode != 0 && (!result.StandardOut?.EndsWith("No installed package found matching input criteria.") ?? true); } - protected override async Task GetPackageState(WingetPackage resource) + return result.ExitCode != 0; + } + + protected override async Task InstallPackage(WingetPackage resource) + { + var arguments = $"install -e --id {resource.Package}"; + + if (resource.Force) { - var arguments = $"list --source winget --id {resource.Package}"; - return await _runner.Run("winget", arguments, supressOutput: true).ConfigureAwait(false); + arguments += " --force"; } - protected override bool IsError(PackageInstallerOperation operation, ProcessRunnerResult result) + if (!string.IsNullOrWhiteSpace(resource.PackageVersion)) { - if (operation == PackageInstallerOperation.RetriveState) - { - return result.ExitCode != 0 && (!result.StandardOut?.EndsWith("No installed package found matching input criteria.") ?? true); - } - - return result.ExitCode != 0; + arguments += $" --version {resource.PackageVersion}"; } - protected override async Task InstallPackage(WingetPackage resource) + if (string.IsNullOrWhiteSpace(resource.Override) is false) { - var arguments = $"install -e --id {resource.Package}"; - - if (resource.Force) - { - arguments += " --force"; - } - - if (!string.IsNullOrWhiteSpace(resource.PackageVersion)) - { - arguments += $" --version {resource.PackageVersion}"; - } - - if (string.IsNullOrWhiteSpace(resource.Override) is false) - { - arguments += $" --override \"{resource.Override}\""; - } - - if (string.IsNullOrWhiteSpace(resource.Source) is false) - { - arguments += $" --source {resource.Source}"; - } - - return await _runner.Run("winget", arguments).ConfigureAwait(false); + arguments += $" --override \"{resource.Override}\""; } - protected override async Task UninstallPackage(WingetPackage resource) + if (string.IsNullOrWhiteSpace(resource.Source) is false) { - return await _runner.Run("winget", $"uninstall -e --id {resource.Package}").ConfigureAwait(false); + arguments += $" --source {resource.Source}"; } + + return await _runner.Run("winget", arguments).ConfigureAwait(false); + } + + protected override async Task UninstallPackage(WingetPackage resource) + { + return await _runner.Run("winget", $"uninstall -e --id {resource.Package}").ConfigureAwait(false); } } diff --git a/src/Cupboard.Providers.Windows/WmiFacts.cs b/src/Cupboard.Providers.Windows/WmiFacts.cs index 465d35b..1c744ae 100644 --- a/src/Cupboard.Providers.Windows/WmiFacts.cs +++ b/src/Cupboard.Providers.Windows/WmiFacts.cs @@ -4,48 +4,47 @@ using System.Runtime.InteropServices; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +internal sealed class WmiFacts : IFactProvider { - internal sealed class WmiFacts : IFactProvider + private static readonly Dictionary _properties; + + static WmiFacts() { - private static readonly Dictionary _properties; + _properties = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "Version", "wmi.os.version" }, + { "WindowsDirectory", "wmi.os.windows_dir" }, + { "FreeVirtualMemory", "wmi.os.free_virtual_mem" }, + { "FreePhysicalMemory", "wmi.os.free_physical_mem" }, + { "BuildNumber", "wmi.os.build" }, + { "TotalVirtualMemorySize", "wmi.os.total_virtual_mem" }, + { "TotalVisibleMemorySize", "wmi.os.total_mem" }, + }; + } - static WmiFacts() + public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + { + if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { - _properties = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "Version", "wmi.os.version" }, - { "WindowsDirectory", "wmi.os.windows_dir" }, - { "FreeVirtualMemory", "wmi.os.free_virtual_mem" }, - { "FreePhysicalMemory", "wmi.os.free_physical_mem" }, - { "BuildNumber", "wmi.os.build" }, - { "TotalVirtualMemorySize", "wmi.os.total_virtual_mem" }, - { "TotalVisibleMemorySize", "wmi.os.total_mem" }, - }; + yield break; } - public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + var keys = string.Join(',', _properties.Keys); + var searcher = new ManagementObjectSearcher($"SELECT {keys} FROM Win32_OperatingSystem"); + var osDetailsCollection = searcher.Get(); + foreach (var prop in osDetailsCollection) { - if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) + foreach (var property in _properties) { - yield break; - } - - var keys = string.Join(',', _properties.Keys); - var searcher = new ManagementObjectSearcher($"SELECT {keys} FROM Win32_OperatingSystem"); - var osDetailsCollection = searcher.Get(); - foreach (var prop in osDetailsCollection) - { - foreach (var property in _properties) - { - yield return (property.Value, prop[property.Key]); - } + yield return (property.Value, prop[property.Key]); } + } - if (osDetailsCollection.Count > 0) - { - yield return ("wmi.os", true); - } + if (osDetailsCollection.Count > 0) + { + yield return ("wmi.os", true); } } } diff --git a/src/Cupboard.Providers/ArgumentFacts.cs b/src/Cupboard.Providers/ArgumentFacts.cs index 72c71b1..3a1f055 100644 --- a/src/Cupboard.Providers/ArgumentFacts.cs +++ b/src/Cupboard.Providers/ArgumentFacts.cs @@ -3,42 +3,41 @@ using System.Linq; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +internal sealed class ArgumentFacts : IFactProvider { - internal sealed class ArgumentFacts : IFactProvider - { - public const string Prefix = "arg"; + public const string Prefix = "arg"; - public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + { + foreach (var argument in args.Parsed) { - foreach (var argument in args.Parsed) - { - yield return ($"{Prefix}." + argument.Key, argument.Last() ?? string.Empty); - } + yield return ($"{Prefix}." + argument.Key, argument.Last() ?? string.Empty); } } +} - public static class ArgumentFactsExtensions +public static class ArgumentFactsExtensions +{ + public static bool HasArgument(this FactCollection facts, string key) { - public static bool HasArgument(this FactCollection facts, string key) - { - return facts[$"{ArgumentFacts.Prefix}.{key}"].As() != null; - } + return facts[$"{ArgumentFacts.Prefix}.{key}"].As() != null; + } - public static string? Argument(this FactCollection facts, string key) - { - return facts[$"{ArgumentFacts.Prefix}.{key}"].As(); - } + public static string? Argument(this FactCollection facts, string key) + { + return facts[$"{ArgumentFacts.Prefix}.{key}"].As(); + } - public static string Argument(this FactCollection facts, string key, string defaultValue) + public static string Argument(this FactCollection facts, string key, string defaultValue) + { + if (defaultValue is null) { - if (defaultValue is null) - { - throw new ArgumentNullException(nameof(defaultValue)); - } - - var value = facts[$"{ArgumentFacts.Prefix}.{key}"].As(); - return value ?? defaultValue; + throw new ArgumentNullException(nameof(defaultValue)); } + + var value = facts[$"{ArgumentFacts.Prefix}.{key}"].As(); + return value ?? defaultValue; } } diff --git a/src/Cupboard.Providers/Directory/Directory.cs b/src/Cupboard.Providers/Directory/Directory.cs index 8cb5ebf..aa33960 100644 --- a/src/Cupboard.Providers/Directory/Directory.cs +++ b/src/Cupboard.Providers/Directory/Directory.cs @@ -1,17 +1,16 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class Directory : Resource { - public sealed class Directory : Resource - { - public DirectoryPath Path { get; set; } - public DirectoryState Ensure { get; set; } = DirectoryState.Present; - public Chmod? Permissions { get; set; } + public DirectoryPath Path { get; set; } + public DirectoryState Ensure { get; set; } = DirectoryState.Present; + public Chmod? Permissions { get; set; } - public Directory(string name) - : base(name) - { - Path = new DirectoryPath(name); - } + public Directory(string name) + : base(name) + { + Path = new DirectoryPath(name); } } diff --git a/src/Cupboard.Providers/Directory/DirectoryExtensions.cs b/src/Cupboard.Providers/Directory/DirectoryExtensions.cs index 2b91f8a..b861e20 100644 --- a/src/Cupboard.Providers/Directory/DirectoryExtensions.cs +++ b/src/Cupboard.Providers/Directory/DirectoryExtensions.cs @@ -1,20 +1,19 @@ -namespace Cupboard +namespace Cupboard; + +public static class DirectoryExtensions { - public static class DirectoryExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, DirectoryState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, DirectoryState state) - { - return builder.Configure(directory => directory.Ensure = state); - } + return builder.Configure(directory => directory.Ensure = state); + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, string chmod) - { - return builder.Configure(directory => directory.Permissions = ChmodParser.Parse(chmod)); - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, string chmod) + { + return builder.Configure(directory => directory.Permissions = ChmodParser.Parse(chmod)); + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) - { - return builder.Configure(directory => directory.Permissions = permissions); - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) + { + return builder.Configure(directory => directory.Permissions = permissions); } } diff --git a/src/Cupboard.Providers/Directory/DirectoryProvider.cs b/src/Cupboard.Providers/Directory/DirectoryProvider.cs index 59ff646..1f1c7dc 100644 --- a/src/Cupboard.Providers/Directory/DirectoryProvider.cs +++ b/src/Cupboard.Providers/Directory/DirectoryProvider.cs @@ -2,103 +2,102 @@ using System.Collections.Generic; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class DirectoryProvider : ResourceProvider { - public sealed class DirectoryProvider : ResourceProvider + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly ICupboardLogger _logger; + private readonly IDictionary> _map; + + public DirectoryProvider( + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + ICupboardLogger logger) { - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly ICupboardLogger _logger; - private readonly IDictionary> _map; + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - public DirectoryProvider( - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - ICupboardLogger logger) + _map = new Dictionary> { - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + { DirectoryState.Present, CreateDirectory }, + { DirectoryState.Absent, DeleteDirectory }, + }; + } - _map = new Dictionary> - { - { DirectoryState.Present, CreateDirectory }, - { DirectoryState.Absent, DeleteDirectory }, - }; - } + public override Directory Create(string name) + { + return new Directory(name); + } - public override Directory Create(string name) + public override ResourceState Run(IExecutionContext context, Directory resource) + { + if (_map.TryGetValue(resource.Ensure, out var action)) { - return new Directory(name); + return action.Invoke(context, resource); } - public override ResourceState Run(IExecutionContext context, Directory resource) - { - if (_map.TryGetValue(resource.Ensure, out var action)) - { - return action.Invoke(context, resource); - } + return ResourceState.Unknown; + } - return ResourceState.Unknown; + private ResourceState DeleteDirectory(IExecutionContext context, Directory resource) + { + if (resource.Path == null) + { + _logger.Error($"The resource '{resource.Name}' does not have a path"); + return ResourceState.Error; } - private ResourceState DeleteDirectory(IExecutionContext context, Directory resource) + var path = resource.Path.MakeAbsolute(_environment); + if (_fileSystem.Exist(path)) { - if (resource.Path == null) + if (!context.DryRun) { - _logger.Error($"The resource '{resource.Name}' does not have a path"); - return ResourceState.Error; + _logger.Information($"Deleting directory '{path.FullPath}'."); + _fileSystem.Directory.Delete(path, true); } - var path = resource.Path.MakeAbsolute(_environment); - if (_fileSystem.Exist(path)) - { - if (!context.DryRun) - { - _logger.Information($"Deleting directory '{path.FullPath}'."); - _fileSystem.Directory.Delete(path, true); - } - - return ResourceState.Changed; - } - else - { - _logger.Information($"Directory '{path.FullPath}' does not exist."); - return ResourceState.Unchanged; - } + return ResourceState.Changed; } + else + { + _logger.Information($"Directory '{path.FullPath}' does not exist."); + return ResourceState.Unchanged; + } + } - private ResourceState CreateDirectory(IExecutionContext context, Directory resource) + private ResourceState CreateDirectory(IExecutionContext context, Directory resource) + { + if (resource.Path == null) { - if (resource.Path == null) - { - _logger.Error($"The resource '{resource.Name}' does not have a path"); - return ResourceState.Error; - } + _logger.Error($"The resource '{resource.Name}' does not have a path"); + return ResourceState.Error; + } - var path = resource.Path.MakeAbsolute(_environment); + var path = resource.Path.MakeAbsolute(_environment); - if (!_fileSystem.Exist(path)) + if (!_fileSystem.Exist(path)) + { + if (!context.DryRun) { - if (!context.DryRun) - { - _logger.Information($"Creating directory '{path.FullPath}'."); - _fileSystem.Directory.Create(path); + _logger.Information($"Creating directory '{path.FullPath}'."); + _fileSystem.Directory.Create(path); - // Not on Windows and got permissions set? - if (resource.Permissions != null && _environment.Platform.Family != PlatformFamily.Windows) - { - path.SetPermissions(resource.Permissions); - } + // Not on Windows and got permissions set? + if (resource.Permissions != null && _environment.Platform.Family != PlatformFamily.Windows) + { + path.SetPermissions(resource.Permissions); } - - return ResourceState.Changed; - } - else - { - _logger.Information($"Directory '{path.FullPath}' already exists."); - return ResourceState.Unchanged; } + + return ResourceState.Changed; + } + else + { + _logger.Information($"Directory '{path.FullPath}' already exists."); + return ResourceState.Unchanged; } } } diff --git a/src/Cupboard.Providers/Directory/DirectoryState.cs b/src/Cupboard.Providers/Directory/DirectoryState.cs index 22b7eb9..0690d03 100644 --- a/src/Cupboard.Providers/Directory/DirectoryState.cs +++ b/src/Cupboard.Providers/Directory/DirectoryState.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum DirectoryState { - public enum DirectoryState - { - Present = 0, - Absent = 1, - } + Present = 0, + Absent = 1, } diff --git a/src/Cupboard.Providers/Download/Download.cs b/src/Cupboard.Providers/Download/Download.cs index 02b1de2..2f37c86 100644 --- a/src/Cupboard.Providers/Download/Download.cs +++ b/src/Cupboard.Providers/Download/Download.cs @@ -1,21 +1,20 @@ using System; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class Download : Resource { - public sealed class Download : Resource - { - public Uri? Url { get; set; } - public Chmod? Permissions { get; set; } - public Path? Destination { get; set; } + public Uri? Url { get; set; } + public Chmod? Permissions { get; set; } + public Path? Destination { get; set; } - public Download(string name) - : base(name) + public Download(string name) + : base(name) + { + if (Uri.TryCreate(name, UriKind.Absolute, out var result)) { - if (Uri.TryCreate(name, UriKind.Absolute, out var result)) - { - Url = result; - } + Url = result; } } } diff --git a/src/Cupboard.Providers/Download/DownloadExtensions.cs b/src/Cupboard.Providers/Download/DownloadExtensions.cs index ec1cf05..38d8210 100644 --- a/src/Cupboard.Providers/Download/DownloadExtensions.cs +++ b/src/Cupboard.Providers/Download/DownloadExtensions.cs @@ -1,44 +1,43 @@ using System; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class DownloadExtensions { - public static class DownloadExtensions + public static IResourceBuilder FromUrl(this IResourceBuilder builder, string url) { - public static IResourceBuilder FromUrl(this IResourceBuilder builder, string url) - { - builder.Configure(res => res.Url = new Uri(url)); - return builder; - } + builder.Configure(res => res.Url = new Uri(url)); + return builder; + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, string permissions) - { - builder.Configure(res => res.Permissions = Chmod.Parse(permissions)); - return builder; - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, string permissions) + { + builder.Configure(res => res.Permissions = Chmod.Parse(permissions)); + return builder; + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) - { - builder.Configure(res => res.Permissions = permissions); - return builder; - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) + { + builder.Configure(res => res.Permissions = permissions); + return builder; + } - public static IResourceBuilder FromUrl(this IResourceBuilder builder, Uri url) - { - builder.Configure(res => res.Url = url); - return builder; - } + public static IResourceBuilder FromUrl(this IResourceBuilder builder, Uri url) + { + builder.Configure(res => res.Url = url); + return builder; + } - public static IResourceBuilder ToFile(this IResourceBuilder builder, FilePath path) - { - builder.Configure(res => res.Destination = path); - return builder; - } + public static IResourceBuilder ToFile(this IResourceBuilder builder, FilePath path) + { + builder.Configure(res => res.Destination = path); + return builder; + } - public static IResourceBuilder ToDirectory(this IResourceBuilder builder, DirectoryPath path) - { - builder.Configure(res => res.Destination = path); - return builder; - } + public static IResourceBuilder ToDirectory(this IResourceBuilder builder, DirectoryPath path) + { + builder.Configure(res => res.Destination = path); + return builder; } } diff --git a/src/Cupboard.Providers/Download/DownloadProvider.cs b/src/Cupboard.Providers/Download/DownloadProvider.cs index bed22b7..c7d5676 100644 --- a/src/Cupboard.Providers/Download/DownloadProvider.cs +++ b/src/Cupboard.Providers/Download/DownloadProvider.cs @@ -5,119 +5,118 @@ using System.Threading.Tasks; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class DownloadProvider : AsyncResourceProvider { - public sealed class DownloadProvider : AsyncResourceProvider + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly ICupboardLogger _logger; + private readonly HttpClient _http; + + private static readonly Regex _contentDispositionRegex = new("filename=\"(?'filename'.*)\""); + + public DownloadProvider( + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + ICupboardLogger logger) { - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly ICupboardLogger _logger; - private readonly HttpClient _http; + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _http = new HttpClient(); + } - private static readonly Regex _contentDispositionRegex = new("filename=\"(?'filename'.*)\""); + public override Download Create(string name) + { + return new Download(name); + } - public DownloadProvider( - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - ICupboardLogger logger) + public override async Task RunAsync(IExecutionContext context, Download resource) + { + if (resource.Url == null) { - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _http = new HttpClient(); + _logger.Error($"Can't download file '{resource.Name}' since no URL has been set"); + return ResourceState.Error; } - public override Download Create(string name) + if (resource.Destination == null) { - return new Download(name); + _logger.Error($"Can't download file from {resource.Url.AbsoluteUri} since destination has not been set"); + return ResourceState.Error; } - public override async Task RunAsync(IExecutionContext context, Download resource) + if (context.DryRun) { - if (resource.Url == null) - { - _logger.Error($"Can't download file '{resource.Name}' since no URL has been set"); - return ResourceState.Error; - } - - if (resource.Destination == null) - { - _logger.Error($"Can't download file from {resource.Url.AbsoluteUri} since destination has not been set"); - return ResourceState.Error; - } - - if (context.DryRun) - { - return ResourceState.Unknown; - } + return ResourceState.Unknown; + } - using (var request = new HttpRequestMessage(HttpMethod.Get, resource.Url)) + using (var request = new HttpRequestMessage(HttpMethod.Get, resource.Url)) + { + using (var response = await _http.SendAsync(request).ConfigureAwait(false)) { - using (var response = await _http.SendAsync(request).ConfigureAwait(false)) + string? filename = null; + if (response.Headers.TryGetValues("Content-Disposition", out var filenames)) { - string? filename = null; - if (response.Headers.TryGetValues("Content-Disposition", out var filenames)) - { - var match = _contentDispositionRegex.Match(filenames.First()); - if (match.Success && match.Groups.ContainsKey("filename")) - { - filename = match.Groups["filename"].Value; - } - } - - var path = GetDestinationPath(resource.Destination, filename); - if (path == null) + var match = _contentDispositionRegex.Match(filenames.First()); + if (match.Success && match.Groups.ContainsKey("filename")) { - return ResourceState.Error; + filename = match.Groups["filename"].Value; } + } - if (_fileSystem.Exist(path)) - { - _logger.Debug($"File has already been downloaded from {resource.Url.AbsoluteUri}"); - return ResourceState.Unchanged; - } + var path = GetDestinationPath(resource.Destination, filename); + if (path == null) + { + return ResourceState.Error; + } - _logger.Debug($"Downloading file from {resource.Url.AbsoluteUri}"); - using (var inputStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - using (var outputStream = _fileSystem.GetFile(path).OpenWrite()) - { - await inputStream.CopyToAsync(outputStream).ConfigureAwait(false); - } + if (_fileSystem.Exist(path)) + { + _logger.Debug($"File has already been downloaded from {resource.Url.AbsoluteUri}"); + return ResourceState.Unchanged; + } - if (resource.Permissions != null) - { - path.SetPermissions(resource.Permissions); - } + _logger.Debug($"Downloading file from {resource.Url.AbsoluteUri}"); + using (var inputStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var outputStream = _fileSystem.GetFile(path).OpenWrite()) + { + await inputStream.CopyToAsync(outputStream).ConfigureAwait(false); + } - return ResourceState.Changed; + if (resource.Permissions != null) + { + path.SetPermissions(resource.Permissions); } + + return ResourceState.Changed; } } + } - private FilePath? GetDestinationPath(Path? path, string? filename) + private FilePath? GetDestinationPath(Path? path, string? filename) + { + if (path != null) { - if (path != null) + if (path is DirectoryPath directory) { - if (path is DirectoryPath directory) - { - if (filename == null) - { - _logger.Error("Could not resolve filename from download URL"); - return null; - } - - return directory - .MakeAbsolute(_environment) - .CombineWithFilePath(filename); - } - else if (path is FilePath file) + if (filename == null) { - return file.MakeAbsolute(_environment); + _logger.Error("Could not resolve filename from download URL"); + return null; } - } - _logger.Error("Unknown destination type"); - return null; + return directory + .MakeAbsolute(_environment) + .CombineWithFilePath(filename); + } + else if (path is FilePath file) + { + return file.MakeAbsolute(_environment); + } } + + _logger.Error("Unknown destination type"); + return null; } } diff --git a/src/Cupboard.Providers/EnvironmentFacts.cs b/src/Cupboard.Providers/EnvironmentFacts.cs index 6d83a3c..91fb1d9 100644 --- a/src/Cupboard.Providers/EnvironmentFacts.cs +++ b/src/Cupboard.Providers/EnvironmentFacts.cs @@ -2,49 +2,48 @@ using System.Collections.Generic; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +internal sealed class EnvironmentFacts : IFactProvider { - internal sealed class EnvironmentFacts : IFactProvider - { - private readonly ICupboardEnvironment _environment; + private readonly ICupboardEnvironment _environment; - public const string Prefix = "env"; + public const string Prefix = "env"; - public EnvironmentFacts(ICupboardEnvironment environment) - { - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - } + public EnvironmentFacts(ICupboardEnvironment environment) + { + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + } - public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + public IEnumerable<(string Name, object Value)> GetFacts(IRemainingArguments args) + { + foreach (var (key, value) in _environment.GetEnvironmentVariables()) { - foreach (var (key, value) in _environment.GetEnvironmentVariables()) - { - yield return ($"{Prefix}.{key}", value ?? string.Empty); - } + yield return ($"{Prefix}.{key}", value ?? string.Empty); } } +} - public static class EnvironmentFactsExtensions +public static class EnvironmentFactsExtensions +{ + public static bool HasEnvironmentVariable(this FactCollection facts, string key) { - public static bool HasEnvironmentVariable(this FactCollection facts, string key) - { - return facts[$"{EnvironmentFacts.Prefix}.{key}"].As() != null; - } + return facts[$"{EnvironmentFacts.Prefix}.{key}"].As() != null; + } - public static string? EnvironmentVariable(this FactCollection facts, string key) - { - return facts[$"{EnvironmentFacts.Prefix}.{key}"].As(); - } + public static string? EnvironmentVariable(this FactCollection facts, string key) + { + return facts[$"{EnvironmentFacts.Prefix}.{key}"].As(); + } - public static string EnvironmentVariable(this FactCollection facts, string key, string defaultValue) + public static string EnvironmentVariable(this FactCollection facts, string key, string defaultValue) + { + if (defaultValue is null) { - if (defaultValue is null) - { - throw new ArgumentNullException(nameof(defaultValue)); - } - - var value = facts[$"{EnvironmentFacts.Prefix}.{key}"].As(); - return value ?? defaultValue; + throw new ArgumentNullException(nameof(defaultValue)); } + + var value = facts[$"{EnvironmentFacts.Prefix}.{key}"].As(); + return value ?? defaultValue; } } diff --git a/src/Cupboard.Providers/Exec/Exec.cs b/src/Cupboard.Providers/Exec/Exec.cs index 4c144f7..88c882b 100644 --- a/src/Cupboard.Providers/Exec/Exec.cs +++ b/src/Cupboard.Providers/Exec/Exec.cs @@ -1,18 +1,17 @@ using System; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class Exec : Resource { - public sealed class Exec : Resource - { - public FilePath Path { get; set; } - public string? Args { get; set; } - public int[]? ValidExitCodes { get; set; } + public FilePath Path { get; set; } + public string? Args { get; set; } + public int[]? ValidExitCodes { get; set; } - public Exec(string name) - : base(name) - { - Path = new FilePath(name ?? throw new ArgumentNullException(nameof(name))); - } + public Exec(string name) + : base(name) + { + Path = new FilePath(name ?? throw new ArgumentNullException(nameof(name))); } } diff --git a/src/Cupboard.Providers/Exec/ExecExtensions.cs b/src/Cupboard.Providers/Exec/ExecExtensions.cs index d758c5b..48c56da 100644 --- a/src/Cupboard.Providers/Exec/ExecExtensions.cs +++ b/src/Cupboard.Providers/Exec/ExecExtensions.cs @@ -1,25 +1,24 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class ExecExtensions { - public static class ExecExtensions + public static IResourceBuilder Path(this IResourceBuilder builder, FilePath file) { - public static IResourceBuilder Path(this IResourceBuilder builder, FilePath file) - { - builder.Configure(res => res.Path = file); - return builder; - } + builder.Configure(res => res.Path = file); + return builder; + } - public static IResourceBuilder Arguments(this IResourceBuilder builder, string args) - { - builder.Configure(res => res.Args = args); - return builder; - } + public static IResourceBuilder Arguments(this IResourceBuilder builder, string args) + { + builder.Configure(res => res.Args = args); + return builder; + } - public static IResourceBuilder ValidExitCodes(this IResourceBuilder builder, params int[] exitCodes) - { - builder.Configure(res => res.ValidExitCodes = exitCodes); - return builder; - } + public static IResourceBuilder ValidExitCodes(this IResourceBuilder builder, params int[] exitCodes) + { + builder.Configure(res => res.ValidExitCodes = exitCodes); + return builder; } } diff --git a/src/Cupboard.Providers/Exec/ExecProvider.cs b/src/Cupboard.Providers/Exec/ExecProvider.cs index 67fa9b1..1f9dad0 100644 --- a/src/Cupboard.Providers/Exec/ExecProvider.cs +++ b/src/Cupboard.Providers/Exec/ExecProvider.cs @@ -3,65 +3,64 @@ using System.Threading.Tasks; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class ExecProvider : AsyncResourceProvider { - public sealed class ExecProvider : AsyncResourceProvider + private readonly IProcessRunner _runner; + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly IEnvironmentRefresher _refresher; + private readonly ICupboardLogger _logger; + + public ExecProvider( + IProcessRunner runner, + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + IEnvironmentRefresher refresher, + ICupboardLogger logger) { - private readonly IProcessRunner _runner; - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly IEnvironmentRefresher _refresher; - private readonly ICupboardLogger _logger; + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public ExecProvider( - IProcessRunner runner, - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - IEnvironmentRefresher refresher, - ICupboardLogger logger) + public override Exec Create(string name) + { + return new Exec(name); + } + + public override async Task RunAsync(IExecutionContext context, Exec resource) + { + var args = resource.Args ?? string.Empty; + + var path = resource.Path.MakeAbsolute(_environment); + if (!_fileSystem.Exist(path)) { - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _logger.Error($"The file {path.FullPath} could not be found"); + return ResourceState.Error; } - public override Exec Create(string name) + if (context.DryRun) { - return new Exec(name); + return ResourceState.Unknown; } - public override async Task RunAsync(IExecutionContext context, Exec resource) + var result = await _runner.Run(path.FullPath, args).ConfigureAwait(false); + if (result.ExitCode != 0) { - var args = resource.Args ?? string.Empty; - - var path = resource.Path.MakeAbsolute(_environment); - if (!_fileSystem.Exist(path)) + if (resource.ValidExitCodes?.Contains(result.ExitCode) == true) { - _logger.Error($"The file {path.FullPath} could not be found"); - return ResourceState.Error; + _refresher.Refresh(); + return ResourceState.Changed; } - if (context.DryRun) - { - return ResourceState.Unknown; - } - - var result = await _runner.Run(path.FullPath, args).ConfigureAwait(false); - if (result.ExitCode != 0) - { - if (resource.ValidExitCodes?.Contains(result.ExitCode) == true) - { - _refresher.Refresh(); - return ResourceState.Changed; - } - - _logger.Error($"The file {path.FullPath} returned exit code {result.ExitCode}"); - return ResourceState.Error; - } - - return ResourceState.Changed; + _logger.Error($"The file {path.FullPath} returned exit code {result.ExitCode}"); + return ResourceState.Error; } + + return ResourceState.Changed; } } diff --git a/src/Cupboard.Providers/File/File.cs b/src/Cupboard.Providers/File/File.cs index 2323392..e2e2a13 100644 --- a/src/Cupboard.Providers/File/File.cs +++ b/src/Cupboard.Providers/File/File.cs @@ -1,18 +1,17 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class File : Resource { - public sealed class File : Resource - { - public FilePath? Destination { get; set; } - public FilePath? Source { get; set; } - public FileState Ensure { get; set; } = FileState.Present; - public bool SymbolicLink { get; set; } - public Chmod? Permissions { get; set; } + public FilePath? Destination { get; set; } + public FilePath? Source { get; set; } + public FileState Ensure { get; set; } = FileState.Present; + public bool SymbolicLink { get; set; } + public Chmod? Permissions { get; set; } - public File(string name) - : base(name) - { - } + public File(string name) + : base(name) + { } } diff --git a/src/Cupboard.Providers/File/FileExtensions.cs b/src/Cupboard.Providers/File/FileExtensions.cs index 3290ce4..88ba049 100644 --- a/src/Cupboard.Providers/File/FileExtensions.cs +++ b/src/Cupboard.Providers/File/FileExtensions.cs @@ -1,38 +1,37 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class FileExtensions { - public static class FileExtensions + public static IResourceBuilder Source(this IResourceBuilder builder, FilePath path) { - public static IResourceBuilder Source(this IResourceBuilder builder, FilePath path) - { - return builder.Configure(file => file.Source = path); - } + return builder.Configure(file => file.Source = path); + } - public static IResourceBuilder Destination(this IResourceBuilder builder, FilePath path) - { - return builder.Configure(file => file.Destination = path); - } + public static IResourceBuilder Destination(this IResourceBuilder builder, FilePath path) + { + return builder.Configure(file => file.Destination = path); + } - public static IResourceBuilder SymbolicLink(this IResourceBuilder builder) - { - return builder.Configure(file => file.SymbolicLink = true); - } + public static IResourceBuilder SymbolicLink(this IResourceBuilder builder) + { + return builder.Configure(file => file.SymbolicLink = true); + } - public static IResourceBuilder Ensure(this IResourceBuilder builder, FileState state) - { - return builder.Configure(file => file.Ensure = state); - } + public static IResourceBuilder Ensure(this IResourceBuilder builder, FileState state) + { + return builder.Configure(file => file.Ensure = state); + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, string chmod) - { - var permissions = ChmodParser.Parse(chmod); - return builder.Configure(file => file.Permissions = permissions); - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, string chmod) + { + var permissions = ChmodParser.Parse(chmod); + return builder.Configure(file => file.Permissions = permissions); + } - public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) - { - return builder.Configure(file => file.Permissions = permissions); - } + public static IResourceBuilder Permissions(this IResourceBuilder builder, Chmod permissions) + { + return builder.Configure(file => file.Permissions = permissions); } } diff --git a/src/Cupboard.Providers/File/FileProvider.cs b/src/Cupboard.Providers/File/FileProvider.cs index 15e95f3..1ac9a31 100644 --- a/src/Cupboard.Providers/File/FileProvider.cs +++ b/src/Cupboard.Providers/File/FileProvider.cs @@ -2,168 +2,167 @@ using Spectre.IO; using FileAttributes = System.IO.FileAttributes; -namespace Cupboard +namespace Cupboard; + +public sealed class FileProvider : ResourceProvider { - public sealed class FileProvider : ResourceProvider + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly ICupboardLogger _logger; + + public FileProvider( + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + ICupboardLogger logger) { - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly ICupboardLogger _logger; - - public FileProvider( - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - ICupboardLogger logger) + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + public override File Create(string name) + { + return new File(name) { - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + Destination = new FilePath(name), + }; + } - public override File Create(string name) + public override ResourceState Run(IExecutionContext context, File resource) + { + if (resource.Destination == null) { - return new File(name) - { - Destination = new FilePath(name), - }; + return ResourceState.Error; } - public override ResourceState Run(IExecutionContext context, File resource) + var destination = resource.Destination.MakeAbsolute(_environment); + + return resource.Ensure switch { - if (resource.Destination == null) + FileState.Present => EnsurePresent(resource, destination), + FileState.Absent => EnsureAbsent(destination), + _ => ResourceState.Error, + }; + } + + private ResourceState EnsurePresent(File resource, FilePath destination) + { + // Make sure that the destination directory exist. + var root = destination.GetDirectory(); + if (!_fileSystem.Exist(root)) + { + _logger.Debug($"Creating root directory {root.FullPath}"); + _fileSystem.Directory.Create(root); + if (!_fileSystem.Exist(root)) { + // Could not create the root directory return ResourceState.Error; } - - var destination = resource.Destination.MakeAbsolute(_environment); - - return resource.Ensure switch - { - FileState.Present => EnsurePresent(resource, destination), - FileState.Absent => EnsureAbsent(destination), - _ => ResourceState.Error, - }; } - private ResourceState EnsurePresent(File resource, FilePath destination) + if (resource.Source != null) { - // Make sure that the destination directory exist. - var root = destination.GetDirectory(); - if (!_fileSystem.Exist(root)) + var source = resource.Source.MakeAbsolute(_environment); + + // Make sure the source file exist + if (!_fileSystem.Exist(source)) { - _logger.Debug($"Creating root directory {root.FullPath}"); - _fileSystem.Directory.Create(root); - if (!_fileSystem.Exist(root)) - { - // Could not create the root directory - return ResourceState.Error; - } + _logger.Error("Source file does not exist"); + return ResourceState.Error; } - if (resource.Source != null) + if (resource.SymbolicLink) { - var source = resource.Source.MakeAbsolute(_environment); - - // Make sure the source file exist - if (!_fileSystem.Exist(source)) + if (_fileSystem.Exist(destination)) { - _logger.Error("Source file does not exist"); - return ResourceState.Error; - } - - if (resource.SymbolicLink) - { - if (_fileSystem.Exist(destination)) + var file = _fileSystem.GetFile(destination); + if ((file.Attributes & FileAttributes.ReparsePoint) != 0) { - var file = _fileSystem.GetFile(destination); - if ((file.Attributes & FileAttributes.ReparsePoint) != 0) - { - // TODO 2021-07-13: Are the symlinks the same? - return ResourceState.Unchanged; - } - - // Delete the file - file.Delete(); - if (_fileSystem.Exist(destination)) - { - // We could not delete the file - _logger.Error("Could not delete destination file"); - return ResourceState.Error; - } - } - - // Create symbolic link - if (!_fileSystem.File.CreateSymbolicLinkSafe(source, destination)) - { - _logger.Error("Could not create symbolic link"); - return ResourceState.Error; - } - - _logger.Information($"Created symbolic link to {destination}"); - return ResourceState.Changed; - } - else - { - if (_fileSystem.Exist(destination)) - { - // TODO 2021-07-13: Are the files the same? + // TODO 2021-07-13: Are the symlinks the same? return ResourceState.Unchanged; } - // Copy the file - var file = _fileSystem.GetFile(source); - file.Copy(destination, true); - if (!_fileSystem.Exist(destination)) + // Delete the file + file.Delete(); + if (_fileSystem.Exist(destination)) { - // We could not copy the file - _logger.Error("Could not copy file"); + // We could not delete the file + _logger.Error("Could not delete destination file"); return ResourceState.Error; } + } - // Not on Windows and got permissions set? - if (resource.Permissions != null && _environment.Platform.Family != PlatformFamily.Windows) - { - destination.SetPermissions(resource.Permissions); - } - - return ResourceState.Changed; + // Create symbolic link + if (!_fileSystem.File.CreateSymbolicLinkSafe(source, destination)) + { + _logger.Error("Could not create symbolic link"); + return ResourceState.Error; } + + _logger.Information($"Created symbolic link to {destination}"); + return ResourceState.Changed; } else { - var file = _fileSystem.GetFile(destination); - using (var stream = file.OpenWrite()) + if (_fileSystem.Exist(destination)) { - if (!_fileSystem.Exist(destination)) - { - // We could not create the file - _logger.Error("Could not create destination file"); - return ResourceState.Error; - } + // TODO 2021-07-13: Are the files the same? + return ResourceState.Unchanged; + } + + // Copy the file + var file = _fileSystem.GetFile(source); + file.Copy(destination, true); + if (!_fileSystem.Exist(destination)) + { + // We could not copy the file + _logger.Error("Could not copy file"); + return ResourceState.Error; + } + + // Not on Windows and got permissions set? + if (resource.Permissions != null && _environment.Platform.Family != PlatformFamily.Windows) + { + destination.SetPermissions(resource.Permissions); } return ResourceState.Changed; } } - - private ResourceState EnsureAbsent(FilePath destination) + else { var file = _fileSystem.GetFile(destination); - if (!file.Exists) + using (var stream = file.OpenWrite()) { - return ResourceState.Unchanged; + if (!_fileSystem.Exist(destination)) + { + // We could not create the file + _logger.Error("Could not create destination file"); + return ResourceState.Error; + } } - file.Delete(); - file.Refresh(); + return ResourceState.Changed; + } + } - if (file.Exists) - { - _logger.Error("Could not delete destination file"); - return ResourceState.Error; - } + private ResourceState EnsureAbsent(FilePath destination) + { + var file = _fileSystem.GetFile(destination); + if (!file.Exists) + { + return ResourceState.Unchanged; + } - return ResourceState.Changed; + file.Delete(); + file.Refresh(); + + if (file.Exists) + { + _logger.Error("Could not delete destination file"); + return ResourceState.Error; } + + return ResourceState.Changed; } } diff --git a/src/Cupboard.Providers/File/FileState.cs b/src/Cupboard.Providers/File/FileState.cs index b33e803..c813b03 100644 --- a/src/Cupboard.Providers/File/FileState.cs +++ b/src/Cupboard.Providers/File/FileState.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum FileState { - public enum FileState - { - Present, - Absent, - } + Present, + Absent, } diff --git a/src/Cupboard.Providers/MachineFacts.cs b/src/Cupboard.Providers/MachineFacts.cs index a1072bb..4b6487d 100644 --- a/src/Cupboard.Providers/MachineFacts.cs +++ b/src/Cupboard.Providers/MachineFacts.cs @@ -3,57 +3,56 @@ using Spectre.Console.Cli; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +internal sealed class MachineFacts : IFactProvider { - internal sealed class MachineFacts : IFactProvider - { - private readonly IPlatform _platform; + private readonly IPlatform _platform; - internal static class Constants - { - public const string OSArchitecture = "os.arch"; - public const string OSPlatform = "os.platform"; - public const string MachineName = "machine.name"; - public const string ComputerName = "computer.name"; - public const string UserName = "user.name"; - } + internal static class Constants + { + public const string OSArchitecture = "os.arch"; + public const string OSPlatform = "os.platform"; + public const string MachineName = "machine.name"; + public const string ComputerName = "computer.name"; + public const string UserName = "user.name"; + } - public MachineFacts(IPlatform platform) - { - _platform = platform ?? throw new ArgumentNullException(nameof(platform)); - } + public MachineFacts(IPlatform platform) + { + _platform = platform ?? throw new ArgumentNullException(nameof(platform)); + } - IEnumerable<(string Name, object Value)> IFactProvider.GetFacts(IRemainingArguments args) - { - yield return (Constants.OSArchitecture, GetOSArchitecture()); - yield return (Constants.OSPlatform, GetOSPlatform()); - yield return (Constants.MachineName, System.Environment.MachineName); - yield return (Constants.ComputerName, System.Environment.MachineName); - yield return (Constants.UserName, System.Environment.UserName); - } + IEnumerable<(string Name, object Value)> IFactProvider.GetFacts(IRemainingArguments args) + { + yield return (Constants.OSArchitecture, GetOSArchitecture()); + yield return (Constants.OSPlatform, GetOSPlatform()); + yield return (Constants.MachineName, System.Environment.MachineName); + yield return (Constants.ComputerName, System.Environment.MachineName); + yield return (Constants.UserName, System.Environment.UserName); + } - private OSArchitecture GetOSArchitecture() + private OSArchitecture GetOSArchitecture() + { + return _platform.Architecture switch { - return _platform.Architecture switch - { - PlatformArchitecture.X86 => OSArchitecture.X86, - PlatformArchitecture.X64 => OSArchitecture.X64, - PlatformArchitecture.Arm => OSArchitecture.ARM, - PlatformArchitecture.Arm64 => OSArchitecture.ARM64, - _ => throw new InvalidOperationException("Unknown OS architecture"), - }; - } + PlatformArchitecture.X86 => OSArchitecture.X86, + PlatformArchitecture.X64 => OSArchitecture.X64, + PlatformArchitecture.Arm => OSArchitecture.ARM, + PlatformArchitecture.Arm64 => OSArchitecture.ARM64, + _ => throw new InvalidOperationException("Unknown OS architecture"), + }; + } - private OSPlatform GetOSPlatform() + private OSPlatform GetOSPlatform() + { + return _platform.Family switch { - return _platform.Family switch - { - PlatformFamily.Windows => OSPlatform.Windows, - PlatformFamily.Linux => OSPlatform.Linux, - PlatformFamily.MacOs => OSPlatform.MacOS, - PlatformFamily.FreeBSD => OSPlatform.FreeBSD, - _ => throw new InvalidOperationException("Unknown OS platform"), - }; - } + PlatformFamily.Windows => OSPlatform.Windows, + PlatformFamily.Linux => OSPlatform.Linux, + PlatformFamily.MacOs => OSPlatform.MacOS, + PlatformFamily.FreeBSD => OSPlatform.FreeBSD, + _ => throw new InvalidOperationException("Unknown OS platform"), + }; } } diff --git a/src/Cupboard.Providers/MachineFactsExtensions.cs b/src/Cupboard.Providers/MachineFactsExtensions.cs index 7237ffa..acabbbb 100644 --- a/src/Cupboard.Providers/MachineFactsExtensions.cs +++ b/src/Cupboard.Providers/MachineFactsExtensions.cs @@ -1,80 +1,79 @@ -namespace Cupboard +namespace Cupboard; + +public static class MachineFactsExtensions { - public static class MachineFactsExtensions + public static OSPlatform Platform(this FactCollection facts) { - public static OSPlatform Platform(this FactCollection facts) - { - return facts[MachineFacts.Constants.OSPlatform].As(); - } + return facts[MachineFacts.Constants.OSPlatform].As(); + } - public static OSArchitecture Architecture(this FactCollection facts) - { - return facts[MachineFacts.Constants.OSArchitecture].As(); - } + public static OSArchitecture Architecture(this FactCollection facts) + { + return facts[MachineFacts.Constants.OSArchitecture].As(); + } - public static string MachineName(this FactCollection facts) - { - return facts[MachineFacts.Constants.MachineName]; - } + public static string MachineName(this FactCollection facts) + { + return facts[MachineFacts.Constants.MachineName]; + } - public static string ComputerName(this FactCollection facts) - { - return facts[MachineFacts.Constants.ComputerName]; - } + public static string ComputerName(this FactCollection facts) + { + return facts[MachineFacts.Constants.ComputerName]; + } - public static string UserName(this FactCollection facts) - { - return facts[MachineFacts.Constants.UserName]; - } + public static string UserName(this FactCollection facts) + { + return facts[MachineFacts.Constants.UserName]; + } - public static bool IsWindows(this FactCollection facts) - { - return Platform(facts) == OSPlatform.Windows; - } + public static bool IsWindows(this FactCollection facts) + { + return Platform(facts) == OSPlatform.Windows; + } - public static bool IsLinux(this FactCollection facts) - { - return Platform(facts) == OSPlatform.Linux; - } + public static bool IsLinux(this FactCollection facts) + { + return Platform(facts) == OSPlatform.Linux; + } - public static bool IsMacOS(this FactCollection facts) - { - return Platform(facts) == OSPlatform.MacOS; - } + public static bool IsMacOS(this FactCollection facts) + { + return Platform(facts) == OSPlatform.MacOS; + } - public static bool IsFreeBSD(this FactCollection facts) - { - return Platform(facts) == OSPlatform.FreeBSD; - } + public static bool IsFreeBSD(this FactCollection facts) + { + return Platform(facts) == OSPlatform.FreeBSD; + } - public static bool IsX86(this FactCollection facts) - { - return Architecture(facts) is OSArchitecture.X86; - } + public static bool IsX86(this FactCollection facts) + { + return Architecture(facts) is OSArchitecture.X86; + } - public static bool IsX64(this FactCollection facts) - { - return Architecture(facts) is OSArchitecture.X64; - } + public static bool IsX64(this FactCollection facts) + { + return Architecture(facts) is OSArchitecture.X64; + } - public static bool IsX86OrX64(this FactCollection facts) - { - return IsX86(facts) || IsX64(facts); - } + public static bool IsX86OrX64(this FactCollection facts) + { + return IsX86(facts) || IsX64(facts); + } - public static bool IsArm(this FactCollection facts) - { - return Architecture(facts) is OSArchitecture.ARM or OSArchitecture.ARM64; - } + public static bool IsArm(this FactCollection facts) + { + return Architecture(facts) is OSArchitecture.ARM or OSArchitecture.ARM64; + } - public static bool IsArm64(this FactCollection facts) - { - return Architecture(facts) is OSArchitecture.ARM64; - } + public static bool IsArm64(this FactCollection facts) + { + return Architecture(facts) is OSArchitecture.ARM64; + } - public static bool IsArmOrArm64(this FactCollection facts) - { - return IsArm(facts) || IsArm64(facts); - } + public static bool IsArmOrArm64(this FactCollection facts) + { + return IsArm(facts) || IsArm64(facts); } } diff --git a/src/Cupboard.Providers/PowerShell/PowerShell.cs b/src/Cupboard.Providers/PowerShell/PowerShell.cs index 6f399a8..660bc4a 100644 --- a/src/Cupboard.Providers/PowerShell/PowerShell.cs +++ b/src/Cupboard.Providers/PowerShell/PowerShell.cs @@ -1,17 +1,16 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class PowerShell : Resource { - public sealed class PowerShell : Resource - { - public FilePath? Script { get; set; } - public string? Command { get; set; } - public string? Unless { get; set; } - public PowerShellFlavor Flavor { get; set; } = PowerShellFlavor.PowerShell; + public FilePath? Script { get; set; } + public string? Command { get; set; } + public string? Unless { get; set; } + public PowerShellFlavor Flavor { get; set; } = PowerShellFlavor.PowerShell; - public PowerShell(string name) - : base(name) - { - } + public PowerShell(string name) + : base(name) + { } } diff --git a/src/Cupboard.Providers/PowerShell/PowerShellFlavor.cs b/src/Cupboard.Providers/PowerShell/PowerShellFlavor.cs index 17fb266..1af05c4 100644 --- a/src/Cupboard.Providers/PowerShell/PowerShellFlavor.cs +++ b/src/Cupboard.Providers/PowerShell/PowerShellFlavor.cs @@ -1,8 +1,7 @@ -namespace Cupboard +namespace Cupboard; + +public enum PowerShellFlavor { - public enum PowerShellFlavor - { - PowerShell, - PowerShellCore, - } + PowerShell, + PowerShellCore, } diff --git a/src/Cupboard.Providers/PowerShell/PowerShellProvider.cs b/src/Cupboard.Providers/PowerShell/PowerShellProvider.cs index e07c77a..19b5af4 100644 --- a/src/Cupboard.Providers/PowerShell/PowerShellProvider.cs +++ b/src/Cupboard.Providers/PowerShell/PowerShellProvider.cs @@ -3,146 +3,145 @@ using System.Threading.Tasks; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class PowerShellProvider : AsyncResourceProvider { - public sealed class PowerShellProvider : AsyncResourceProvider + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly IProcessRunner _runner; + private readonly IEnvironmentRefresher _refresher; + private readonly ICupboardLogger _logger; + + public PowerShellProvider( + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + IProcessRunner runner, + IEnvironmentRefresher refresher, + ICupboardLogger logger) { - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly IProcessRunner _runner; - private readonly IEnvironmentRefresher _refresher; - private readonly ICupboardLogger _logger; - - public PowerShellProvider( - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - IProcessRunner runner, - IEnvironmentRefresher refresher, - ICupboardLogger logger) - { - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); - _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public override PowerShell Create(string name) - { - return new PowerShell(name); - } + public override PowerShell Create(string name) + { + return new PowerShell(name); + } - public override async Task RunAsync(IExecutionContext context, PowerShell resource) + public override async Task RunAsync(IExecutionContext context, PowerShell resource) + { + if (resource.Unless != null) { - if (resource.Unless != null) + _logger.Debug($"Evaluating PowerShell condition: {resource.Unless}"); + if (await RunPowerShell(context, resource.Flavor, resource.Unless).ConfigureAwait(false) != 0) { - _logger.Debug($"Evaluating PowerShell condition: {resource.Unless}"); - if (await RunPowerShell(context, resource.Flavor, resource.Unless).ConfigureAwait(false) != 0) - { - _logger.Verbose("Skipping PowerShell script since condition did not evaluate to 0 (zero)"); - return ResourceState.Skipped; - } + _logger.Verbose("Skipping PowerShell script since condition did not evaluate to 0 (zero)"); + return ResourceState.Skipped; } + } - if (!context.DryRun) + if (!context.DryRun) + { + if (resource.Script != null) { - if (resource.Script != null) + // Script + var path = resource.Script.MakeAbsolute(_environment); + if (!_fileSystem.Exist(path)) { - // Script - var path = resource.Script.MakeAbsolute(_environment); - if (!_fileSystem.Exist(path)) - { - _logger.Error("PowerShell script path does not exist"); - return ResourceState.Error; - } - - _logger.Debug($"Running PowerShell script [yellow]{path}[/]"); - if (await RunPowerShell(context, resource.Flavor, path).ConfigureAwait(false) != 0) - { - _logger.Error("Powershell script exited with an unexpected exit code"); - return ResourceState.Error; - } + _logger.Error("PowerShell script path does not exist"); + return ResourceState.Error; } - else if (resource.Command != null) + + _logger.Debug($"Running PowerShell script [yellow]{path}[/]"); + if (await RunPowerShell(context, resource.Flavor, path).ConfigureAwait(false) != 0) { - // Command - _logger.Debug($"Running PowerShell command: [yellow]{resource.Command}[/]"); - if (await RunPowerShell(context, resource.Flavor, resource.Command).ConfigureAwait(false) != 0) - { - _logger.Error("Powershell script exited with an unexpected exit code"); - return ResourceState.Error; - } + _logger.Error("Powershell script exited with an unexpected exit code"); + return ResourceState.Error; } - else + } + else if (resource.Command != null) + { + // Command + _logger.Debug($"Running PowerShell command: [yellow]{resource.Command}[/]"); + if (await RunPowerShell(context, resource.Flavor, resource.Command).ConfigureAwait(false) != 0) { - _logger.Error("PowerShell Command or script path has not been set"); + _logger.Error("Powershell script exited with an unexpected exit code"); return ResourceState.Error; } - - _logger.Debug("Refreshing environment variables for user"); - _refresher.Refresh(); + } + else + { + _logger.Error("PowerShell Command or script path has not been set"); + return ResourceState.Error; } - return ResourceState.Executed; + _logger.Debug("Refreshing environment variables for user"); + _refresher.Refresh(); } - private async Task RunPowerShell(IExecutionContext context, PowerShellFlavor flavor, string command) - { - var path = _environment - .GetTempFilePath() - .ChangeExtension("ps1") - .MakeAbsolute(_environment); + return ResourceState.Executed; + } - try - { - // Create file on disk - using (var stream = _fileSystem.File.OpenWrite(path)) - using (var writer = new StreamWriter(stream)) - { - writer.Write(command); - } + private async Task RunPowerShell(IExecutionContext context, PowerShellFlavor flavor, string command) + { + var path = _environment + .GetTempFilePath() + .ChangeExtension("ps1") + .MakeAbsolute(_environment); - return await RunPowerShell(context, flavor, path).ConfigureAwait(false); + try + { + // Create file on disk + using (var stream = _fileSystem.File.OpenWrite(path)) + using (var writer = new StreamWriter(stream)) + { + writer.Write(command); } - finally + + return await RunPowerShell(context, flavor, path).ConfigureAwait(false); + } + finally + { + if (_fileSystem.Exist(path)) { - if (_fileSystem.Exist(path)) - { - _fileSystem.File.Delete(path); - } + _fileSystem.File.Delete(path); } } + } - private async Task RunPowerShell(IExecutionContext context, PowerShellFlavor flavor, FilePath path) + private async Task RunPowerShell(IExecutionContext context, PowerShellFlavor flavor, FilePath path) + { + var executable = GetPowerShellExecutable(context, flavor); + var args = flavor switch { - var executable = GetPowerShellExecutable(context, flavor); - var args = flavor switch - { - PowerShellFlavor.PowerShell => $"–noprofile & '{path.FullPath}'", - PowerShellFlavor.PowerShellCore => $"–noprofile \"{path.FullPath}\"", - _ => throw new InvalidOperationException($"Unknown PowerShell provider '{flavor}'"), - }; + PowerShellFlavor.PowerShell => $"–noprofile & '{path.FullPath}'", + PowerShellFlavor.PowerShellCore => $"–noprofile \"{path.FullPath}\"", + _ => throw new InvalidOperationException($"Unknown PowerShell provider '{flavor}'"), + }; - var result = await _runner.Run(executable, args).ConfigureAwait(false); + var result = await _runner.Run(executable, args).ConfigureAwait(false); - return result.ExitCode; - } + return result.ExitCode; + } - private static string GetPowerShellExecutable(IExecutionContext context, PowerShellFlavor flavor) + private static string GetPowerShellExecutable(IExecutionContext context, PowerShellFlavor flavor) + { + if (context.Facts.IsWindows()) { - if (context.Facts.IsWindows()) + return flavor switch { - return flavor switch - { - PowerShellFlavor.PowerShell => "powershell.exe", - PowerShellFlavor.PowerShellCore => "pwsh.exe", - _ => throw new InvalidOperationException($"Unknown PowerShell provider '{flavor}'"), - }; - } - else - { - return "pwsh"; - } + PowerShellFlavor.PowerShell => "powershell.exe", + PowerShellFlavor.PowerShellCore => "pwsh.exe", + _ => throw new InvalidOperationException($"Unknown PowerShell provider '{flavor}'"), + }; + } + else + { + return "pwsh"; } } } diff --git a/src/Cupboard.Providers/PowerShell/PowerShellScriptExtensions.cs b/src/Cupboard.Providers/PowerShell/PowerShellScriptExtensions.cs index 3afb210..17e9da7 100644 --- a/src/Cupboard.Providers/PowerShell/PowerShellScriptExtensions.cs +++ b/src/Cupboard.Providers/PowerShell/PowerShellScriptExtensions.cs @@ -1,31 +1,30 @@ using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public static class PowerShellScriptExtensions { - public static class PowerShellScriptExtensions + public static IResourceBuilder Script(this IResourceBuilder builder, FilePath file) { - public static IResourceBuilder Script(this IResourceBuilder builder, FilePath file) - { - builder.Configure(res => res.Script = file); - return builder; - } + builder.Configure(res => res.Script = file); + return builder; + } - public static IResourceBuilder Command(this IResourceBuilder builder, string command) - { - builder.Configure(res => res.Command = command); - return builder; - } + public static IResourceBuilder Command(this IResourceBuilder builder, string command) + { + builder.Configure(res => res.Command = command); + return builder; + } - public static IResourceBuilder Flavor(this IResourceBuilder builder, PowerShellFlavor flavor) - { - builder.Configure(res => res.Flavor = flavor); - return builder; - } + public static IResourceBuilder Flavor(this IResourceBuilder builder, PowerShellFlavor flavor) + { + builder.Configure(res => res.Flavor = flavor); + return builder; + } - public static IResourceBuilder Unless(this IResourceBuilder builder, string script) - { - builder.Configure(res => res.Unless = script); - return builder; - } + public static IResourceBuilder Unless(this IResourceBuilder builder, string script) + { + builder.Configure(res => res.Unless = script); + return builder; } } diff --git a/src/Cupboard.Providers/ResourcesModule.cs b/src/Cupboard.Providers/ResourcesModule.cs index b2a0e0e..12f8ff2 100644 --- a/src/Cupboard.Providers/ResourcesModule.cs +++ b/src/Cupboard.Providers/ResourcesModule.cs @@ -1,23 +1,22 @@ using Microsoft.Extensions.DependencyInjection; -namespace Cupboard +namespace Cupboard; + +public sealed class ResourcesModule : ServiceModule { - public sealed class ResourcesModule : ServiceModule + public override void Configure(IServiceCollection services) { - public override void Configure(IServiceCollection services) - { - // Resources - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + // Resources + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); - // Facts - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - } + // Facts + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } } diff --git a/src/Cupboard.Providers/VSCode/VSCodeExtension.cs b/src/Cupboard.Providers/VSCode/VSCodeExtension.cs index 684b9ca..1ddbb0b 100644 --- a/src/Cupboard.Providers/VSCode/VSCodeExtension.cs +++ b/src/Cupboard.Providers/VSCode/VSCodeExtension.cs @@ -1,16 +1,15 @@ using System; -namespace Cupboard +namespace Cupboard; + +public sealed class VSCodeExtension : Resource, IHasPackageName, IHasPackageState { - public sealed class VSCodeExtension : Resource, IHasPackageName, IHasPackageState - { - public string Package { get; set; } - public PackageState Ensure { get; set; } = PackageState.Installed; + public string Package { get; set; } + public PackageState Ensure { get; set; } = PackageState.Installed; - public VSCodeExtension(string name) - : base(name) - { - Package = name ?? throw new ArgumentNullException(nameof(name)); - } + public VSCodeExtension(string name) + : base(name) + { + Package = name ?? throw new ArgumentNullException(nameof(name)); } } diff --git a/src/Cupboard.Providers/VSCode/VSCodeExtensionExtensions.cs b/src/Cupboard.Providers/VSCode/VSCodeExtensionExtensions.cs index c1c5979..e2c4e95 100644 --- a/src/Cupboard.Providers/VSCode/VSCodeExtensionExtensions.cs +++ b/src/Cupboard.Providers/VSCode/VSCodeExtensionExtensions.cs @@ -1,15 +1,14 @@ -namespace Cupboard +namespace Cupboard; + +public static class VSCodeExtensionExtensions { - public static class VSCodeExtensionExtensions + public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) { - public static IResourceBuilder Ensure(this IResourceBuilder builder, PackageState state) - { - return builder.Configure(file => file.Ensure = state); - } + return builder.Configure(file => file.Ensure = state); + } - public static IResourceBuilder Package(this IResourceBuilder builder, string package) - { - return builder.Configure(pkg => pkg.Package = package); - } + public static IResourceBuilder Package(this IResourceBuilder builder, string package) + { + return builder.Configure(pkg => pkg.Package = package); } } diff --git a/src/Cupboard.Providers/VSCode/VSCodeExtensionProvider.cs b/src/Cupboard.Providers/VSCode/VSCodeExtensionProvider.cs index 0b50583..b499766 100644 --- a/src/Cupboard.Providers/VSCode/VSCodeExtensionProvider.cs +++ b/src/Cupboard.Providers/VSCode/VSCodeExtensionProvider.cs @@ -2,72 +2,71 @@ using System.Threading.Tasks; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class VSCodeExtensionProvider : PackageInstallerProvider { - public sealed class VSCodeExtensionProvider : PackageInstallerProvider - { - private readonly IProcessRunner _runner; - private readonly ICupboardEnvironment _environment; + private readonly IProcessRunner _runner; + private readonly ICupboardEnvironment _environment; - protected override bool ShouldCache { get; } = true; - protected override string Name { get; } = "VSCode"; - protected override string Kind { get; } = "extension"; + protected override bool ShouldCache { get; } = true; + protected override string Name { get; } = "VSCode"; + protected override string Kind { get; } = "extension"; - public VSCodeExtensionProvider( - IProcessRunner runner, - ICupboardEnvironment environment, - ICupboardLogger logger, - IEnvironmentRefresher refresher) - : base(logger, refresher) - { - _runner = runner ?? throw new ArgumentNullException(nameof(runner)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - } + public VSCodeExtensionProvider( + IProcessRunner runner, + ICupboardEnvironment environment, + ICupboardLogger logger, + IEnvironmentRefresher refresher) + : base(logger, refresher) + { + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + } - public override VSCodeExtension Create(string name) + public override VSCodeExtension Create(string name) + { + return new VSCodeExtension(name) { - return new VSCodeExtension(name) - { - Package = name, - }; - } + Package = name, + }; + } - protected override bool IsPackageInstalled(VSCodeExtension resource, string output) - { - return output.Contains(resource.Package, StringComparison.OrdinalIgnoreCase); - } + protected override bool IsPackageInstalled(VSCodeExtension resource, string output) + { + return output.Contains(resource.Package, StringComparison.OrdinalIgnoreCase); + } - protected override async Task GetPackageState(VSCodeExtension resource) - { - var executable = GetCodeExecutable(); - return await _runner.Run(executable, "--list-extensions", supressOutput: true).ConfigureAwait(false); - } + protected override async Task GetPackageState(VSCodeExtension resource) + { + var executable = GetCodeExecutable(); + return await _runner.Run(executable, "--list-extensions", supressOutput: true).ConfigureAwait(false); + } - protected override async Task InstallPackage(VSCodeExtension resource) - { - var executable = GetCodeExecutable(); - var arguments = $"--install-extension {resource.Package}"; - return await _runner.Run(executable, arguments).ConfigureAwait(false); - } + protected override async Task InstallPackage(VSCodeExtension resource) + { + var executable = GetCodeExecutable(); + var arguments = $"--install-extension {resource.Package}"; + return await _runner.Run(executable, arguments).ConfigureAwait(false); + } + + protected override async Task UninstallPackage(VSCodeExtension resource) + { + var executable = GetCodeExecutable(); + var arguments = $"--uninstall-extension {resource.Package}"; + return await _runner.Run(executable, arguments).ConfigureAwait(false); + } - protected override async Task UninstallPackage(VSCodeExtension resource) + private string GetCodeExecutable() + { + if (_environment.Platform.Family == PlatformFamily.Windows) { - var executable = GetCodeExecutable(); - var arguments = $"--uninstall-extension {resource.Package}"; - return await _runner.Run(executable, arguments).ConfigureAwait(false); + // TODO 2021-07-14: This is not good + return "C:/Program Files/Microsoft VS Code/bin/code.cmd"; } - - private string GetCodeExecutable() + else { - if (_environment.Platform.Family == PlatformFamily.Windows) - { - // TODO 2021-07-14: This is not good - return "C:/Program Files/Microsoft VS Code/bin/code.cmd"; - } - else - { - return "code"; - } + return "code"; } } } diff --git a/src/Cupboard.Testing/CupboardFixture.cs b/src/Cupboard.Testing/CupboardFixture.cs index ec772af..25a7de9 100644 --- a/src/Cupboard.Testing/CupboardFixture.cs +++ b/src/Cupboard.Testing/CupboardFixture.cs @@ -6,108 +6,107 @@ using Spectre.Console.Testing; using Spectre.IO; -namespace Cupboard.Testing -{ - public sealed class CupboardFixture - { - private readonly List _catalogs; - private readonly FakeReportSubscriber _interceptor; - private readonly FakeFactBuilder _factBuilder; - private readonly List> _registrations; +namespace Cupboard.Testing; - public TestConsole Console { get; } - public FakeLogger Logger { get; } - public FakeProcessRunner Process { get; } - public FakeSecurityPrincipal Security { get; } - public FakeEnvironmentRefresher EnvironmentRefresher { get; } - public FakeCupboardFileSystem FileSystem { get; } - public FakeCupboardEnvironment Environment { get; } - public FakeWindowsRegistry WindowsRegistry { get; } - public FakeRebootDetector RebootDetector { get; } +public sealed class CupboardFixture +{ + private readonly List _catalogs; + private readonly FakeReportSubscriber _interceptor; + private readonly FakeFactBuilder _factBuilder; + private readonly List> _registrations; - public FactCollection Facts => _factBuilder.Facts; + public TestConsole Console { get; } + public FakeLogger Logger { get; } + public FakeProcessRunner Process { get; } + public FakeSecurityPrincipal Security { get; } + public FakeEnvironmentRefresher EnvironmentRefresher { get; } + public FakeCupboardFileSystem FileSystem { get; } + public FakeCupboardEnvironment Environment { get; } + public FakeWindowsRegistry WindowsRegistry { get; } + public FakeRebootDetector RebootDetector { get; } - public CupboardFixture(PlatformFamily family = PlatformFamily.Windows) - { - _catalogs = new List(); - _interceptor = new FakeReportSubscriber(); - _factBuilder = new FakeFactBuilder(); - _registrations = new List>(); + public FactCollection Facts => _factBuilder.Facts; - Console = new TestConsole(); - Logger = new FakeLogger(); - Process = new FakeProcessRunner(); - Security = new FakeSecurityPrincipal(); - EnvironmentRefresher = new FakeEnvironmentRefresher(); - Environment = new FakeCupboardEnvironment(family); - FileSystem = new FakeCupboardFileSystem(Environment); - WindowsRegistry = new FakeWindowsRegistry(); - RebootDetector = new FakeRebootDetector(); + public CupboardFixture(PlatformFamily family = PlatformFamily.Windows) + { + _catalogs = new List(); + _interceptor = new FakeReportSubscriber(); + _factBuilder = new FakeFactBuilder(); + _registrations = new List>(); - switch (family) - { - case PlatformFamily.Windows: - Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.Windows); - break; - case PlatformFamily.Linux: - Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.Linux); - break; - case PlatformFamily.MacOs: - Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.OSX); - break; - case PlatformFamily.Unknown: - throw new InvalidOperationException("Unknown platform"); - } - } + Console = new TestConsole(); + Logger = new FakeLogger(); + Process = new FakeProcessRunner(); + Security = new FakeSecurityPrincipal(); + EnvironmentRefresher = new FakeEnvironmentRefresher(); + Environment = new FakeCupboardEnvironment(family); + FileSystem = new FakeCupboardFileSystem(Environment); + WindowsRegistry = new FakeWindowsRegistry(); + RebootDetector = new FakeRebootDetector(); - public void Register(Action action) + switch (family) { - _registrations.Add(action); + case PlatformFamily.Windows: + Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.Windows); + break; + case PlatformFamily.Linux: + Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.Linux); + break; + case PlatformFamily.MacOs: + Facts.Add("os.platform", System.Runtime.InteropServices.OSPlatform.OSX); + break; + case PlatformFamily.Unknown: + throw new InvalidOperationException("Unknown platform"); } + } - public void Configure(Action action) - { - _catalogs.Add(new LambdaCatalog(action)); - } + public void Register(Action action) + { + _registrations.Add(action); + } - public (int ExitCode, Report? Report) Run(params string[] args) - { - var result = BuildHost().Run(args); - return (result, _interceptor.Report); - } + public void Configure(Action action) + { + _catalogs.Add(new LambdaCatalog(action)); + } - private CupboardHost BuildHost() + public (int ExitCode, Report? Report) Run(params string[] args) + { + var result = BuildHost().Run(args); + return (result, _interceptor.Report); + } + + private CupboardHost BuildHost() + { + var builder = new CupboardHostBuilder(Console); + builder.PropagateExceptions(); + builder.ConfigureServices(services => { - var builder = new CupboardHostBuilder(Console); - builder.PropagateExceptions(); - builder.ConfigureServices(services => - { - // Register the report interceptor - services.AddSingleton(_interceptor); + // Register the report interceptor + services.AddSingleton(_interceptor); - // Replace existing services - services.Replace(ServiceDescriptor.Singleton(_ => Process)); - services.Replace(ServiceDescriptor.Singleton(_ => Security)); - services.Replace(ServiceDescriptor.Singleton(_ => FileSystem)); - services.Replace(ServiceDescriptor.Singleton(_ => Environment)); - services.Replace(ServiceDescriptor.Singleton(_ => EnvironmentRefresher)); - services.Replace(ServiceDescriptor.Singleton(_ => WindowsRegistry)); - services.Replace(ServiceDescriptor.Singleton(_ => RebootDetector)); - services.Replace(ServiceDescriptor.Singleton(_ => Logger)); - services.Replace(ServiceDescriptor.Singleton(_ => _factBuilder)); + // Replace existing services + services.Replace(ServiceDescriptor.Singleton(_ => Process)); + services.Replace(ServiceDescriptor.Singleton(_ => Security)); + services.Replace(ServiceDescriptor.Singleton(_ => FileSystem)); + services.Replace(ServiceDescriptor.Singleton(_ => Environment)); + services.Replace(ServiceDescriptor.Singleton(_ => EnvironmentRefresher)); + services.Replace(ServiceDescriptor.Singleton(_ => WindowsRegistry)); + services.Replace(ServiceDescriptor.Singleton(_ => RebootDetector)); + services.Replace(ServiceDescriptor.Singleton(_ => Logger)); + services.Replace(ServiceDescriptor.Singleton(_ => _factBuilder)); - foreach (var registration in _registrations) - { - registration(services); - } + foreach (var registration in _registrations) + { + registration(services); + } - foreach (var catalog in _catalogs) - { - services.AddSingleton(catalog); - } - }); + foreach (var catalog in _catalogs) + { + services.AddSingleton(catalog); + } + }); - return builder.Build(); - } + return builder.Build(); } } diff --git a/src/Cupboard.Testing/Extensions/CupboardFixtureExtensions.cs b/src/Cupboard.Testing/Extensions/CupboardFixtureExtensions.cs index 2b27e70..b8b8dbc 100644 --- a/src/Cupboard.Testing/Extensions/CupboardFixtureExtensions.cs +++ b/src/Cupboard.Testing/Extensions/CupboardFixtureExtensions.cs @@ -1,64 +1,63 @@ using System; using Spectre.IO; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public static class CupboardFixtureExtensions { - public static class CupboardFixtureExtensions + public static void FileShouldExist(this CupboardFixture fixture, FilePath path) { - public static void FileShouldExist(this CupboardFixture fixture, FilePath path) + if (fixture is null) { - if (fixture is null) - { - throw new ArgumentNullException(nameof(fixture)); - } + throw new ArgumentNullException(nameof(fixture)); + } - if (path is null) - { - throw new ArgumentNullException(nameof(path)); - } + if (path is null) + { + throw new ArgumentNullException(nameof(path)); + } - if (!fixture.FileSystem.File.Exists(path)) - { - throw new InvalidOperationException($"File at {path.FullPath} does not exist"); - } + if (!fixture.FileSystem.File.Exists(path)) + { + throw new InvalidOperationException($"File at {path.FullPath} does not exist"); } + } - public static void FileShouldNotExist(this CupboardFixture fixture, FilePath path) + public static void FileShouldNotExist(this CupboardFixture fixture, FilePath path) + { + if (fixture is null) { - if (fixture is null) - { - throw new ArgumentNullException(nameof(fixture)); - } + throw new ArgumentNullException(nameof(fixture)); + } - if (path is null) - { - throw new ArgumentNullException(nameof(path)); - } + if (path is null) + { + throw new ArgumentNullException(nameof(path)); + } - if (fixture.FileSystem.File.Exists(path)) - { - throw new InvalidOperationException($"File at {path.FullPath} should not exist"); - } + if (fixture.FileSystem.File.Exists(path)) + { + throw new InvalidOperationException($"File at {path.FullPath} should not exist"); } + } - public static void FileShouldBeSymbolicLink(this CupboardFixture fixture, FilePath path) + public static void FileShouldBeSymbolicLink(this CupboardFixture fixture, FilePath path) + { + if (fixture is null) { - if (fixture is null) - { - throw new ArgumentNullException(nameof(fixture)); - } + throw new ArgumentNullException(nameof(fixture)); + } - if (path is null) - { - throw new ArgumentNullException(nameof(path)); - } + if (path is null) + { + throw new ArgumentNullException(nameof(path)); + } - FileShouldExist(fixture, path); + FileShouldExist(fixture, path); - if (fixture.FileSystem.GetFakeFile(path)?.SymbolicLink == null) - { - throw new InvalidOperationException($"File at {path.FullPath} is not a symbolic link"); - } + if (fixture.FileSystem.GetFakeFile(path)?.SymbolicLink == null) + { + throw new InvalidOperationException($"File at {path.FullPath} is not a symbolic link"); } } } diff --git a/src/Cupboard.Testing/Extensions/ReportExtensions.cs b/src/Cupboard.Testing/Extensions/ReportExtensions.cs index df0cdb8..dbce3a3 100644 --- a/src/Cupboard.Testing/Extensions/ReportExtensions.cs +++ b/src/Cupboard.Testing/Extensions/ReportExtensions.cs @@ -1,23 +1,22 @@ using System; using System.Linq; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public static class ReportExtensions { - public static class ReportExtensions + public static ResourceState GetState(this Report report, string name) + where TResource : Resource { - public static ResourceState GetState(this Report report, string name) - where TResource : Resource + if (report == null) { - if (report == null) - { - return ResourceState.Unknown; - } + return ResourceState.Unknown; + } - var item = report.Items.SingleOrDefault( - x => x.Resource.GetType() == typeof(TResource) - && x.Resource.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + var item = report.Items.SingleOrDefault( + x => x.Resource.GetType() == typeof(TResource) + && x.Resource.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); - return item?.State ?? ResourceState.Unknown; - } + return item?.State ?? ResourceState.Unknown; } } diff --git a/src/Cupboard.Testing/Fakes/FakeCupboardEnvironment.cs b/src/Cupboard.Testing/Fakes/FakeCupboardEnvironment.cs index 135a1b7..75bd239 100644 --- a/src/Cupboard.Testing/Fakes/FakeCupboardEnvironment.cs +++ b/src/Cupboard.Testing/Fakes/FakeCupboardEnvironment.cs @@ -4,79 +4,78 @@ using Spectre.IO; using Spectre.IO.Testing; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeCupboardEnvironment : ICupboardEnvironment { - public sealed class FakeCupboardEnvironment : ICupboardEnvironment - { - private readonly FakeEnvironment _environment; - private readonly object _lock; - private int _counter; + private readonly FakeEnvironment _environment; + private readonly object _lock; + private int _counter; - public DirectoryPath WorkingDirectory => _environment.WorkingDirectory; - public DirectoryPath HomeDirectory => _environment.HomeDirectory; - public IPlatform Platform => _environment.Platform; + public DirectoryPath WorkingDirectory => _environment.WorkingDirectory; + public DirectoryPath HomeDirectory => _environment.HomeDirectory; + public IPlatform Platform => _environment.Platform; - public FakeCupboardEnvironment(PlatformFamily family, PlatformArchitecture architecture = PlatformArchitecture.X64) - { - _environment = new FakeEnvironment(family, architecture); - _lock = new object(); - _counter = 0; - } + public FakeCupboardEnvironment(PlatformFamily family, PlatformArchitecture architecture = PlatformArchitecture.X64) + { + _environment = new FakeEnvironment(family, architecture); + _lock = new object(); + _counter = 0; + } - public static FakeCupboardEnvironment CreateWindowsEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) - { - return new FakeCupboardEnvironment(PlatformFamily.Windows, architecture); - } + public static FakeCupboardEnvironment CreateWindowsEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) + { + return new FakeCupboardEnvironment(PlatformFamily.Windows, architecture); + } - public static FakeCupboardEnvironment CreateLinuxEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) - { - return new FakeCupboardEnvironment(PlatformFamily.Linux, architecture); - } + public static FakeCupboardEnvironment CreateLinuxEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) + { + return new FakeCupboardEnvironment(PlatformFamily.Linux, architecture); + } - public static FakeCupboardEnvironment CreateMacOSEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) - { - return new FakeCupboardEnvironment(PlatformFamily.MacOs, architecture); - } + public static FakeCupboardEnvironment CreateMacOSEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) + { + return new FakeCupboardEnvironment(PlatformFamily.MacOs, architecture); + } - public static FakeCupboardEnvironment CreateFreeBSDEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) - { - return new FakeCupboardEnvironment(PlatformFamily.FreeBSD, architecture); - } + public static FakeCupboardEnvironment CreateFreeBSDEnvironment(PlatformArchitecture architecture = PlatformArchitecture.X64) + { + return new FakeCupboardEnvironment(PlatformFamily.FreeBSD, architecture); + } - public string? GetEnvironmentVariable(string variable) - { - return _environment.GetEnvironmentVariable(variable); - } + public string? GetEnvironmentVariable(string variable) + { + return _environment.GetEnvironmentVariable(variable); + } - public IDictionary GetEnvironmentVariables() - { - return _environment.GetEnvironmentVariables(); - } + public IDictionary GetEnvironmentVariables() + { + return _environment.GetEnvironmentVariables(); + } - public FilePath GetTempFilePath() + public FilePath GetTempFilePath() + { + lock (_lock) { - lock (_lock) - { - var filename = Interlocked.Increment(ref _counter) - .ToString() - .PadLeft(5, '0'); + var filename = Interlocked.Increment(ref _counter) + .ToString() + .PadLeft(5, '0'); - var path = _environment.Platform.Family switch - { - PlatformFamily.Windows => new FilePath($"C:/Temp/{filename}.tmp"), - PlatformFamily.Linux => new FilePath($"/tmp/{filename}.tmp"), - PlatformFamily.MacOs => new FilePath($"/private/tmp/{filename}.tmp"), - PlatformFamily.FreeBSD => new FilePath($"/tmp/{filename}.tmp"), - _ => throw new InvalidOperationException("Unknown platform family"), - }; + var path = _environment.Platform.Family switch + { + PlatformFamily.Windows => new FilePath($"C:/Temp/{filename}.tmp"), + PlatformFamily.Linux => new FilePath($"/tmp/{filename}.tmp"), + PlatformFamily.MacOs => new FilePath($"/private/tmp/{filename}.tmp"), + PlatformFamily.FreeBSD => new FilePath($"/tmp/{filename}.tmp"), + _ => throw new InvalidOperationException("Unknown platform family"), + }; - return path.MakeAbsolute(_environment); - } + return path.MakeAbsolute(_environment); } + } - public void SetWorkingDirectory(DirectoryPath path) - { - _environment.SetWorkingDirectory(path); - } + public void SetWorkingDirectory(DirectoryPath path) + { + _environment.SetWorkingDirectory(path); } } diff --git a/src/Cupboard.Testing/Fakes/FakeCupboardFileSystem.cs b/src/Cupboard.Testing/Fakes/FakeCupboardFileSystem.cs index 4d690ea..ea92ff6 100644 --- a/src/Cupboard.Testing/Fakes/FakeCupboardFileSystem.cs +++ b/src/Cupboard.Testing/Fakes/FakeCupboardFileSystem.cs @@ -2,48 +2,47 @@ using Spectre.IO; using Spectre.IO.Testing; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeCupboardFileSystem : ICupboardFileSystem { - public sealed class FakeCupboardFileSystem : ICupboardFileSystem + private readonly FakeFileSystem _fileSystem; + + public IFileProvider File => _fileSystem.File; + public IDirectoryProvider Directory => _fileSystem.Directory; + + public FakeCupboardFileSystem(ICupboardEnvironment environment) + { + _fileSystem = new FakeFileSystem(environment); + } + + public FakeDirectory CreateDirectory(DirectoryPath path) + { + return _fileSystem.CreateDirectory(path); + } + + public FakeFile CreateFile(FilePath path, FileAttributes attributes = 0) + { + return _fileSystem.CreateFile(path, attributes); + } + + public FakeFile CreateFile(FilePath path, byte[] contentsBytes) + { + return _fileSystem.CreateFile(path, contentsBytes); + } + + public void EnsureFileDoesNotExist(FilePath path) + { + _fileSystem.EnsureFileDoesNotExist(path); + } + + public FakeDirectory GetFakeDirectory(DirectoryPath path) + { + return _fileSystem.GetFakeDirectory(path); + } + + public FakeFile GetFakeFile(FilePath path) { - private readonly FakeFileSystem _fileSystem; - - public IFileProvider File => _fileSystem.File; - public IDirectoryProvider Directory => _fileSystem.Directory; - - public FakeCupboardFileSystem(ICupboardEnvironment environment) - { - _fileSystem = new FakeFileSystem(environment); - } - - public FakeDirectory CreateDirectory(DirectoryPath path) - { - return _fileSystem.CreateDirectory(path); - } - - public FakeFile CreateFile(FilePath path, FileAttributes attributes = 0) - { - return _fileSystem.CreateFile(path, attributes); - } - - public FakeFile CreateFile(FilePath path, byte[] contentsBytes) - { - return _fileSystem.CreateFile(path, contentsBytes); - } - - public void EnsureFileDoesNotExist(FilePath path) - { - _fileSystem.EnsureFileDoesNotExist(path); - } - - public FakeDirectory GetFakeDirectory(DirectoryPath path) - { - return _fileSystem.GetFakeDirectory(path); - } - - public FakeFile GetFakeFile(FilePath path) - { - return _fileSystem.GetFakeFile(path); - } + return _fileSystem.GetFakeFile(path); } } diff --git a/src/Cupboard.Testing/Fakes/FakeEnvironmentRefresher.cs b/src/Cupboard.Testing/Fakes/FakeEnvironmentRefresher.cs index a99f08e..ffca712 100644 --- a/src/Cupboard.Testing/Fakes/FakeEnvironmentRefresher.cs +++ b/src/Cupboard.Testing/Fakes/FakeEnvironmentRefresher.cs @@ -1,9 +1,8 @@ -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeEnvironmentRefresher : IEnvironmentRefresher { - public sealed class FakeEnvironmentRefresher : IEnvironmentRefresher + public void Refresh() { - public void Refresh() - { - } } } diff --git a/src/Cupboard.Testing/Fakes/FakeFactBuilder.cs b/src/Cupboard.Testing/Fakes/FakeFactBuilder.cs index 8e454af..c496335 100644 --- a/src/Cupboard.Testing/Fakes/FakeFactBuilder.cs +++ b/src/Cupboard.Testing/Fakes/FakeFactBuilder.cs @@ -1,19 +1,18 @@ using Spectre.Console.Cli; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeFactBuilder : IFactBuilder { - public sealed class FakeFactBuilder : IFactBuilder - { - public FactCollection Facts { get; set; } + public FactCollection Facts { get; set; } - public FakeFactBuilder() - { - Facts = new FactCollection(); - } + public FakeFactBuilder() + { + Facts = new FactCollection(); + } - public FactCollection Build(IRemainingArguments args) - { - return Facts; - } + public FactCollection Build(IRemainingArguments args) + { + return Facts; } } diff --git a/src/Cupboard.Testing/Fakes/FakeLogger.cs b/src/Cupboard.Testing/Fakes/FakeLogger.cs index e1a97ef..ba0069e 100644 --- a/src/Cupboard.Testing/Fakes/FakeLogger.cs +++ b/src/Cupboard.Testing/Fakes/FakeLogger.cs @@ -2,75 +2,74 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeLogger : ICupboardLogger { - public sealed class FakeLogger : ICupboardLogger - { - private readonly List _messages; + private readonly List _messages; - public Verbosity Verbosity { get; private set; } = Verbosity.Normal; + public Verbosity Verbosity { get; private set; } = Verbosity.Normal; - private sealed class LoggedMessage - { - public Verbosity Verbosity { get; init; } - public LogLevel Level { get; init; } - public string Message { get; init; } + private sealed class LoggedMessage + { + public Verbosity Verbosity { get; init; } + public LogLevel Level { get; init; } + public string Message { get; init; } - public LoggedMessage() - { - Message = string.Empty; - } + public LoggedMessage() + { + Message = string.Empty; } + } - public FakeLogger() + public FakeLogger() + { + _messages = new List(); + } + + public void Log(Verbosity verbosity, LogLevel level, string text) + { + _messages.Add(new LoggedMessage { - _messages = new List(); - } + Verbosity = verbosity, + Level = level, + Message = text, + }); + } - public void Log(Verbosity verbosity, LogLevel level, string text) + public void Log(Verbosity verbosity, LogLevel level, string title, string text) + { + _messages.Add(new LoggedMessage { - _messages.Add(new LoggedMessage - { - Verbosity = verbosity, - Level = level, - Message = text, - }); - } + Verbosity = verbosity, + Level = level, + Message = title + " " + text, + }); + } + + public void SetVerbosity(Verbosity verbosity) + { + Verbosity = verbosity; + } - public void Log(Verbosity verbosity, LogLevel level, string title, string text) + public void WasLogged(string message, Verbosity? verbosity = null, LogLevel? level = null) + { + var messages = _messages.Where(x => x.Message.Equals(message, StringComparison.Ordinal)); + + if (verbosity != null) { - _messages.Add(new LoggedMessage - { - Verbosity = verbosity, - Level = level, - Message = title + " " + text, - }); + messages = messages.Where(x => x.Verbosity == verbosity.Value); } - public void SetVerbosity(Verbosity verbosity) + if (level != null) { - Verbosity = verbosity; + messages = messages.Where(x => x.Level == level.Value); } - public void WasLogged(string message, Verbosity? verbosity = null, LogLevel? level = null) + if (!messages.Any()) { - var messages = _messages.Where(x => x.Message.Equals(message, StringComparison.Ordinal)); - - if (verbosity != null) - { - messages = messages.Where(x => x.Verbosity == verbosity.Value); - } - - if (level != null) - { - messages = messages.Where(x => x.Level == level.Value); - } - - if (!messages.Any()) - { - var list = string.Join("\n", _messages.Select(m => $"* {m.Message}")); - throw new InvalidOperationException($"Received no log calls that matched.\nReceived messages:\n\n{list}"); - } + var list = string.Join("\n", _messages.Select(m => $"* {m.Message}")); + throw new InvalidOperationException($"Received no log calls that matched.\nReceived messages:\n\n{list}"); } } } diff --git a/src/Cupboard.Testing/Fakes/FakeProcessRunner.cs b/src/Cupboard.Testing/Fakes/FakeProcessRunner.cs index 0af7aad..270866d 100644 --- a/src/Cupboard.Testing/Fakes/FakeProcessRunner.cs +++ b/src/Cupboard.Testing/Fakes/FakeProcessRunner.cs @@ -3,75 +3,74 @@ using System.Linq; using System.Threading.Tasks; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeProcessRunner : IProcessRunner { - public sealed class FakeProcessRunner : IProcessRunner + private readonly Dictionary> _registrations; + private readonly List<(string File, string Arguments)> _calls; + private ProcessRunnerResult? _defaultRegistration; + + public FakeProcessRunner() { - private readonly Dictionary> _registrations; - private readonly List<(string File, string Arguments)> _calls; - private ProcessRunnerResult? _defaultRegistration; + _registrations = new Dictionary>(StringComparer.Ordinal); + _calls = new List<(string, string)>(); + } - public FakeProcessRunner() - { - _registrations = new Dictionary>(StringComparer.Ordinal); - _calls = new List<(string, string)>(); - } + public void RegisterDefaultResult(ProcessRunnerResult result) + { + _defaultRegistration = result; + } - public void RegisterDefaultResult(ProcessRunnerResult result) + public void Register(string file, string arguments, params ProcessRunnerResult[] results) + { + var key = GetKey(file, arguments); + if (!_registrations.ContainsKey(key)) { - _defaultRegistration = result; + _registrations[key] = new Queue(); } - public void Register(string file, string arguments, params ProcessRunnerResult[] results) + foreach (var result in results) { - var key = GetKey(file, arguments); - if (!_registrations.ContainsKey(key)) - { - _registrations[key] = new Queue(); - } - - foreach (var result in results) - { - _registrations[key].Enqueue(result); - } + _registrations[key].Enqueue(result); } + } - public bool ReceivedCallToFile(string file) - { - return _calls.Any(c => c.File.Equals(file, StringComparison.OrdinalIgnoreCase)); - } + public bool ReceivedCallToFile(string file) + { + return _calls.Any(c => c.File.Equals(file, StringComparison.OrdinalIgnoreCase)); + } - public Task Run(string file, string arguments, Func? filter = null, bool supressOutput = false) + public Task Run(string file, string arguments, Func? filter = null, bool supressOutput = false) + { + var key = GetKey(file, arguments); + if (_registrations.ContainsKey(key)) { - var key = GetKey(file, arguments); - if (_registrations.ContainsKey(key)) - { - if (_registrations[key].Count > 0) - { - _calls.Add((file, arguments)); - return Task.FromResult(_registrations[key].Dequeue()); - } - } - - if (_defaultRegistration != null) + if (_registrations[key].Count > 0) { _calls.Add((file, arguments)); - return Task.FromResult(_defaultRegistration); - } - - var message = $"No process registration found for \"{key}\"."; - var list = string.Join("\n", _calls.Select(m => $"* {m.File} {m.Arguments}")); - if (!string.IsNullOrWhiteSpace(list)) - { - message += $"\nReceived calls:\n\n{list}"; + return Task.FromResult(_registrations[key].Dequeue()); } + } - throw new InvalidOperationException(message); + if (_defaultRegistration != null) + { + _calls.Add((file, arguments)); + return Task.FromResult(_defaultRegistration); } - private static string GetKey(string file, string arguments) + var message = $"No process registration found for \"{key}\"."; + var list = string.Join("\n", _calls.Select(m => $"* {m.File} {m.Arguments}")); + if (!string.IsNullOrWhiteSpace(list)) { - return $"{file} {arguments}"; + message += $"\nReceived calls:\n\n{list}"; } + + throw new InvalidOperationException(message); + } + + private static string GetKey(string file, string arguments) + { + return $"{file} {arguments}"; } } diff --git a/src/Cupboard.Testing/Fakes/FakeRebootDetector.cs b/src/Cupboard.Testing/Fakes/FakeRebootDetector.cs index a1019ed..d8c765a 100644 --- a/src/Cupboard.Testing/Fakes/FakeRebootDetector.cs +++ b/src/Cupboard.Testing/Fakes/FakeRebootDetector.cs @@ -1,12 +1,11 @@ -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeRebootDetector : IRebootDetector { - public sealed class FakeRebootDetector : IRebootDetector - { - public bool PendingReboot { get; set; } + public bool PendingReboot { get; set; } - public bool HasPendingReboot() - { - return PendingReboot; - } + public bool HasPendingReboot() + { + return PendingReboot; } } diff --git a/src/Cupboard.Testing/Fakes/FakeReportSubscriber.cs b/src/Cupboard.Testing/Fakes/FakeReportSubscriber.cs index a642310..b86a7f1 100644 --- a/src/Cupboard.Testing/Fakes/FakeReportSubscriber.cs +++ b/src/Cupboard.Testing/Fakes/FakeReportSubscriber.cs @@ -1,12 +1,11 @@ -namespace Cupboard.Testing +namespace Cupboard.Testing; + +internal sealed class FakeReportSubscriber : IReportSubscriber { - internal sealed class FakeReportSubscriber : IReportSubscriber - { - public Report? Report { get; set; } + public Report? Report { get; set; } - public void Notify(Report report) - { - Report = report; - } + public void Notify(Report report) + { + Report = report; } } diff --git a/src/Cupboard.Testing/Fakes/FakeSecurityPrincipal.cs b/src/Cupboard.Testing/Fakes/FakeSecurityPrincipal.cs index 3ced8fd..f59001a 100644 --- a/src/Cupboard.Testing/Fakes/FakeSecurityPrincipal.cs +++ b/src/Cupboard.Testing/Fakes/FakeSecurityPrincipal.cs @@ -1,12 +1,11 @@ -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeSecurityPrincipal : ISecurityPrincipal { - public sealed class FakeSecurityPrincipal : ISecurityPrincipal - { - public bool IsAdmin { get; set; } + public bool IsAdmin { get; set; } - public bool IsAdministrator() - { - return IsAdmin; - } + public bool IsAdministrator() + { + return IsAdmin; } } diff --git a/src/Cupboard.Testing/Fakes/FakeWindowsRegistry.cs b/src/Cupboard.Testing/Fakes/FakeWindowsRegistry.cs index e1b7c4f..82db744 100644 --- a/src/Cupboard.Testing/Fakes/FakeWindowsRegistry.cs +++ b/src/Cupboard.Testing/Fakes/FakeWindowsRegistry.cs @@ -1,22 +1,21 @@ -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeWindowsRegistry : IWindowsRegistry { - public sealed class FakeWindowsRegistry : IWindowsRegistry - { - public IWindowsRegistryKey ClassesRoot { get; } - public IWindowsRegistryKey CurrentConfig { get; } - public IWindowsRegistryKey CurrentUser { get; } - public IWindowsRegistryKey LocalMachine { get; } - public IWindowsRegistryKey PerformanceData { get; } - public IWindowsRegistryKey Users { get; } + public IWindowsRegistryKey ClassesRoot { get; } + public IWindowsRegistryKey CurrentConfig { get; } + public IWindowsRegistryKey CurrentUser { get; } + public IWindowsRegistryKey LocalMachine { get; } + public IWindowsRegistryKey PerformanceData { get; } + public IWindowsRegistryKey Users { get; } - public FakeWindowsRegistry() - { - ClassesRoot = new FakeWindowsRegistryKey(new RegistryPath("HKCR")); - CurrentConfig = new FakeWindowsRegistryKey(new RegistryPath("HKCC")); - CurrentUser = new FakeWindowsRegistryKey(new RegistryPath("HKCU")); - LocalMachine = new FakeWindowsRegistryKey(new RegistryPath("HKLM")); - PerformanceData = new FakeWindowsRegistryKey(new RegistryPath("HKPD")); - Users = new FakeWindowsRegistryKey(new RegistryPath("HKU")); - } + public FakeWindowsRegistry() + { + ClassesRoot = new FakeWindowsRegistryKey(new RegistryPath("HKCR")); + CurrentConfig = new FakeWindowsRegistryKey(new RegistryPath("HKCC")); + CurrentUser = new FakeWindowsRegistryKey(new RegistryPath("HKCU")); + LocalMachine = new FakeWindowsRegistryKey(new RegistryPath("HKLM")); + PerformanceData = new FakeWindowsRegistryKey(new RegistryPath("HKPD")); + Users = new FakeWindowsRegistryKey(new RegistryPath("HKU")); } } diff --git a/src/Cupboard.Testing/Fakes/FakeWindowsRegistryKey.cs b/src/Cupboard.Testing/Fakes/FakeWindowsRegistryKey.cs index 15aadb1..7d2d989 100644 --- a/src/Cupboard.Testing/Fakes/FakeWindowsRegistryKey.cs +++ b/src/Cupboard.Testing/Fakes/FakeWindowsRegistryKey.cs @@ -1,55 +1,54 @@ using System; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class FakeWindowsRegistryKey : IWindowsRegistryKey { - public sealed class FakeWindowsRegistryKey : IWindowsRegistryKey - { - public RegistryPath Path { get; } - - public FakeWindowsRegistryKey(RegistryPath path) - { - Path = path ?? throw new ArgumentNullException(nameof(path)); - } - - public IWindowsRegistryKey? CreateSubKey(string name, bool writable) - { - throw new NotSupportedException(); - } - - public int GetValueCount() - { - throw new NotSupportedException(); - } - - public void DeleteValue(string name) - { - throw new NotSupportedException(); - } - - public object? GetValue(string name) - { - throw new NotSupportedException(); - } - - public bool ValueExists(string name) - { - throw new NotSupportedException(); - } - - public IWindowsRegistryKey? OpenSubKey(string name, bool writable) - { - throw new NotSupportedException(); - } - - [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] - public void SetValue(string name, object value, RegistryKeyValueKind registryValueKind) - { - throw new NotSupportedException(); - } - - public void SetValue(string name, object value, RegistryValueKind kind) - { - throw new NotSupportedException(); - } + public RegistryPath Path { get; } + + public FakeWindowsRegistryKey(RegistryPath path) + { + Path = path ?? throw new ArgumentNullException(nameof(path)); + } + + public IWindowsRegistryKey? CreateSubKey(string name, bool writable) + { + throw new NotSupportedException(); + } + + public int GetValueCount() + { + throw new NotSupportedException(); + } + + public void DeleteValue(string name) + { + throw new NotSupportedException(); + } + + public object? GetValue(string name) + { + throw new NotSupportedException(); + } + + public bool ValueExists(string name) + { + throw new NotSupportedException(); + } + + public IWindowsRegistryKey? OpenSubKey(string name, bool writable) + { + throw new NotSupportedException(); + } + + [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] + public void SetValue(string name, object value, RegistryKeyValueKind registryValueKind) + { + throw new NotSupportedException(); + } + + public void SetValue(string name, object value, RegistryValueKind kind) + { + throw new NotSupportedException(); } } diff --git a/src/Cupboard.Testing/LambdaCatalog.cs b/src/Cupboard.Testing/LambdaCatalog.cs index fdab4de..b051838 100644 --- a/src/Cupboard.Testing/LambdaCatalog.cs +++ b/src/Cupboard.Testing/LambdaCatalog.cs @@ -1,19 +1,18 @@ using System; -namespace Cupboard.Testing +namespace Cupboard.Testing; + +public sealed class LambdaCatalog : Catalog { - public sealed class LambdaCatalog : Catalog - { - private readonly Action _action; + private readonly Action _action; - public LambdaCatalog(Action action) - { - _action = action ?? throw new ArgumentNullException(nameof(action)); - } + public LambdaCatalog(Action action) + { + _action = action ?? throw new ArgumentNullException(nameof(action)); + } - public override void Execute(CatalogContext context) - { - _action(context); - } + public override void Execute(CatalogContext context) + { + _action(context); } } diff --git a/src/Cupboard.Tests/Fixtures/FakeProcessRunnerFixture.cs b/src/Cupboard.Tests/Fixtures/FakeProcessRunnerFixture.cs index bf1bba4..c94395f 100644 --- a/src/Cupboard.Tests/Fixtures/FakeProcessRunnerFixture.cs +++ b/src/Cupboard.Tests/Fixtures/FakeProcessRunnerFixture.cs @@ -1,19 +1,18 @@ using NSubstitute; -namespace Cupboard.Tests.Resources +namespace Cupboard.Tests.Resources; + +public sealed class FakeProcessRunnerFixture { - public sealed class FakeProcessRunnerFixture - { - public IProcessRunner Runner { get; } + public IProcessRunner Runner { get; } - public FakeProcessRunnerFixture() - { - Runner = Substitute.For(); - } + public FakeProcessRunnerFixture() + { + Runner = Substitute.For(); + } - public void Register(string file, string arguments, ProcessRunnerResult result, params ProcessRunnerResult[] results) - { - Runner.Run(Arg.Is(file), Arg.Is(arguments)).Returns(result, results); - } + public void Register(string file, string arguments, ProcessRunnerResult result, params ProcessRunnerResult[] results) + { + Runner.Run(Arg.Is(file), Arg.Is(arguments)).Returns(result, results); } } diff --git a/src/Cupboard.Tests/Properties/WindowsFact.cs b/src/Cupboard.Tests/Properties/WindowsFact.cs index 6795a61..3d79f82 100644 --- a/src/Cupboard.Tests/Properties/WindowsFact.cs +++ b/src/Cupboard.Tests/Properties/WindowsFact.cs @@ -1,23 +1,22 @@ using System.Runtime.InteropServices; using Xunit; -namespace Cupboard.Tests.Unit +namespace Cupboard.Tests.Unit; + +public sealed class WindowsFact : FactAttribute { - public sealed class WindowsFact : FactAttribute - { - private static readonly bool _isWindows; + private static readonly bool _isWindows; - static WindowsFact() - { - _isWindows = RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows); - } + static WindowsFact() + { + _isWindows = RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows); + } - public WindowsFact(string reason = null) + public WindowsFact(string reason = null) + { + if (!_isWindows) { - if (!_isWindows) - { - Skip = reason ?? "Windows test."; - } + Skip = reason ?? "Windows test."; } } } diff --git a/src/Cupboard.Tests/Unit/FactCollectionTests.cs b/src/Cupboard.Tests/Unit/FactCollectionTests.cs index f91ca43..c156a15 100644 --- a/src/Cupboard.Tests/Unit/FactCollectionTests.cs +++ b/src/Cupboard.Tests/Unit/FactCollectionTests.cs @@ -1,111 +1,110 @@ using Shouldly; using Xunit; -namespace Cupboard.Tests.Unit +namespace Cupboard.Tests.Unit; + +public sealed class FactCollectionTests { - public sealed class FactCollectionTests + [Theory] + [InlineData("foo")] + [InlineData("FOO")] + [InlineData("Foo")] + [InlineData("FoO")] + public void Should_Consider_Fact_Name_Case_Insensitive(string name) { - [Theory] - [InlineData("foo")] - [InlineData("FOO")] - [InlineData("Foo")] - [InlineData("FoO")] - public void Should_Consider_Fact_Name_Case_Insensitive(string name) + // Then + var c = new FactCollection { - // Then - var c = new FactCollection - { - { "foo", 1 }, - }; + { "foo", 1 }, + }; - // When - int value = c[name]; + // When + int value = c[name]; - // Then - value.ShouldBe(1); - } + // Then + value.ShouldBe(1); + } + + [Fact] + public void Should_Get_Value_By_Path_Segments() + { + // Then + var c = new FactCollection + { + { "foo.bar.baz", 1 }, + }; + + // When + int value = c["foo"]["bar"]["baz"]; + + // Then + value.ShouldBe(1); + } + + [Fact] + public void Should_Get_Value_By_Full_Path() + { + // Then + var c = new FactCollection + { + { "foo.bar.baz", 1 }, + }; + // When + int value = c["foo.bar.baz"]; + + // Then + value.ShouldBe(1); + } + + public sealed class TheIsArmOrArm64Method + { [Fact] - public void Should_Get_Value_By_Path_Segments() + public void Should_Return_True_If_ARM() { - // Then - var c = new FactCollection + // Given + var facts = new FactCollection { - { "foo.bar.baz", 1 }, + { "os.arch", OSArchitecture.ARM }, }; // When - int value = c["foo"]["bar"]["baz"]; + var result = facts.IsArmOrArm64(); // Then - value.ShouldBe(1); + result.ShouldBeTrue(); } [Fact] - public void Should_Get_Value_By_Full_Path() + public void Should_Return_True_If_ARM64() { - // Then - var c = new FactCollection + // Given + var facts = new FactCollection { - { "foo.bar.baz", 1 }, + { "os.arch", OSArchitecture.ARM64 }, }; // When - int value = c["foo.bar.baz"]; + var result = facts.IsArmOrArm64(); // Then - value.ShouldBe(1); + result.ShouldBeTrue(); } - public sealed class TheIsArmOrArm64Method + [Fact] + public void Should_Return_False_If_Not_ARM_OR_ARM64() { - [Fact] - public void Should_Return_True_If_ARM() - { - // Given - var facts = new FactCollection - { - { "os.arch", OSArchitecture.ARM }, - }; - - // When - var result = facts.IsArmOrArm64(); - - // Then - result.ShouldBeTrue(); - } - - [Fact] - public void Should_Return_True_If_ARM64() + // Given + var facts = new FactCollection { - // Given - var facts = new FactCollection - { - { "os.arch", OSArchitecture.ARM64 }, - }; - - // When - var result = facts.IsArmOrArm64(); + { "os.arch", OSArchitecture.X64 }, + }; - // Then - result.ShouldBeTrue(); - } + // When + var result = facts.IsArmOrArm64(); - [Fact] - public void Should_Return_False_If_Not_ARM_OR_ARM64() - { - // Given - var facts = new FactCollection - { - { "os.arch", OSArchitecture.X64 }, - }; - - // When - var result = facts.IsArmOrArm64(); - - // Then - result.ShouldBeFalse(); - } + // Then + result.ShouldBeFalse(); } } } diff --git a/src/Cupboard.Tests/Unit/IO/ChmodParserTests.cs b/src/Cupboard.Tests/Unit/IO/ChmodParserTests.cs index 0e270da..306d3ac 100644 --- a/src/Cupboard.Tests/Unit/IO/ChmodParserTests.cs +++ b/src/Cupboard.Tests/Unit/IO/ChmodParserTests.cs @@ -1,37 +1,36 @@ using Xunit; -namespace Cupboard.Tests.Unit.IO +namespace Cupboard.Tests.Unit.IO; + +public sealed class ChmodParserTests { - public sealed class ChmodParserTests + public sealed class TheParseMethod { - public sealed class TheParseMethod + [Theory] + [InlineData("000", SpecialMode.None, Permissions.None, Permissions.None, Permissions.None)] + [InlineData("500", SpecialMode.None, Permissions.Read | Permissions.Execute, Permissions.None, Permissions.None)] + [InlineData("050", SpecialMode.None, Permissions.None, Permissions.Read | Permissions.Execute, Permissions.None)] + [InlineData("005", SpecialMode.None, Permissions.None, Permissions.None, Permissions.Read | Permissions.Execute)] + [InlineData("777", SpecialMode.None, Permissions.All, Permissions.All, Permissions.All)] + [InlineData("0000", SpecialMode.None, Permissions.None, Permissions.None, Permissions.None)] + [InlineData("0500", SpecialMode.None, Permissions.Read | Permissions.Execute, Permissions.None, Permissions.None)] + [InlineData("0050", SpecialMode.None, Permissions.None, Permissions.Read | Permissions.Execute, Permissions.None)] + [InlineData("0005", SpecialMode.None, Permissions.None, Permissions.None, Permissions.Read | Permissions.Execute)] + [InlineData("0777", SpecialMode.None, Permissions.All, Permissions.All, Permissions.All)] + [InlineData("1000", SpecialMode.Sticky, Permissions.None, Permissions.None, Permissions.None)] + [InlineData("2000", SpecialMode.Setgid, Permissions.None, Permissions.None, Permissions.None)] + [InlineData("4000", SpecialMode.Setuid, Permissions.None, Permissions.None, Permissions.None)] + [InlineData("7000", SpecialMode.Sticky | SpecialMode.Setgid | SpecialMode.Setuid, Permissions.None, Permissions.None, Permissions.None)] + public void Should_Return_Correct_Permissions(string pattern, SpecialMode mode, Permissions owner, Permissions group, Permissions other) { - [Theory] - [InlineData("000", SpecialMode.None, Permissions.None, Permissions.None, Permissions.None)] - [InlineData("500", SpecialMode.None, Permissions.Read | Permissions.Execute, Permissions.None, Permissions.None)] - [InlineData("050", SpecialMode.None, Permissions.None, Permissions.Read | Permissions.Execute, Permissions.None)] - [InlineData("005", SpecialMode.None, Permissions.None, Permissions.None, Permissions.Read | Permissions.Execute)] - [InlineData("777", SpecialMode.None, Permissions.All, Permissions.All, Permissions.All)] - [InlineData("0000", SpecialMode.None, Permissions.None, Permissions.None, Permissions.None)] - [InlineData("0500", SpecialMode.None, Permissions.Read | Permissions.Execute, Permissions.None, Permissions.None)] - [InlineData("0050", SpecialMode.None, Permissions.None, Permissions.Read | Permissions.Execute, Permissions.None)] - [InlineData("0005", SpecialMode.None, Permissions.None, Permissions.None, Permissions.Read | Permissions.Execute)] - [InlineData("0777", SpecialMode.None, Permissions.All, Permissions.All, Permissions.All)] - [InlineData("1000", SpecialMode.Sticky, Permissions.None, Permissions.None, Permissions.None)] - [InlineData("2000", SpecialMode.Setgid, Permissions.None, Permissions.None, Permissions.None)] - [InlineData("4000", SpecialMode.Setuid, Permissions.None, Permissions.None, Permissions.None)] - [InlineData("7000", SpecialMode.Sticky | SpecialMode.Setgid | SpecialMode.Setuid, Permissions.None, Permissions.None, Permissions.None)] - public void Should_Return_Correct_Permissions(string pattern, SpecialMode mode, Permissions owner, Permissions group, Permissions other) - { - // Given, When - var result = ChmodParser.Parse(pattern); + // Given, When + var result = ChmodParser.Parse(pattern); - // Then - Assert.Equal(mode, result.Mode); - Assert.Equal(owner, result.Owner); - Assert.Equal(group, result.Group); - Assert.Equal(other, result.Other); - } + // Then + Assert.Equal(mode, result.Mode); + Assert.Equal(owner, result.Owner); + Assert.Equal(group, result.Group); + Assert.Equal(other, result.Other); } } } diff --git a/src/Cupboard.Tests/Unit/IO/ChmodTests.cs b/src/Cupboard.Tests/Unit/IO/ChmodTests.cs index b4eb849..c24858b 100644 --- a/src/Cupboard.Tests/Unit/IO/ChmodTests.cs +++ b/src/Cupboard.Tests/Unit/IO/ChmodTests.cs @@ -2,113 +2,112 @@ using Shouldly; using Xunit; -namespace Cupboard.Tests.Unit.IO +namespace Cupboard.Tests.Unit.IO; + +public sealed class ChmodTests { - public sealed class ChmodTests + public sealed class TheToFMethod + { + [Fact] + public void Should_Convert_Permissions_To_Correct_File_Access_Permissions_1() + { + // Given + var chmod = Chmod.Parse("766"); + + // When + var result = chmod.ToFileAccessPermissions(); + + // Then + result.ShouldBe( + FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | FileAccessPermissions.UserExecute | + FileAccessPermissions.GroupRead | FileAccessPermissions.GroupWrite | + FileAccessPermissions.OtherRead | FileAccessPermissions.OtherWrite); + } + + [Fact] + public void Should_Convert_Default_Permissions_To_Correct_File_Access_Permissions() + { + // Given + var chmod = Chmod.Parse("666"); + + // When + var result = chmod.ToFileAccessPermissions(); + + // Then + result.ShouldBe(FileAccessPermissions.DefaultPermissions); + result.ShouldBe( + FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | + FileAccessPermissions.GroupRead | FileAccessPermissions.GroupWrite | + FileAccessPermissions.OtherRead | FileAccessPermissions.OtherWrite); + } + } + + public sealed class TheToStringMethod { - public sealed class TheToFMethod + public sealed class WithCustomFormattingOption { [Fact] - public void Should_Convert_Permissions_To_Correct_File_Access_Permissions_1() + public void Should_Return_Expected_Output_For_Numeric_Formatting() { // Given - var chmod = Chmod.Parse("766"); + var chmod = new Chmod(Permissions.All, Permissions.All, Permissions.All); // When - var result = chmod.ToFileAccessPermissions(); + var result = chmod.ToString(ChmodFormatting.Numeric); // Then - result.ShouldBe( - FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | FileAccessPermissions.UserExecute | - FileAccessPermissions.GroupRead | FileAccessPermissions.GroupWrite | - FileAccessPermissions.OtherRead | FileAccessPermissions.OtherWrite); + Assert.Equal("0777", result); } - [Fact] - public void Should_Convert_Default_Permissions_To_Correct_File_Access_Permissions() + [Theory] + [InlineData(SpecialMode.None, "0777")] + [InlineData(SpecialMode.All, "7777")] + [InlineData(SpecialMode.Sticky, "1777")] + [InlineData(SpecialMode.Setgid, "2777")] + [InlineData(SpecialMode.Setuid, "4777")] + [InlineData(SpecialMode.Sticky | SpecialMode.Setgid, "3777")] + [InlineData(SpecialMode.Sticky | SpecialMode.Setuid, "5777")] + [InlineData(SpecialMode.Setuid | SpecialMode.Setgid, "6777")] + public void Should_Return_Expected_Output_For_Special_Mode_With_Numeric_Formatting(SpecialMode mode, string expected) { // Given - var chmod = Chmod.Parse("666"); + var chmod = new Chmod(mode, Permissions.All, Permissions.All, Permissions.All); // When - var result = chmod.ToFileAccessPermissions(); + var result = chmod.ToString(ChmodFormatting.Numeric); // Then - result.ShouldBe(FileAccessPermissions.DefaultPermissions); - result.ShouldBe( - FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | - FileAccessPermissions.GroupRead | FileAccessPermissions.GroupWrite | - FileAccessPermissions.OtherRead | FileAccessPermissions.OtherWrite); - } - } - - public sealed class TheToStringMethod - { - public sealed class WithCustomFormattingOption - { - [Fact] - public void Should_Return_Expected_Output_For_Numeric_Formatting() - { - // Given - var chmod = new Chmod(Permissions.All, Permissions.All, Permissions.All); - - // When - var result = chmod.ToString(ChmodFormatting.Numeric); - - // Then - Assert.Equal("0777", result); - } - - [Theory] - [InlineData(SpecialMode.None, "0777")] - [InlineData(SpecialMode.All, "7777")] - [InlineData(SpecialMode.Sticky, "1777")] - [InlineData(SpecialMode.Setgid, "2777")] - [InlineData(SpecialMode.Setuid, "4777")] - [InlineData(SpecialMode.Sticky | SpecialMode.Setgid, "3777")] - [InlineData(SpecialMode.Sticky | SpecialMode.Setuid, "5777")] - [InlineData(SpecialMode.Setuid | SpecialMode.Setgid, "6777")] - public void Should_Return_Expected_Output_For_Special_Mode_With_Numeric_Formatting(SpecialMode mode, string expected) - { - // Given - var chmod = new Chmod(mode, Permissions.All, Permissions.All, Permissions.All); - - // When - var result = chmod.ToString(ChmodFormatting.Numeric); - - // Then - Assert.Equal(expected, result); - } - - [Fact] - public void Should_Return_Expected_Output_For_Symbolic_Formatting() - { - // Given - var chmod = new Chmod( - Permissions.Read | Permissions.Execute, - Permissions.Write, - Permissions.Write | Permissions.Execute); - - // When - var result = chmod.ToString(ChmodFormatting.Symbolic); - - // Then - Assert.Equal("r-x-w--wx", result); - } + Assert.Equal(expected, result); } [Fact] - public void Should_Return_Expected_Output() + public void Should_Return_Expected_Output_For_Symbolic_Formatting() { // Given - var permissions = new Chmod(Permissions.All, Permissions.All, Permissions.All); + var chmod = new Chmod( + Permissions.Read | Permissions.Execute, + Permissions.Write, + Permissions.Write | Permissions.Execute); // When - var result = permissions.ToString(); + var result = chmod.ToString(ChmodFormatting.Symbolic); // Then - Assert.Equal("0777", result); + Assert.Equal("r-x-w--wx", result); } } + + [Fact] + public void Should_Return_Expected_Output() + { + // Given + var permissions = new Chmod(Permissions.All, Permissions.All, Permissions.All); + + // When + var result = permissions.ToString(); + + // Then + Assert.Equal("0777", result); + } } } diff --git a/src/Cupboard.Tests/Unit/IO/RegistryKeyTests.cs b/src/Cupboard.Tests/Unit/IO/RegistryKeyTests.cs index 78bd561..fb1f027 100644 --- a/src/Cupboard.Tests/Unit/IO/RegistryKeyTests.cs +++ b/src/Cupboard.Tests/Unit/IO/RegistryKeyTests.cs @@ -1,63 +1,62 @@ using Shouldly; using Xunit; -namespace Cupboard.Tests.Unit.IO +namespace Cupboard.Tests.Unit.IO; + +public sealed class RegistryKeyPathTests { - public sealed class RegistryKeyPathTests + [Fact] + public void Should_Not_Consider_Path_Missing_Key_Valid() + { + // Given, When + var path = new RegistryPath("HKEY_CURRENT_USER"); + + // Then + path.IsValid.ShouldBeFalse(); + } + + [Fact] + public void Should_Not_Consider_Path_Missing_Sub_Key_Valid() + { + // Given, When + var path = new RegistryPath("HKEY_CURRENT_USER\\Foo"); + + // Then + path.IsValid.ShouldBeFalse(); + } + + [Fact] + public void Should_Normalize_Separators() { - [Fact] - public void Should_Not_Consider_Path_Missing_Key_Valid() - { - // Given, When - var path = new RegistryPath("HKEY_CURRENT_USER"); - - // Then - path.IsValid.ShouldBeFalse(); - } - - [Fact] - public void Should_Not_Consider_Path_Missing_Sub_Key_Valid() - { - // Given, When - var path = new RegistryPath("HKEY_CURRENT_USER\\Foo"); - - // Then - path.IsValid.ShouldBeFalse(); - } - - [Fact] - public void Should_Normalize_Separators() - { - // Given, When - var path = new RegistryPath("HKEY_CURRENT_USER/Foo/Bar/Baz"); - - // Then - path.ToString().ShouldBe(@"HKEY_CURRENT_USER\Foo\Bar\Baz"); - path.Path.ShouldBe(@"Foo\Bar\Baz"); - path.IsValid.ShouldBeTrue(); - } - - [Theory] - [InlineData("HKCR/Foo/Bar/Baz", RegistryHive.ClassesRoot)] - [InlineData("HKCU/Foo/Bar/Baz", RegistryHive.CurrentUser)] - [InlineData("HKLM/Foo/Bar/Baz", RegistryHive.LocalMachine)] - [InlineData("HKU/Foo/Bar/Baz", RegistryHive.Users)] - [InlineData("HKPD/Foo/Bar/Baz", RegistryHive.PerformanceData)] - [InlineData("HKCC/Foo/Bar/Baz", RegistryHive.CurrentConfig)] - [InlineData("HKCR:/Foo/Bar/Baz", RegistryHive.ClassesRoot)] - [InlineData("HKCU:/Foo/Bar/Baz", RegistryHive.CurrentUser)] - [InlineData("HKLM:/Foo/Bar/Baz", RegistryHive.LocalMachine)] - [InlineData("HKU:/Foo/Bar/Baz", RegistryHive.Users)] - [InlineData("HKPD:/Foo/Bar/Baz", RegistryHive.PerformanceData)] - [InlineData("HKCC:/Foo/Bar/Baz", RegistryHive.CurrentConfig)] - public void Should_Substitute_Roots(string path, RegistryHive expected) - { - // Given, When - var result = new RegistryPath(path); - - // Then - result.IsValid.ShouldBeTrue(); - result.Hive.ShouldBe(expected); - } + // Given, When + var path = new RegistryPath("HKEY_CURRENT_USER/Foo/Bar/Baz"); + + // Then + path.ToString().ShouldBe(@"HKEY_CURRENT_USER\Foo\Bar\Baz"); + path.Path.ShouldBe(@"Foo\Bar\Baz"); + path.IsValid.ShouldBeTrue(); + } + + [Theory] + [InlineData("HKCR/Foo/Bar/Baz", RegistryHive.ClassesRoot)] + [InlineData("HKCU/Foo/Bar/Baz", RegistryHive.CurrentUser)] + [InlineData("HKLM/Foo/Bar/Baz", RegistryHive.LocalMachine)] + [InlineData("HKU/Foo/Bar/Baz", RegistryHive.Users)] + [InlineData("HKPD/Foo/Bar/Baz", RegistryHive.PerformanceData)] + [InlineData("HKCC/Foo/Bar/Baz", RegistryHive.CurrentConfig)] + [InlineData("HKCR:/Foo/Bar/Baz", RegistryHive.ClassesRoot)] + [InlineData("HKCU:/Foo/Bar/Baz", RegistryHive.CurrentUser)] + [InlineData("HKLM:/Foo/Bar/Baz", RegistryHive.LocalMachine)] + [InlineData("HKU:/Foo/Bar/Baz", RegistryHive.Users)] + [InlineData("HKPD:/Foo/Bar/Baz", RegistryHive.PerformanceData)] + [InlineData("HKCC:/Foo/Bar/Baz", RegistryHive.CurrentConfig)] + public void Should_Substitute_Roots(string path, RegistryHive expected) + { + // Given, When + var result = new RegistryPath(path); + + // Then + result.IsValid.ShouldBeTrue(); + result.Hive.ShouldBe(expected); } } diff --git a/src/Cupboard.Tests/Unit/ManifestContextTests.cs b/src/Cupboard.Tests/Unit/ManifestContextTests.cs index 181871b..1331daf 100644 --- a/src/Cupboard.Tests/Unit/ManifestContextTests.cs +++ b/src/Cupboard.Tests/Unit/ManifestContextTests.cs @@ -4,80 +4,79 @@ using Shouldly; using Xunit; -namespace Cupboard.Tests.Unit +namespace Cupboard.Tests.Unit; + +public sealed class ManifestContextTests { - public sealed class ManifestContextTests + public sealed class Resources { - public sealed class Resources + public sealed class DummyResource : Resource { - public sealed class DummyResource : Resource - { - public int Foo { get; set; } - public string Bar { get; set; } + public int Foo { get; set; } + public string Bar { get; set; } - public DummyResource(string name) - : base(name) - { - } + public DummyResource(string name) + : base(name) + { } + } - public sealed class DummyResourceProvider : ResourceProvider - { - private readonly ICupboardLogger _logger; + public sealed class DummyResourceProvider : ResourceProvider + { + private readonly ICupboardLogger _logger; - public DummyResourceProvider(ICupboardLogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + public DummyResourceProvider(ICupboardLogger logger) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public override DummyResource Create(string name) - { - return new DummyResource(name); - } + public override DummyResource Create(string name) + { + return new DummyResource(name); + } - public override ResourceState Run(IExecutionContext context, DummyResource resource) - { - _logger.Information($"{resource.Name}: Foo={resource.Foo}, Bar={resource.Bar}"); - return ResourceState.Executed; - } + public override ResourceState Run(IExecutionContext context, DummyResource resource) + { + _logger.Information($"{resource.Name}: Foo={resource.Foo}, Bar={resource.Bar}"); + return ResourceState.Executed; } } + } - public sealed class Manifests + public sealed class Manifests + { + public sealed class Default : Manifest { - public sealed class Default : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + context.Resources(new Resources.DummyResource[] { - context.Resources(new Resources.DummyResource[] - { - new("baz") { Foo = 1, Bar = "BAR" }, - new("qux") { Foo = 2, Bar = "QUX" }, - }); - } + new("baz") { Foo = 1, Bar = "BAR" }, + new("qux") { Foo = 2, Bar = "QUX" }, + }); } } + } - [Fact] - public void Can_Add_Multiple_Resources_At_Once() + [Fact] + public void Can_Add_Multiple_Resources_At_Once() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + fixture.Register(services => { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - fixture.Register(services => - { - services.AddSingleton(); - }); + services.AddSingleton(); + }); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.ExitCode.ShouldBe(0); - fixture.Logger.WasLogged("baz: Foo=1, Bar=BAR"); - fixture.Logger.WasLogged("qux: Foo=2, Bar=QUX"); - } + // Then + result.ExitCode.ShouldBe(0); + fixture.Logger.WasLogged("baz: Foo=1, Bar=BAR"); + fixture.Logger.WasLogged("qux: Foo=2, Bar=QUX"); } } diff --git a/src/Cupboard.Tests/Unit/Providers/ChocolateyProviderTests.cs b/src/Cupboard.Tests/Unit/Providers/ChocolateyProviderTests.cs index 7b3eeaf..6fbdb95 100644 --- a/src/Cupboard.Tests/Unit/Providers/ChocolateyProviderTests.cs +++ b/src/Cupboard.Tests/Unit/Providers/ChocolateyProviderTests.cs @@ -1,328 +1,327 @@ using Cupboard.Testing; using Shouldly; -namespace Cupboard.Tests.Unit.Providers +namespace Cupboard.Tests.Unit.Providers; + +public sealed class ChocolateyProviderTests { - public sealed class ChocolateyProviderTests + public sealed class Manifests { - public sealed class Manifests + public sealed class Install : Manifest { - public sealed class Install : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Visual Studio Code") - .Package("vscode") - .Ensure(PackageState.Installed); - } + context.Resource("Visual Studio Code") + .Package("vscode") + .Ensure(PackageState.Installed); } + } - public sealed class InstallVersion : Manifest + public sealed class InstallVersion : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Visual Studio Code") - .Package("vscode") - .UseVersion("1.58.0") - .Ensure(PackageState.Installed); - } + context.Resource("Visual Studio Code") + .Package("vscode") + .UseVersion("1.58.0") + .Ensure(PackageState.Installed); } + } - public sealed class InstallVersionAllowDowngrade : Manifest + public sealed class InstallVersionAllowDowngrade : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Visual Studio Code") - .Package("vscode") - .UseVersion("1.58.0") - .AllowDowngrade() - .Ensure(PackageState.Installed); - } + context.Resource("Visual Studio Code") + .Package("vscode") + .UseVersion("1.58.0") + .AllowDowngrade() + .Ensure(PackageState.Installed); } + } - public sealed class Uninstall : Manifest + public sealed class Uninstall : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Visual Studio Code") - .Package("vscode") - .Ensure(PackageState.Uninstalled); - } + context.Resource("Visual Studio Code") + .Package("vscode") + .Ensure(PackageState.Uninstalled); } } + } - public sealed class EnsureInstalled + public sealed class EnsureInstalled + { + [WindowsFact] + public void Should_Install_Package_If_Missing() { - [WindowsFact] - public void Should_Install_Package_If_Missing() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "\n"), - new ProcessRunnerResult(0, "vscode|1.58.0\n")); - - fixture.Process.Register("choco", "install vscode -y", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "\n"), + new ProcessRunnerResult(0, "vscode|1.58.0\n")); + + fixture.Process.Register("choco", "install vscode -y", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Not_Install_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Install_Package_If_Present() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.58.0\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.58.0\n")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); + } - [WindowsFact] - public void Should_Install_Package_Version_If_Missing() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "\n"), - new ProcessRunnerResult(0, "vscode|1.58.0\n")); - - fixture.Process.Register("choco", "install vscode -y --version 1.58.0", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + [WindowsFact] + public void Should_Install_Package_Version_If_Missing() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "\n"), + new ProcessRunnerResult(0, "vscode|1.58.0\n")); + + fixture.Process.Register("choco", "install vscode -y --version 1.58.0", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Install_Package_If_Lower_Version() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.57.0\n"), - new ProcessRunnerResult(0, "vscode|1.58.0\n")); - - fixture.Process.Register("choco", "install vscode -y --version 1.58.0", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + [WindowsFact] + public void Should_Install_Package_If_Lower_Version() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.57.0\n"), + new ProcessRunnerResult(0, "vscode|1.58.0\n")); + + fixture.Process.Register("choco", "install vscode -y --version 1.58.0", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Install_Package_If_Lower_Version_With_No_NewLine() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.57.0"), - new ProcessRunnerResult(0, "vscode|1.58.0")); - - fixture.Process.Register("choco", "install vscode -y --version 1.58.0", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + [WindowsFact] + public void Should_Install_Package_If_Lower_Version_With_No_NewLine() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.57.0"), + new ProcessRunnerResult(0, "vscode|1.58.0")); + + fixture.Process.Register("choco", "install vscode -y --version 1.58.0", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Not_Install_Package_Of_Same_Version() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Install_Package_Of_Same_Version() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.58.0\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.58.0\n")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); + } - [WindowsFact] - public void Should_Not_Install_Package_Of_Higher_Version() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Install_Package_Of_Higher_Version() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.59.0\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.59.0\n")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); + } - [WindowsFact] - public void Should_Install_Package_If_Higher_Version_With_Allow_Downgrade() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.59.0\n"), - new ProcessRunnerResult(0, "vscode|1.58.0\n")); - - fixture.Process.Register("choco", "install vscode -y --allow-downgrade --version 1.58.0", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + [WindowsFact] + public void Should_Install_Package_If_Higher_Version_With_Allow_Downgrade() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.59.0\n"), + new ProcessRunnerResult(0, "vscode|1.58.0\n")); + + fixture.Process.Register("choco", "install vscode -y --allow-downgrade --version 1.58.0", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Install_Package_If_Lower_Version_With_Allow_Downgrade() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.57.0\n"), - new ProcessRunnerResult(0, "vscode|1.58.0\n")); - - fixture.Process.Register("choco", "install vscode -y --allow-downgrade --version 1.58.0", - new ProcessRunnerResult(0, "Lol installed VSCode")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); - } + [WindowsFact] + public void Should_Install_Package_If_Lower_Version_With_Allow_Downgrade() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.57.0\n"), + new ProcessRunnerResult(0, "vscode|1.58.0\n")); + + fixture.Process.Register("choco", "install vscode -y --allow-downgrade --version 1.58.0", + new ProcessRunnerResult(0, "Lol installed VSCode")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was installed"); + } - [WindowsFact] - public void Should_Not_Install_Package_Of_Same_Version_With_Allow_Downgrade() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Install_Package_Of_Same_Version_With_Allow_Downgrade() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.58.0\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.58.0\n")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already installed"); } + } - public sealed class EnsureUninstalled + public sealed class EnsureUninstalled + { + [WindowsFact] + public void Should_Uninstall_Package_If_Present() { - [WindowsFact] - public void Should_Uninstall_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "vscode|1.58.0\n"), - new ProcessRunnerResult(0, "\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "vscode|1.58.0\n"), + new ProcessRunnerResult(0, "\n")); - fixture.Process.Register("choco", "uninstall vscode", new ProcessRunnerResult(0)); + fixture.Process.Register("choco", "uninstall vscode", new ProcessRunnerResult(0)); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Uninstalling Chocolatey package [yellow]vscode[/]"); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was uninstalled"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Uninstalling Chocolatey package [yellow]vscode[/]"); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] was uninstalled"); + } - [WindowsFact] - public void Should_Not_Uninstall_Package_If_Absent() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Uninstall_Package_If_Absent() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", - new ProcessRunnerResult(0, "\n")); + fixture.Process.Register("choco", "list --limit-output --local-only --exact vscode", + new ProcessRunnerResult(0, "\n")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already uninstalled"); - } + // Then + result.Report.GetState("Visual Studio Code").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Chocolatey package [yellow]vscode[/] is already uninstalled"); } } } diff --git a/src/Cupboard.Tests/Unit/Providers/FileProviderTests.cs b/src/Cupboard.Tests/Unit/Providers/FileProviderTests.cs index 2e148e7..f96d655 100644 --- a/src/Cupboard.Tests/Unit/Providers/FileProviderTests.cs +++ b/src/Cupboard.Tests/Unit/Providers/FileProviderTests.cs @@ -3,90 +3,89 @@ using Spectre.IO; using Xunit; -namespace Cupboard.Tests.Unit.Providers +namespace Cupboard.Tests.Unit.Providers; + +public sealed class FileProviderTests { - public sealed class FileProviderTests + public sealed class Manifests { - public sealed class Manifests + public sealed class FilePresent : Manifest { - public sealed class FilePresent : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("~/foo.txt") - .Ensure(FileState.Present) - .Source("~/bar/qux.txt"); - } + context.Resource("~/foo.txt") + .Ensure(FileState.Present) + .Source("~/bar/qux.txt"); } + } - public sealed class FileAbsent : Manifest + public sealed class FileAbsent : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("~/foo.txt") - .Ensure(FileState.Absent); - } + context.Resource("~/foo.txt") + .Ensure(FileState.Absent); } + } - public sealed class SymlinkedFile : Manifest + public sealed class SymlinkedFile : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("~/foo.txt") - .SymbolicLink() - .Ensure(FileState.Present) - .Source("~/bar/qux.txt"); - } + context.Resource("~/foo.txt") + .SymbolicLink() + .Ensure(FileState.Present) + .Source("~/bar/qux.txt"); } } + } - [Fact] - public void Should_Copy_File() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.FileSystem.CreateFile("~/bar/qux.txt"); - fixture.Configure(ctx => ctx.UseManifest()); + [Fact] + public void Should_Copy_File() + { + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.FileSystem.CreateFile("~/bar/qux.txt"); + fixture.Configure(ctx => ctx.UseManifest()); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); - fixture.FileShouldExist("/home/JohnDoe/foo.txt"); - } + // Then + result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); + fixture.FileShouldExist("/home/JohnDoe/foo.txt"); + } - [Fact] - public void Should_Create_Symlink() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.FileSystem.CreateFile("~/bar/qux.txt"); - fixture.Configure(ctx => ctx.UseManifest()); + [Fact] + public void Should_Create_Symlink() + { + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.FileSystem.CreateFile("~/bar/qux.txt"); + fixture.Configure(ctx => ctx.UseManifest()); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); - fixture.FileShouldExist("/home/JohnDoe/foo.txt"); - fixture.FileShouldBeSymbolicLink("/home/JohnDoe/foo.txt"); - } + // Then + result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); + fixture.FileShouldExist("/home/JohnDoe/foo.txt"); + fixture.FileShouldBeSymbolicLink("/home/JohnDoe/foo.txt"); + } - [Fact] - public void Should_Delete_File() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.FileSystem.CreateFile("~/foo.txt"); - fixture.Configure(ctx => ctx.UseManifest()); + [Fact] + public void Should_Delete_File() + { + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.FileSystem.CreateFile("~/foo.txt"); + fixture.Configure(ctx => ctx.UseManifest()); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); - fixture.FileShouldNotExist("/home/JohnDoe/foo.txt"); - } + // Then + result.Report.GetState("~/foo.txt").ShouldBe(ResourceState.Changed); + fixture.FileShouldNotExist("/home/JohnDoe/foo.txt"); } } diff --git a/src/Cupboard.Tests/Unit/Providers/PowerShellProviderTests.cs b/src/Cupboard.Tests/Unit/Providers/PowerShellProviderTests.cs index 1d668c1..5555ba8 100644 --- a/src/Cupboard.Tests/Unit/Providers/PowerShellProviderTests.cs +++ b/src/Cupboard.Tests/Unit/Providers/PowerShellProviderTests.cs @@ -3,177 +3,176 @@ using Spectre.IO; using Xunit; -namespace Cupboard.Tests.Unit.Providers +namespace Cupboard.Tests.Unit.Providers; + +public sealed class PowerShellProviderTests { - public sealed class PowerShellProviderTests + public sealed class Windows { - public sealed class Windows + public sealed class Manifests { - public sealed class Manifests + public class RunScript : Manifest { - public class RunScript : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Run PowerShell Script") - .Script("C:/lol.ps1"); - } + context.Resource("Run PowerShell Script") + .Script("C:/lol.ps1"); } + } - public class RunCommand : Manifest + public class RunCommand : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Run PowerShell Command") - .Command("Not really executed, but must be present"); - } + context.Resource("Run PowerShell Command") + .Command("Not really executed, but must be present"); } + } - public class RunUnless : Manifest + public class RunUnless : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Run PowerShell Unless") - .Unless("Not really executed, but must be present"); - } + context.Resource("Run PowerShell Unless") + .Unless("Not really executed, but must be present"); } + } - public class RunCore : Manifest + public class RunCore : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Run PowerShell Core Script") - .Flavor(PowerShellFlavor.PowerShellCore) - .Script("C:/lol.ps1"); - } + context.Resource("Run PowerShell Core Script") + .Flavor(PowerShellFlavor.PowerShellCore) + .Script("C:/lol.ps1"); } } + } - [WindowsFact] - public void Should_Run_Script() - { - // Given - var fixture = new CupboardFixture(); - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.FileSystem.CreateFile("C:/lol.ps1"); - fixture.Configure(ctx => ctx.UseManifest()); - - // When - var result = fixture.Run("-y"); - - // Then - result.ExitCode.ShouldBe(0); - result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Executed); - fixture.Logger.WasLogged("Running PowerShell script [yellow]C:/lol.ps1[/]"); - } + [WindowsFact] + public void Should_Run_Script() + { + // Given + var fixture = new CupboardFixture(); + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.FileSystem.CreateFile("C:/lol.ps1"); + fixture.Configure(ctx => ctx.UseManifest()); + + // When + var result = fixture.Run("-y"); + + // Then + result.ExitCode.ShouldBe(0); + result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Executed); + fixture.Logger.WasLogged("Running PowerShell script [yellow]C:/lol.ps1[/]"); + } - [WindowsFact] - public void Should_Run_Command() - { - // Given - var fixture = new CupboardFixture(); - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.FileSystem.CreateDirectory("C:/Temp"); - fixture.Configure(ctx => ctx.UseManifest()); - - // When - var result = fixture.Run("-y"); - - // Then - result.ExitCode.ShouldBe(0); - result.Report.GetState("Run PowerShell Command").ShouldBe(ResourceState.Executed); - fixture.Logger.WasLogged("Running PowerShell command: [yellow]Not really executed, but must be present[/]"); - } + [WindowsFact] + public void Should_Run_Command() + { + // Given + var fixture = new CupboardFixture(); + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.FileSystem.CreateDirectory("C:/Temp"); + fixture.Configure(ctx => ctx.UseManifest()); + + // When + var result = fixture.Run("-y"); + + // Then + result.ExitCode.ShouldBe(0); + result.Report.GetState("Run PowerShell Command").ShouldBe(ResourceState.Executed); + fixture.Logger.WasLogged("Running PowerShell command: [yellow]Not really executed, but must be present[/]"); + } - [WindowsFact] - public void Should_Skip_Running_Skip_If_Condition_Script_Does_Not_Have_Exit_Code_1() - { - // Given - var fixture = new CupboardFixture(); - - fixture.FileSystem.CreateDirectory("C:/Temp"); - fixture.FileSystem.CreateFile("C:/lol.ps1"); - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(1)); - fixture.Configure(ctx => ctx.UseManifest()); - - // When - var result = fixture.Run("-y"); - - // Then - result.ExitCode.ShouldBe(0); - result.Report.GetState("Run PowerShell Unless").ShouldBe(ResourceState.Skipped); - fixture.Logger.WasLogged("Evaluating PowerShell condition: Not really executed, but must be present"); - fixture.Logger.WasLogged("Skipping PowerShell script since condition did not evaluate to 0 (zero)"); - } + [WindowsFact] + public void Should_Skip_Running_Skip_If_Condition_Script_Does_Not_Have_Exit_Code_1() + { + // Given + var fixture = new CupboardFixture(); + + fixture.FileSystem.CreateDirectory("C:/Temp"); + fixture.FileSystem.CreateFile("C:/lol.ps1"); + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(1)); + fixture.Configure(ctx => ctx.UseManifest()); + + // When + var result = fixture.Run("-y"); + + // Then + result.ExitCode.ShouldBe(0); + result.Report.GetState("Run PowerShell Unless").ShouldBe(ResourceState.Skipped); + fixture.Logger.WasLogged("Evaluating PowerShell condition: Not really executed, but must be present"); + fixture.Logger.WasLogged("Skipping PowerShell script since condition did not evaluate to 0 (zero)"); + } - [WindowsFact] - public void Should_Return_Error_If_Script_Does_Not_Exist() - { - // Given - var fixture = new CupboardFixture(); - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Return_Error_If_Script_Does_Not_Exist() + { + // Given + var fixture = new CupboardFixture(); + fixture.Configure(ctx => ctx.UseManifest()); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.ExitCode.ShouldBe(-1); - result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Error); - fixture.Logger.WasLogged("PowerShell script path does not exist"); - } + // Then + result.ExitCode.ShouldBe(-1); + result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Error); + fixture.Logger.WasLogged("PowerShell script path does not exist"); + } - [WindowsFact] - public void Should_Run_Script_Using_PowerShell_Core_On_Windows_If_Specified() - { - // Given - var fixture = new CupboardFixture(); - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.FileSystem.CreateFile("C:/lol.ps1"); - fixture.Configure(ctx => ctx.UseManifest()); - - // When - var result = fixture.Run("-y"); - - // Then - result.ExitCode.ShouldBe(0); - result.Report.GetState("Run PowerShell Core Script").ShouldBe(ResourceState.Executed); - fixture.Logger.WasLogged("Running PowerShell script [yellow]C:/lol.ps1[/]"); - } + [WindowsFact] + public void Should_Run_Script_Using_PowerShell_Core_On_Windows_If_Specified() + { + // Given + var fixture = new CupboardFixture(); + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.FileSystem.CreateFile("C:/lol.ps1"); + fixture.Configure(ctx => ctx.UseManifest()); + + // When + var result = fixture.Run("-y"); + + // Then + result.ExitCode.ShouldBe(0); + result.Report.GetState("Run PowerShell Core Script").ShouldBe(ResourceState.Executed); + fixture.Logger.WasLogged("Running PowerShell script [yellow]C:/lol.ps1[/]"); } + } - public sealed class Unix + public sealed class Unix + { + public sealed class Manifests { - public sealed class Manifests + public class RunScript : Manifest { - public class RunScript : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("Run PowerShell Script") - .Script("/Working/lol.ps1"); - } + context.Resource("Run PowerShell Script") + .Script("/Working/lol.ps1"); } } + } - [Theory] - [InlineData(PlatformFamily.Linux)] - [InlineData(PlatformFamily.MacOs)] - public void Should_Run_Script(PlatformFamily family) - { - // Given - var fixture = new CupboardFixture(family); - fixture.FileSystem.CreateFile("/Working/lol.ps1"); - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - // When - var result = fixture.Run("-y"); - - // Then - result.ExitCode.ShouldBe(0); - result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Executed); - fixture.Logger.WasLogged("Running PowerShell script [yellow]/Working/lol.ps1[/]"); - } + [Theory] + [InlineData(PlatformFamily.Linux)] + [InlineData(PlatformFamily.MacOs)] + public void Should_Run_Script(PlatformFamily family) + { + // Given + var fixture = new CupboardFixture(family); + fixture.FileSystem.CreateFile("/Working/lol.ps1"); + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + // When + var result = fixture.Run("-y"); + + // Then + result.ExitCode.ShouldBe(0); + result.Report.GetState("Run PowerShell Script").ShouldBe(ResourceState.Executed); + fixture.Logger.WasLogged("Running PowerShell script [yellow]/Working/lol.ps1[/]"); } } } diff --git a/src/Cupboard.Tests/Unit/Providers/VSCodeExtensionProviderTests.cs b/src/Cupboard.Tests/Unit/Providers/VSCodeExtensionProviderTests.cs index 2a9622c..707fdf1 100644 --- a/src/Cupboard.Tests/Unit/Providers/VSCodeExtensionProviderTests.cs +++ b/src/Cupboard.Tests/Unit/Providers/VSCodeExtensionProviderTests.cs @@ -3,224 +3,223 @@ using Spectre.IO; using Xunit; -namespace Cupboard.Tests.Unit.Providers +namespace Cupboard.Tests.Unit.Providers; + +public sealed class VSCodeExtensionProviderTests { - public sealed class VSCodeExtensionProviderTests + private const string ExtensionName = "bar"; + private const string WindowsExecutable = "C:/Program Files/Microsoft VS Code/bin/code.cmd"; + private const string LinuxExecutable = "code"; + + public sealed class Manifests { - private const string ExtensionName = "bar"; - private const string WindowsExecutable = "C:/Program Files/Microsoft VS Code/bin/code.cmd"; - private const string LinuxExecutable = "code"; + public sealed class Install : Manifest + { + public override void Execute(ManifestContext context) + { + context.Resource(ExtensionName) + .Ensure(PackageState.Installed); + } + } + + public sealed class Uninstall : Manifest + { + public override void Execute(ManifestContext context) + { + context.Resource(ExtensionName) + .Ensure(PackageState.Uninstalled); + } + } + } - public sealed class Manifests + public sealed class Windows + { + public sealed class EnsureInstalled { - public sealed class Install : Manifest + [WindowsFact] + public void Should_Install_Package_If_Missing() { - public override void Execute(ManifestContext context) - { - context.Resource(ExtensionName) - .Ensure(PackageState.Installed); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Windows); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(WindowsExecutable, "--list-extensions", + new ProcessRunnerResult(0, string.Empty), + new ProcessRunnerResult(0, ExtensionName)); + + fixture.Process.Register(WindowsExecutable, $"--install-extension {ExtensionName}", + new ProcessRunnerResult(0)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged($"Installing VSCode extension [yellow]{ExtensionName}[/]"); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was installed"); } - public sealed class Uninstall : Manifest + [WindowsFact] + public void Should_Not_Install_Package_If_Present() { - public override void Execute(ManifestContext context) - { - context.Resource(ExtensionName) - .Ensure(PackageState.Uninstalled); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Windows); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(WindowsExecutable, "--list-extensions", + new ProcessRunnerResult(0, ExtensionName)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already installed"); } } - public sealed class Windows + public sealed class EnsureUninstalled { - public sealed class EnsureInstalled + [WindowsFact] + public void Should_Uninstall_Package_If_Present() { - [WindowsFact] - public void Should_Install_Package_If_Missing() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Windows); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(WindowsExecutable, "--list-extensions", - new ProcessRunnerResult(0, string.Empty), - new ProcessRunnerResult(0, ExtensionName)); - - fixture.Process.Register(WindowsExecutable, $"--install-extension {ExtensionName}", - new ProcessRunnerResult(0)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged($"Installing VSCode extension [yellow]{ExtensionName}[/]"); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was installed"); - } - - [WindowsFact] - public void Should_Not_Install_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Windows); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(WindowsExecutable, "--list-extensions", - new ProcessRunnerResult(0, ExtensionName)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already installed"); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Windows); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(WindowsExecutable, "--list-extensions", + new ProcessRunnerResult(0, $"foo\n{ExtensionName}\nbaz"), + new ProcessRunnerResult(0, "foo\nbaz")); + + fixture.Process.Register(WindowsExecutable, $"--uninstall-extension {ExtensionName}", + new ProcessRunnerResult(0)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged($"Uninstalling VSCode extension [yellow]{ExtensionName}[/]"); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was uninstalled"); } - public sealed class EnsureUninstalled + [WindowsFact] + public void Should_Not_Uninstall_Package_If_Absent() { - [WindowsFact] - public void Should_Uninstall_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Windows); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(WindowsExecutable, "--list-extensions", - new ProcessRunnerResult(0, $"foo\n{ExtensionName}\nbaz"), - new ProcessRunnerResult(0, "foo\nbaz")); - - fixture.Process.Register(WindowsExecutable, $"--uninstall-extension {ExtensionName}", - new ProcessRunnerResult(0)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged($"Uninstalling VSCode extension [yellow]{ExtensionName}[/]"); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was uninstalled"); - } - - [WindowsFact] - public void Should_Not_Uninstall_Package_If_Absent() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Windows); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(WindowsExecutable, "--list-extensions", - new ProcessRunnerResult(0, "foo\nbaz")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already uninstalled"); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Windows); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(WindowsExecutable, "--list-extensions", + new ProcessRunnerResult(0, "foo\nbaz")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already uninstalled"); } } + } - public sealed class Linux + public sealed class Linux + { + public sealed class EnsureInstalled { - public sealed class EnsureInstalled + [WindowsFact] + public void Should_Install_Package_If_Missing() { - [WindowsFact] - public void Should_Install_Package_If_Missing() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.Security.IsAdmin = true; - fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(LinuxExecutable, "--list-extensions", - new ProcessRunnerResult(0, string.Empty), - new ProcessRunnerResult(0, ExtensionName)); - - fixture.Process.Register(LinuxExecutable, $"--install-extension {ExtensionName}", - new ProcessRunnerResult(0)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged($"Installing VSCode extension [yellow]{ExtensionName}[/]"); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was installed"); - } - - [WindowsFact] - public void Should_Not_Install_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(LinuxExecutable, "--list-extensions", - new ProcessRunnerResult(0, ExtensionName)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already installed"); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.Security.IsAdmin = true; + fixture.Process.RegisterDefaultResult(new ProcessRunnerResult(0)); + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(LinuxExecutable, "--list-extensions", + new ProcessRunnerResult(0, string.Empty), + new ProcessRunnerResult(0, ExtensionName)); + + fixture.Process.Register(LinuxExecutable, $"--install-extension {ExtensionName}", + new ProcessRunnerResult(0)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged($"Installing VSCode extension [yellow]{ExtensionName}[/]"); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was installed"); } - public sealed class EnsureUninstalled + [WindowsFact] + public void Should_Not_Install_Package_If_Present() + { + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(LinuxExecutable, "--list-extensions", + new ProcessRunnerResult(0, ExtensionName)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already installed"); + } + } + + public sealed class EnsureUninstalled + { + [WindowsFact] + public void Should_Uninstall_Package_If_Present() { - [WindowsFact] - public void Should_Uninstall_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(LinuxExecutable, "--list-extensions", - new ProcessRunnerResult(0, $"foo\n{ExtensionName}\nbaz"), - new ProcessRunnerResult(0, "foo\nbaz")); - - fixture.Process.Register(LinuxExecutable, $"--uninstall-extension {ExtensionName}", - new ProcessRunnerResult(0)); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged($"Uninstalling VSCode extension [yellow]{ExtensionName}[/]"); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was uninstalled"); - } - - [WindowsFact] - public void Should_Not_Uninstall_Package_If_Absent() - { - // Given - var fixture = new CupboardFixture(PlatformFamily.Linux); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); - - fixture.Process.Register(LinuxExecutable, "--list-extensions", - new ProcessRunnerResult(0, "foo\nbaz")); - - // When - var result = fixture.Run("-y"); - - // Then - result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already uninstalled"); - } + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(LinuxExecutable, "--list-extensions", + new ProcessRunnerResult(0, $"foo\n{ExtensionName}\nbaz"), + new ProcessRunnerResult(0, "foo\nbaz")); + + fixture.Process.Register(LinuxExecutable, $"--uninstall-extension {ExtensionName}", + new ProcessRunnerResult(0)); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged($"Uninstalling VSCode extension [yellow]{ExtensionName}[/]"); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] was uninstalled"); + } + + [WindowsFact] + public void Should_Not_Uninstall_Package_If_Absent() + { + // Given + var fixture = new CupboardFixture(PlatformFamily.Linux); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); + + fixture.Process.Register(LinuxExecutable, "--list-extensions", + new ProcessRunnerResult(0, "foo\nbaz")); + + // When + var result = fixture.Run("-y"); + + // Then + result.Report.GetState(ExtensionName).ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged($"The VSCode extension [yellow]{ExtensionName}[/] is already uninstalled"); } } } diff --git a/src/Cupboard.Tests/Unit/Providers/WingetProviderTests.cs b/src/Cupboard.Tests/Unit/Providers/WingetProviderTests.cs index 53b0385..6263591 100644 --- a/src/Cupboard.Tests/Unit/Providers/WingetProviderTests.cs +++ b/src/Cupboard.Tests/Unit/Providers/WingetProviderTests.cs @@ -1,122 +1,121 @@ using Cupboard.Testing; using Shouldly; -namespace Cupboard.Tests.Unit.Providers +namespace Cupboard.Tests.Unit.Providers; + +public sealed class WingetProviderTests { - public sealed class WingetProviderTests + public sealed class Manifests { - public sealed class Manifests + public sealed class Install : Manifest { - public sealed class Install : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("GitHub CLI") - .Package("GitHub.cli") - .Ensure(PackageState.Installed); - } + context.Resource("GitHub CLI") + .Package("GitHub.cli") + .Ensure(PackageState.Installed); } + } - public sealed class Uninstall : Manifest + public sealed class Uninstall : Manifest + { + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - context.Resource("GitHub CLI") - .Package("GitHub.cli") - .Ensure(PackageState.Uninstalled); - } + context.Resource("GitHub CLI") + .Package("GitHub.cli") + .Ensure(PackageState.Uninstalled); } } + } - public sealed class EnsureInstalled + public sealed class EnsureInstalled + { + [WindowsFact] + public void Should_Install_Package_If_Missing() { - [WindowsFact] - public void Should_Install_Package_If_Missing() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("winget", "list --source winget --id GitHub.cli", - new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria."), - new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1")); + fixture.Process.Register("winget", "list --source winget --id GitHub.cli", + new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria."), + new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1")); - fixture.Process.Register("winget", "install -e --id GitHub.cli", - new ProcessRunnerResult(0, "Lol installed GitHub.cli")); + fixture.Process.Register("winget", "install -e --id GitHub.cli", + new ProcessRunnerResult(0, "Lol installed GitHub.cli")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Installing Winget package [yellow]GitHub.cli[/]"); - fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] was installed"); - } + // Then + result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Installing Winget package [yellow]GitHub.cli[/]"); + fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] was installed"); + } - [WindowsFact] - public void Should_Not_Install_Package_If_Present_lol() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Install_Package_If_Present_lol() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("winget", "list --source winget --id GitHub.cli", - new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1")); + fixture.Process.Register("winget", "list --source winget --id GitHub.cli", + new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] is already installed"); - } + // Then + result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] is already installed"); } + } - public sealed class EnsureUninstalled + public sealed class EnsureUninstalled + { + [WindowsFact] + public void Should_Uninstall_Package_If_Present() { - [WindowsFact] - public void Should_Uninstall_Package_If_Present() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("winget", "list --source winget --id GitHub.cli", - new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1"), - new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria.")); + fixture.Process.Register("winget", "list --source winget --id GitHub.cli", + new ProcessRunnerResult(0, "GitHub CLI GitHub.cli 1.12.1"), + new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria.")); - fixture.Process.Register("winget", "uninstall -e --id GitHub.cli", new ProcessRunnerResult(0)); + fixture.Process.Register("winget", "uninstall -e --id GitHub.cli", new ProcessRunnerResult(0)); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Changed); - fixture.Logger.WasLogged("Uninstalling Winget package [yellow]GitHub.cli[/]"); - fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] was uninstalled"); - } + // Then + result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Changed); + fixture.Logger.WasLogged("Uninstalling Winget package [yellow]GitHub.cli[/]"); + fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] was uninstalled"); + } - [WindowsFact] - public void Should_Not_Uninstall_Package_If_Absent() - { - // Given - var fixture = new CupboardFixture(); - fixture.Security.IsAdmin = true; - fixture.Configure(ctx => ctx.UseManifest()); + [WindowsFact] + public void Should_Not_Uninstall_Package_If_Absent() + { + // Given + var fixture = new CupboardFixture(); + fixture.Security.IsAdmin = true; + fixture.Configure(ctx => ctx.UseManifest()); - fixture.Process.Register("winget", "list --source winget --id GitHub.cli", - new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria.")); + fixture.Process.Register("winget", "list --source winget --id GitHub.cli", + new ProcessRunnerResult(int.MinValue, "No installed package found matching input criteria.")); - // When - var result = fixture.Run("-y"); + // When + var result = fixture.Run("-y"); - // Then - result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Unchanged); - fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] is already uninstalled"); - } + // Then + result.Report.GetState("GitHub CLI").ShouldBe(ResourceState.Unchanged); + fixture.Logger.WasLogged("The Winget package [yellow]GitHub.cli[/] is already uninstalled"); } } } diff --git a/src/Cupboard/Cli/FactCommand.cs b/src/Cupboard/Cli/FactCommand.cs index f3b4ff8..e41f9b6 100644 --- a/src/Cupboard/Cli/FactCommand.cs +++ b/src/Cupboard/Cli/FactCommand.cs @@ -4,51 +4,50 @@ using Spectre.Console; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class FactCommand : Command { - internal sealed class FactCommand : Command - { - private readonly IFactBuilder _builder; - private readonly IAnsiConsole _console; + private readonly IFactBuilder _builder; + private readonly IAnsiConsole _console; - public sealed class Settings : CommandSettings - { - [CommandOption("--env")] - public bool Environment { get; set; } - } + public sealed class Settings : CommandSettings + { + [CommandOption("--env")] + public bool Environment { get; set; } + } - public FactCommand(IFactBuilder builder, IAnsiConsole console) - { - _builder = builder ?? throw new ArgumentNullException(nameof(builder)); - _console = console ?? throw new ArgumentNullException(nameof(console)); - } + public FactCommand(IFactBuilder builder, IAnsiConsole console) + { + _builder = builder ?? throw new ArgumentNullException(nameof(builder)); + _console = console ?? throw new ArgumentNullException(nameof(console)); + } - public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) - { - var facts = _builder.Build(context.Remaining); + public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) + { + var facts = _builder.Build(context.Remaining); - var table = new Table().BorderColor(Color.Grey); - table.AddColumns("[grey]Path[/]", "[grey]Type[/]", "[grey]Value[/]"); + var table = new Table().BorderColor(Color.Grey); + table.AddColumns("[grey]Path[/]", "[grey]Type[/]", "[grey]Value[/]"); - foreach (var fact in facts.OrderBy(f => f.FullName)) + foreach (var fact in facts.OrderBy(f => f.FullName)) + { + if (fact.FullName.StartsWith("env.", StringComparison.OrdinalIgnoreCase) && !settings.Environment) { - if (fact.FullName.StartsWith("env.", StringComparison.OrdinalIgnoreCase) && !settings.Environment) - { - continue; - } - - var value = fact.Value?.ToString() ?? string.Empty; - value = value.Replace("\u001b", "ESC"); - - table.AddRow( - fact.FullName, - fact.Value?.GetType().Name ?? "?", - "[grey]" + value.EscapeMarkup() + "[/]"); + continue; } - _console.Write(table); + var value = fact.Value?.ToString() ?? string.Empty; + value = value.Replace("\u001b", "ESC"); - return 0; + table.AddRow( + fact.FullName, + fact.Value?.GetType().Name ?? "?", + "[grey]" + value.EscapeMarkup() + "[/]"); } + + _console.Write(table); + + return 0; } } diff --git a/src/Cupboard/Cli/Infrastructure/DirectoryPathConverter.cs b/src/Cupboard/Cli/Infrastructure/DirectoryPathConverter.cs index 7cd163e..408b9cb 100644 --- a/src/Cupboard/Cli/Infrastructure/DirectoryPathConverter.cs +++ b/src/Cupboard/Cli/Infrastructure/DirectoryPathConverter.cs @@ -3,22 +3,21 @@ using System.Globalization; using Spectre.IO; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +/// +/// A type converter for . +/// +internal sealed class DirectoryPathConverter : TypeConverter { - /// - /// A type converter for . - /// - internal sealed class DirectoryPathConverter : TypeConverter + /// + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { - /// - public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + if (value is string stringValue) { - if (value is string stringValue) - { - return new DirectoryPath(stringValue); - } - - throw new NotSupportedException("Can't convert value to file path."); + return new DirectoryPath(stringValue); } + + throw new NotSupportedException("Can't convert value to file path."); } } diff --git a/src/Cupboard/Cli/Infrastructure/FilePathConverter.cs b/src/Cupboard/Cli/Infrastructure/FilePathConverter.cs index 1ff8bb2..1d80461 100644 --- a/src/Cupboard/Cli/Infrastructure/FilePathConverter.cs +++ b/src/Cupboard/Cli/Infrastructure/FilePathConverter.cs @@ -3,22 +3,21 @@ using System.Globalization; using Spectre.IO; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +/// +/// A type converter for . +/// +internal sealed class FilePathConverter : TypeConverter { - /// - /// A type converter for . - /// - internal sealed class FilePathConverter : TypeConverter + /// + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { - /// - public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + if (value is string stringValue) { - if (value is string stringValue) - { - return new FilePath(stringValue); - } - - throw new NotSupportedException("Can't convert value to file path."); + return new FilePath(stringValue); } + + throw new NotSupportedException("Can't convert value to file path."); } } diff --git a/src/Cupboard/Cli/Infrastructure/TypeRegistrar.cs b/src/Cupboard/Cli/Infrastructure/TypeRegistrar.cs index d58aa22..1fb91f3 100644 --- a/src/Cupboard/Cli/Infrastructure/TypeRegistrar.cs +++ b/src/Cupboard/Cli/Infrastructure/TypeRegistrar.cs @@ -2,35 +2,34 @@ using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class TypeRegistrar : ITypeRegistrar { - internal sealed class TypeRegistrar : ITypeRegistrar - { - private readonly IServiceCollection _provider; + private readonly IServiceCollection _provider; - public TypeRegistrar(IServiceCollection provider) - { - _provider = provider; - } + public TypeRegistrar(IServiceCollection provider) + { + _provider = provider; + } - public ITypeResolver Build() - { - return new TypeResolver(_provider.BuildServiceProvider()); - } + public ITypeResolver Build() + { + return new TypeResolver(_provider.BuildServiceProvider()); + } - public void Register(Type service, Type implementation) - { - _provider.AddSingleton(service, implementation); - } + public void Register(Type service, Type implementation) + { + _provider.AddSingleton(service, implementation); + } - public void RegisterInstance(Type service, object implementation) - { - _provider.AddSingleton(service, implementation); - } + public void RegisterInstance(Type service, object implementation) + { + _provider.AddSingleton(service, implementation); + } - public void RegisterLazy(Type service, Func factory) - { - _provider.AddSingleton(service, _ => factory()); - } + public void RegisterLazy(Type service, Func factory) + { + _provider.AddSingleton(service, _ => factory()); } } diff --git a/src/Cupboard/Cli/Infrastructure/TypeResolver.cs b/src/Cupboard/Cli/Infrastructure/TypeResolver.cs index 089e393..ba414c2 100644 --- a/src/Cupboard/Cli/Infrastructure/TypeResolver.cs +++ b/src/Cupboard/Cli/Infrastructure/TypeResolver.cs @@ -1,25 +1,24 @@ using System; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class TypeResolver : ITypeResolver { - internal sealed class TypeResolver : ITypeResolver + private readonly IServiceProvider _provider; + + public TypeResolver(IServiceProvider provider) { - private readonly IServiceProvider _provider; + _provider = provider; + } - public TypeResolver(IServiceProvider provider) + public object? Resolve(Type? type) + { + if (type == null) { - _provider = provider; + return null; } - public object? Resolve(Type? type) - { - if (type == null) - { - return null; - } - - return _provider.GetService(type); - } + return _provider.GetService(type); } } diff --git a/src/Cupboard/Cli/Infrastructure/VerbosityConverter.cs b/src/Cupboard/Cli/Infrastructure/VerbosityConverter.cs index b01e994..aad402b 100644 --- a/src/Cupboard/Cli/Infrastructure/VerbosityConverter.cs +++ b/src/Cupboard/Cli/Infrastructure/VerbosityConverter.cs @@ -3,48 +3,47 @@ using System.ComponentModel; using System.Globalization; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class VerbosityConverter : TypeConverter { - internal sealed class VerbosityConverter : TypeConverter - { - private readonly Dictionary _lookup; + private readonly Dictionary _lookup; - public VerbosityConverter() + public VerbosityConverter() + { + _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { - _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "q", Verbosity.Quiet }, - { "quiet", Verbosity.Quiet }, - { "m", Verbosity.Minimal }, - { "minimal", Verbosity.Minimal }, - { "n", Verbosity.Normal }, - { "normal", Verbosity.Normal }, - { "v", Verbosity.Verbose }, - { "verbose", Verbosity.Verbose }, - { "d", Verbosity.Diagnostic }, - { "diagnostic", Verbosity.Diagnostic }, - }; - } + { "q", Verbosity.Quiet }, + { "quiet", Verbosity.Quiet }, + { "m", Verbosity.Minimal }, + { "minimal", Verbosity.Minimal }, + { "n", Verbosity.Normal }, + { "normal", Verbosity.Normal }, + { "v", Verbosity.Verbose }, + { "verbose", Verbosity.Verbose }, + { "d", Verbosity.Diagnostic }, + { "diagnostic", Verbosity.Diagnostic }, + }; + } - /// - public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + /// + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string stringValue) { - if (value is string stringValue) + var result = _lookup.TryGetValue(stringValue, out var verbosity); + if (!result) { - var result = _lookup.TryGetValue(stringValue, out var verbosity); - if (!result) - { - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "The value '{0}' is not a valid verbosity.", - value)); - } - - return verbosity; + throw new InvalidOperationException( + string.Format( + CultureInfo.InvariantCulture, + "The value '{0}' is not a valid verbosity.", + value)); } - throw new NotSupportedException("Can't convert value to verbosity."); + return verbosity; } + + throw new NotSupportedException("Can't convert value to verbosity."); } } diff --git a/src/Cupboard/Cli/RunCommand.cs b/src/Cupboard/Cli/RunCommand.cs index 15d75f8..aea79bc 100644 --- a/src/Cupboard/Cli/RunCommand.cs +++ b/src/Cupboard/Cli/RunCommand.cs @@ -7,197 +7,196 @@ using Spectre.Console.Cli; using Spectre.IO; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class RunCommand : AsyncCommand { - internal sealed class RunCommand : AsyncCommand + private readonly ExecutionEngine _executor; + private readonly ReportRenderer _renderer; + private readonly ICupboardLogger _logger; + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; + private readonly ISecurityPrincipal _security; + private readonly IAnsiConsole _console; + private readonly IExecutionController _defaultController; + private readonly IExecutionController _interactiveController; + + public sealed class Settings : CommandSettings { - private readonly ExecutionEngine _executor; - private readonly ReportRenderer _renderer; - private readonly ICupboardLogger _logger; - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; - private readonly ISecurityPrincipal _security; - private readonly IAnsiConsole _console; - private readonly IExecutionController _defaultController; - private readonly IExecutionController _interactiveController; - - public sealed class Settings : CommandSettings - { - [CommandOption("--dryrun")] - [Description("Performs a dry run of the configuration.")] - public bool DryRun { get; set; } - - [CommandOption("--debug")] - [Description("Launches a debugger when starting up.")] - public bool Debug { get; set; } - - [CommandOption("-y|--yes|--confirm")] - [Description("Confirm all prompts. Chooses affirmative answer instead of prompting.")] - public bool AutoConfirm { get; set; } - - [CommandOption("--ignore-reboots")] - [Description("Ignore any pending reboots.")] - public bool IgnoreReboots { get; set; } - - [CommandOption("-w|--working|--workingdir")] - [Description("Sets the working directory.")] - [TypeConverter(typeof(DirectoryPathConverter))] - public DirectoryPath? WorkingDirectory { get; set; } - - [CommandOption("-i|--interactive")] - [Description("Asks the user for permission before executing resources")] - public bool Interactive { get; set; } - - [CommandOption("-v|--verbosity")] - [DefaultValue(Verbosity.Normal)] - [TypeConverter(typeof(VerbosityConverter))] - [Description( - "Specifies the amount of information to be displayed.\n" - + "([blue]q[/]uiet, [blue]m[/]inimal, [blue]n[/]ormal, " - + "[blue]v[/]erbose, [blue]d[/]iagnostic)")] - public Verbosity Verbosity { get; set; } - } + [CommandOption("--dryrun")] + [Description("Performs a dry run of the configuration.")] + public bool DryRun { get; set; } + + [CommandOption("--debug")] + [Description("Launches a debugger when starting up.")] + public bool Debug { get; set; } + + [CommandOption("-y|--yes|--confirm")] + [Description("Confirm all prompts. Chooses affirmative answer instead of prompting.")] + public bool AutoConfirm { get; set; } + + [CommandOption("--ignore-reboots")] + [Description("Ignore any pending reboots.")] + public bool IgnoreReboots { get; set; } + + [CommandOption("-w|--working|--workingdir")] + [Description("Sets the working directory.")] + [TypeConverter(typeof(DirectoryPathConverter))] + public DirectoryPath? WorkingDirectory { get; set; } + + [CommandOption("-i|--interactive")] + [Description("Asks the user for permission before executing resources")] + public bool Interactive { get; set; } + + [CommandOption("-v|--verbosity")] + [DefaultValue(Verbosity.Normal)] + [TypeConverter(typeof(VerbosityConverter))] + [Description( + "Specifies the amount of information to be displayed.\n" + + "([blue]q[/]uiet, [blue]m[/]inimal, [blue]n[/]ormal, " + + "[blue]v[/]erbose, [blue]d[/]iagnostic)")] + public Verbosity Verbosity { get; set; } + } - public RunCommand( - ExecutionEngine executor, - ReportRenderer renderer, - ICupboardLogger logger, - ICupboardFileSystem fileSystem, - ICupboardEnvironment environment, - ISecurityPrincipal security, - IAnsiConsole console) - { - _executor = executor ?? throw new ArgumentNullException(nameof(executor)); - _renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - _security = security ?? throw new ArgumentNullException(nameof(security)); - _console = console ?? throw new ArgumentNullException(nameof(console)); - _defaultController = new DefaultExecutionController(); - _interactiveController = new InteractiveExecutionController(_console); - } + public RunCommand( + ExecutionEngine executor, + ReportRenderer renderer, + ICupboardLogger logger, + ICupboardFileSystem fileSystem, + ICupboardEnvironment environment, + ISecurityPrincipal security, + IAnsiConsole console) + { + _executor = executor ?? throw new ArgumentNullException(nameof(executor)); + _renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _security = security ?? throw new ArgumentNullException(nameof(security)); + _console = console ?? throw new ArgumentNullException(nameof(console)); + _defaultController = new DefaultExecutionController(); + _interactiveController = new InteractiveExecutionController(_console); + } - public override ValidationResult Validate([NotNull] CommandContext context, [NotNull] Settings settings) + public override ValidationResult Validate([NotNull] CommandContext context, [NotNull] Settings settings) + { + if (settings.WorkingDirectory != null) { - if (settings.WorkingDirectory != null) + settings.WorkingDirectory = settings.WorkingDirectory.MakeAbsolute(_environment); + if (!_fileSystem.Exist(settings.WorkingDirectory)) { - settings.WorkingDirectory = settings.WorkingDirectory.MakeAbsolute(_environment); - if (!_fileSystem.Exist(settings.WorkingDirectory)) - { - return ValidationResult.Error("The specified working directory does not exist"); - } + return ValidationResult.Error("The specified working directory does not exist"); } + } - return ValidationResult.Success(); + return ValidationResult.Success(); + } + + public override async Task ExecuteAsync(CommandContext context, Settings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + else if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); } - public override async Task ExecuteAsync(CommandContext context, Settings settings) + if (settings.Debug) { - if (context is null) + if (!Debugger.IsAttached) { - throw new ArgumentNullException(nameof(context)); - } - else if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); + Debugger.Launch(); } + } - if (settings.Debug) - { - if (!Debugger.IsAttached) - { - Debugger.Launch(); - } - } + _logger.SetVerbosity(settings.Verbosity); - _logger.SetVerbosity(settings.Verbosity); + if (settings.WorkingDirectory != null) + { + _environment.SetWorkingDirectory(settings.WorkingDirectory); + } - if (settings.WorkingDirectory != null) - { - _environment.SetWorkingDirectory(settings.WorkingDirectory); - } + var report = await Run(context, settings).ConfigureAwait(false); + if (report == null) + { + return -1; + } - var report = await Run(context, settings).ConfigureAwait(false); - if (report == null) - { - return -1; - } + if (report.Items.Count == 0) + { + _console.MarkupLine("[red]Error:[/] No manifest were found."); + _console.MarkupLine("Have you added a [yellow]Catalog[/]?"); + _console.WriteLine(); + _console.MarkupLine("Write [grey]dotnet run -- --help[/] for more information."); - if (report.Items.Count == 0) - { - _console.MarkupLine("[red]Error:[/] No manifest were found."); - _console.MarkupLine("Have you added a [yellow]Catalog[/]?"); - _console.WriteLine(); - _console.MarkupLine("Write [grey]dotnet run -- --help[/] for more information."); + return -1; + } - return -1; - } + _renderer.Render(report, _logger.Verbosity); + return report.Successful ? 0 : -1; + } - _renderer.Render(report, _logger.Verbosity); - return report.Successful ? 0 : -1; + private async Task Run(CommandContext context, Settings settings) + { + if (settings.DryRun) + { + return await _executor.Run( + context.Remaining, new DummyUpdater(), _defaultController, + dryRun: true, ignoreReboots: settings.IgnoreReboots).ConfigureAwait(false); } - - private async Task Run(CommandContext context, Settings settings) + else { - if (settings.DryRun) + if (!settings.AutoConfirm) { - return await _executor.Run( + var report = await _executor.Run( context.Remaining, new DummyUpdater(), _defaultController, dryRun: true, ignoreReboots: settings.IgnoreReboots).ConfigureAwait(false); - } - else - { - if (!settings.AutoConfirm) - { - var report = await _executor.Run( - context.Remaining, new DummyUpdater(), _defaultController, - dryRun: true, ignoreReboots: settings.IgnoreReboots).ConfigureAwait(false); - if (report.Items.Count == 0) - { - return report; - } + if (report.Items.Count == 0) + { + return report; + } - _renderer.Render(report, _logger.Verbosity); - _console.WriteLine(); + _renderer.Render(report, _logger.Verbosity); + _console.WriteLine(); - if (report.RequiresAdministrator) + if (report.RequiresAdministrator) + { + if (!_security.IsAdministrator()) { - if (!_security.IsAdministrator()) - { - _console.MarkupLine("[red]ERROR:[/] The current execution plan [yellow]require administrative permissions[/]."); - _console.MarkupLine("[grey]Restart the application as administrator to execute plan.[/]"); - return null; - } + _console.MarkupLine("[red]ERROR:[/] The current execution plan [yellow]require administrative permissions[/]."); + _console.MarkupLine("[grey]Restart the application as administrator to execute plan.[/]"); + return null; } + } - if (report.PendingReboot) + if (report.PendingReboot) + { + if (settings.IgnoreReboots) { - if (settings.IgnoreReboots) - { - _console.MarkupLine("[yellow]WARNING:[/] A pending reboot have been detected."); - } - else - { - _console.MarkupLine("[red]ERROR:[/] A pending reboot have been detected."); - _console.MarkupLine("[grey]To ignore, pass the [yellow]--ignore-reboots[/] flag.[/]"); - return null; - } + _console.MarkupLine("[yellow]WARNING:[/] A pending reboot have been detected."); } - - _console.MarkupLine("[yellow]WARNING[/]: This will change the state of the current machine."); - if (!_console.Confirm("Are you sure you want to continue?", defaultValue: false)) + else { + _console.MarkupLine("[red]ERROR:[/] A pending reboot have been detected."); + _console.MarkupLine("[grey]To ignore, pass the [yellow]--ignore-reboots[/] flag.[/]"); return null; } } - var controller = settings.Interactive ? _interactiveController : _defaultController; - return await _executor.Run( - context.Remaining, new StatusUpdater(_console), controller, - dryRun: false, ignoreReboots: settings.IgnoreReboots).ConfigureAwait(false); + _console.MarkupLine("[yellow]WARNING[/]: This will change the state of the current machine."); + if (!_console.Confirm("Are you sure you want to continue?", defaultValue: false)) + { + return null; + } } + + var controller = settings.Interactive ? _interactiveController : _defaultController; + return await _executor.Run( + context.Remaining, new StatusUpdater(_console), controller, + dryRun: false, ignoreReboots: settings.IgnoreReboots).ConfigureAwait(false); } } } diff --git a/src/Cupboard/ColorPalette.cs b/src/Cupboard/ColorPalette.cs index 0e581aa..9ecf682 100644 --- a/src/Cupboard/ColorPalette.cs +++ b/src/Cupboard/ColorPalette.cs @@ -2,47 +2,46 @@ using System.Collections.Generic; using Spectre.Console; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ColorPalette + where T : notnull { - internal sealed class ColorPalette - where T : notnull + private readonly Dictionary _colors; + + public ColorPalette(IEnumerable items, IEqualityComparer? comparer = null) { - private readonly Dictionary _colors; + _colors = new Dictionary(comparer ?? EqualityComparer.Default); - public ColorPalette(IEnumerable items, IEqualityComparer? comparer = null) + var random = new Random(DateTime.Now.Millisecond); + var colors = new HashSet(); + foreach (var item in items) { - _colors = new Dictionary(comparer ?? EqualityComparer.Default); - - var random = new Random(DateTime.Now.Millisecond); - var colors = new HashSet(); - foreach (var item in items) + Color color; + while (true) { - Color color; - while (true) + color = new Color( + (byte)random.Next(70, 200), + (byte)random.Next(100, 225), + (byte)random.Next(100, 230)); + + if (colors.Add(color)) { - color = new Color( - (byte)random.Next(70, 200), - (byte)random.Next(100, 225), - (byte)random.Next(100, 230)); - - if (colors.Add(color)) - { - break; - } + break; } - - _colors[item] = color; } + + _colors[item] = color; } + } - public Color GetColor(T item) + public Color GetColor(T item) + { + if (_colors.TryGetValue(item, out var color)) { - if (_colors.TryGetValue(item, out var color)) - { - return color; - } - - return Color.White; + return color; } + + return Color.White; } } diff --git a/src/Cupboard/CupboardHost.cs b/src/Cupboard/CupboardHost.cs index 67a3ec8..a6f00df 100644 --- a/src/Cupboard/CupboardHost.cs +++ b/src/Cupboard/CupboardHost.cs @@ -4,41 +4,40 @@ using Spectre.Console; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +public sealed class CupboardHost { - public sealed class CupboardHost + private readonly IAnsiConsole _console; + private readonly IHost _host; + private readonly bool _propagateExceptions; + + internal CupboardHost(IAnsiConsole console, IHost host, bool propagateExceptions) { - private readonly IAnsiConsole _console; - private readonly IHost _host; - private readonly bool _propagateExceptions; + _console = console ?? throw new ArgumentNullException(nameof(console)); + _host = host ?? throw new ArgumentNullException(nameof(host)); + _propagateExceptions = propagateExceptions; + } - internal CupboardHost(IAnsiConsole console, IHost host, bool propagateExceptions) - { - _console = console ?? throw new ArgumentNullException(nameof(console)); - _host = host ?? throw new ArgumentNullException(nameof(host)); - _propagateExceptions = propagateExceptions; - } + public static CupboardHostBuilder CreateBuilder() + { + return new CupboardHostBuilder(); + } - public static CupboardHostBuilder CreateBuilder() + public int Run(string[] args) + { + try { - return new CupboardHostBuilder(); + var app = _host.Services.GetRequiredService(); + return app.Run(args); } - - public int Run(string[] args) + catch (Exception ex) when (!_propagateExceptions) { - try - { - var app = _host.Services.GetRequiredService(); - return app.Run(args); - } - catch (Exception ex) when (!_propagateExceptions) - { - _console.WriteLine(); - _console.Write(new Panel("An error occured during execution").BorderColor(Color.Red).RoundedBorder()); - _console.WriteException(ex, ExceptionFormats.ShortenEverything); + _console.WriteLine(); + _console.Write(new Panel("An error occured during execution").BorderColor(Color.Red).RoundedBorder()); + _console.WriteException(ex, ExceptionFormats.ShortenEverything); - return -1; - } + return -1; } } } diff --git a/src/Cupboard/CupboardHostBuilder.cs b/src/Cupboard/CupboardHostBuilder.cs index bf51689..a8e2c95 100644 --- a/src/Cupboard/CupboardHostBuilder.cs +++ b/src/Cupboard/CupboardHostBuilder.cs @@ -7,91 +7,90 @@ using Spectre.Console.Cli; using Spectre.IO; -namespace Cupboard +namespace Cupboard; + +public sealed class CupboardHostBuilder { - public sealed class CupboardHostBuilder - { - private readonly List> _configurations; - private readonly IAnsiConsole _console; - private bool _propagateExceptions = false; + private readonly List> _configurations; + private readonly IAnsiConsole _console; + private bool _propagateExceptions = false; - public CupboardHostBuilder(IAnsiConsole? console = null) + public CupboardHostBuilder(IAnsiConsole? console = null) + { + _console = console ?? AnsiConsole.Console; + _configurations = new List> { - _console = console ?? AnsiConsole.Console; - _configurations = new List> + builder => builder.ConfigureServices(services => { - builder => builder.ConfigureServices(services => + services.AddAll(); + + services.AddModule(); + services.AddModule(); + + services.AddSingleton(_console); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddCommandLine(config => { - services.AddAll(); - - services.AddModule(); - services.AddModule(); - - services.AddSingleton(_console); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddCommandLine(config => - { - config.ConfigureConsole(_console); - config.PropagateExceptions(); - - config.AddCommand("facts"); - }); - }), - }; - } - - public CupboardHostBuilder PropagateExceptions() - { - _propagateExceptions = true; - return this; - } + config.ConfigureConsole(_console); + config.PropagateExceptions(); - public CupboardHostBuilder AddCatalog() - where TCatalog : Catalog - { - _configurations.Add(b => b.ConfigureServices(s => s.AddSingleton())); - return this; - } + config.AddCommand("facts"); + }); + }), + }; + } - public CupboardHostBuilder ConfigureServices(Action services) - { - _configurations.Add(b => b.ConfigureServices(services)); - return this; - } + public CupboardHostBuilder PropagateExceptions() + { + _propagateExceptions = true; + return this; + } - public CupboardHost Build() - { - var builder = Host.CreateDefaultBuilder(); - _configurations.ForEach(action => action(builder)); + public CupboardHostBuilder AddCatalog() + where TCatalog : Catalog + { + _configurations.Add(b => b.ConfigureServices(s => s.AddSingleton())); + return this; + } - var host = builder.Build(); - var console = host.Services.GetRequiredService(); + public CupboardHostBuilder ConfigureServices(Action services) + { + _configurations.Add(b => b.ConfigureServices(services)); + return this; + } - return new CupboardHost(console, host, _propagateExceptions); - } + public CupboardHost Build() + { + var builder = Host.CreateDefaultBuilder(); + _configurations.ForEach(action => action(builder)); - public int Run(string[] args) - { - var host = Build(); - return host.Run(args); - } + var host = builder.Build(); + var console = host.Services.GetRequiredService(); + + return new CupboardHost(console, host, _propagateExceptions); + } + + public int Run(string[] args) + { + var host = Build(); + return host.Run(args); } } diff --git a/src/Cupboard/CupboardLogger.cs b/src/Cupboard/CupboardLogger.cs index 5c1643f..12135f0 100644 --- a/src/Cupboard/CupboardLogger.cs +++ b/src/Cupboard/CupboardLogger.cs @@ -1,84 +1,83 @@ using System; using Spectre.Console; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class CupboardLogger : ICupboardLogger { - internal sealed class CupboardLogger : ICupboardLogger + private readonly IAnsiConsole _console; + private Verbosity _verbosity; + + public Verbosity Verbosity => _verbosity; + + public CupboardLogger(IAnsiConsole console) { - private readonly IAnsiConsole _console; - private Verbosity _verbosity; + _console = console ?? throw new ArgumentNullException(nameof(console)); + _verbosity = Verbosity.Normal; + } - public Verbosity Verbosity => _verbosity; + public void SetVerbosity(Verbosity verbosity) + { + _verbosity = verbosity; + } - public CupboardLogger(IAnsiConsole console) + public void Log(Verbosity verbosity, LogLevel level, string text) + { + if (verbosity > _verbosity) { - _console = console ?? throw new ArgumentNullException(nameof(console)); - _verbosity = Verbosity.Normal; + return; } - public void SetVerbosity(Verbosity verbosity) + switch (level) { - _verbosity = verbosity; + case LogLevel.Fatal: + case LogLevel.Error: + _console.MarkupLine($"[red]{text}[/]"); + break; + case LogLevel.Warning: + _console.MarkupLine($"[yellow]{text}[/]"); + break; + case LogLevel.Information: + _console.MarkupLine($"{text}"); + break; + case LogLevel.Verbose: + case LogLevel.Debug: + _console.MarkupLine($"[grey]{text}[/]"); + break; } + } - public void Log(Verbosity verbosity, LogLevel level, string text) + public void Log(Verbosity verbosity, LogLevel level, string title, string text) + { + if (verbosity > _verbosity) { - if (verbosity > _verbosity) - { - return; - } - - switch (level) - { - case LogLevel.Fatal: - case LogLevel.Error: - _console.MarkupLine($"[red]{text}[/]"); - break; - case LogLevel.Warning: - _console.MarkupLine($"[yellow]{text}[/]"); - break; - case LogLevel.Information: - _console.MarkupLine($"{text}"); - break; - case LogLevel.Verbose: - case LogLevel.Debug: - _console.MarkupLine($"[grey]{text}[/]"); - break; - } + return; } - public void Log(Verbosity verbosity, LogLevel level, string title, string text) + switch (level) { - if (verbosity > _verbosity) - { - return; - } - - switch (level) - { - case LogLevel.Fatal: - case LogLevel.Error: - WriteGrid($"[red]{title}[/]", $"[red]{text}[/]"); - break; - case LogLevel.Warning: - WriteGrid($"[yellow]{title}[/]", $"[red]{text}[/]"); - break; - case LogLevel.Information: - WriteGrid(title, text); - break; - case LogLevel.Verbose: - case LogLevel.Debug: - WriteGrid($"[grey]{title}[/]", $"[grey]{text}[/]"); - break; - } + case LogLevel.Fatal: + case LogLevel.Error: + WriteGrid($"[red]{title}[/]", $"[red]{text}[/]"); + break; + case LogLevel.Warning: + WriteGrid($"[yellow]{title}[/]", $"[red]{text}[/]"); + break; + case LogLevel.Information: + WriteGrid(title, text); + break; + case LogLevel.Verbose: + case LogLevel.Debug: + WriteGrid($"[grey]{title}[/]", $"[grey]{text}[/]"); + break; } + } - private void WriteGrid(string title, string text) - { - _console.Write(new Grid() - .AddColumn(new GridColumn().PadRight(1)) - .AddColumn() - .AddRow(title, text)); - } + private void WriteGrid(string title, string text) + { + _console.Write(new Grid() + .AddColumn(new GridColumn().PadRight(1)) + .AddColumn() + .AddRow(title, text)); } } diff --git a/src/Cupboard/EnvironmentRefresher.cs b/src/Cupboard/EnvironmentRefresher.cs index e013217..a4be523 100644 --- a/src/Cupboard/EnvironmentRefresher.cs +++ b/src/Cupboard/EnvironmentRefresher.cs @@ -3,55 +3,54 @@ using System.Runtime.InteropServices; using Microsoft.Win32; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal class EnvironmentRefresher : IEnvironmentRefresher { - internal class EnvironmentRefresher : IEnvironmentRefresher + public void Refresh() { - public void Refresh() + if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) - { - return; - } + return; + } - var roots = new[] - { - Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"), - Registry.CurrentUser.OpenSubKey("Environment"), - }; + var roots = new[] + { + Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"), + Registry.CurrentUser.OpenSubKey("Environment"), + }; - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var root in roots) + foreach (var root in roots) + { + if (root == null) { - if (root == null) - { - continue; - } + continue; + } - var keys = root.GetValueNames(); - if (keys != null) + var keys = root.GetValueNames(); + if (keys != null) + { + foreach (var key in keys) { - foreach (var key in keys) + if (key.Equals("PATH", StringComparison.OrdinalIgnoreCase)) + { + result.TryGetValue(key, out var path); + path ??= string.Empty; + result[key] = (path + ";" + root.GetValue(key)?.ToString() ?? string.Empty).TrimStart(';'); + } + else { - if (key.Equals("PATH", StringComparison.OrdinalIgnoreCase)) - { - result.TryGetValue(key, out var path); - path ??= string.Empty; - result[key] = (path + ";" + root.GetValue(key)?.ToString() ?? string.Empty).TrimStart(';'); - } - else - { - result[key] = root.GetValue(key)?.ToString() ?? string.Empty; - } + result[key] = root.GetValue(key)?.ToString() ?? string.Empty; } } } + } - foreach (var envVar in result) - { - System.Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); - } + foreach (var envVar in result) + { + System.Environment.SetEnvironmentVariable(envVar.Key, envVar.Value, EnvironmentVariableTarget.Process); } } } diff --git a/src/Cupboard/ExecutionAction.cs b/src/Cupboard/ExecutionAction.cs index 06aea4c..7bac473 100644 --- a/src/Cupboard/ExecutionAction.cs +++ b/src/Cupboard/ExecutionAction.cs @@ -1,9 +1,8 @@ -namespace Cupboard +namespace Cupboard; + +public enum ExecutionAction { - public enum ExecutionAction - { - Run = 0, - Skip = 1, - Abort = 2, - } + Run = 0, + Skip = 1, + Abort = 2, } diff --git a/src/Cupboard/ExecutionEngine.cs b/src/Cupboard/ExecutionEngine.cs index c3a46e7..8d38c2e 100644 --- a/src/Cupboard/ExecutionEngine.cs +++ b/src/Cupboard/ExecutionEngine.cs @@ -3,158 +3,157 @@ using System.Threading.Tasks; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ExecutionEngine { - internal sealed class ExecutionEngine + private readonly IFactBuilder _factBuilder; + private readonly ExecutionPlanBuilder _executionPlanBuilder; + private readonly ISecurityPrincipal _security; + private readonly IRebootDetector _reboot; + private readonly List _specifications; + private readonly List _manifests; + private readonly ICupboardLogger _logger; + private readonly IReportSubscriber? _subscriber; + + public ExecutionEngine( + IFactBuilder factBuilder, + IEnumerable specifications, + IEnumerable manifests, + ExecutionPlanBuilder executionPlanBuilder, + ISecurityPrincipal security, + IRebootDetector reboot, + ICupboardLogger logger, + IReportSubscriber? subscriber = null) { - private readonly IFactBuilder _factBuilder; - private readonly ExecutionPlanBuilder _executionPlanBuilder; - private readonly ISecurityPrincipal _security; - private readonly IRebootDetector _reboot; - private readonly List _specifications; - private readonly List _manifests; - private readonly ICupboardLogger _logger; - private readonly IReportSubscriber? _subscriber; - - public ExecutionEngine( - IFactBuilder factBuilder, - IEnumerable specifications, - IEnumerable manifests, - ExecutionPlanBuilder executionPlanBuilder, - ISecurityPrincipal security, - IRebootDetector reboot, - ICupboardLogger logger, - IReportSubscriber? subscriber = null) - { - _factBuilder = factBuilder ?? throw new ArgumentNullException(nameof(factBuilder)); - _executionPlanBuilder = executionPlanBuilder ?? throw new ArgumentNullException(nameof(executionPlanBuilder)); - _security = security ?? throw new ArgumentNullException(nameof(security)); - _reboot = reboot ?? throw new ArgumentNullException(nameof(reboot)); - _specifications = new List(specifications ?? Array.Empty()); - _manifests = new List(manifests ?? Array.Empty()); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _subscriber = subscriber; - } + _factBuilder = factBuilder ?? throw new ArgumentNullException(nameof(factBuilder)); + _executionPlanBuilder = executionPlanBuilder ?? throw new ArgumentNullException(nameof(executionPlanBuilder)); + _security = security ?? throw new ArgumentNullException(nameof(security)); + _reboot = reboot ?? throw new ArgumentNullException(nameof(reboot)); + _specifications = new List(specifications ?? Array.Empty()); + _manifests = new List(manifests ?? Array.Empty()); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _subscriber = subscriber; + } - public async Task Run( - IRemainingArguments args, - IStatusUpdater status, - IExecutionController controller, - bool dryRun, bool ignoreReboots) - { - var facts = _factBuilder.Build(args); + public async Task Run( + IRemainingArguments args, + IStatusUpdater status, + IExecutionController controller, + bool dryRun, bool ignoreReboots) + { + var facts = _factBuilder.Build(args); - // Build and execute the plan - var plan = _executionPlanBuilder.Build(_specifications, _manifests, _factBuilder, args); - var report = await ExecutePlan(plan, facts, status, controller, dryRun, ignoreReboots).ConfigureAwait(false); + // Build and execute the plan + var plan = _executionPlanBuilder.Build(_specifications, _manifests, _factBuilder, args); + var report = await ExecutePlan(plan, facts, status, controller, dryRun, ignoreReboots).ConfigureAwait(false); - // Notify any subscribers about the plan - _subscriber?.Notify(report); + // Notify any subscribers about the plan + _subscriber?.Notify(report); - return report; + return report; + } + + private async Task ExecutePlan( + ExecutionPlan plan, FactCollection facts, + IStatusUpdater status, + IExecutionController controller, + bool dryRun, bool ignoreReboots) + { + var pendingReboot = _reboot.HasPendingReboot(); + + if (plan.Count == 0) + { + return new Report(Array.Empty(), facts, plan.RequiresAdministrator, dryRun, pendingReboot); } - private async Task ExecutePlan( - ExecutionPlan plan, FactCollection facts, - IStatusUpdater status, - IExecutionController controller, - bool dryRun, bool ignoreReboots) + // Do we need administrator privileges? + // Make sure we're running with elevated permissions + if (!dryRun && plan.RequiresAdministrator && !_security.IsAdministrator()) { - var pendingReboot = _reboot.HasPendingReboot(); + throw new InvalidOperationException("Not running as administrator"); + } - if (plan.Count == 0) - { - return new Report(Array.Empty(), facts, plan.RequiresAdministrator, dryRun, pendingReboot); - } + // Is there a pending reboot? + if (!dryRun && pendingReboot && !ignoreReboots) + { + throw new InvalidOperationException("A pending reboot have been detected"); + } - // Do we need administrator privileges? - // Make sure we're running with elevated permissions - if (!dryRun && plan.RequiresAdministrator && !_security.IsAdministrator()) - { - throw new InvalidOperationException("Not running as administrator"); - } + // Create the execution context + var context = new ExecutionContext(facts) + { + DryRun = dryRun, + }; - // Is there a pending reboot? - if (!dryRun && pendingReboot && !ignoreReboots) + var results = new List(); + foreach (var node in plan) + { + if (context.DryRun) { - throw new InvalidOperationException("A pending reboot have been detected"); + results.Add(new ReportItem(node.Provider, node.Resource, ResourceState.Unknown, node.RequireAdministrator)); } - - // Create the execution context - var context = new ExecutionContext(facts) + else { - DryRun = dryRun, - }; - - var results = new List(); - foreach (var node in plan) - { - if (context.DryRun) + var request = controller.GetAction(node.Provider, node.Resource); + if (request == ExecutionAction.Skip) { - results.Add(new ReportItem(node.Provider, node.Resource, ResourceState.Unknown, node.RequireAdministrator)); + _logger.Error("[yellow]Skipping resource[/]"); + results.Add(new ReportItem(node.Provider, node.Resource, ResourceState.ManuallySkipped, node.RequireAdministrator)); + continue; } - else + else if (request == ExecutionAction.Abort) + { + _logger.Error("Aborting run"); + break; + } + + var result = await status.Update($"Executing [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]", async () => { - var request = controller.GetAction(node.Provider, node.Resource); - if (request == ExecutionAction.Skip) + _logger.Verbose($"Executing [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]"); + + // Abort if we cannot run a provider + if (!node.Provider.CanRun(facts)) { - _logger.Error("[yellow]Skipping resource[/]"); - results.Add(new ReportItem(node.Provider, node.Resource, ResourceState.ManuallySkipped, node.RequireAdministrator)); - continue; + _logger.Error($"The resource [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/] cannot be run"); + return false; } - else if (request == ExecutionAction.Abort) + + // Run the provider + var state = await node.Provider.RunAsync(context, node.Resource).ConfigureAwait(false); + results.Add(new ReportItem(node.Provider, node.Resource, state, node.RequireAdministrator)); + + if (state.IsError() && node.Resource.Error != ErrorOptions.IgnoreErrors) { - _logger.Error("Aborting run"); - break; + _logger.Error($"Aborting run due to error in [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]"); + return false; } - var result = await status.Update($"Executing [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]", async () => + // Pending reboot? + if (_reboot.HasPendingReboot()) { - _logger.Verbose($"Executing [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]"); - - // Abort if we cannot run a provider - if (!node.Provider.CanRun(facts)) - { - _logger.Error($"The resource [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/] cannot be run"); - return false; - } - - // Run the provider - var state = await node.Provider.RunAsync(context, node.Resource).ConfigureAwait(false); - results.Add(new ReportItem(node.Provider, node.Resource, state, node.RequireAdministrator)); - - if (state.IsError() && node.Resource.Error != ErrorOptions.IgnoreErrors) + if (!pendingReboot) { - _logger.Error($"Aborting run due to error in [green]{node.Provider.ResourceType.Name}[/]::[blue]{node.Resource.Name}[/]"); - return false; + _logger.Warning("A pending reboot has been detected"); } - // Pending reboot? - if (_reboot.HasPendingReboot()) + pendingReboot = true; + if (node.Resource.Reboot != RebootOptions.IgnorePendingReboot) { - if (!pendingReboot) - { - _logger.Warning("A pending reboot has been detected"); - } - - pendingReboot = true; - if (node.Resource.Reboot != RebootOptions.IgnorePendingReboot) + if (!ignoreReboots) { - if (!ignoreReboots) - { - _logger.Information("Aborting due to pending reboot."); - return false; - } + _logger.Information("Aborting due to pending reboot."); + return false; } } + } - return true; - }).ConfigureAwait(false); - } + return true; + }).ConfigureAwait(false); } - - _logger.Debug("Execution done."); - return new Report(results, facts, plan.RequiresAdministrator, context.DryRun, pendingReboot); } + + _logger.Debug("Execution done."); + return new Report(results, facts, plan.RequiresAdministrator, context.DryRun, pendingReboot); } } diff --git a/src/Cupboard/ExecutionPlan.cs b/src/Cupboard/ExecutionPlan.cs index 2ff62a3..4051378 100644 --- a/src/Cupboard/ExecutionPlan.cs +++ b/src/Cupboard/ExecutionPlan.cs @@ -1,31 +1,30 @@ using System.Collections; using System.Collections.Generic; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ExecutionPlan : IEnumerable { - internal sealed class ExecutionPlan : IEnumerable - { - private readonly IReadOnlyList _resources; + private readonly IReadOnlyList _resources; - public bool RequiresAdministrator { get; } - public int Count => _resources.Count; + public bool RequiresAdministrator { get; } + public int Count => _resources.Count; - public ExecutionPlan( - IEnumerable resources, - bool requiresAdministrator) - { - _resources = resources.ToReadOnlyList(); - RequiresAdministrator = requiresAdministrator; - } + public ExecutionPlan( + IEnumerable resources, + bool requiresAdministrator) + { + _resources = resources.ToReadOnlyList(); + RequiresAdministrator = requiresAdministrator; + } - public IEnumerator GetEnumerator() - { - return _resources.GetEnumerator(); - } + public IEnumerator GetEnumerator() + { + return _resources.GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); } } diff --git a/src/Cupboard/ExecutionPlanBuilder.cs b/src/Cupboard/ExecutionPlanBuilder.cs index 03b726d..c516c47 100644 --- a/src/Cupboard/ExecutionPlanBuilder.cs +++ b/src/Cupboard/ExecutionPlanBuilder.cs @@ -3,86 +3,85 @@ using System.Linq; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ExecutionPlanBuilder { - internal sealed class ExecutionPlanBuilder - { - private readonly ResourceProviderRepository _providers; + private readonly ResourceProviderRepository _providers; - public ExecutionPlanBuilder(ResourceProviderRepository providers) - { - _providers = providers ?? throw new ArgumentNullException(nameof(providers)); - } + public ExecutionPlanBuilder(ResourceProviderRepository providers) + { + _providers = providers ?? throw new ArgumentNullException(nameof(providers)); + } - public ExecutionPlan Build( - IEnumerable catalogs, - IEnumerable manifests, - IFactBuilder factBuilder, - IRemainingArguments args) - { - // Build facts - var facts = factBuilder.Build(args); + public ExecutionPlan Build( + IEnumerable catalogs, + IEnumerable manifests, + IFactBuilder factBuilder, + IRemainingArguments args) + { + // Build facts + var facts = factBuilder.Build(args); - // Get all manifests added by catalogs - var catalogManifests = GetCatalogManifests(catalogs, manifests, facts); + // Get all manifests added by catalogs + var catalogManifests = GetCatalogManifests(catalogs, manifests, facts); - // Build the resource graph - var graph = ResourceGraphBuilder.Build(_providers, catalogManifests, facts); - graph.Configurations.ForEach(action => action()); + // Build the resource graph + var graph = ResourceGraphBuilder.Build(_providers, catalogManifests, facts); + graph.Configurations.ForEach(action => action()); - // Build the execution plan - return Build(graph, facts); - } + // Build the execution plan + return Build(graph, facts); + } - private static IEnumerable GetCatalogManifests( - IEnumerable catalogs, - IEnumerable manifests, - FactCollection facts) + private static IEnumerable GetCatalogManifests( + IEnumerable catalogs, + IEnumerable manifests, + FactCollection facts) + { + // Execute all catalogs + var ctx = new CatalogContext(facts); + foreach (var catalog in catalogs) { - // Execute all catalogs - var ctx = new CatalogContext(facts); - foreach (var catalog in catalogs) + if (catalog.CanRun(facts)) { - if (catalog.CanRun(facts)) - { - catalog.Execute(ctx); - } + catalog.Execute(ctx); } - - var catalogManifests = ctx.GetManifests(); - return manifests.Where(x => catalogManifests.Contains(x.GetType())); } - private ExecutionPlan Build(ResourceGraph graph, FactCollection facts) + var catalogManifests = ctx.GetManifests(); + return manifests.Where(x => catalogManifests.Contains(x.GetType())); + } + + private ExecutionPlan Build(ResourceGraph graph, FactCollection facts) + { + var resources = new List(); + + foreach (var node in graph.Traverse()) { - var resources = new List(); + // Find the resource. + var resource = graph.Resources.SingleOrDefault(x => x.Name == node.Name); + if (resource == null) + { + throw new InvalidOperationException($"Could not find resource '{node.Name}' ({node.ResourceType.Name})."); + } - foreach (var node in graph.Traverse()) + // Get the provider. + var provider = _providers.GetProvider(resource.ResourceType); + if (provider == null) { - // Find the resource. - var resource = graph.Resources.SingleOrDefault(x => x.Name == node.Name); - if (resource == null) - { - throw new InvalidOperationException($"Could not find resource '{node.Name}' ({node.ResourceType.Name})."); - } - - // Get the provider. - var provider = _providers.GetProvider(resource.ResourceType); - if (provider == null) - { - throw new InvalidOperationException($"Could not find resource provider for '{node.Name}' ({node.ResourceType.Name})."); - } - - // Do we need to be administrator for this resource? - var requireAdministrator = resource.RequireAdministrator || provider.RequireAdministrator(facts); - - resources.Add(new ExecutionPlanItem(provider, resource, requireAdministrator)); + throw new InvalidOperationException($"Could not find resource provider for '{node.Name}' ({node.ResourceType.Name})."); } - // Do we need to be administrator for this plan? - var requiresAdministrator = resources.Any(item => item.RequireAdministrator); + // Do we need to be administrator for this resource? + var requireAdministrator = resource.RequireAdministrator || provider.RequireAdministrator(facts); - return new ExecutionPlan(resources, requiresAdministrator); + resources.Add(new ExecutionPlanItem(provider, resource, requireAdministrator)); } + + // Do we need to be administrator for this plan? + var requiresAdministrator = resources.Any(item => item.RequireAdministrator); + + return new ExecutionPlan(resources, requiresAdministrator); } } diff --git a/src/Cupboard/ExecutionPlanItem.cs b/src/Cupboard/ExecutionPlanItem.cs index c16aaca..05145c9 100644 --- a/src/Cupboard/ExecutionPlanItem.cs +++ b/src/Cupboard/ExecutionPlanItem.cs @@ -1,18 +1,17 @@ using System; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ExecutionPlanItem { - internal sealed class ExecutionPlanItem - { - public IResourceProvider Provider { get; } - public Resource Resource { get; } - public bool RequireAdministrator { get; } + public IResourceProvider Provider { get; } + public Resource Resource { get; } + public bool RequireAdministrator { get; } - public ExecutionPlanItem(IResourceProvider provider, Resource resource, bool requireAdministrator) - { - Provider = provider ?? throw new ArgumentNullException(nameof(provider)); - Resource = resource ?? throw new ArgumentNullException(nameof(resource)); - RequireAdministrator = requireAdministrator; - } + public ExecutionPlanItem(IResourceProvider provider, Resource resource, bool requireAdministrator) + { + Provider = provider ?? throw new ArgumentNullException(nameof(provider)); + Resource = resource ?? throw new ArgumentNullException(nameof(resource)); + RequireAdministrator = requireAdministrator; } } diff --git a/src/Cupboard/Extensions/IAnsiConsoleExtensions.cs b/src/Cupboard/Extensions/IAnsiConsoleExtensions.cs index c894325..13a3151 100644 --- a/src/Cupboard/Extensions/IAnsiConsoleExtensions.cs +++ b/src/Cupboard/Extensions/IAnsiConsoleExtensions.cs @@ -1,16 +1,15 @@ using Spectre.Console; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal static class IAnsiConsoleExtensions { - internal static class IAnsiConsoleExtensions + public static bool Confirm(this IAnsiConsole console, string markup, bool defaultValue = true) { - public static bool Confirm(this IAnsiConsole console, string markup, bool defaultValue = true) + return new ConfirmationPrompt(markup) { - return new ConfirmationPrompt(markup) - { - DefaultValue = defaultValue, - } - .Show(console); + DefaultValue = defaultValue, } + .Show(console); } } diff --git a/src/Cupboard/Extensions/RegistryKeyValueKindExtensions.cs b/src/Cupboard/Extensions/RegistryKeyValueKindExtensions.cs index 504232c..12f6aaa 100644 --- a/src/Cupboard/Extensions/RegistryKeyValueKindExtensions.cs +++ b/src/Cupboard/Extensions/RegistryKeyValueKindExtensions.cs @@ -1,26 +1,25 @@ using System; using System.Diagnostics.CodeAnalysis; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +[Obsolete("Please use RegistryValueKindExtensions instead")] +internal static class RegistryKeyValueKindExtensions { - [Obsolete("Please use RegistryValueKindExtensions instead")] - internal static class RegistryKeyValueKindExtensions + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] + public static Microsoft.Win32.RegistryValueKind ToWin32(this RegistryKeyValueKind type) { - [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] - public static Microsoft.Win32.RegistryValueKind ToWin32(this RegistryKeyValueKind type) + return type switch { - return type switch - { - RegistryKeyValueKind.None => Microsoft.Win32.RegistryValueKind.None, - RegistryKeyValueKind.Unknown => Microsoft.Win32.RegistryValueKind.Unknown, - RegistryKeyValueKind.String => Microsoft.Win32.RegistryValueKind.String, - RegistryKeyValueKind.ExpandString => Microsoft.Win32.RegistryValueKind.ExpandString, - RegistryKeyValueKind.Binary => Microsoft.Win32.RegistryValueKind.Binary, - RegistryKeyValueKind.DWord => Microsoft.Win32.RegistryValueKind.DWord, - RegistryKeyValueKind.MultiString => Microsoft.Win32.RegistryValueKind.MultiString, - RegistryKeyValueKind.QWord => Microsoft.Win32.RegistryValueKind.QWord, - _ => Microsoft.Win32.RegistryValueKind.Unknown, - }; - } + RegistryKeyValueKind.None => Microsoft.Win32.RegistryValueKind.None, + RegistryKeyValueKind.Unknown => Microsoft.Win32.RegistryValueKind.Unknown, + RegistryKeyValueKind.String => Microsoft.Win32.RegistryValueKind.String, + RegistryKeyValueKind.ExpandString => Microsoft.Win32.RegistryValueKind.ExpandString, + RegistryKeyValueKind.Binary => Microsoft.Win32.RegistryValueKind.Binary, + RegistryKeyValueKind.DWord => Microsoft.Win32.RegistryValueKind.DWord, + RegistryKeyValueKind.MultiString => Microsoft.Win32.RegistryValueKind.MultiString, + RegistryKeyValueKind.QWord => Microsoft.Win32.RegistryValueKind.QWord, + _ => Microsoft.Win32.RegistryValueKind.Unknown, + }; } } diff --git a/src/Cupboard/Extensions/RegistryValueKindExtensions.cs b/src/Cupboard/Extensions/RegistryValueKindExtensions.cs index 920d9b6..8500fa0 100644 --- a/src/Cupboard/Extensions/RegistryValueKindExtensions.cs +++ b/src/Cupboard/Extensions/RegistryValueKindExtensions.cs @@ -1,24 +1,23 @@ using System.Diagnostics.CodeAnalysis; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal static class RegistryValueKindExtensions { - internal static class RegistryValueKindExtensions + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] + public static Microsoft.Win32.RegistryValueKind ToWin32(this RegistryValueKind type) { - [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] - public static Microsoft.Win32.RegistryValueKind ToWin32(this RegistryValueKind type) + return type switch { - return type switch - { - RegistryValueKind.None => Microsoft.Win32.RegistryValueKind.None, - RegistryValueKind.Unknown => Microsoft.Win32.RegistryValueKind.Unknown, - RegistryValueKind.String => Microsoft.Win32.RegistryValueKind.String, - RegistryValueKind.ExpandString => Microsoft.Win32.RegistryValueKind.ExpandString, - RegistryValueKind.Binary => Microsoft.Win32.RegistryValueKind.Binary, - RegistryValueKind.DWord => Microsoft.Win32.RegistryValueKind.DWord, - RegistryValueKind.MultiString => Microsoft.Win32.RegistryValueKind.MultiString, - RegistryValueKind.QWord => Microsoft.Win32.RegistryValueKind.QWord, - _ => Microsoft.Win32.RegistryValueKind.Unknown, - }; - } + RegistryValueKind.None => Microsoft.Win32.RegistryValueKind.None, + RegistryValueKind.Unknown => Microsoft.Win32.RegistryValueKind.Unknown, + RegistryValueKind.String => Microsoft.Win32.RegistryValueKind.String, + RegistryValueKind.ExpandString => Microsoft.Win32.RegistryValueKind.ExpandString, + RegistryValueKind.Binary => Microsoft.Win32.RegistryValueKind.Binary, + RegistryValueKind.DWord => Microsoft.Win32.RegistryValueKind.DWord, + RegistryValueKind.MultiString => Microsoft.Win32.RegistryValueKind.MultiString, + RegistryValueKind.QWord => Microsoft.Win32.RegistryValueKind.QWord, + _ => Microsoft.Win32.RegistryValueKind.Unknown, + }; } } diff --git a/src/Cupboard/Extensions/ServiceCollectionExtensions.cs b/src/Cupboard/Extensions/ServiceCollectionExtensions.cs index 42963ba..0fae83d 100644 --- a/src/Cupboard/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cupboard/Extensions/ServiceCollectionExtensions.cs @@ -5,77 +5,76 @@ using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Cupboard +namespace Cupboard; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddModule(this IServiceCollection services) + where T : ServiceModule, new() { - public static IServiceCollection AddModule(this IServiceCollection services) - where T : ServiceModule, new() + if (services is null) { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - var module = new T(); - module.Configure(services); - return services; + throw new ArgumentNullException(nameof(services)); } - internal static IServiceCollection AddAll(this IServiceCollection services, Assembly? assembly = null) - { - var serviceType = typeof(TService); - var isInterface = serviceType.IsInterface; + var module = new T(); + module.Configure(services); + return services; + } + + internal static IServiceCollection AddAll(this IServiceCollection services, Assembly? assembly = null) + { + var serviceType = typeof(TService); + var isInterface = serviceType.IsInterface; - var assemblies = assembly != null - ? new Assembly[] { assembly } - : AppDomain.CurrentDomain.GetAssemblies(); + var assemblies = assembly != null + ? new Assembly[] { assembly } + : AppDomain.CurrentDomain.GetAssemblies(); - foreach (var type in assemblies.SelectMany(assembly => assembly.GetTypes())) + foreach (var type in assemblies.SelectMany(assembly => assembly.GetTypes())) + { + if (isInterface && type.IsInterface) { - if (isInterface && type.IsInterface) - { - continue; - } + continue; + } - if (!type.IsAbstract && serviceType.IsAssignableFrom(type)) + if (!type.IsAbstract && serviceType.IsAssignableFrom(type)) + { + if (!services.Any(x => x.ImplementationType == type)) { - if (!services.Any(x => x.ImplementationType == type)) - { - services.AddSingleton(serviceType, type); - } + services.AddSingleton(serviceType, type); } } - - return services; } - internal static IServiceCollection AddCommandLine( - this IServiceCollection services, - Action configurator) - { - var app = new CommandApp(new TypeRegistrar(services)); - app.Configure(configurator); - services.AddSingleton(app); - - return services; - } + return services; + } - internal static IServiceCollection AddCommandLine( - this IServiceCollection services, - Action? configurator = null) - where TCommand : class, ICommand - { - var app = new CommandApp(new TypeRegistrar(services)); + internal static IServiceCollection AddCommandLine( + this IServiceCollection services, + Action configurator) + { + var app = new CommandApp(new TypeRegistrar(services)); + app.Configure(configurator); + services.AddSingleton(app); - if (configurator != null) - { - app.Configure(configurator); - } + return services; + } - services.AddSingleton(app); + internal static IServiceCollection AddCommandLine( + this IServiceCollection services, + Action? configurator = null) + where TCommand : class, ICommand + { + var app = new CommandApp(new TypeRegistrar(services)); - return services; + if (configurator != null) + { + app.Configure(configurator); } + + services.AddSingleton(app); + + return services; } } diff --git a/src/Cupboard/FactBuilder.cs b/src/Cupboard/FactBuilder.cs index da8c5f8..9755760 100644 --- a/src/Cupboard/FactBuilder.cs +++ b/src/Cupboard/FactBuilder.cs @@ -1,29 +1,28 @@ using System.Collections.Generic; using Spectre.Console.Cli; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class FactBuilder : IFactBuilder { - internal sealed class FactBuilder : IFactBuilder - { - private readonly IReadOnlyList _providers; + private readonly IReadOnlyList _providers; - public FactBuilder(IEnumerable providers) - { - _providers = providers.ToReadOnlyList(); - } + public FactBuilder(IEnumerable providers) + { + _providers = providers.ToReadOnlyList(); + } - public FactCollection Build(IRemainingArguments args) + public FactCollection Build(IRemainingArguments args) + { + var facts = new FactCollection(); + foreach (var provider in _providers) { - var facts = new FactCollection(); - foreach (var provider in _providers) + foreach (var (name, value) in provider.GetFacts(args)) { - foreach (var (name, value) in provider.GetFacts(args)) - { - facts.Add(name, value ?? string.Empty); - } + facts.Add(name, value ?? string.Empty); } - - return facts; } + + return facts; } } diff --git a/src/Cupboard/IExecutionController.cs b/src/Cupboard/IExecutionController.cs index e4f35da..42468f7 100644 --- a/src/Cupboard/IExecutionController.cs +++ b/src/Cupboard/IExecutionController.cs @@ -1,56 +1,55 @@ using System; using Spectre.Console; -namespace Cupboard +namespace Cupboard; + +public interface IExecutionController +{ + ExecutionAction GetAction(IResourceProvider provider, Resource resource); +} + +internal sealed class DefaultExecutionController : IExecutionController { - public interface IExecutionController + public ExecutionAction GetAction(IResourceProvider provider, Resource resource) { - ExecutionAction GetAction(IResourceProvider provider, Resource resource); + return ExecutionAction.Run; } +} + +internal sealed class InteractiveExecutionController : IExecutionController +{ + private readonly IAnsiConsole _console; - internal sealed class DefaultExecutionController : IExecutionController + public InteractiveExecutionController(IAnsiConsole console) { - public ExecutionAction GetAction(IResourceProvider provider, Resource resource) - { - return ExecutionAction.Run; - } + _console = console ?? throw new ArgumentNullException(nameof(console)); } - internal sealed class InteractiveExecutionController : IExecutionController + public ExecutionAction GetAction(IResourceProvider provider, Resource resource) { - private readonly IAnsiConsole _console; + var name = $"[green]{provider.ResourceType.Name.EscapeMarkup()}[/]::[blue]{resource.Name.EscapeMarkup()}[/]"; + var prompt = new TextPrompt($"Do you want to run {name}?") + .InvalidChoiceMessage("[red]Please select one of the available options[/]") + .ValidationErrorMessage("[red]Please select one of the available options[/]") + .ShowChoices(true) + .ShowDefaultValue() + .DefaultValue("n") + .AddChoice("y") + .AddChoice("n") + .AddChoice("a"); - public InteractiveExecutionController(IAnsiConsole console) + var result = prompt.Show(_console); + if (result.Equals("y")) { - _console = console ?? throw new ArgumentNullException(nameof(console)); + return ExecutionAction.Run; } - - public ExecutionAction GetAction(IResourceProvider provider, Resource resource) + else if (result.Equals("a")) { - var name = $"[green]{provider.ResourceType.Name.EscapeMarkup()}[/]::[blue]{resource.Name.EscapeMarkup()}[/]"; - var prompt = new TextPrompt($"Do you want to run {name}?") - .InvalidChoiceMessage("[red]Please select one of the available options[/]") - .ValidationErrorMessage("[red]Please select one of the available options[/]") - .ShowChoices(true) - .ShowDefaultValue() - .DefaultValue("n") - .AddChoice("y") - .AddChoice("n") - .AddChoice("a"); - - var result = prompt.Show(_console); - if (result.Equals("y")) - { - return ExecutionAction.Run; - } - else if (result.Equals("a")) - { - return ExecutionAction.Abort; - } - else - { - return ExecutionAction.Skip; - } + return ExecutionAction.Abort; + } + else + { + return ExecutionAction.Skip; } } } diff --git a/src/Cupboard/IO/CupboardEnvironment.cs b/src/Cupboard/IO/CupboardEnvironment.cs index 1ee497f..e119243 100644 --- a/src/Cupboard/IO/CupboardEnvironment.cs +++ b/src/Cupboard/IO/CupboardEnvironment.cs @@ -1,39 +1,38 @@ using System.Collections.Generic; using Spectre.IO; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class CupboardEnvironment : ICupboardEnvironment { - internal sealed class CupboardEnvironment : ICupboardEnvironment + private readonly IEnvironment _environment; + + public DirectoryPath WorkingDirectory => _environment.WorkingDirectory; + public DirectoryPath HomeDirectory => _environment.HomeDirectory; + public IPlatform Platform => _environment.Platform; + + public CupboardEnvironment(IPlatform platform) + { + _environment = new Spectre.IO.Environment(platform); + } + + public string? GetEnvironmentVariable(string variable) + { + return _environment.GetEnvironmentVariable(variable); + } + + public IDictionary GetEnvironmentVariables() + { + return _environment.GetEnvironmentVariables(); + } + + public void SetWorkingDirectory(DirectoryPath path) + { + _environment.SetWorkingDirectory(path); + } + + public FilePath GetTempFilePath() { - private readonly IEnvironment _environment; - - public DirectoryPath WorkingDirectory => _environment.WorkingDirectory; - public DirectoryPath HomeDirectory => _environment.HomeDirectory; - public IPlatform Platform => _environment.Platform; - - public CupboardEnvironment(IPlatform platform) - { - _environment = new Spectre.IO.Environment(platform); - } - - public string? GetEnvironmentVariable(string variable) - { - return _environment.GetEnvironmentVariable(variable); - } - - public IDictionary GetEnvironmentVariables() - { - return _environment.GetEnvironmentVariables(); - } - - public void SetWorkingDirectory(DirectoryPath path) - { - _environment.SetWorkingDirectory(path); - } - - public FilePath GetTempFilePath() - { - return new FilePath(System.IO.Path.GetTempFileName()).MakeAbsolute(this); - } + return new FilePath(System.IO.Path.GetTempFileName()).MakeAbsolute(this); } } diff --git a/src/Cupboard/IO/CupboardFileSystem.cs b/src/Cupboard/IO/CupboardFileSystem.cs index 237c030..d08ffef 100644 --- a/src/Cupboard/IO/CupboardFileSystem.cs +++ b/src/Cupboard/IO/CupboardFileSystem.cs @@ -1,17 +1,16 @@ using Spectre.IO; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class CupboardFileSystem : ICupboardFileSystem { - internal sealed class CupboardFileSystem : ICupboardFileSystem - { - private readonly IFileSystem _fileSystem; + private readonly IFileSystem _fileSystem; - public IFileProvider File => _fileSystem.File; - public IDirectoryProvider Directory => _fileSystem.Directory; + public IFileProvider File => _fileSystem.File; + public IDirectoryProvider Directory => _fileSystem.Directory; - public CupboardFileSystem() - { - _fileSystem = new FileSystem(); - } + public CupboardFileSystem() + { + _fileSystem = new FileSystem(); } } diff --git a/src/Cupboard/IO/ProcessRunner.cs b/src/Cupboard/IO/ProcessRunner.cs index 4c62a9c..a2710f8 100644 --- a/src/Cupboard/IO/ProcessRunner.cs +++ b/src/Cupboard/IO/ProcessRunner.cs @@ -5,61 +5,60 @@ using CliWrap.EventStream; using Spectre.Console; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ProcessRunner : IProcessRunner { - internal sealed class ProcessRunner : IProcessRunner + private readonly ICupboardLogger _logger; + + public ProcessRunner(ICupboardLogger logger) { - private readonly ICupboardLogger _logger; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } - public ProcessRunner(ICupboardLogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + public async Task Run(string file, string? arguments = null, Func? filter = null, bool supressOutput = false) + { + var cli = Cli.Wrap(file); + cli = cli.WithValidation(CommandResultValidation.None); - public async Task Run(string file, string? arguments = null, Func? filter = null, bool supressOutput = false) + if (arguments != null) { - var cli = Cli.Wrap(file); - cli = cli.WithValidation(CommandResultValidation.None); - - if (arguments != null) - { - cli = cli.WithArguments(arguments); - } + cli = cli.WithArguments(arguments); + } - var standardOut = new StringBuilder(); - var standardError = new StringBuilder(); - var exitCode = -1; + var standardOut = new StringBuilder(); + var standardError = new StringBuilder(); + var exitCode = -1; - await foreach (var cmdEvent in cli.ListenAsync()) + await foreach (var cmdEvent in cli.ListenAsync()) + { + switch (cmdEvent) { - switch (cmdEvent) - { - case StandardOutputCommandEvent output: - standardOut.Append(output.Text); - if (!supressOutput && !string.IsNullOrWhiteSpace(output.Text) && (filter?.Invoke(output.Text) ?? true)) - { - _logger.Verbose("OUT>", output.Text.EscapeMarkup().TrimStart()); - } + case StandardOutputCommandEvent output: + standardOut.Append(output.Text); + if (!supressOutput && !string.IsNullOrWhiteSpace(output.Text) && (filter?.Invoke(output.Text) ?? true)) + { + _logger.Verbose("OUT>", output.Text.EscapeMarkup().TrimStart()); + } - break; - case StandardErrorCommandEvent error: - if (!supressOutput && !string.IsNullOrWhiteSpace(error.Text) && (filter?.Invoke(error.Text) ?? true)) - { - _logger.Error("ERR>", error.Text.EscapeMarkup().TrimStart()); - } + break; + case StandardErrorCommandEvent error: + if (!supressOutput && !string.IsNullOrWhiteSpace(error.Text) && (filter?.Invoke(error.Text) ?? true)) + { + _logger.Error("ERR>", error.Text.EscapeMarkup().TrimStart()); + } - standardError.Append(error.Text); - break; - case ExitedCommandEvent exited: - exitCode = exited.ExitCode; - break; - } + standardError.Append(error.Text); + break; + case ExitedCommandEvent exited: + exitCode = exited.ExitCode; + break; } - - return new ProcessRunnerResult( - exitCode, - standardOut.ToString(), - standardError.ToString()); } + + return new ProcessRunnerResult( + exitCode, + standardOut.ToString(), + standardError.ToString()); } } diff --git a/src/Cupboard/IO/WindowsRegistry.cs b/src/Cupboard/IO/WindowsRegistry.cs index 17dca60..4c10a5e 100644 --- a/src/Cupboard/IO/WindowsRegistry.cs +++ b/src/Cupboard/IO/WindowsRegistry.cs @@ -1,16 +1,15 @@ using System.Diagnostics.CodeAnalysis; using Win32Registry = Microsoft.Win32.Registry; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] +internal sealed class WindowsRegistry : IWindowsRegistry { - [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] - internal sealed class WindowsRegistry : IWindowsRegistry - { - public IWindowsRegistryKey ClassesRoot => new WindowsRegistryKey(Win32Registry.ClassesRoot); - public IWindowsRegistryKey CurrentConfig => new WindowsRegistryKey(Win32Registry.CurrentConfig); - public IWindowsRegistryKey CurrentUser => new WindowsRegistryKey(Win32Registry.CurrentUser); - public IWindowsRegistryKey LocalMachine => new WindowsRegistryKey(Win32Registry.LocalMachine); - public IWindowsRegistryKey PerformanceData => new WindowsRegistryKey(Win32Registry.PerformanceData); - public IWindowsRegistryKey Users => new WindowsRegistryKey(Win32Registry.Users); - } + public IWindowsRegistryKey ClassesRoot => new WindowsRegistryKey(Win32Registry.ClassesRoot); + public IWindowsRegistryKey CurrentConfig => new WindowsRegistryKey(Win32Registry.CurrentConfig); + public IWindowsRegistryKey CurrentUser => new WindowsRegistryKey(Win32Registry.CurrentUser); + public IWindowsRegistryKey LocalMachine => new WindowsRegistryKey(Win32Registry.LocalMachine); + public IWindowsRegistryKey PerformanceData => new WindowsRegistryKey(Win32Registry.PerformanceData); + public IWindowsRegistryKey Users => new WindowsRegistryKey(Win32Registry.Users); } diff --git a/src/Cupboard/IO/WindowsRegistryKey.cs b/src/Cupboard/IO/WindowsRegistryKey.cs index 54f57a7..749fa66 100644 --- a/src/Cupboard/IO/WindowsRegistryKey.cs +++ b/src/Cupboard/IO/WindowsRegistryKey.cs @@ -3,64 +3,63 @@ using System.Linq; using Win32RegistryKey = Microsoft.Win32.RegistryKey; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] +internal sealed class WindowsRegistryKey : IWindowsRegistryKey { - [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] - internal sealed class WindowsRegistryKey : IWindowsRegistryKey + private readonly Win32RegistryKey _key; + + public WindowsRegistryKey(Win32RegistryKey key) { - private readonly Win32RegistryKey _key; + _key = key ?? throw new ArgumentNullException(nameof(key)); + } - public WindowsRegistryKey(Win32RegistryKey key) - { - _key = key ?? throw new ArgumentNullException(nameof(key)); - } + public IWindowsRegistryKey? CreateSubKey(string name, bool writable) + { + var key = _key.CreateSubKey(name, writable); + return new WindowsRegistryKey(key); + } - public IWindowsRegistryKey? CreateSubKey(string name, bool writable) - { - var key = _key.CreateSubKey(name, writable); - return new WindowsRegistryKey(key); - } + public int GetValueCount() + { + return _key.ValueCount; + } - public int GetValueCount() - { - return _key.ValueCount; - } + public void DeleteValue(string name) + { + _key.DeleteValue(name); + } - public void DeleteValue(string name) - { - _key.DeleteValue(name); - } + public bool ValueExists(string name) + { + return _key.GetValueNames().Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); + } - public bool ValueExists(string name) - { - return _key.GetValueNames().Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); - } + public object? GetValue(string name) + { + return _key.GetValue(name, null); + } - public object? GetValue(string name) + public IWindowsRegistryKey? OpenSubKey(string name, bool writable) + { + var key = _key.OpenSubKey(name, writable); + if (key == null) { - return _key.GetValue(name, null); + return null; } - public IWindowsRegistryKey? OpenSubKey(string name, bool writable) - { - var key = _key.OpenSubKey(name, writable); - if (key == null) - { - return null; - } - - return new WindowsRegistryKey(key); - } + return new WindowsRegistryKey(key); + } - [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] - public void SetValue(string name, object value, RegistryKeyValueKind kind) - { - _key.SetValue(name, value, kind.ToWin32()); - } + [Obsolete("Please use SetValue overload accepting a RegistryValueKind instead")] + public void SetValue(string name, object value, RegistryKeyValueKind kind) + { + _key.SetValue(name, value, kind.ToWin32()); + } - public void SetValue(string name, object value, RegistryValueKind kind) - { - _key.SetValue(name, value, kind.ToWin32()); - } + public void SetValue(string name, object value, RegistryValueKind kind) + { + _key.SetValue(name, value, kind.ToWin32()); } } diff --git a/src/Cupboard/IStatusUpdater.cs b/src/Cupboard/IStatusUpdater.cs index 81cb5fe..136007e 100644 --- a/src/Cupboard/IStatusUpdater.cs +++ b/src/Cupboard/IStatusUpdater.cs @@ -2,34 +2,33 @@ using System.Threading.Tasks; using Spectre.Console; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal interface IStatusUpdater { - internal interface IStatusUpdater + Task Update(string markup, Func> func); +} + +internal sealed class StatusUpdater : IStatusUpdater +{ + private readonly IAnsiConsole _console; + + public StatusUpdater(IAnsiConsole console) { - Task Update(string markup, Func> func); + _console = console; } - internal sealed class StatusUpdater : IStatusUpdater + public async Task Update(string markup, Func> func) { - private readonly IAnsiConsole _console; - - public StatusUpdater(IAnsiConsole console) - { - _console = console; - } - - public async Task Update(string markup, Func> func) - { - return await _console.Status().StartAsync(markup, async _ => - await func().ConfigureAwait(false)).ConfigureAwait(false); - } + return await _console.Status().StartAsync(markup, async _ => + await func().ConfigureAwait(false)).ConfigureAwait(false); } +} - internal sealed class DummyUpdater : IStatusUpdater +internal sealed class DummyUpdater : IStatusUpdater +{ + public async Task Update(string markup, Func> func) { - public async Task Update(string markup, Func> func) - { - return await func().ConfigureAwait(false); - } + return await func().ConfigureAwait(false); } } diff --git a/src/Cupboard/RebootDetector.cs b/src/Cupboard/RebootDetector.cs index 49ea3b6..cac2250 100644 --- a/src/Cupboard/RebootDetector.cs +++ b/src/Cupboard/RebootDetector.cs @@ -3,82 +3,81 @@ using System.Linq; using System.Runtime.InteropServices; -namespace Cupboard +namespace Cupboard; + +internal sealed class RebootDetector : IRebootDetector { - internal sealed class RebootDetector : IRebootDetector + private readonly IWindowsRegistry _registry; + + private readonly List _checkForExistence = new() { - private readonly IWindowsRegistry _registry; + @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending", + @"HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress", + @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired", + @"HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending", + @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting", + @"HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttemps", + }; - private readonly List _checkForExistence = new() - { - @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending", - @"HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress", - @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired", - @"HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending", - @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting", - @"HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttemps", - }; + private readonly List<(RegistryPath Path, string Value)> _checkForValue = new() + { + (@"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "DVDRebootSignal"), + (@"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon", "JoinDomain"), + (@"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon", "AvoidSpnSet"), + (@"HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager", "PendingFileRenameOperations"), + (@"HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager", "PendingFileRenameOperations2"), + }; - private readonly List<(RegistryPath Path, string Value)> _checkForValue = new() - { - (@"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "DVDRebootSignal"), - (@"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon", "JoinDomain"), - (@"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon", "AvoidSpnSet"), - (@"HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager", "PendingFileRenameOperations"), - (@"HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager", "PendingFileRenameOperations2"), - }; + public RebootDetector(IWindowsRegistry registry) + { + _registry = registry ?? throw new ArgumentNullException(nameof(registry)); + } - public RebootDetector(IWindowsRegistry registry) + public bool HasPendingReboot() + { + if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { - _registry = registry ?? throw new ArgumentNullException(nameof(registry)); + return false; } - public bool HasPendingReboot() + // Check registry keys that must exist + if (_checkForExistence.Any(path => KeyExist(path))) { - if (!RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) - { - return false; - } - - // Check registry keys that must exist - if (_checkForExistence.Any(path => KeyExist(path))) - { - return true; - } - - // Check registry values that must exist - if (_checkForValue.Any(p => KeyHasValue(p.Path, p.Value))) - { - return true; - } - - // Check if Windows Update is waiting on updating any executables - var wu = _registry.GetKey(@"HKLM:\SOFTWARE\Microsoft\Updates", writable: false); - if (wu?.GetValue("UpdateExeVolatile") is int updateExeVolatile && updateExeVolatile != 0) - { - return true; - } - - // Check for pending Windows updates - wu = _registry.GetKey(@"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending", writable: false); - return wu?.GetValueCount() > 0; + return true; } - private bool KeyExist(RegistryPath path) + // Check registry values that must exist + if (_checkForValue.Any(p => KeyHasValue(p.Path, p.Value))) { - var key = _registry.GetKey(path, writable: false); - return key != null; + return true; } - private bool KeyHasValue(RegistryPath path, string value) + // Check if Windows Update is waiting on updating any executables + var wu = _registry.GetKey(@"HKLM:\SOFTWARE\Microsoft\Updates", writable: false); + if (wu?.GetValue("UpdateExeVolatile") is int updateExeVolatile && updateExeVolatile != 0) { - var key = _registry.GetKey(path, writable: false); - if (key != null) - { - return key.ValueExists(value); - } + return true; + } - return false; + // Check for pending Windows updates + wu = _registry.GetKey(@"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending", writable: false); + return wu?.GetValueCount() > 0; + } + + private bool KeyExist(RegistryPath path) + { + var key = _registry.GetKey(path, writable: false); + return key != null; + } + + private bool KeyHasValue(RegistryPath path, string value) + { + var key = _registry.GetKey(path, writable: false); + if (key != null) + { + return key.ValueExists(value); } + + return false; } } diff --git a/src/Cupboard/ReportRenderer.cs b/src/Cupboard/ReportRenderer.cs index edf1b8a..5481792 100644 --- a/src/Cupboard/ReportRenderer.cs +++ b/src/Cupboard/ReportRenderer.cs @@ -5,133 +5,132 @@ using Spectre.Console; using Spectre.Console.Rendering; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ReportRenderer { - internal sealed class ReportRenderer + private readonly IAnsiConsole _console; + + public ReportRenderer(IAnsiConsole console) + { + _console = console ?? throw new ArgumentNullException(nameof(console)); + } + + public void Render(Report report, Verbosity verbosity) { - private readonly IAnsiConsole _console; + var table = new Table().Expand().BorderColor(Color.Grey).MinimalBorder(); + table.AddColumns("[grey]#[/]", "[grey]Provider[/]", "[grey]Resource[/]"); - public ReportRenderer(IAnsiConsole console) + if (!report.DryRun) { - _console = console ?? throw new ArgumentNullException(nameof(console)); + table.AddColumn("Status"); } - public void Render(Report report, Verbosity verbosity) + var index = 1; + foreach (var item in report) { - var table = new Table().Expand().BorderColor(Color.Grey).MinimalBorder(); - table.AddColumns("[grey]#[/]", "[grey]Provider[/]", "[grey]Resource[/]"); - - if (!report.DryRun) + var resourceName = "[green]" + item.Provider.ResourceType.Name + "[/]"; + if (item.RequireAdministrator && report.DryRun) { - table.AddColumn("Status"); + resourceName += "[yellow]*[/]"; } - var index = 1; - foreach (var item in report) + var columns = new List { - var resourceName = "[green]" + item.Provider.ResourceType.Name + "[/]"; - if (item.RequireAdministrator && report.DryRun) - { - resourceName += "[yellow]*[/]"; - } - - var columns = new List - { - new Text(index.ToString(CultureInfo.InvariantCulture), new Style(foreground: Color.Grey)), - new Markup(resourceName), - new Text(item.Resource.Name, new Style(foreground: Color.Blue)), - }; + new Text(index.ToString(CultureInfo.InvariantCulture), new Style(foreground: Color.Grey)), + new Markup(resourceName), + new Text(item.Resource.Name, new Style(foreground: Color.Blue)), + }; - if (!report.DryRun) + if (!report.DryRun) + { + if (verbosity < Verbosity.Verbose) { - if (verbosity < Verbosity.Verbose) + if (item.State == ResourceState.Unchanged) { - if (item.State == ResourceState.Unchanged) - { - continue; - } + continue; } - - columns.Add(new Text(GetName(item.State), new Style(foreground: GetColor(item.State)))); } - table.AddRow(columns.ToArray()); - index++; + columns.Add(new Text(GetName(item.State), new Style(foreground: GetColor(item.State)))); } - _console.WriteLine(); - _console.Write( - new Panel(table) - .Padding(1, 1) - .Expand() - .Header(report.DryRun ? "[blue]Execution plan[/]" : "[blue]Report[/]") - .BorderColor(Color.Grey)); + table.AddRow(columns.ToArray()); + index++; + } - if (!report.DryRun) - { - var chart = new BreakdownChart(); - var grouped = report.Items.GroupBy(x => x.State); - var colors = new ColorPalette(grouped.Select(g => g.Key)); + _console.WriteLine(); + _console.Write( + new Panel(table) + .Padding(1, 1) + .Expand() + .Header(report.DryRun ? "[blue]Execution plan[/]" : "[blue]Report[/]") + .BorderColor(Color.Grey)); - foreach (var group in grouped) - { - chart.AddItem(GetName(group.Key), group.Count(), GetColor(group.Key)); - } + if (!report.DryRun) + { + var chart = new BreakdownChart(); + var grouped = report.Items.GroupBy(x => x.State); + var colors = new ColorPalette(grouped.Select(g => g.Key)); - _console.Write( - new Panel(chart) - .Padding(2, 1) - .Header("Summary") - .BorderColor(Color.Grey)); + foreach (var group in grouped) + { + chart.AddItem(GetName(group.Key), group.Count(), GetColor(group.Key)); } - if (report.DryRun) - { - var breakdown = new BreakdownChart(); - var groupedTypes = report.Items.GroupBy(x => x.Resource.GetType()); - var colors = new ColorPalette(groupedTypes.Select(g => g.Key)); + _console.Write( + new Panel(chart) + .Padding(2, 1) + .Header("Summary") + .BorderColor(Color.Grey)); + } - foreach (var group in groupedTypes) - { - breakdown.AddItem(group.Key.Name, group.Count(), colors.GetColor(group.Key)); - } + if (report.DryRun) + { + var breakdown = new BreakdownChart(); + var groupedTypes = report.Items.GroupBy(x => x.Resource.GetType()); + var colors = new ColorPalette(groupedTypes.Select(g => g.Key)); - _console.Write( - new Panel(breakdown) - .Padding(2, 1) - .Header("Breakdown") - .BorderColor(Color.Grey)); + foreach (var group in groupedTypes) + { + breakdown.AddItem(group.Key.Name, group.Count(), colors.GetColor(group.Key)); } + + _console.Write( + new Panel(breakdown) + .Padding(2, 1) + .Header("Breakdown") + .BorderColor(Color.Grey)); } + } - private static string GetName(ResourceState state) + private static string GetName(ResourceState state) + { + return state switch { - return state switch - { - ResourceState.Unknown => "Unknown", - ResourceState.Changed => "Changed", - ResourceState.Unchanged => "Unchanged", - ResourceState.Executed => "Executed", - ResourceState.Skipped => "Skipped", - ResourceState.ManuallySkipped => "Skipped (manually)", - ResourceState.Error => "Error", - _ => state.ToString(), - }; - } + ResourceState.Unknown => "Unknown", + ResourceState.Changed => "Changed", + ResourceState.Unchanged => "Unchanged", + ResourceState.Executed => "Executed", + ResourceState.Skipped => "Skipped", + ResourceState.ManuallySkipped => "Skipped (manually)", + ResourceState.Error => "Error", + _ => state.ToString(), + }; + } - private static Color GetColor(ResourceState state) + private static Color GetColor(ResourceState state) + { + return state switch { - return state switch - { - ResourceState.Unknown => Color.Grey, - ResourceState.Changed => Color.Green, - ResourceState.Unchanged => Color.Silver, - ResourceState.Executed => Color.Green, - ResourceState.Skipped => Color.Yellow, - ResourceState.ManuallySkipped => Color.Yellow, - ResourceState.Error => Color.Red, - _ => Color.Aqua, - }; - } + ResourceState.Unknown => Color.Grey, + ResourceState.Changed => Color.Green, + ResourceState.Unchanged => Color.Silver, + ResourceState.Executed => Color.Green, + ResourceState.Skipped => Color.Yellow, + ResourceState.ManuallySkipped => Color.Yellow, + ResourceState.Error => Color.Red, + _ => Color.Aqua, + }; } } diff --git a/src/Cupboard/ResourceComparer.cs b/src/Cupboard/ResourceComparer.cs index 6269f88..b96b68f 100644 --- a/src/Cupboard/ResourceComparer.cs +++ b/src/Cupboard/ResourceComparer.cs @@ -1,44 +1,43 @@ using System; using System.Collections.Generic; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceComparer : IEqualityComparer { - internal sealed class ResourceComparer : IEqualityComparer + private readonly IEqualityComparer _typeComparer; + private readonly IEqualityComparer _stringComparer; + + public ResourceComparer() { - private readonly IEqualityComparer _typeComparer; - private readonly IEqualityComparer _stringComparer; + _typeComparer = EqualityComparer.Default; + _stringComparer = StringComparer.OrdinalIgnoreCase; + } - public ResourceComparer() + public bool Equals(IResourceIdentity? x, IResourceIdentity? y) + { + if (x == null && y == null) { - _typeComparer = EqualityComparer.Default; - _stringComparer = StringComparer.OrdinalIgnoreCase; + return true; } - public bool Equals(IResourceIdentity? x, IResourceIdentity? y) + if (x == null || y == null) { - if (x == null && y == null) - { - return true; - } - - if (x == null || y == null) - { - return false; - } - - return _typeComparer.Equals(x.ResourceType, y.ResourceType) - && _stringComparer.Equals(x.Name, y.Name); + return false; } - public int GetHashCode(IResourceIdentity obj) + return _typeComparer.Equals(x.ResourceType, y.ResourceType) + && _stringComparer.Equals(x.Name, y.Name); + } + + public int GetHashCode(IResourceIdentity obj) + { + unchecked { - unchecked - { - var hash = 27; - hash = (13 * hash) + _typeComparer.GetHashCode(obj.ResourceType); - hash = (13 * hash) + _stringComparer.GetHashCode(obj.Name); - return hash; - } + var hash = 27; + hash = (13 * hash) + _typeComparer.GetHashCode(obj.ResourceType); + hash = (13 * hash) + _stringComparer.GetHashCode(obj.Name); + return hash; } } } diff --git a/src/Cupboard/ResourceGraph.cs b/src/Cupboard/ResourceGraph.cs index 3fa7fcb..4fc97d2 100644 --- a/src/Cupboard/ResourceGraph.cs +++ b/src/Cupboard/ResourceGraph.cs @@ -2,90 +2,89 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceGraph { - internal sealed class ResourceGraph + private readonly IEqualityComparer _comparer; + + public HashSet Nodes { get; } + public HashSet Edges { get; } + public HashSet Resources { get; } + public List Configurations { get; set; } + + public ResourceGraph() { - private readonly IEqualityComparer _comparer; + _comparer = new ResourceComparer(); - public HashSet Nodes { get; } - public HashSet Edges { get; } - public HashSet Resources { get; } - public List Configurations { get; set; } + Nodes = new HashSet(); + Edges = new HashSet(); + Resources = new HashSet(_comparer); + Configurations = new List(); + } + + public void Add(Resource resource) + { + Resources.Add(resource); + } - public ResourceGraph() + public void Connect(IResourceIdentity from, IResourceIdentity to) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (to == null) { - _comparer = new ResourceComparer(); + throw new ArgumentNullException(nameof(to)); + } - Nodes = new HashSet(); - Edges = new HashSet(); - Resources = new HashSet(_comparer); - Configurations = new List(); + if (_comparer.Equals(from, to)) + { + throw new InvalidOperationException("Reflexive dependencies are not allowed."); } - public void Add(Resource resource) + if (Edges.Any(e => _comparer.Equals(e.From, to) && _comparer.Equals(e.To, from))) { - Resources.Add(resource); + throw new InvalidOperationException("Unidirectional dependencies are not allowed."); } - public void Connect(IResourceIdentity from, IResourceIdentity to) + if (!Nodes.Contains(from)) { - if (from == null) - { - throw new ArgumentNullException(nameof(from)); - } - - if (to == null) - { - throw new ArgumentNullException(nameof(to)); - } - - if (_comparer.Equals(from, to)) - { - throw new InvalidOperationException("Reflexive dependencies are not allowed."); - } - - if (Edges.Any(e => _comparer.Equals(e.From, to) && _comparer.Equals(e.To, from))) - { - throw new InvalidOperationException("Unidirectional dependencies are not allowed."); - } - - if (!Nodes.Contains(from)) - { - Nodes.Add(from); - } - - if (!Nodes.Contains(to)) - { - Nodes.Add(to); - } - - if (!Edges.Any(e => _comparer.Equals(e.From, from) && _comparer.Equals(e.To, to))) - { - Edges.Add(new ResourceGraphEdge(from, to)); - } + Nodes.Add(from); } - public IEnumerable Traverse() + if (!Nodes.Contains(to)) { - var walker = new ResourceGraphWalker(); - return walker.Walk(this); + Nodes.Add(to); } - public ResourceGraph ShallowClone() + if (!Edges.Any(e => _comparer.Equals(e.From, from) && _comparer.Equals(e.To, to))) { - var graph = new ResourceGraph(); - foreach (var edge in Edges) - { - graph.Connect(edge.From, edge.To); - } - - foreach (var resource in Resources) - { - graph.Add(resource); - } - - return graph; + Edges.Add(new ResourceGraphEdge(from, to)); } } + + public IEnumerable Traverse() + { + var walker = new ResourceGraphWalker(); + return walker.Walk(this); + } + + public ResourceGraph ShallowClone() + { + var graph = new ResourceGraph(); + foreach (var edge in Edges) + { + graph.Connect(edge.From, edge.To); + } + + foreach (var resource in Resources) + { + graph.Add(resource); + } + + return graph; + } } diff --git a/src/Cupboard/ResourceGraphBuilder.cs b/src/Cupboard/ResourceGraphBuilder.cs index 0a7ced7..2238f8c 100644 --- a/src/Cupboard/ResourceGraphBuilder.cs +++ b/src/Cupboard/ResourceGraphBuilder.cs @@ -1,63 +1,62 @@ using System; using System.Collections.Generic; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal static class ResourceGraphBuilder { - internal static class ResourceGraphBuilder + public static ResourceGraph Build( + ResourceProviderRepository repository, + IEnumerable manifests, + FactCollection facts) { - public static ResourceGraph Build( - ResourceProviderRepository repository, - IEnumerable manifests, - FactCollection facts) + // Execute all manifests. + var ctx = new ManifestContext(facts); + foreach (var manifest in manifests) + { + manifest.Execute(ctx); + } + + // Build the graph using the builders in the context. + var graph = new ResourceGraph(); + foreach (var builder in ctx.Builders) { - // Execute all manifests. - var ctx = new ManifestContext(facts); - foreach (var manifest in manifests) + var provider = repository.GetProvider(builder.Type); + if (provider == null) + { + throw new InvalidOperationException($"Could not find resource provider for '{builder.Name}' ({builder.Type.Name})."); + } + + // Create the resource. + var resource = provider.Create(builder.Name); + + // Add the resource to the graph. + if (!graph.Resources.Add(resource)) + { + // TODO 2021-07-11: Log that the resource was skipped + continue; + } + + // Connect dependees to resource. + foreach (var before in builder.RunBefore) { - manifest.Execute(ctx); + graph.Connect(new ResourceIdentity(resource), new ResourceIdentity(before)); } - // Build the graph using the builders in the context. - var graph = new ResourceGraph(); - foreach (var builder in ctx.Builders) + // Connect resource to dependencies. + foreach (var after in builder.RunAfter) { - var provider = repository.GetProvider(builder.Type); - if (provider == null) - { - throw new InvalidOperationException($"Could not find resource provider for '{builder.Name}' ({builder.Type.Name})."); - } - - // Create the resource. - var resource = provider.Create(builder.Name); - - // Add the resource to the graph. - if (!graph.Resources.Add(resource)) - { - // TODO 2021-07-11: Log that the resource was skipped - continue; - } - - // Connect dependees to resource. - foreach (var before in builder.RunBefore) - { - graph.Connect(new ResourceIdentity(resource), new ResourceIdentity(before)); - } - - // Connect resource to dependencies. - foreach (var after in builder.RunAfter) - { - graph.Connect(new ResourceIdentity(after), new ResourceIdentity(resource)); - } - - // Run configuration. - foreach (var configuration in builder.Configurations) - { - graph.Configurations.Add(() => configuration(resource)); - } + graph.Connect(new ResourceIdentity(after), new ResourceIdentity(resource)); } - // Return the graph. - return graph; + // Run configuration. + foreach (var configuration in builder.Configurations) + { + graph.Configurations.Add(() => configuration(resource)); + } } + + // Return the graph. + return graph; } } diff --git a/src/Cupboard/ResourceGraphEdge.cs b/src/Cupboard/ResourceGraphEdge.cs index eca5d16..f410f8a 100644 --- a/src/Cupboard/ResourceGraphEdge.cs +++ b/src/Cupboard/ResourceGraphEdge.cs @@ -1,14 +1,13 @@ -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceGraphEdge { - internal sealed class ResourceGraphEdge - { - public IResourceIdentity From { get; } - public IResourceIdentity To { get; } + public IResourceIdentity From { get; } + public IResourceIdentity To { get; } - public ResourceGraphEdge(IResourceIdentity from, IResourceIdentity to) - { - From = from; - To = to; - } + public ResourceGraphEdge(IResourceIdentity from, IResourceIdentity to) + { + From = from; + To = to; } } diff --git a/src/Cupboard/ResourceGraphWalker.cs b/src/Cupboard/ResourceGraphWalker.cs index 2303976..ad289d7 100644 --- a/src/Cupboard/ResourceGraphWalker.cs +++ b/src/Cupboard/ResourceGraphWalker.cs @@ -2,100 +2,99 @@ using System.Collections.Generic; using System.Linq; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceGraphWalker { - internal sealed class ResourceGraphWalker + private readonly ResourceComparer _comparer; + + public ResourceGraphWalker() { - private readonly ResourceComparer _comparer; + _comparer = new ResourceComparer(); + } - public ResourceGraphWalker() + private class TargetResource : Resource + { + public TargetResource() + : base("__target__") { - _comparer = new ResourceComparer(); } + } + + public IEnumerable Walk(ResourceGraph graph) + { + // Clone the graph. + graph = graph.ShallowClone(); - private class TargetResource : Resource + // Sanity check to make sure that all edges exist in the graph. + foreach (var edge in graph.Edges) { - public TargetResource() - : base("__target__") - { - } + EnsureResourceExist(graph, edge.From); + EnsureResourceExist(graph, edge.To); } - public IEnumerable Walk(ResourceGraph graph) + // Find all nodes without any edges. + var orphans = graph.Resources + .Where(x => !graph.Edges.Any(edge => _comparer.Equals(x, edge.From)) + && !graph.Edges.Any(edge => _comparer.Equals(x, edge.To))) + .ToArray(); + + // Find all leaves in the graph. + var leaves = graph.Nodes + .Where(x => graph.Edges.Any(y => _comparer.Equals(x, y.To)) + && !graph.Edges.Any(z => _comparer.Equals(x, z.From))) + .ToArray(); + + // Add an artifical destination node to all leaves. + // This will be the target to traverse to it's roots. + var target = new TargetResource(); + foreach (var leaf in leaves.Concat(orphans)) { - // Clone the graph. - graph = graph.ShallowClone(); + graph.Connect(leaf, target); + } - // Sanity check to make sure that all edges exist in the graph. - foreach (var edge in graph.Edges) - { - EnsureResourceExist(graph, edge.From); - EnsureResourceExist(graph, edge.To); - } + // Traverse the graph. + var result = new List(); + Traverse(graph, target, result); - // Find all nodes without any edges. - var orphans = graph.Resources - .Where(x => !graph.Edges.Any(edge => _comparer.Equals(x, edge.From)) - && !graph.Edges.Any(edge => _comparer.Equals(x, edge.To))) - .ToArray(); + // Remove the target node from the results. + result.RemoveAll(x => x.ResourceType == typeof(TargetResource)); - // Find all leaves in the graph. - var leaves = graph.Nodes - .Where(x => graph.Edges.Any(y => _comparer.Equals(x, y.To)) - && !graph.Edges.Any(z => _comparer.Equals(x, z.From))) - .ToArray(); + // Return the result. + return result; + } - // Add an artifical destination node to all leaves. - // This will be the target to traverse to it's roots. - var target = new TargetResource(); - foreach (var leaf in leaves.Concat(orphans)) + private void Traverse( + ResourceGraph graph, + IResourceIdentity node, + ICollection result, + ISet? visited = null) + { + visited ??= new HashSet(_comparer); + if (!visited.Contains(node)) + { + visited.Add(node); + var incoming = graph.Edges.Where(x => _comparer.Equals(x.To, node)).Select(x => x.From); + foreach (var child in incoming) { - graph.Connect(leaf, target); + Traverse(graph, child, result, visited); } - // Traverse the graph. - var result = new List(); - Traverse(graph, target, result); - - // Remove the target node from the results. - result.RemoveAll(x => x.ResourceType == typeof(TargetResource)); - - // Return the result. - return result; + result.Add(node); } - - private void Traverse( - ResourceGraph graph, - IResourceIdentity node, - ICollection result, - ISet? visited = null) + else if (!result.Any(x => _comparer.Equals(x, node))) { - visited ??= new HashSet(_comparer); - if (!visited.Contains(node)) - { - visited.Add(node); - var incoming = graph.Edges.Where(x => _comparer.Equals(x.To, node)).Select(x => x.From); - foreach (var child in incoming) - { - Traverse(graph, child, result, visited); - } - - result.Add(node); - } - else if (!result.Any(x => _comparer.Equals(x, node))) - { - throw new InvalidOperationException("Graph contains circular references."); - } + throw new InvalidOperationException("Graph contains circular references."); } + } - private static void EnsureResourceExist(ResourceGraph graph, IResourceIdentity identity) + private static void EnsureResourceExist(ResourceGraph graph, IResourceIdentity identity) + { + if (!graph.Resources.Any(r => r.Name.Equals(identity.Name, StringComparison.OrdinalIgnoreCase) + && r.ResourceType == identity.ResourceType)) { - if (!graph.Resources.Any(r => r.Name.Equals(identity.Name, StringComparison.OrdinalIgnoreCase) - && r.ResourceType == identity.ResourceType)) - { - throw new InvalidOperationException( - $"Could not find resource '{identity.Name}' of type '{identity.ResourceType.Name}'."); - } + throw new InvalidOperationException( + $"Could not find resource '{identity.Name}' of type '{identity.ResourceType.Name}'."); } } } diff --git a/src/Cupboard/ResourceIdentity.cs b/src/Cupboard/ResourceIdentity.cs index 9ac6665..84eb73c 100644 --- a/src/Cupboard/ResourceIdentity.cs +++ b/src/Cupboard/ResourceIdentity.cs @@ -1,28 +1,27 @@ using System; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceIdentity : IResourceIdentity { - internal sealed class ResourceIdentity : IResourceIdentity - { - public Type ResourceType { get; } - public string Name { get; } + public Type ResourceType { get; } + public string Name { get; } - public ResourceIdentity(Type resourceType, string name) - { - ResourceType = resourceType; - Name = name; - } + public ResourceIdentity(Type resourceType, string name) + { + ResourceType = resourceType; + Name = name; + } - public ResourceIdentity(Resource resource) - { - ResourceType = resource.ResourceType; - Name = resource.Name; - } + public ResourceIdentity(Resource resource) + { + ResourceType = resource.ResourceType; + Name = resource.Name; + } - public ResourceIdentity(Tuple tuple) - { - ResourceType = tuple.Item1; - Name = tuple.Item2; - } + public ResourceIdentity(Tuple tuple) + { + ResourceType = tuple.Item1; + Name = tuple.Item2; } } diff --git a/src/Cupboard/ResourceProviderRepository.cs b/src/Cupboard/ResourceProviderRepository.cs index 95ca492..128be38 100644 --- a/src/Cupboard/ResourceProviderRepository.cs +++ b/src/Cupboard/ResourceProviderRepository.cs @@ -1,31 +1,30 @@ using System; using System.Collections.Generic; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class ResourceProviderRepository { - internal sealed class ResourceProviderRepository - { - private readonly Dictionary _lookup; + private readonly Dictionary _lookup; - public ResourceProviderRepository(IEnumerable providers) + public ResourceProviderRepository(IEnumerable providers) + { + _lookup = new Dictionary(); + foreach (var provider in providers) { - _lookup = new Dictionary(); - foreach (var provider in providers) + if (_lookup.ContainsKey(provider.ResourceType)) { - if (_lookup.ContainsKey(provider.ResourceType)) - { - throw new InvalidOperationException( - $"Encountered duplicate providers for {provider.ResourceType}"); - } - - _lookup.Add(provider.ResourceType, provider); + throw new InvalidOperationException( + $"Encountered duplicate providers for {provider.ResourceType}"); } - } - public IResourceProvider? GetProvider(Type type) - { - _lookup.TryGetValue(type, out var provider); - return provider; + _lookup.Add(provider.ResourceType, provider); } } + + public IResourceProvider? GetProvider(Type type) + { + _lookup.TryGetValue(type, out var provider); + return provider; + } } diff --git a/src/Cupboard/SecurityPrincipal.cs b/src/Cupboard/SecurityPrincipal.cs index 54c563a..ede905e 100644 --- a/src/Cupboard/SecurityPrincipal.cs +++ b/src/Cupboard/SecurityPrincipal.cs @@ -2,16 +2,15 @@ using System.Security.Principal; using Mono.Unix.Native; -namespace Cupboard.Internal +namespace Cupboard.Internal; + +internal sealed class SecurityPrincipal : ISecurityPrincipal { - internal sealed class SecurityPrincipal : ISecurityPrincipal + public bool IsAdministrator() { - public bool IsAdministrator() - { - return RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows) ? - new WindowsPrincipal(WindowsIdentity.GetCurrent()) - .IsInRole(WindowsBuiltInRole.Administrator) : - Syscall.geteuid() == 0; - } + return RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows) ? + new WindowsPrincipal(WindowsIdentity.GetCurrent()) + .IsInRole(WindowsBuiltInRole.Administrator) : + Syscall.geteuid() == 0; } } diff --git a/src/Cupboard/WindowsCatalog.cs b/src/Cupboard/WindowsCatalog.cs index afe6648..cf3828a 100644 --- a/src/Cupboard/WindowsCatalog.cs +++ b/src/Cupboard/WindowsCatalog.cs @@ -1,10 +1,9 @@ -namespace Cupboard +namespace Cupboard; + +public abstract class WindowsCatalog : Catalog { - public abstract class WindowsCatalog : Catalog + public override bool CanRun(FactCollection facts) { - public override bool CanRun(FactCollection facts) - { - return facts.IsWindows(); - } + return facts.IsWindows(); } } diff --git a/src/Sandbox/Facts/RustFactProvider.cs b/src/Sandbox/Facts/RustFactProvider.cs index a0353fc..d9a844d 100644 --- a/src/Sandbox/Facts/RustFactProvider.cs +++ b/src/Sandbox/Facts/RustFactProvider.cs @@ -4,23 +4,22 @@ using Spectre.Console.Cli; using Spectre.IO; -namespace Sandbox +namespace Sandbox; + +public sealed class RustFactProvider : IFactProvider { - public sealed class RustFactProvider : IFactProvider - { - private readonly ICupboardFileSystem _fileSystem; - private readonly ICupboardEnvironment _environment; + private readonly ICupboardFileSystem _fileSystem; + private readonly ICupboardEnvironment _environment; - public RustFactProvider(ICupboardFileSystem fileSystem, ICupboardEnvironment environment) - { - _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); - _environment = environment ?? throw new ArgumentNullException(nameof(environment)); - } + public RustFactProvider(ICupboardFileSystem fileSystem, ICupboardEnvironment environment) + { + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + } - IEnumerable<(string Name, object Value)> IFactProvider.GetFacts(IRemainingArguments args) - { - var path = new DirectoryPath("~/.cargo").MakeAbsolute(_environment); - yield return ("rust.installed", _fileSystem.Exist(path)); - } + IEnumerable<(string Name, object Value)> IFactProvider.GetFacts(IRemainingArguments args) + { + var path = new DirectoryPath("~/.cargo").MakeAbsolute(_environment); + yield return ("rust.installed", _fileSystem.Exist(path)); } } diff --git a/src/Sandbox/Manifests/Chocolatey.cs b/src/Sandbox/Manifests/Chocolatey.cs index 7077f7c..771b704 100644 --- a/src/Sandbox/Manifests/Chocolatey.cs +++ b/src/Sandbox/Manifests/Chocolatey.cs @@ -1,35 +1,35 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class Chocolatey : Manifest { - public sealed class Chocolatey : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + // Do not run this in sandbox + if (context.Facts["windows"]["sandbox"]) { - // Do not run this in sandbox - if (context.Facts["windows"]["sandbox"]) - { - return; - } + return; + } - // Download - context.Resource("https://chocolatey.org/install.ps1") - .ToFile("~/install-chocolatey.ps1"); + // Download + context.Resource("https://chocolatey.org/install.ps1") + .ToFile("~/install-chocolatey.ps1"); - // Set execution policy - context.Resource("Set execution policy") - .Path(@"HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell") - .Value("ExecutionPolicy") - .Data("Unrestricted", RegistryValueKind.String); + // Set execution policy + context.Resource("Set execution policy") + .Path(@"HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell") + .Value("ExecutionPolicy") + .Ensure(RegistryKeyState.Exist) + .Data("Unrestricted", RegistryValueKind.String); - // Install - context.Resource("Install Chocolatey") - .Script("~/install-chocolatey.ps1") - .Flavor(PowerShellFlavor.PowerShell) - .RequireAdministrator() - .Unless("if (Test-Path \"$($env:ProgramData)/chocolatey/choco.exe\") { exit 1 }") - .After("Set execution policy") - .After("https://chocolatey.org/install.ps1"); - } + // Install + context.Resource("Install Chocolatey") + .Script("~/install-chocolatey.ps1") + .Flavor(PowerShellFlavor.PowerShell) + .RequireAdministrator() + .Unless("if (Test-Path \"$($env:ProgramData)/chocolatey/choco.exe\") { exit 1 }") + .After("Set execution policy") + .After("https://chocolatey.org/install.ps1"); } } diff --git a/src/Sandbox/Manifests/ChocolateyPackages.cs b/src/Sandbox/Manifests/ChocolateyPackages.cs index c26dde3..4a4719a 100644 --- a/src/Sandbox/Manifests/ChocolateyPackages.cs +++ b/src/Sandbox/Manifests/ChocolateyPackages.cs @@ -1,17 +1,16 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class ChocolateyPackages : Manifest { - public sealed class ChocolateyPackages : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + foreach (var package in new[] { "screentogif", "repoz" }) { - foreach (var package in new[] { "screentogif", "repoz" }) - { - context.Resource(package) - .Ensure(PackageState.Installed) - .After("Install Chocolatey"); - } + context.Resource(package) + .Ensure(PackageState.Installed) + .After("Install Chocolatey"); } } } \ No newline at end of file diff --git a/src/Sandbox/Manifests/Rust.cs b/src/Sandbox/Manifests/Rust.cs index 4254363..a748edf 100644 --- a/src/Sandbox/Manifests/Rust.cs +++ b/src/Sandbox/Manifests/Rust.cs @@ -1,46 +1,45 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class Rust : Manifest { - public sealed class Rust : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) - { - // Download directory - context.Resource("~/Downloads") - .Ensure(DirectoryState.Present); + // Download directory + context.Resource("~/Downloads") + .Ensure(DirectoryState.Present); - if (context.Facts["rust.installed"]) - { - return; - } + if (context.Facts["rust.installed"]) + { + return; + } - if (context.Facts.IsWindows()) - { - // Download Rust installer - context.Resource("https://win.rustup.rs/x86_64") - .ToFile("~/Downloads/rustup-init.exe"); + if (context.Facts.IsWindows()) + { + // Download Rust installer + context.Resource("https://win.rustup.rs/x86_64") + .ToFile("~/Downloads/rustup-init.exe"); - // Run Rust installer - context.Resource("~/Downloads/rustup-init.exe") - .Arguments("-y") - .ValidExitCodes(0, 1) - .After("https://win.rustup.rs/x86_64"); - } - else - { - // Download Rust installer script - context.Resource("https://sh.rustup.rs") - .Permissions("700") - .After("~/Downloads") - .ToFile("~/Downloads/rustup.sh"); + // Run Rust installer + context.Resource("~/Downloads/rustup-init.exe") + .Arguments("-y") + .ValidExitCodes(0, 1) + .After("https://win.rustup.rs/x86_64"); + } + else + { + // Download Rust installer script + context.Resource("https://sh.rustup.rs") + .Permissions("700") + .After("~/Downloads") + .ToFile("~/Downloads/rustup.sh"); - // Run Rust installer - context.Resource("~/Downloads/rustup.sh") - .Arguments("-y") - .ValidExitCodes(0, 1) - .After("https://sh.rustup.rs"); - } + // Run Rust installer + context.Resource("~/Downloads/rustup.sh") + .Arguments("-y") + .ValidExitCodes(0, 1) + .After("https://sh.rustup.rs"); } } } diff --git a/src/Sandbox/Manifests/VSCode.cs b/src/Sandbox/Manifests/VSCode.cs index 0b20325..6c3a7b4 100644 --- a/src/Sandbox/Manifests/VSCode.cs +++ b/src/Sandbox/Manifests/VSCode.cs @@ -1,43 +1,42 @@ using System.Collections.Generic; using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class VSCode : Manifest { - public sealed class VSCode : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + if (!context.Facts.IsX86OrX64()) + { + return; + } + + var packages = new List { - if (!context.Facts.IsX86OrX64()) - { - return; - } + "cake-build.cake-vscode", + "matklad.rust-analyzer", + "ms-vscode.powershell", + "bungcip.better-toml", + "ms-azuretools.vscode-docker", + "octref.vetur", + "ms-vscode-remote.remote-wsl", + "jolaleye.horizon-theme-vscode", + "vscode-icons-team.vscode-icons", + "hediet.vscode-drawio", + }; - var packages = new List - { - "cake-build.cake-vscode", - "matklad.rust-analyzer", - "ms-vscode.powershell", - "bungcip.better-toml", - "ms-azuretools.vscode-docker", - "octref.vetur", - "ms-vscode-remote.remote-wsl", - "jolaleye.horizon-theme-vscode", - "vscode-icons-team.vscode-icons", - "hediet.vscode-drawio", - }; + // VSCode + context.Resource("vscode") + .Ensure(PackageState.Installed) + .After("Install Chocolatey"); - // VSCode - context.Resource("vscode") + // Extensions + foreach (var package in packages) + { + context.Resource(package) .Ensure(PackageState.Installed) - .After("Install Chocolatey"); - - // Extensions - foreach (var package in packages) - { - context.Resource(package) - .Ensure(PackageState.Installed) - .After("vscode"); - } + .After("vscode"); } } } diff --git a/src/Sandbox/Manifests/WindowsSettings.cs b/src/Sandbox/Manifests/WindowsSettings.cs index 903b928..3063d71 100644 --- a/src/Sandbox/Manifests/WindowsSettings.cs +++ b/src/Sandbox/Manifests/WindowsSettings.cs @@ -1,58 +1,57 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class WindowsSettings : Manifest { - public sealed class WindowsSettings : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + if (!context.Facts["windows"]["sandbox"]) { - if (!context.Facts["windows"]["sandbox"]) - { - context.Resource("Windows Sandbox") - .FeatureName("Containers-DisposableClientVM") - .Ensure(WindowsFeatureState.Enabled); - } - - context.Resource("Disable Game bar tips") - .Path(@"HKCU:\SOFTWARE\Microsoft\GameBar") - .Value("ShowStartupPanel") - .Data(0, RegistryValueKind.DWord); - - context.Resource("Disable Bing suggestions") - .Path(@"HKCU:\Software\Policies\Microsoft\Windows\Explorer") - .Value("DisableSearchBoxSuggestions") - .Data(1, RegistryValueKind.DWord); - - context.Resource("Disable Bing search") - .Path(@"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Search") - .Value("BingSearchEnabled") - .Data(0, RegistryValueKind.DWord); - - context.Resource("Disable lock screen") - .Path(@"HKLM:\SOFTWARE\Policies\Microsoft\Windows\Personalization") - .Value("NoLockScreen") - .Data(1, RegistryValueKind.DWord); - - context.Resource("Disable People in taskbar") - .Path(@"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People") - .Value("PeopleBand") - .Ensure(RegistryKeyState.DoNotExist); - - // File Explorer options - context.Resource("Show file extensions in File Explorer.") - .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced") - .Value("HideFileExt") - .Data(0, RegistryValueKind.DWord); - - context.Resource("Show hidden files in File Explorer") - .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced") - .Value("Hidden") - .Data(1, RegistryValueKind.DWord); - - context.Resource("Show full path in File Explorer title bar") - .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState") - .Value("FullPathAddress") - .Data(1, RegistryValueKind.DWord); + context.Resource("Windows Sandbox") + .FeatureName("Containers-DisposableClientVM") + .Ensure(WindowsFeatureState.Enabled); } + + context.Resource("Disable Game bar tips") + .Path(@"HKCU:\SOFTWARE\Microsoft\GameBar") + .Value("ShowStartupPanel") + .Data(0, RegistryValueKind.DWord); + + context.Resource("Disable Bing suggestions") + .Path(@"HKCU:\Software\Policies\Microsoft\Windows\Explorer") + .Value("DisableSearchBoxSuggestions") + .Data(1, RegistryValueKind.DWord); + + context.Resource("Disable Bing search") + .Path(@"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Search") + .Value("BingSearchEnabled") + .Data(0, RegistryValueKind.DWord); + + context.Resource("Disable lock screen") + .Path(@"HKLM:\SOFTWARE\Policies\Microsoft\Windows\Personalization") + .Value("NoLockScreen") + .Data(1, RegistryValueKind.DWord); + + context.Resource("Disable People in taskbar") + .Path(@"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People") + .Value("PeopleBand") + .Ensure(RegistryKeyState.DoNotExist); + + // File Explorer options + context.Resource("Show file extensions in File Explorer.") + .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced") + .Value("HideFileExt") + .Data(0, RegistryValueKind.DWord); + + context.Resource("Show hidden files in File Explorer") + .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced") + .Value("Hidden") + .Data(1, RegistryValueKind.DWord); + + context.Resource("Show full path in File Explorer title bar") + .Path(@"HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState") + .Value("FullPathAddress") + .Data(1, RegistryValueKind.DWord); } } diff --git a/src/Sandbox/Manifests/WingetPackages.cs b/src/Sandbox/Manifests/WingetPackages.cs index d9415b4..131a06d 100644 --- a/src/Sandbox/Manifests/WingetPackages.cs +++ b/src/Sandbox/Manifests/WingetPackages.cs @@ -1,16 +1,15 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public sealed class WingetPackages : Manifest { - public sealed class WingetPackages : Manifest + public override void Execute(ManifestContext context) { - public override void Execute(ManifestContext context) + foreach (var package in new[] { "GitHub.cli" }) { - foreach (var package in new[] { "GitHub.cli" }) - { - context.Resource(package) - .Ensure(PackageState.Installed); - } + context.Resource(package) + .Ensure(PackageState.Installed); } } } diff --git a/src/Sandbox/Program.cs b/src/Sandbox/Program.cs index a423ebc..db9bd52 100644 --- a/src/Sandbox/Program.cs +++ b/src/Sandbox/Program.cs @@ -1,23 +1,22 @@ using Cupboard; -namespace Sandbox +namespace Sandbox; + +public static class Program { - public static class Program + public static int Main(string[] args) { - public static int Main(string[] args) - { - return CupboardHost.CreateBuilder() - .AddCatalog() - .Run(args); - } + return CupboardHost.CreateBuilder() + .AddCatalog() + .Run(args); } +} - public sealed class SandboxCatalog : WindowsCatalog +public sealed class SandboxCatalog : WindowsCatalog +{ + public override void Execute(CatalogContext context) { - public override void Execute(CatalogContext context) - { - context.UseManifest(); - context.UseManifest(); - } + context.UseManifest(); + context.UseManifest(); } }