diff --git a/src/LocalStack.AwsLocal/AmbientContexts/ConsoleContext.cs b/src/LocalStack.AwsLocal/AmbientContexts/ConsoleContext.cs index 5b168fe..94ffac5 100644 --- a/src/LocalStack.AwsLocal/AmbientContexts/ConsoleContext.cs +++ b/src/LocalStack.AwsLocal/AmbientContexts/ConsoleContext.cs @@ -1,23 +1,20 @@ -using System; +namespace LocalStack.AwsLocal.AmbientContexts; -namespace LocalStack.AwsLocal.AmbientContexts +public abstract class ConsoleContext { - public abstract class ConsoleContext - { - private static ConsoleContext _current = DefaultConsoleContext.Instance; + private static ConsoleContext _current = DefaultConsoleContext.Instance; - public static ConsoleContext Current - { - get => _current; + public static ConsoleContext Current + { + get => _current; - set => _current = value ?? throw new ArgumentNullException(nameof(value)); - } + set => _current = value ?? throw new ArgumentNullException(nameof(value)); + } - public abstract void WriteLine(string text); + public abstract void WriteLine(string text); - public static void ResetToDefault() - { - _current = DefaultConsoleContext.Instance; - } + public static void ResetToDefault() + { + _current = DefaultConsoleContext.Instance; } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/AmbientContexts/DefaultConsoleContext.cs b/src/LocalStack.AwsLocal/AmbientContexts/DefaultConsoleContext.cs index a0997a8..dd52f78 100644 --- a/src/LocalStack.AwsLocal/AmbientContexts/DefaultConsoleContext.cs +++ b/src/LocalStack.AwsLocal/AmbientContexts/DefaultConsoleContext.cs @@ -1,16 +1,13 @@ -using System; +namespace LocalStack.AwsLocal.AmbientContexts; -namespace LocalStack.AwsLocal.AmbientContexts +public class DefaultConsoleContext : ConsoleContext { - public class DefaultConsoleContext : ConsoleContext - { - private static readonly Lazy LazyInstance = new Lazy(() => new DefaultConsoleContext()); - - public override void WriteLine(string text) - { - Console.WriteLine(text); - } + private static readonly Lazy LazyInstance = new(() => new DefaultConsoleContext()); - public static DefaultConsoleContext Instance => LazyInstance.Value; + public override void WriteLine(string text) + { + Console.WriteLine(text); } + + public static DefaultConsoleContext Instance => LazyInstance.Value; } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/AmbientContexts/DefaultEnvironmentContext.cs b/src/LocalStack.AwsLocal/AmbientContexts/DefaultEnvironmentContext.cs index 396e97a..08306e1 100644 --- a/src/LocalStack.AwsLocal/AmbientContexts/DefaultEnvironmentContext.cs +++ b/src/LocalStack.AwsLocal/AmbientContexts/DefaultEnvironmentContext.cs @@ -1,16 +1,13 @@ -using System; +namespace LocalStack.AwsLocal.AmbientContexts; -namespace LocalStack.AwsLocal.AmbientContexts +public class DefaultEnvironmentContext : EnvironmentContext { - public class DefaultEnvironmentContext : EnvironmentContext - { - private static readonly Lazy LazyInstance = new Lazy(() => new DefaultEnvironmentContext()); - - public override void Exit(int value) - { - Environment.Exit(value); - } + private static readonly Lazy LazyInstance = new(valueFactory: () => new DefaultEnvironmentContext()); - public static DefaultEnvironmentContext Instance => LazyInstance.Value; + public override void Exit(int value) + { + Environment.Exit(value); } + + public static DefaultEnvironmentContext Instance => LazyInstance.Value; } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/AmbientContexts/EnvironmentContext.cs b/src/LocalStack.AwsLocal/AmbientContexts/EnvironmentContext.cs index 6d0b3d6..3681117 100644 --- a/src/LocalStack.AwsLocal/AmbientContexts/EnvironmentContext.cs +++ b/src/LocalStack.AwsLocal/AmbientContexts/EnvironmentContext.cs @@ -1,23 +1,20 @@ -using System; +namespace LocalStack.AwsLocal.AmbientContexts; -namespace LocalStack.AwsLocal.AmbientContexts +public abstract class EnvironmentContext { - public abstract class EnvironmentContext - { - private static EnvironmentContext _current = DefaultEnvironmentContext.Instance; + private static EnvironmentContext _current = DefaultEnvironmentContext.Instance; - public static EnvironmentContext Current - { - get => _current; + public static EnvironmentContext Current + { + get => _current; - set => _current = value ?? throw new ArgumentNullException(nameof(value)); - } + set => _current = value ?? throw new ArgumentNullException(nameof(value)); + } - public abstract void Exit(int value); + public abstract void Exit(int value); - public static void ResetToDefault() - { - _current = DefaultEnvironmentContext.Instance; - } + public static void ResetToDefault() + { + _current = DefaultEnvironmentContext.Instance; } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/CommandDispatcher.cs b/src/LocalStack.AwsLocal/CommandDispatcher.cs index d958c9b..db412cd 100644 --- a/src/LocalStack.AwsLocal/CommandDispatcher.cs +++ b/src/LocalStack.AwsLocal/CommandDispatcher.cs @@ -1,184 +1,168 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using LocalStack.AwsLocal.AmbientContexts; -using LocalStack.AwsLocal.Contracts; -using LocalStack.AwsLocal.Extensions; -using LocalStack.AwsLocal.ProcessCore; -using LocalStack.AwsLocal.ProcessCore.IO; -using LocalStack.Client.Contracts; -using LocalStack.Client.Models; - -namespace LocalStack.AwsLocal +namespace LocalStack.AwsLocal; + +public class CommandDispatcher { - public class CommandDispatcher - { - private const string UsageResource = "LocalStack.AwsLocal.Docs.Usage.txt"; + private const string UsageResource = "LocalStack.AwsLocal.Docs.Usage.txt"; - private readonly IProcessRunner _processRunner; - private readonly IConfig _config; - private readonly IFileSystem _fileSystem; - private readonly string[] _args; + private readonly IProcessRunner _processRunner; + private readonly IConfig _config; + private readonly IFileSystem _fileSystem; + private readonly string[] _args; - public CommandDispatcher(IProcessRunner processRunner, IConfig config, IFileSystem fileSystem, string[] args) + public CommandDispatcher(IProcessRunner processRunner, IConfig config, IFileSystem fileSystem, string[] args) + { + _processRunner = processRunner; + _config = config; + _fileSystem = fileSystem; + _args = args; + } + + public void Run() + { + if (_args.Length == 0 || (_args[0] == "-h")) { - _processRunner = processRunner; - _config = config; - _fileSystem = fileSystem; - _args = args; + string usageInfo = GetUsageInfo(); + ConsoleContext.Current.WriteLine(usageInfo); + EnvironmentContext.Current.Exit(0); + return; } - public void Run() - { - if (_args.Length == 0 || (_args[0] == "-h")) - { - string usageInfo = GetUsageInfo(); - ConsoleContext.Current.WriteLine(usageInfo); - EnvironmentContext.Current.Exit(0); - return; - } + string serviceName = _args.ExtractServiceName(); - string serviceName = _args.ExtractServiceName(); + if (string.IsNullOrEmpty(serviceName)) + { + ConsoleContext.Current.WriteLine("ERROR: Invalid argument, please enter a valid aws cli command"); + EnvironmentContext.Current.Exit(1); + return; + } - if (string.IsNullOrEmpty(serviceName)) - { - ConsoleContext.Current.WriteLine("ERROR: Invalid argument, please enter a valid aws cli command"); - EnvironmentContext.Current.Exit(1); - return; - } + AwsServiceEndpoint awsServiceEndpoint = _config.GetServiceEndpoint(serviceName); - AwsServiceEndpoint? awsServiceEndpoint = _config.GetServiceEndpoint(serviceName); + if (awsServiceEndpoint == null) + { + ConsoleContext.Current.WriteLine($"ERROR: Unable to find LocalStack endpoint for service {serviceName}"); + EnvironmentContext.Current.Exit(1); + return; + } - if (awsServiceEndpoint == null) - { - ConsoleContext.Current.WriteLine($"ERROR: Unable to find LocalStack endpoint for service {serviceName}"); - EnvironmentContext.Current.Exit(1); - return; - } + var processSettings = new ProcessSettings { NoWorkingDirectory = true, Silent = true, EnvironmentVariables = new Dictionary() }; - var processSettings = new ProcessSettings - { NoWorkingDirectory = true, Silent = true, EnvironmentVariables = new Dictionary() }; + string defaultRegion = Environment.GetEnvironmentVariable("DEFAULT_REGION"); - string? defaultRegion = Environment.GetEnvironmentVariable("DEFAULT_REGION"); + if (!string.IsNullOrEmpty(defaultRegion)) + { + ConsoleContext.Current.WriteLine("Environment variable \"AWS_DEFAULT_REGION\" will be overwritten by \"DEFAULT_REGION\""); - if (!string.IsNullOrEmpty(defaultRegion)) - { - ConsoleContext.Current.WriteLine("Environment variable \"AWS_DEFAULT_REGION\" will be overwritten by \"DEFAULT_REGION\""); + Environment.SetEnvironmentVariable("AWS_DEFAULT_REGION", defaultRegion); + } - Environment.SetEnvironmentVariable("AWS_DEFAULT_REGION", defaultRegion); - } + processSettings.EnvironmentVariables.Add("AWS_DEFAULT_REGION", Environment.GetEnvironmentVariable("AWS_DEFAULT_REGION") ?? "us-east-1"); + processSettings.EnvironmentVariables.Add("AWS_ACCESS_KEY_ID", Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID") ?? "_not_needed_locally_"); + processSettings.EnvironmentVariables.Add("AWS_SECRET_ACCESS_KEY", Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY") ?? "_not_needed_locally_"); - processSettings.EnvironmentVariables.Add("AWS_DEFAULT_REGION", Environment.GetEnvironmentVariable("AWS_DEFAULT_REGION") ?? "us-east-1"); - processSettings.EnvironmentVariables.Add("AWS_ACCESS_KEY_ID", Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID") ?? "_not_needed_locally_"); - processSettings.EnvironmentVariables.Add("AWS_SECRET_ACCESS_KEY", Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY") ?? "_not_needed_locally_"); + var builder = new ProcessArgumentBuilder(); + builder.Append(_args[0]); + builder.AppendSwitch("--endpoint-url", "=", awsServiceEndpoint.ServiceUrl); - var builder = new ProcessArgumentBuilder(); - builder.Append(_args[0]); - builder.AppendSwitch("--endpoint-url", "=", awsServiceEndpoint.ServiceUrl); + if (awsServiceEndpoint.ServiceUrl.StartsWith("https")) + { + builder.Append("--no-verify-ssl"); + } - if (awsServiceEndpoint.ServiceUrl.StartsWith("https")) + var passToNextArgument = false; + for (var i = 0; i < _args.Length; i++) + { + string argument = _args[i]; + + if (argument == _args[0]) { - builder.Append("--no-verify-ssl"); + continue; } - var passToNextArgument = false; - for (var i = 0; i < _args.Length; i++) + if (passToNextArgument) { - string argument = _args[i]; - - if (argument == _args[0]) - { - continue; - } + passToNextArgument = false; + continue; + } - if (passToNextArgument) - { - passToNextArgument = false; - continue; - } + if (argument.StartsWith("--") && !argument.Contains("=") && i + 1 < _args.Length) // switch argument + { + string nextArgument = _args[i + 1]; + builder.AppendSwitchQuoted(argument, " ", nextArgument); - if (argument.StartsWith("--") && !argument.Contains("=") && i + 1 < _args.Length) // switch argument - { - string nextArgument = _args[i + 1]; - builder.AppendSwitchQuoted(argument, " ", nextArgument); + passToNextArgument = true; + continue; + } - passToNextArgument = true; - continue; - } + builder.Append(argument); + } - builder.Append(argument); - } + processSettings.Arguments = builder; - processSettings.Arguments = builder; + string[] awsExec = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? new[] {"aws.exe", "aws.cmd"} + : new[] {"aws"}; - string[] awsExec = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? new[] {"aws.exe", "aws.cmd"} - : new[] {"aws"}; + FilePath awsPath = GetAwsPath(awsExec); - FilePath? awsPath = GetAwsPath(awsExec); + if (awsPath == null) + { + ConsoleContext.Current.WriteLine($"ERROR: Unable to find aws cli. Executable name: {string.Join(',', awsExec)}"); + EnvironmentContext.Current.Exit(1); + return; + } - if (awsPath == null) - { - ConsoleContext.Current.WriteLine( - $"ERROR: Unable to find aws cli. Executable name: {string.Join(',', awsExec)}"); - EnvironmentContext.Current.Exit(1); - return; - } + IProcess process = _processRunner.Start(awsPath, processSettings); - IProcess? process = _processRunner.Start(awsPath, processSettings); + process?.WaitForExit(); + } - process?.WaitForExit(); - } + private static string GetUsageInfo() + { + using Stream stream = Assembly.GetCallingAssembly().GetManifestResourceStream(UsageResource); + using var reader = new StreamReader(stream ?? throw new NullReferenceException(nameof(stream))); + string result = reader.ReadToEnd(); - private static string GetUsageInfo() - { - using Stream? stream = Assembly.GetCallingAssembly().GetManifestResourceStream(UsageResource); - using var reader = new StreamReader(stream ?? throw new NullReferenceException(nameof(stream))); - string result = reader.ReadToEnd(); + return result; + } - return result; - } + private FilePath GetAwsPath(params string[] awsPaths) + { + string[] pathDirs = null; - private FilePath? GetAwsPath(params string[] awsPaths) + // Look for each possible executable name in various places. + foreach (string toolExeName in awsPaths) { - string[]? pathDirs = null; - // Look for each possible executable name in various places. - foreach (string toolExeName in awsPaths) + // Cache the PATH directory list if we didn't already. + if (pathDirs == null) { - - // Cache the PATH directory list if we didn't already. - if (pathDirs == null) + string pathEnv = Environment.GetEnvironmentVariable("PATH"); + if (!string.IsNullOrEmpty(pathEnv)) { - string? pathEnv = Environment.GetEnvironmentVariable("PATH"); - if (!string.IsNullOrEmpty(pathEnv)) - { - pathDirs = pathEnv.Split(new[] { !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ':' : ';' }, - StringSplitOptions.RemoveEmptyEntries); - } - else - { - pathDirs = new string[] { }; - } + pathDirs = pathEnv.Split(new[] { !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ':' : ';' }, + StringSplitOptions.RemoveEmptyEntries); } - - // Look in every PATH directory for the file. - foreach (var pathDir in pathDirs) + else { - FilePath file = new DirectoryPath(pathDir).CombineWithFilePath(toolExeName); - if (_fileSystem.Exist(file)) - { - return file.FullPath; - } + pathDirs = Array.Empty(); } } - return null; + // Look in every PATH directory for the file. + foreach (string pathDir in pathDirs) + { + FilePath file = new DirectoryPath(pathDir).CombineWithFilePath(toolExeName); + if (_fileSystem.Exist(file)) + { + return file.FullPath; + } + } } + + return null; } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IDirectory.cs b/src/LocalStack.AwsLocal/Contracts/IDirectory.cs index a701380..fee17b4 100644 --- a/src/LocalStack.AwsLocal/Contracts/IDirectory.cs +++ b/src/LocalStack.AwsLocal/Contracts/IDirectory.cs @@ -7,51 +7,47 @@ * ***************************************************************************************/ -using System.Collections.Generic; -using LocalStack.AwsLocal.ProcessCore.IO; +namespace LocalStack.AwsLocal.Contracts; -namespace LocalStack.AwsLocal.Contracts +/// Represents a directory. +public interface IDirectory : IFileSystemInfo { - /// Represents a directory. - public interface IDirectory : IFileSystemInfo - { - /// - /// Gets the path to the directory. - /// - /// The path. - new DirectoryPath? Path { get; } + /// + /// Gets the path to the directory. + /// + /// The path. + new DirectoryPath Path { get; } - /// - /// Creates the directory. - /// - void Create(); + /// + /// Creates the directory. + /// + void Create(); - /// - /// Moves the directory to the specified destination path. - /// - /// The destination path. - void Move(DirectoryPath destination); + /// + /// Moves the directory to the specified destination path. + /// + /// The destination path. + void Move(DirectoryPath destination); - /// - /// Deletes the directory. - /// - /// Will perform a recursive delete if set to true. - void Delete(bool recursive); + /// + /// Deletes the directory. + /// + /// Will perform a recursive delete if set to true. + void Delete(bool recursive); - /// - /// Gets directories matching the specified filter and scope. - /// - /// The filter. - /// The search scope. - /// Directories matching the filter and scope. - IEnumerable GetDirectories(string filter, SearchScope scope); + /// + /// Gets directories matching the specified filter and scope. + /// + /// The filter. + /// The search scope. + /// Directories matching the filter and scope. + IEnumerable GetDirectories(string filter, SearchScope scope); - /// - /// Gets files matching the specified filter and scope. - /// - /// The filter. - /// The search scope. - /// Files matching the specified filter and scope. - IEnumerable GetFiles(string filter, SearchScope scope); - } + /// + /// Gets files matching the specified filter and scope. + /// + /// The filter. + /// The search scope. + /// Files matching the specified filter and scope. + IEnumerable GetFiles(string filter, SearchScope scope); } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IFile.cs b/src/LocalStack.AwsLocal/Contracts/IFile.cs index 1e33c44..50757d8 100644 --- a/src/LocalStack.AwsLocal/Contracts/IFile.cs +++ b/src/LocalStack.AwsLocal/Contracts/IFile.cs @@ -7,59 +7,55 @@ * ***************************************************************************************/ -using System.IO; -using LocalStack.AwsLocal.ProcessCore.IO; +namespace LocalStack.AwsLocal.Contracts; -namespace LocalStack.AwsLocal.Contracts +/// +/// Represents a file. +/// +public interface IFile : IFileSystemInfo { /// - /// Represents a file. + /// Gets the path to the file. /// - public interface IFile : IFileSystemInfo - { - /// - /// Gets the path to the file. - /// - /// The path. - new FilePath? Path { get; } + /// The path. + new FilePath Path { get; } - /// - /// Gets the length of the file. - /// - /// The length of the file. - long Length { get; } + /// + /// Gets the length of the file. + /// + /// The length of the file. + long Length { get; } - /// - /// Gets or sets the file attributes. - /// - /// The file attributes. - FileAttributes Attributes { get; set; } + /// + /// Gets or sets the file attributes. + /// + /// The file attributes. + FileAttributes Attributes { get; set; } - /// - /// Copies the file to the specified destination path. - /// - /// The destination path. - /// Will overwrite existing destination file if set to true. - void Copy(FilePath destination, bool overwrite); + /// + /// Copies the file to the specified destination path. + /// + /// The destination path. + /// Will overwrite existing destination file if set to true. + void Copy(FilePath destination, bool overwrite); - /// - /// Moves the file to the specified destination path. - /// - /// The destination path. - void Move(FilePath destination); + /// + /// Moves the file to the specified destination path. + /// + /// The destination path. + void Move(FilePath destination); - /// - /// Deletes the file. - /// - void Delete(); + /// + /// Deletes the file. + /// + void Delete(); - /// - /// Opens the file using the specified options. - /// - /// The file mode. - /// The file access. - /// The file share. - /// A to the file. - Stream Open(FileMode fileMode, FileAccess fileAccess, FileShare fileShare); - } + /// + /// Opens the file using the specified options. + /// + /// The file mode. + /// The file access. + /// The file share. + /// A to the file. + Stream Open(FileMode fileMode, FileAccess fileAccess, FileShare fileShare); } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IFileSystem.cs b/src/LocalStack.AwsLocal/Contracts/IFileSystem.cs index 79c281d..7d8188b 100644 --- a/src/LocalStack.AwsLocal/Contracts/IFileSystem.cs +++ b/src/LocalStack.AwsLocal/Contracts/IFileSystem.cs @@ -7,27 +7,24 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.ProcessCore.IO; +namespace LocalStack.AwsLocal.Contracts; -namespace LocalStack.AwsLocal.Contracts +/// +/// Represents a file system. +/// +public interface IFileSystem { /// - /// Represents a file system. + /// Gets a instance representing the specified path. /// - public interface IFileSystem - { - /// - /// Gets a instance representing the specified path. - /// - /// The path. - /// A instance representing the specified path. - IFile GetFile(FilePath path); + /// The path. + /// A instance representing the specified path. + IFile GetFile(FilePath path); - /// - /// Gets a instance representing the specified path. - /// - /// The path. - /// A instance representing the specified path. - IDirectory GetDirectory(DirectoryPath path); - } -} + /// + /// Gets a instance representing the specified path. + /// + /// The path. + /// A instance representing the specified path. + IDirectory GetDirectory(DirectoryPath path); +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IFileSystemInfo.cs b/src/LocalStack.AwsLocal/Contracts/IFileSystemInfo.cs index 23f5591..2003ef7 100644 --- a/src/LocalStack.AwsLocal/Contracts/IFileSystemInfo.cs +++ b/src/LocalStack.AwsLocal/Contracts/IFileSystemInfo.cs @@ -7,35 +7,34 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.ProcessCore.IO; +using Path = LocalStack.AwsLocal.ProcessCore.IO.Path; -namespace LocalStack.AwsLocal.Contracts +namespace LocalStack.AwsLocal.Contracts; + +/// +/// Represents an entry in the file system +/// +public interface IFileSystemInfo { /// - /// Represents an entry in the file system + /// Gets the path to the entry. /// - public interface IFileSystemInfo - { - /// - /// Gets the path to the entry. - /// - /// The path. - Path? Path { get; } + /// The path. + Path Path { get; } - /// - /// Gets a value indicating whether this exists. - /// - /// - /// true if the entry exists; otherwise, false. - /// - bool Exists { get; } + /// + /// Gets a value indicating whether this exists. + /// + /// + /// true if the entry exists; otherwise, false. + /// + bool Exists { get; } - /// - /// Gets a value indicating whether this is hidden. - /// - /// - /// true if the entry is hidden; otherwise, false. - /// - bool Hidden { get; } - } + /// + /// Gets a value indicating whether this is hidden. + /// + /// + /// true if the entry is hidden; otherwise, false. + /// + bool Hidden { get; } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IProcess.cs b/src/LocalStack.AwsLocal/Contracts/IProcess.cs index 8413959..12a0c3b 100644 --- a/src/LocalStack.AwsLocal/Contracts/IProcess.cs +++ b/src/LocalStack.AwsLocal/Contracts/IProcess.cs @@ -7,49 +7,45 @@ * ***************************************************************************************/ -using System; -using System.Collections.Generic; +namespace LocalStack.AwsLocal.Contracts; -namespace LocalStack.AwsLocal.Contracts +/// +/// Represents a process. +/// +public interface IProcess : IDisposable { /// - /// Represents a process. + /// Waits for the process to exit. /// - public interface IProcess : IDisposable - { - /// - /// Waits for the process to exit. - /// - void WaitForExit(); + void WaitForExit(); - /// - /// Waits for the process to exit with possible timeout for command. - /// - /// The amount of time, in milliseconds, to wait for the associated process to exit. The maximum is the largest possible value of a 32-bit integer, which represents infinity to the operating system. - /// true if the associated process has exited; otherwise, false. - bool WaitForExit(int milliseconds); + /// + /// Waits for the process to exit with possible timeout for command. + /// + /// The amount of time, in milliseconds, to wait for the associated process to exit. The maximum is the largest possible value of a 32-bit integer, which represents infinity to the operating system. + /// true if the associated process has exited; otherwise, false. + bool WaitForExit(int milliseconds); - /// - /// Gets the exit code of the process. - /// - /// The exit code of the process. - int GetExitCode(); + /// + /// Gets the exit code of the process. + /// + /// The exit code of the process. + int GetExitCode(); - /// - /// Get the standard error of process. - /// - /// Returns process error output if RedirectStandardError is true - IEnumerable GetStandardError(); + /// + /// Get the standard error of process. + /// + /// Returns process error output if RedirectStandardError is true + IEnumerable GetStandardError(); - /// - /// Get the standard output of process - /// - /// Returns process output if RedirectStandardOutput is true - IEnumerable GetStandardOutput(); + /// + /// Get the standard output of process + /// + /// Returns process output if RedirectStandardOutput is true + IEnumerable GetStandardOutput(); - /// - /// Immediately stops the associated process. - /// - void Kill(); - } -} + /// + /// Immediately stops the associated process. + /// + void Kill(); +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IProcessArgument.cs b/src/LocalStack.AwsLocal/Contracts/IProcessArgument.cs index 4d9cc97..f1d296f 100644 --- a/src/LocalStack.AwsLocal/Contracts/IProcessArgument.cs +++ b/src/LocalStack.AwsLocal/Contracts/IProcessArgument.cs @@ -7,25 +7,24 @@ * ***************************************************************************************/ -namespace LocalStack.AwsLocal.Contracts +namespace LocalStack.AwsLocal.Contracts; + +/// +/// Represents a process argument. +/// +public interface IProcessArgument { /// - /// Represents a process argument. + /// Render the arguments as a . + /// Sensitive information will be included. /// - public interface IProcessArgument - { - /// - /// Render the arguments as a . - /// Sensitive information will be included. - /// - /// A string representation of the argument. - string Render(); + /// A string representation of the argument. + string Render(); - /// - /// Renders the argument as a . - /// Sensitive information will be redacted. - /// - /// A safe string representation of the argument. - string RenderSafe(); - } -} + /// + /// Renders the argument as a . + /// Sensitive information will be redacted. + /// + /// A safe string representation of the argument. + string RenderSafe(); +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Contracts/IProcessRunner.cs b/src/LocalStack.AwsLocal/Contracts/IProcessRunner.cs index e9534df..36d03b9 100644 --- a/src/LocalStack.AwsLocal/Contracts/IProcessRunner.cs +++ b/src/LocalStack.AwsLocal/Contracts/IProcessRunner.cs @@ -7,10 +7,6 @@ * ***************************************************************************************/ - -using LocalStack.AwsLocal.ProcessCore; -using LocalStack.AwsLocal.ProcessCore.IO; - namespace LocalStack.AwsLocal.Contracts { /// @@ -24,6 +20,6 @@ public interface IProcessRunner /// The file name such as an application or document with which to start the process. /// The information about the process to start. /// A process handle. - IProcess? Start(FilePath filePath, ProcessSettings settings); + IProcess Start(FilePath filePath, ProcessSettings settings); } } diff --git a/src/LocalStack.AwsLocal/Extensions/ArgumentExtensions.cs b/src/LocalStack.AwsLocal/Extensions/ArgumentExtensions.cs index 32e95c6..1a8c528 100644 --- a/src/LocalStack.AwsLocal/Extensions/ArgumentExtensions.cs +++ b/src/LocalStack.AwsLocal/Extensions/ArgumentExtensions.cs @@ -1,37 +1,33 @@ -using System.Collections.Generic; -using System.Linq; +namespace LocalStack.AwsLocal.Extensions; -namespace LocalStack.AwsLocal.Extensions +public static class ArgumentExtensions { - public static class ArgumentExtensions + public static string ExtractServiceName(this IEnumerable args) { - public static string ExtractServiceName(this IEnumerable args) + foreach (string arg in args) { - foreach (string arg in args) + if (arg.StartsWith('-')) { - if (arg.StartsWith('-')) - { - continue; - } - - return arg == "s3api" ? "s3" : arg; + continue; } - return string.Empty; + return arg == "s3api" ? "s3" : arg; } - public static string GetCliCommand(this IEnumerable args, string serviceUrl) - { - var arguments = args.ToList(); - arguments.Insert(0, "aws"); - arguments.Insert(1, $"--endpoint-url={serviceUrl}"); + return string.Empty; + } - if (serviceUrl.StartsWith("https")) - { - arguments.Insert(2, "--no-verify-ssl"); - } + public static string GetCliCommand(this IEnumerable args, string serviceUrl) + { + List arguments = args.ToList(); + arguments.Insert(0, "aws"); + arguments.Insert(1, $"--endpoint-url={serviceUrl}"); - return string.Join(' ', arguments); + if (serviceUrl.StartsWith("https")) + { + arguments.Insert(2, "--no-verify-ssl"); } + + return string.Join(' ', arguments); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Extensions/ConfigExtensions.cs b/src/LocalStack.AwsLocal/Extensions/ConfigExtensions.cs index 9c9e5f9..a9f125a 100644 --- a/src/LocalStack.AwsLocal/Extensions/ConfigExtensions.cs +++ b/src/LocalStack.AwsLocal/Extensions/ConfigExtensions.cs @@ -1,17 +1,11 @@ -using System.Collections.Generic; -using System.Linq; -using LocalStack.Client.Contracts; -using LocalStack.Client.Models; +namespace LocalStack.AwsLocal.Extensions; -namespace LocalStack.AwsLocal.Extensions +public static class ConfigExtensions { - public static class ConfigExtensions + public static AwsServiceEndpoint GetServiceEndpoint(this IConfig config, string serviceName) { - public static AwsServiceEndpoint? GetServiceEndpoint(this IConfig config, string serviceName) - { - IEnumerable? awsServiceEndpoints = config.GetAwsServiceEndpoints(); + IEnumerable awsServiceEndpoints = config.GetAwsServiceEndpoints(); - return awsServiceEndpoints.SingleOrDefault(endpoint => endpoint.CliName == serviceName); - } + return awsServiceEndpoints.SingleOrDefault(endpoint => endpoint.CliName == serviceName); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Extensions/FileSystemExtensions.cs b/src/LocalStack.AwsLocal/Extensions/FileSystemExtensions.cs index f49f33f..810034b 100644 --- a/src/LocalStack.AwsLocal/Extensions/FileSystemExtensions.cs +++ b/src/LocalStack.AwsLocal/Extensions/FileSystemExtensions.cs @@ -1,44 +1,41 @@ -using System; -using LocalStack.AwsLocal.Contracts; -using LocalStack.AwsLocal.ProcessCore.IO; +namespace LocalStack.AwsLocal.Extensions; -namespace LocalStack.AwsLocal.Extensions +/// +/// Contains extensions for . +/// +public static class FileSystemExtensions { /// - /// Contains extensions for . + /// Determines if a specified exist. /// - public static class FileSystemExtensions + /// The file system. + /// The file system. + /// Whether or not the specified file exist. + public static bool Exist(this IFileSystem fileSystem, FilePath path) { - /// - /// Determines if a specified exist. - /// - /// The file system. - /// The path. - /// Whether or not the specified file exist. - public static bool Exist(this IFileSystem fileSystem, FilePath path) + if (fileSystem == null) { - if (fileSystem == null) - { - throw new ArgumentNullException(nameof(fileSystem)); - } - var file = fileSystem.GetFile(path); - return file != null && file.Exists; + throw new ArgumentNullException(nameof(fileSystem)); } + IFile file = fileSystem.GetFile(path); + + return file is { Exists: true }; + } - /// - /// Determines if a specified exist. - /// - /// The file system. - /// The path. - /// Whether or not the specified directory exist. - public static bool Exist(this IFileSystem fileSystem, DirectoryPath path) + /// + /// Determines if a specified exist. + /// + /// The file system. + /// The path. + /// Whether or not the specified directory exist. + public static bool Exist(this IFileSystem fileSystem, DirectoryPath path) + { + if (fileSystem == null) { - if (fileSystem == null) - { - throw new ArgumentNullException(nameof(fileSystem)); - } - var directory = fileSystem.GetDirectory(path); - return directory != null && directory.Exists; + throw new ArgumentNullException(nameof(fileSystem)); } + IDirectory directory = fileSystem.GetDirectory(path); + + return directory is { Exists: true }; } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Extensions/ProcessArgumentListExtensions.cs b/src/LocalStack.AwsLocal/Extensions/ProcessArgumentListExtensions.cs index 9298c75..9bfbf91 100644 --- a/src/LocalStack.AwsLocal/Extensions/ProcessArgumentListExtensions.cs +++ b/src/LocalStack.AwsLocal/Extensions/ProcessArgumentListExtensions.cs @@ -7,704 +7,697 @@ * ***************************************************************************************/ -using System; -using System.Globalization; -using LocalStack.AwsLocal.Contracts; -using LocalStack.AwsLocal.ProcessCore; -using LocalStack.AwsLocal.ProcessCore.Arguments; +namespace LocalStack.AwsLocal.Extensions; -namespace LocalStack.AwsLocal.Extensions +public static class ProcessArgumentListExtensions { - public static class ProcessArgumentListExtensions - { - /// - /// Appends the specified text to the argument builder. - /// - /// The builder. - /// The text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? Append(this ProcessArgumentBuilder builder, string text) - { - builder?.Append(new TextArgument(text)); - return builder; - } + /// + /// Appends the specified text to the argument builder. + /// + /// The builder. + /// The text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder Append(this ProcessArgumentBuilder builder, string text) + { + builder?.Append(new TextArgument(text)); + return builder; + } - /// - /// Prepend the specified text to the argument builder. - /// - /// The builder. - /// The text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? Prepend(this ProcessArgumentBuilder builder, string text) - { - builder?.Prepend(new TextArgument(text)); - return builder; - } + /// + /// Prepend the specified text to the argument builder. + /// + /// The builder. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder Prepend(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new TextArgument(text)); + return builder; + } - /// - /// Formats and appends the specified text to the argument builder. - /// - /// The builder. - /// A composite format string. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - public static ProcessArgumentBuilder? Append(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return Append(builder, text); - } + /// + /// Formats and appends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder Append(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return Append(builder, text); + } - /// - /// Formats and prepends the specified text to the argument builder. - /// - /// The builder. - /// A composite format string. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - public static ProcessArgumentBuilder? Prepend(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return Prepend(builder, text); - } + /// + /// Formats and prepends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder Prepend(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return Prepend(builder, text); + } - /// - /// Quotes and appends the specified text to the argument builder. - /// - /// The builder. - /// The text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuoted(this ProcessArgumentBuilder builder, string text) - { - builder?.Append(new QuotedArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and appends the specified text to the argument builder. + /// + /// The builder. + /// The text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder builder, string text) + { + builder?.Append(new QuotedArgument(new TextArgument(text))); + return builder; + } - /// - /// Quotes and prepends the specified text to the argument builder. - /// - /// The builder. - /// The text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuoted(this ProcessArgumentBuilder builder, string text) - { - builder?.Prepend(new QuotedArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new QuotedArgument(new TextArgument(text))); + return builder; + } - /// - /// Formats, quotes and appends the specified text to the argument builder. - /// - /// The builder. - /// A composite format string to be quoted and appended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - public static ProcessArgumentBuilder? AppendQuoted(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return AppendQuoted(builder, text); - } + /// + /// Formats, quotes and appends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string to be quoted and appended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return AppendQuoted(builder, text); + } - /// - /// Formats, quotes and prepends the specified text to the argument builder. - /// - /// The builder. - /// A composite format string to be quoted and prepended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - public static ProcessArgumentBuilder? PrependQuoted(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return PrependQuoted(builder, text); - } + /// + /// Formats, quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string to be quoted and prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependQuoted(builder, text); + } - /// - /// Quotes and appends the specified argument to the argument builder. - /// - /// The builder. - /// The argument to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuoted(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.Append(new QuotedArgument(argument)); - return builder; - } + /// + /// Quotes and appends the specified argument to the argument builder. + /// + /// The builder. + /// The argument to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Append(new QuotedArgument(argument)); + return builder; + } - /// - /// Quotes and prepends the specified argument to the argument builder. - /// - /// The builder. - /// The argument to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuoted(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.Prepend(new QuotedArgument(argument)); - return builder; - } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Prepend(new QuotedArgument(argument)); + return builder; + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSecret(this ProcessArgumentBuilder builder, string text) - { - builder?.Append(new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.Append(new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Prepends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSecret(this ProcessArgumentBuilder builder, string text) - { - builder?.Prepend(new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Formats and appends the specified secret text to the argument builder. - /// - /// The builder. - /// A composite format string for the secret text to be appended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSecret(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return AppendSecret(builder, text); - } + /// + /// Formats and appends the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be appended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return AppendSecret(builder, text); + } - /// - /// Formats and prepend the specified secret text to the argument builder. - /// - /// The builder. - /// A composite format string for the secret text to be prepended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSecret(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return PrependSecret(builder, text); - } + /// + /// Formats and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependSecret(builder, text); + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.Append(new SecretArgument(argument)); - return builder; - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Append(new SecretArgument(argument)); + return builder; + } - /// - /// Prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.Prepend(new SecretArgument(argument)); - return builder; - } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Prepend(new SecretArgument(argument)); + return builder; + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuotedSecret(this ProcessArgumentBuilder builder, string text) - { - builder?.AppendQuoted(new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.AppendQuoted(new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Quotes and prepends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuotedSecret(this ProcessArgumentBuilder builder, string text) - { - builder?.PrependQuoted(new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.PrependQuoted(new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Formats, quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// A composite format string for the secret text to be quoted and appended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuotedSecret(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return AppendQuotedSecret(builder, text); - } + /// + /// Formats, quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be quoted and appended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return AppendQuotedSecret(builder, text); + } - /// - /// Formats, quotes and prepends the specified secret text to the argument builder. - /// - /// The builder. - /// A composite format string for the secret text to be quoted and prepended. - /// An object array that contains zero or more objects to format. - /// The same instance so that multiple calls can be chained. - /// or is null. - /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuotedSecret(this ProcessArgumentBuilder builder, string format, params object[] args) - { - var text = string.Format(CultureInfo.InvariantCulture, format, args); - return PrependQuotedSecret(builder, text); - } + /// + /// Formats, quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be quoted and prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + string text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependQuotedSecret(builder, text); + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuotedSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.AppendQuoted(new SecretArgument(argument)); - return builder; - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.AppendQuoted(new SecretArgument(argument)); + return builder; + } - /// - /// Quotes and prepends the specified secret text to the argument builder. - /// - /// The builder. - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuotedSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) - { - builder?.PrependQuoted(new SecretArgument(argument)); - return builder; - } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.PrependQuoted(new SecretArgument(argument)); + return builder; + } - /// - /// Appends the specified switch to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitch(this ProcessArgumentBuilder builder, string @switch, string text) - { - return AppendSwitch(builder, @switch, " ", text); - } + /// + /// Appends the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder builder, string @switch, string text) + { + return AppendSwitch(builder, @switch, " ", text); + } - /// - /// Prepend the specified switch to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string text) - { - return PrependSwitch(builder, @switch, " ", text); - } + /// + /// Prepend the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitch(builder, @switch, " ", text); + } - /// - /// Appends the specified switch to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Append(new SwitchArgument(@switch, new TextArgument(text), separator)); - return builder; - } + /// + /// Appends the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Append(new SwitchArgument(@switch, new TextArgument(text), separator)); + return builder; + } - /// - /// Prepend the specified switch to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Prepend(new SwitchArgument(@switch, new TextArgument(text), separator)); - return builder; - } + /// + /// Prepend the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new TextArgument(text), separator)); + return builder; + } - /// - /// Quotes and appends the specified text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string text) - { - return AppendSwitchQuoted(builder, @switch, " ", text); - } + /// + /// Quotes and appends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string text) + { + return AppendSwitchQuoted(builder, @switch, " ", text); + } - /// - /// Quotes and prepends the specified text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string text) - { - return PrependSwitchQuoted(builder, @switch, " ", text); - } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchQuoted(builder, @switch, " ", text); + } - /// - /// Quotes and appends the specified text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Append(new SwitchArgument(@switch, new QuotedArgument(new TextArgument(text)), separator)); - return builder; - } + /// + /// Quotes and appends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Append(new SwitchArgument(@switch, new QuotedArgument(new TextArgument(text)), separator)); + return builder; + } - /// - /// Quotes and prepends the specified text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(new TextArgument(text)), separator)); - return builder; - } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(new TextArgument(text)), separator)); + return builder; + } - /// - /// Quotes and appends the specified argument to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The argument to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return AppendSwitchQuoted(builder, @switch, " ", argument); - } + /// + /// Quotes and appends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The argument to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return AppendSwitchQuoted(builder, @switch, " ", argument); + } - /// - /// Quotes and prepends the specified argument to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The argument to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return PrependSwitchQuoted(builder, @switch, " ", argument); - } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependSwitchQuoted(builder, @switch, " ", argument); + } - /// - /// Quotes and appends the specified argument to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The argument to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) - { - builder?.Append(new SwitchArgument(@switch, new QuotedArgument(argument), separator)); - return builder; - } + /// + /// Quotes and appends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The argument to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Append(new SwitchArgument(@switch, new QuotedArgument(argument), separator)); + return builder; + } - /// - /// Quotes and prepends the specified argument to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The argument to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) - { - builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(argument), separator)); - return builder; - } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(argument), separator)); + return builder; + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string text) - { - return AppendSwitchSecret(builder, @switch, " ", text); - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return AppendSwitchSecret(builder, @switch, " ", text); + } - /// - /// Prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string text) - { - return PrependSwitchSecret(builder, @switch, " ", text); - } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchSecret(builder, @switch, " ", text); + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret text to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Append(new SwitchArgument(@switch, new SecretArgument(new TextArgument(text)), separator)); - return builder; - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret text to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Append(new SwitchArgument(@switch, new SecretArgument(new TextArgument(text)), separator)); + return builder; + } - /// - /// Prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret text to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(new TextArgument(text)), separator)); - return builder; - } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(new TextArgument(text)), separator)); + return builder; + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return AppendSwitchSecret(builder, @switch, " ", argument); - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return AppendSwitchSecret(builder, @switch, " ", argument); + } - /// - /// Prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return PrependSwitchSecret(builder, @switch, " ", argument); - } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependSwitchSecret(builder, @switch, " ", argument); + } - /// - /// Appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) - { - builder?.Append(new SwitchArgument(@switch, new SecretArgument(argument), separator)); - return builder; - } + /// + /// Appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Append(new SwitchArgument(@switch, new SecretArgument(argument), separator)); + return builder; + } - /// - /// Prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) - { - builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(argument), separator)); - return builder; - } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(argument), separator)); + return builder; + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string text) - { - return AppendSwitchQuotedSecret(builder, @switch, " ", text); - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return AppendSwitchQuotedSecret(builder, @switch, " ", text); + } - /// - /// Quotes and prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string text) - { - return PrependSwitchQuotedSecret(builder, @switch, " ", text); - } + /// + /// Quotes and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchQuotedSecret(builder, @switch, " ", text); + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The secret text to be quoted and appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.AppendSwitchQuoted(@switch, separator, new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The secret text to be quoted and appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.AppendSwitchQuoted(@switch, separator, new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Quotes and prepends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument. - /// The secret text to be quoted and prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) - { - builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(new TextArgument(text))); - return builder; - } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(new TextArgument(text))); + return builder; + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuotedSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return AppendQuotedSecret(builder, @switch, " ", argument); - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return AppendQuotedSecret(builder, @switch, " ", argument); + } - /// - /// Quotes and prepends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) - { - return PrependQuotedSecret(builder, @switch, " ", argument); - } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependQuotedSecret(builder, @switch, " ", argument); + } - /// - /// Quotes and appends the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret argument to be appended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? AppendQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) - { - builder?.AppendSwitchQuoted(@switch, separator, new SecretArgument(argument)); - return builder; - } + /// + /// Quotes and appends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.AppendSwitchQuoted(@switch, separator, new SecretArgument(argument)); + return builder; + } + + /// + /// Quotes and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(argument)); + return builder; + } + + /// + /// Indicates whether a is null or renders empty. + /// + /// The builder. + /// true if refers to a null or empty ; + /// false if the refers to non null or empty + public static bool IsNullOrEmpty(this ProcessArgumentBuilder builder) + { + return builder == null || builder.Count == 0 || string.IsNullOrEmpty(builder.Render()); + } - /// - /// Quotes and prepend the specified secret text to the argument builder. - /// - /// The builder. - /// The switch preceding the text. - /// The separator between the switch and argument - /// The secret argument to be prepended. - /// The same instance so that multiple calls can be chained. - public static ProcessArgumentBuilder? PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + /// + /// Copies all the arguments of the source to target . + /// + /// The argument builder to copy from.. + /// The argument builder to copy to. + public static void CopyTo(this ProcessArgumentBuilder source, ProcessArgumentBuilder target) + { + if (source == null) { - builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(argument)); - return builder; + throw new ArgumentNullException(nameof(source)); } - /// - /// Indicates whether a is null or renders empty. - /// - /// The builder. - /// true if refers to a null or empty ; - /// false if the refers to non null or empty - public static bool IsNullOrEmpty(this ProcessArgumentBuilder builder) + if (target == null) { - return builder == null || builder.Count == 0 || string.IsNullOrEmpty(builder.Render()); + throw new ArgumentNullException(nameof(target)); } - /// - /// Copies all the arguments of the source to target . - /// - /// The argument builder to copy from.. - /// The argument builder to copy to. - public static void CopyTo(this ProcessArgumentBuilder source, ProcessArgumentBuilder target) + foreach (IProcessArgument token in source) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } - - foreach (var token in source) - { - target.Append(token); - } + target.Append(token); } } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Extensions/StringExtensions.cs b/src/LocalStack.AwsLocal/Extensions/StringExtensions.cs index fdbf87a..4f909cc 100644 --- a/src/LocalStack.AwsLocal/Extensions/StringExtensions.cs +++ b/src/LocalStack.AwsLocal/Extensions/StringExtensions.cs @@ -7,74 +7,72 @@ * ***************************************************************************************/ -using System; +namespace LocalStack.AwsLocal.Extensions; -namespace LocalStack.AwsLocal.Extensions +/// +/// Contains extension methods for . +/// +public static class StringExtensions { /// - /// Contains extension methods for . + /// Quotes the specified . /// - public static class StringExtensions + /// The string to quote. + /// A quoted string. + public static string Quote(this string value) { - /// - /// Quotes the specified . - /// - /// The string to quote. - /// A quoted string. - public static string Quote(this string value) + if (!IsQuoted(value)) { - if (!IsQuoted(value)) - { - value = string.Concat("\"", value, "\""); - } - return value; + value = string.Concat("\"", value, "\""); } + return value; + } - /// - /// Unquote the specified . - /// - /// The string to unquote. - /// An unquoted string. - public static string UnQuote(this string value) + /// + /// Unquote the specified . + /// + /// The string to unquote. + /// An unquoted string. + public static string UnQuote(this string value) + { + if (IsQuoted(value)) { - if (IsQuoted(value)) - { - value = value.Trim('"'); - } - return value; + value = value.Trim('"'); } + return value; + } - /// - /// Splits the into lines. - /// - /// The string to split. - /// The lines making up the provided string. - public static string[] SplitLines(this string content) - { - content = NormalizeLineEndings(content); - return content.Split(new[] { "\r\n" }, StringSplitOptions.None); - } + /// + /// Splits the into lines. + /// + /// The string to split. + /// The lines making up the provided string. + public static string[] SplitLines(this string content) + { + content = NormalizeLineEndings(content); + return content.Split(new[] { "\r\n" }, StringSplitOptions.None); + } - /// - /// Normalizes the line endings in a . - /// - /// The string to normalize line endings in. - /// A with normalized line endings. - public static string NormalizeLineEndings(this string value) + /// + /// Normalizes the line endings in a . + /// + /// The string to normalize line endings in. + /// A with normalized line endings. + public static string NormalizeLineEndings(this string value) + { + if (value == null) { - if (value != null) - { - value = value.Replace("\r\n", "\n"); - value = value.Replace("\r", string.Empty); - return value.Replace("\n", "\r\n"); - } return string.Empty; } - private static bool IsQuoted(this string value) - { - return value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) - && value.EndsWith("\"", StringComparison.OrdinalIgnoreCase); - } + value = value.Replace("\r\n", "\n"); + value = value.Replace("\r", string.Empty); + return value.Replace("\n", "\r\n"); + } + + private static bool IsQuoted(this string value) + { + return value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) + && value.EndsWith("\"", StringComparison.OrdinalIgnoreCase); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/GlobalUsings.cs b/src/LocalStack.AwsLocal/GlobalUsings.cs new file mode 100644 index 0000000..b9ae5fd --- /dev/null +++ b/src/LocalStack.AwsLocal/GlobalUsings.cs @@ -0,0 +1,38 @@ +global using System; +global using System.Collections.Generic; +global using LocalStack.AwsLocal.ProcessCore.IO; +global using LocalStack.AwsLocal.ProcessCore; +global using System.IO; +global using System.Linq; +global using LocalStack.Client.Contracts; +global using LocalStack.Client.Models; +global using LocalStack.AwsLocal.Contracts; +global using System.Globalization; +global using LocalStack.AwsLocal.ProcessCore.Arguments; +global using LocalStack.AwsLocal.Extensions; +global using System.Reflection; +global using System.Runtime.InteropServices; +global using LocalStack.AwsLocal.AmbientContexts; +global using System.Collections.Concurrent; +global using System.Diagnostics; +global using System.Collections; +global using System.Text; +global using LocalStack.Client.Enums; +global using System.Diagnostics.CodeAnalysis; +global using LocalStack.Client.Options; +global using LocalStack.Client; + +#if NETCOREAPP3_1 +namespace System.Runtime.CompilerServices +{ + using System.ComponentModel; + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit + { + } +} +#endif \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/Arguments/QuotedArgument.cs b/src/LocalStack.AwsLocal/ProcessCore/Arguments/QuotedArgument.cs index 7b58d56..38304cd 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/Arguments/QuotedArgument.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/Arguments/QuotedArgument.cs @@ -7,53 +7,50 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.Arguments; -namespace LocalStack.AwsLocal.ProcessCore.Arguments +/// +/// Represents a quoted argument. +/// +public sealed class QuotedArgument : IProcessArgument { + private readonly IProcessArgument _argument; + /// - /// Represents a quoted argument. + /// Initializes a new instance of the class. /// - public sealed class QuotedArgument : IProcessArgument + /// The argument. + public QuotedArgument(IProcessArgument argument) { - private readonly IProcessArgument _argument; - - /// - /// Initializes a new instance of the class. - /// - /// The argument. - public QuotedArgument(IProcessArgument argument) - { - _argument = argument; - } + _argument = argument; + } - /// - /// Render the arguments as a . - /// Sensitive information will be included. - /// - /// A string representation of the argument. - public string Render() - { - return string.Concat("\"", _argument.Render(), "\""); - } + /// + /// Render the arguments as a . + /// Sensitive information will be included. + /// + /// A string representation of the argument. + public string Render() + { + return string.Concat("\"", _argument.Render(), "\""); + } - /// - /// Renders the argument as a . - /// Sensitive information will be redacted. - /// - /// A safe string representation of the argument. - public string RenderSafe() - { - return string.Concat("\"", _argument.RenderSafe(), "\""); - } + /// + /// Renders the argument as a . + /// Sensitive information will be redacted. + /// + /// A safe string representation of the argument. + public string RenderSafe() + { + return string.Concat("\"", _argument.RenderSafe(), "\""); + } - /// - /// Returns a that represents the current object. - /// - /// A string that represents the current object. - public override string ToString() - { - return RenderSafe(); - } + /// + /// Returns a that represents the current object. + /// + /// A string that represents the current object. + public override string ToString() + { + return RenderSafe(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/Arguments/SecretArgument.cs b/src/LocalStack.AwsLocal/ProcessCore/Arguments/SecretArgument.cs index 5cde693..d777be4 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/Arguments/SecretArgument.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/Arguments/SecretArgument.cs @@ -7,50 +7,47 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.Arguments; -namespace LocalStack.AwsLocal.ProcessCore.Arguments +public sealed class SecretArgument : IProcessArgument { - public sealed class SecretArgument : IProcessArgument - { - private readonly IProcessArgument _argument; + private readonly IProcessArgument _argument; - /// - /// Initializes a new instance of the class. - /// - /// The argument. - public SecretArgument(IProcessArgument argument) - { - _argument = argument; - } + /// + /// Initializes a new instance of the class. + /// + /// The argument. + public SecretArgument(IProcessArgument argument) + { + _argument = argument; + } - /// - /// Render the arguments as a . - /// The secret text will be included. - /// - /// A string representation of the argument. - public string Render() - { - return _argument.Render(); - } + /// + /// Render the arguments as a . + /// The secret text will be included. + /// + /// A string representation of the argument. + public string Render() + { + return _argument.Render(); + } - /// - /// Renders the argument as a . - /// The secret text will be redacted. - /// - /// A safe string representation of the argument. - public string RenderSafe() - { - return "[REDACTED]"; - } + /// + /// Renders the argument as a . + /// The secret text will be redacted. + /// + /// A safe string representation of the argument. + public string RenderSafe() + { + return "[REDACTED]"; + } - /// - /// Returns a that represents the current object. - /// - /// A string that represents the current object. - public override string ToString() - { - return RenderSafe(); - } + /// + /// Returns a that represents the current object. + /// + /// A string that represents the current object. + public override string ToString() + { + return RenderSafe(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/Arguments/SwitchArgument.cs b/src/LocalStack.AwsLocal/ProcessCore/Arguments/SwitchArgument.cs index 0aea3bf..788f850 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/Arguments/SwitchArgument.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/Arguments/SwitchArgument.cs @@ -7,63 +7,60 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.Arguments; -namespace LocalStack.AwsLocal.ProcessCore.Arguments +/// +/// Represents a argument preceded by a switch. +/// +public class SwitchArgument : IProcessArgument { + private readonly string _switch; + private readonly IProcessArgument _argument; + private readonly string _separator; + /// - /// Represents a argument preceded by a switch. + /// Initializes a new instance of the class. /// - public class SwitchArgument : IProcessArgument + /// The switch. + /// The argument. + /// The separator between the and the . + public SwitchArgument(string @switch, IProcessArgument argument, string separator = " ") { - private readonly string _switch; - private readonly IProcessArgument _argument; - private readonly string _separator; - - /// - /// Initializes a new instance of the class. - /// - /// The switch. - /// The argument. - /// The separator between the and the . - public SwitchArgument(string @switch, IProcessArgument argument, string separator = " ") - { - _switch = @switch; - _argument = argument; - _separator = separator; - } + _switch = @switch; + _argument = argument; + _separator = separator; + } - /// - /// Render the arguments as a . - /// Sensitive information will be included. - /// - /// - /// A string representation of the argument. - /// - public string Render() - { - return string.Concat(_switch, _separator, _argument.Render()); - } + /// + /// Render the arguments as a . + /// Sensitive information will be included. + /// + /// + /// A string representation of the argument. + /// + public string Render() + { + return string.Concat(_switch, _separator, _argument.Render()); + } - /// - /// Renders the argument as a . - /// The secret text will be redacted. - /// - /// A safe string representation of the argument. - public string RenderSafe() - { - return string.Concat(_switch, _separator, _argument.RenderSafe()); - } + /// + /// Renders the argument as a . + /// The secret text will be redacted. + /// + /// A safe string representation of the argument. + public string RenderSafe() + { + return string.Concat(_switch, _separator, _argument.RenderSafe()); + } - /// - /// Returns a string that represents the current object. - /// - /// - /// A string that represents the current object. - /// - public override string ToString() - { - return RenderSafe(); - } + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + public override string ToString() + { + return RenderSafe(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/Arguments/TextArgument.cs b/src/LocalStack.AwsLocal/ProcessCore/Arguments/TextArgument.cs index b6fcd22..fd5c148 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/Arguments/TextArgument.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/Arguments/TextArgument.cs @@ -8,57 +8,54 @@ ***************************************************************************************/ -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.Arguments; -namespace LocalStack.AwsLocal.ProcessCore.Arguments +/// +/// Represents a text argument. +/// +public sealed class TextArgument : IProcessArgument { + private readonly string _text; + /// - /// Represents a text argument. + /// Initializes a new instance of the class. /// - public sealed class TextArgument : IProcessArgument + /// The text. + public TextArgument(string text) { - private readonly string _text; - - /// - /// Initializes a new instance of the class. - /// - /// The text. - public TextArgument(string text) - { - _text = text; - } + _text = text; + } - /// - /// Render the arguments as a . - /// Sensitive information will be included. - /// - /// - /// A string representation of the argument. - /// - public string Render() - { - return _text ?? string.Empty; - } + /// + /// Render the arguments as a . + /// Sensitive information will be included. + /// + /// + /// A string representation of the argument. + /// + public string Render() + { + return _text ?? string.Empty; + } - /// - /// Renders the argument as a . - /// Sensitive information will be redacted. - /// - /// - /// A safe string representation of the argument. - /// - public string RenderSafe() - { - return Render(); - } + /// + /// Renders the argument as a . + /// Sensitive information will be redacted. + /// + /// + /// A safe string representation of the argument. + /// + public string RenderSafe() + { + return Render(); + } - /// - /// Returns a that represents the current object. - /// - /// A string that represents the current object. - public override string ToString() - { - return RenderSafe(); - } + /// + /// Returns a that represents the current object. + /// + /// A string that represents the current object. + public override string ToString() + { + return RenderSafe(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/Directory.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/Directory.cs index 7405db9..b44933d 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/Directory.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/Directory.cs @@ -7,65 +7,58 @@ * ***************************************************************************************/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +internal sealed class Directory : IDirectory { - internal sealed class Directory : IDirectory - { - private readonly DirectoryInfo _directory; + private readonly DirectoryInfo _directory; - public DirectoryPath? Path { get; } + public DirectoryPath Path { get; } - Path? IFileSystemInfo.Path => Path; + Path IFileSystemInfo.Path => Path; - public bool Exists => _directory.Exists; + public bool Exists => _directory.Exists; - public bool Hidden => (_directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; + public bool Hidden => (_directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; - public DateTime LastWriteTime => _directory.LastWriteTime; + public DateTime LastWriteTime => _directory.LastWriteTime; - public Directory(DirectoryPath? path) - { - Path = path; - _directory = new DirectoryInfo(Path?.FullPath); - } + public Directory(DirectoryPath path) + { + Path = path; + _directory = new DirectoryInfo(Path?.FullPath); + } - public void Create() - { - _directory.Create(); - } + public void Create() + { + _directory.Create(); + } - public void Move(DirectoryPath destination) + public void Move(DirectoryPath destination) + { + if (destination == null) { - if (destination == null) - { - throw new ArgumentNullException(nameof(destination)); - } - _directory.MoveTo(destination.FullPath); + throw new ArgumentNullException(nameof(destination)); } + _directory.MoveTo(destination.FullPath); + } - public void Delete(bool recursive) - { - _directory.Delete(recursive); - } + public void Delete(bool recursive) + { + _directory.Delete(recursive); + } - public IEnumerable GetDirectories(string filter, SearchScope scope) - { - var option = scope == SearchScope.Current ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories; - return _directory.GetDirectories(filter, option) - .Select(directory => new Directory(directory.FullName)); - } + public IEnumerable GetDirectories(string filter, SearchScope scope) + { + var option = scope == SearchScope.Current ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories; + return _directory.GetDirectories(filter, option) + .Select(directory => new Directory(directory.FullName)); + } - public IEnumerable GetFiles(string filter, SearchScope scope) - { - SearchOption option = scope == SearchScope.Current ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories; - return _directory.GetFiles(filter, option) - .Select(file => new File(file.FullName)); - } + public IEnumerable GetFiles(string filter, SearchScope scope) + { + SearchOption option = scope == SearchScope.Current ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories; + return _directory.GetFiles(filter, option) + .Select(file => new File(file.FullName)); } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/DirectoryPath.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/DirectoryPath.cs index 0701836..0837042 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/DirectoryPath.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/DirectoryPath.cs @@ -7,167 +7,163 @@ * ***************************************************************************************/ -using System; -using System.Linq; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +/// +/// Represents a directory path. +/// +public sealed class DirectoryPath : Path { /// - /// Represents a directory path. + /// Initializes a new instance of the class. /// - public sealed class DirectoryPath : Path + /// The path. + public DirectoryPath(string path) + : base(path) { - /// - /// Initializes a new instance of the class. - /// - /// The path. - public DirectoryPath(string path) - : base(path) - { - } + } - /// - /// Gets the name of the directory. - /// - /// The directory name. - /// - /// If this is passed a file path, it will return the file name. - /// This is by-and-large equivalent to how DirectoryInfo handles this scenario. - /// If we wanted to return the *actual* directory name, we'd need to pull in IFileSystem, - /// and do various checks to make sure things exists. - /// - public string GetDirectoryName() - { - return Segments.Last(); - } + /// + /// Gets the name of the directory. + /// + /// The directory name. + /// + /// If this is passed a file path, it will return the file name. + /// This is by-and-large equivalent to how DirectoryInfo handles this scenario. + /// If we wanted to return the *actual* directory name, we'd need to pull in IFileSystem, + /// and do various checks to make sure things exists. + /// + public string GetDirectoryName() + { + return Segments.Last(); + } - /// - /// Combines the current path with the file name of a . - /// - /// The path. - /// A combination of the current path and the file name of the provided . - public FilePath GetFilePath(FilePath path) + /// + /// Combines the current path with the file name of a . + /// + /// The path. + /// A combination of the current path and the file name of the provided . + public FilePath GetFilePath(FilePath path) + { + if (path == null) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - - return new FilePath(PathHelper.Combine(FullPath, path.GetFilename().FullPath)); + throw new ArgumentNullException(nameof(path)); } - /// - /// Combines the current path with a . - /// The provided must be relative. - /// - /// The path. - /// A combination of the current path and the provided . - public FilePath CombineWithFilePath(FilePath? path) - { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - if (!path.IsRelative) - { - throw new InvalidOperationException("Cannot combine a directory path with an absolute file path."); - } - - return new FilePath(PathHelper.Combine(FullPath, path.FullPath)); - } + return new FilePath(PathHelper.Combine(FullPath, path.GetFilename().FullPath)); + } - /// - /// Combines the current path with another . - /// The provided must be relative. - /// - /// The path. - /// A combination of the current path and the provided . - public DirectoryPath Combine(DirectoryPath path) + /// + /// Combines the current path with a . + /// The provided must be relative. + /// + /// The path. + /// A combination of the current path and the provided . + public FilePath CombineWithFilePath(FilePath path) + { + if (path == null) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - if (!path.IsRelative) - { - throw new InvalidOperationException("Cannot combine a directory path with an absolute directory path."); - } - - return new DirectoryPath(PathHelper.Combine(FullPath, path.FullPath)); + throw new ArgumentNullException(nameof(path)); } - - /// - /// Makes the path absolute to another (absolute) path. - /// - /// The path. - /// An absolute path. - public DirectoryPath MakeAbsolute(DirectoryPath path) + if (!path.IsRelative) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - if (path.IsRelative) - { - throw new Exception("The provided path cannot be relative."); - } - return IsRelative - ? path.Combine(this).Collapse() - : new DirectoryPath(FullPath); + throw new InvalidOperationException("Cannot combine a directory path with an absolute file path."); } - /// - /// Collapses a containing ellipses. - /// - /// A collapsed . - public DirectoryPath Collapse() + return new FilePath(PathHelper.Combine(FullPath, path.FullPath)); + } + + /// + /// Combines the current path with another . + /// The provided must be relative. + /// + /// The path. + /// A combination of the current path and the provided . + public DirectoryPath Combine(DirectoryPath path) + { + if (path == null) { - return new DirectoryPath(PathCollapser.Collapse(this)); + throw new ArgumentNullException(nameof(path)); } - - /// - /// Performs an implicit conversion from to . - /// - /// The path. - /// A . - public static implicit operator DirectoryPath?(string path) + if (!path.IsRelative) { - return path is null ? null : FromString(path); + throw new InvalidOperationException("Cannot combine a directory path with an absolute directory path."); } - /// - /// Performs a conversion from to . - /// - /// The path. - /// A . - public static DirectoryPath FromString(string path) + return new DirectoryPath(PathHelper.Combine(FullPath, path.FullPath)); + } + + /// + /// Makes the path absolute to another (absolute) path. + /// + /// The path. + /// An absolute path. + public DirectoryPath MakeAbsolute(DirectoryPath path) + { + if (path == null) { - return new DirectoryPath(path); + throw new ArgumentNullException(nameof(path)); } - - /// - /// Get the relative path to another directory. - /// - /// The target directory path. - /// A . - public DirectoryPath GetRelativePath(DirectoryPath to) + if (path.IsRelative) { - return RelativePathResolver.Resolve(this, to); + throw new Exception("The provided path cannot be relative."); } + return IsRelative + ? path.Combine(this).Collapse() + : new DirectoryPath(FullPath); + } - /// - /// Get the relative path to another file. - /// - /// The target file path. - /// A . - public FilePath GetRelativePath(FilePath to) - { - if (to == null) - { - throw new ArgumentNullException(nameof(to)); - } + /// + /// Collapses a containing ellipses. + /// + /// A collapsed . + public DirectoryPath Collapse() + { + return new DirectoryPath(PathCollapser.Collapse(this)); + } - return GetRelativePath(to.GetDirectory()).GetFilePath(to.GetFilename()); + /// + /// Performs an implicit conversion from to . + /// + /// The path. + /// A . + public static implicit operator DirectoryPath(string path) + { + return path is null ? null : FromString(path); + } + + /// + /// Performs a conversion from to . + /// + /// The path. + /// A . + public static DirectoryPath FromString(string path) + { + return new DirectoryPath(path); + } + + /// + /// Get the relative path to another directory. + /// + /// The target directory path. + /// A . + public DirectoryPath GetRelativePath(DirectoryPath to) + { + return RelativePathResolver.Resolve(this, to); + } + + /// + /// Get the relative path to another file. + /// + /// The target file path. + /// A . + public FilePath GetRelativePath(FilePath to) + { + if (to == null) + { + throw new ArgumentNullException(nameof(to)); } + + return GetRelativePath(to.GetDirectory()).GetFilePath(to.GetFilename()); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/File.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/File.cs index 3bcbff9..e4be186 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/File.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/File.cs @@ -17,9 +17,9 @@ internal sealed class File : IFile { private readonly FileInfo _file; - public FilePath? Path { get; } + public FilePath Path { get; } - Path? IFileSystemInfo.Path => Path; + Path IFileSystemInfo.Path => Path; public bool Exists => _file.Exists; @@ -35,7 +35,7 @@ public FileAttributes Attributes set => _file.Attributes = value; } - public File(FilePath? path) + public File(FilePath path) { Path = path; _file = new FileInfo(path?.FullPath); diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/FilePath.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/FilePath.cs index e63d938..f11b724 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/FilePath.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/FilePath.cs @@ -7,192 +7,189 @@ * ***************************************************************************************/ -using System; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +/// +/// Represents a file path. +/// +public sealed class FilePath : Path { /// - /// Represents a file path. + /// Gets a value indicating whether this path has a file extension. /// - public sealed class FilePath : Path + /// + /// true if this file path has a file extension; otherwise, false. + /// + public bool HasExtension => PathHelper.HasExtension(this); + + /// + /// Initializes a new instance of the class. + /// + /// The path. + public FilePath(string path) + : base(path) { - /// - /// Gets a value indicating whether this path has a file extension. - /// - /// - /// true if this file path has a file extension; otherwise, false. - /// - public bool HasExtension => PathHelper.HasExtension(this); - - /// - /// Initializes a new instance of the class. - /// - /// The path. - public FilePath(string path) - : base(path) - { - } + } - /// - /// Gets the directory part of the path. - /// - /// The directory part of the path. - public DirectoryPath GetDirectory() + /// + /// Gets the directory part of the path. + /// + /// The directory part of the path. + public DirectoryPath GetDirectory() + { + var directory = PathHelper.GetDirectoryName(this); + if (string.IsNullOrWhiteSpace(directory)) { - var directory = PathHelper.GetDirectoryName(this); - if (string.IsNullOrWhiteSpace(directory)) - { - directory = "./"; - } - return new DirectoryPath(directory); + directory = "./"; } + return new DirectoryPath(directory); + } - /// - /// Gets the filename. - /// - /// The filename. - public FilePath GetFilename() - { - var filename = PathHelper.GetFileName(this) ?? "./"; - return new FilePath(filename); - } + /// + /// Gets the filename. + /// + /// The filename. + public FilePath GetFilename() + { + var filename = PathHelper.GetFileName(this) ?? "./"; + return new FilePath(filename); + } - /// - /// Gets the filename without its extension. - /// - /// The filename without its extension. - public FilePath GetFilenameWithoutExtension() + /// + /// Gets the filename without its extension. + /// + /// The filename without its extension. + public FilePath GetFilenameWithoutExtension() + { + var filename = PathHelper.GetFileNameWithoutExtension(this); + if (filename == null) { - var filename = PathHelper.GetFileNameWithoutExtension(this); - if (filename == null) - { - return new FilePath("./"); - } - - return new FilePath(filename); + return new FilePath("./"); } - /// - /// Gets the file extension. - /// - /// The file extension. - public string? GetExtension() - { - var filename = PathHelper.GetFileName(this); - if (filename != null) - { - var index = filename.LastIndexOf('.'); - if (index != -1) - { - return filename.Substring(index, filename.Length - index); - } - } - - return null; - } + return new FilePath(filename); + } - /// - /// Changes the file extension of the path. - /// - /// The new extension. - /// A new with a new extension. - public FilePath ChangeExtension(string extension) + /// + /// Gets the file extension. + /// + /// The file extension. + public string GetExtension() + { + var filename = PathHelper.GetFileName(this); + if (filename != null) { - var filename = PathHelper.ChangeExtension(this, extension); - if (filename == null) + var index = filename.LastIndexOf('.'); + if (index != -1) { - return new FilePath("./"); + return filename.Substring(index, filename.Length - index); } - - return new FilePath(filename); } - /// - /// Appends a file extension to the path. - /// - /// The extension. - /// A new with an appended extension. - public FilePath AppendExtension(string extension) - { - if (extension == null) - { - throw new ArgumentNullException(nameof(extension)); - } - if (!extension.StartsWith(".", StringComparison.OrdinalIgnoreCase)) - { - extension = string.Concat(".", extension); - } - return new FilePath(string.Concat(FullPath, extension)); - } + return null; + } - /// - /// Makes the path absolute (if relative) using the specified directory path. - /// - /// The path. - /// An absolute path. - public FilePath MakeAbsolute(DirectoryPath path) + /// + /// Changes the file extension of the path. + /// + /// The new extension. + /// A new with a new extension. + public FilePath ChangeExtension(string extension) + { + var filename = PathHelper.ChangeExtension(this, extension); + if (filename == null) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - if (path.IsRelative) - { - throw new InvalidOperationException("Cannot make a file path absolute with a relative directory path."); - } - - return IsRelative - ? path.CombineWithFilePath(this).Collapse() - : new FilePath(FullPath); + return new FilePath("./"); } - /// - /// Collapses a containing ellipses. - /// - /// A collapsed . - public FilePath Collapse() - { - return new FilePath(PathCollapser.Collapse(this)); - } + return new FilePath(filename); + } - /// - /// Performs an implicit conversion from to . - /// - /// The path. - /// A . - public static implicit operator FilePath?(string path) + /// + /// Appends a file extension to the path. + /// + /// The extension. + /// A new with an appended extension. + public FilePath AppendExtension(string extension) + { + if (extension == null) { - return path is null ? null : FromString(path); + throw new ArgumentNullException(nameof(extension)); } - - /// - /// Performs a conversion from to . - /// - /// The path. - /// A . - public static FilePath FromString(string path) + if (!extension.StartsWith(".", StringComparison.OrdinalIgnoreCase)) { - return new FilePath(path); + extension = string.Concat(".", extension); } + return new FilePath(string.Concat(FullPath, extension)); + } - /// - /// Get the relative path to another directory. - /// - /// The target directory path. - /// A . - public DirectoryPath GetRelativePath(DirectoryPath to) + /// + /// Makes the path absolute (if relative) using the specified directory path. + /// + /// The path. + /// An absolute path. + public FilePath MakeAbsolute(DirectoryPath path) + { + if (path == null) { - return GetDirectory().GetRelativePath(to); + throw new ArgumentNullException(nameof(path)); } - - /// - /// Get the relative path to another file. - /// - /// The target file path. - /// A . - public FilePath GetRelativePath(FilePath to) + if (path.IsRelative) { - return GetDirectory().GetRelativePath(to); + throw new InvalidOperationException("Cannot make a file path absolute with a relative directory path."); } + + return IsRelative + ? path.CombineWithFilePath(this).Collapse() + : new FilePath(FullPath); + } + + /// + /// Collapses a containing ellipses. + /// + /// A collapsed . + public FilePath Collapse() + { + return new FilePath(PathCollapser.Collapse(this)); + } + + /// + /// Performs an implicit conversion from to . + /// + /// The path. + /// A . + public static implicit operator FilePath(string path) + { + return path is null ? null : FromString(path); + } + + /// + /// Performs a conversion from to . + /// + /// The path. + /// A . + public static FilePath FromString(string path) + { + return new FilePath(path); + } + + /// + /// Get the relative path to another directory. + /// + /// The target directory path. + /// A . + public DirectoryPath GetRelativePath(DirectoryPath to) + { + return GetDirectory().GetRelativePath(to); + } + + /// + /// Get the relative path to another file. + /// + /// The target file path. + /// A . + public FilePath GetRelativePath(FilePath to) + { + return GetDirectory().GetRelativePath(to); } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/FileSystem.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/FileSystem.cs index b5fab8a..cc55d7d 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/FileSystem.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/FileSystem.cs @@ -7,33 +7,30 @@ * ***************************************************************************************/ -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +/// +/// A physical file system implementation. +/// +public sealed class FileSystem : IFileSystem { /// - /// A physical file system implementation. + /// Gets a instance representing the specified path. /// - public sealed class FileSystem : IFileSystem + /// The path. + /// A instance representing the specified path. + public IFile GetFile(FilePath path) { - /// - /// Gets a instance representing the specified path. - /// - /// The path. - /// A instance representing the specified path. - public IFile GetFile(FilePath path) - { - return new File(path); - } + return new File(path); + } - /// - /// Gets a instance representing the specified path. - /// - /// The path. - /// A instance representing the specified path. - public IDirectory GetDirectory(DirectoryPath path) - { - return new Directory(path); - } + /// + /// Gets a instance representing the specified path. + /// + /// The path. + /// A instance representing the specified path. + public IDirectory GetDirectory(DirectoryPath path) + { + return new Directory(path); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/Path.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/Path.cs index e828252..fc4b7ba 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/Path.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/Path.cs @@ -7,138 +7,135 @@ * ***************************************************************************************/ -using System; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +/// +/// Provides properties and instance methods for working with paths. +/// This class must be inherited. +/// +public abstract class Path { /// - /// Provides properties and instance methods for working with paths. - /// This class must be inherited. + /// Gets the full path. /// - public abstract class Path + /// The full path. + public string FullPath { get; } + + /// + /// Gets a value indicating whether or not this path is relative. + /// + /// + /// true if this path is relative; otherwise, false. + /// + public bool IsRelative { get; } + + /// + /// Gets a value indicating whether or not this path is an UNC path. + /// + /// + /// true if this path is an UNC path; otherwise, false. + /// + public bool IsUNC { get; } + + /// + /// Gets the separator this path was normalized with. + /// + public char Separator { get; } + + /// + /// Gets the segments making up the path. + /// + /// The segments making up the path. + public string[] Segments { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The path. + protected Path(string path) { - /// - /// Gets the full path. - /// - /// The full path. - public string FullPath { get; } - - /// - /// Gets a value indicating whether or not this path is relative. - /// - /// - /// true if this path is relative; otherwise, false. - /// - public bool IsRelative { get; } - - /// - /// Gets a value indicating whether or not this path is an UNC path. - /// - /// - /// true if this path is an UNC path; otherwise, false. - /// - public bool IsUNC { get; } - - /// - /// Gets the separator this path was normalized with. - /// - public char Separator { get; } - - /// - /// Gets the segments making up the path. - /// - /// The segments making up the path. - public string[] Segments { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The path. - protected Path(string path) - { - path = path?.Trim() ?? string.Empty; + path = path?.Trim() ?? string.Empty; - IsUNC = path.StartsWith(@"\\"); - Separator = IsUNC ? '\\' : '/'; + IsUNC = path.StartsWith(@"\\"); + Separator = IsUNC ? '\\' : '/'; - if (IsUNC) - { - FullPath = path.Replace('/', Separator).Trim(); - } - else - { - FullPath = path.Replace('\\', Separator).Trim(); - } + if (IsUNC) + { + FullPath = path.Replace('/', Separator).Trim(); + } + else + { + FullPath = path.Replace('\\', Separator).Trim(); + } - // Relative paths are considered empty. - FullPath = FullPath == "./" ? string.Empty : FullPath; + // Relative paths are considered empty. + FullPath = FullPath == "./" ? string.Empty : FullPath; - // Remove relative part of a path. - if (FullPath.StartsWith("./", StringComparison.Ordinal)) - { - FullPath = FullPath.Substring(2); - } + // Remove relative part of a path. + if (FullPath.StartsWith("./", StringComparison.Ordinal)) + { + FullPath = FullPath.Substring(2); + } - // Remove trailing slashes. - if (FullPath.Length > 1) + // Remove trailing slashes. + if (FullPath.Length > 1) + { + FullPath = FullPath.TrimEnd(Separator); + if (IsUNC && string.IsNullOrWhiteSpace(FullPath)) { - FullPath = FullPath.TrimEnd(Separator); - if (IsUNC && string.IsNullOrWhiteSpace(FullPath)) - { - FullPath = @"\\"; - } + FullPath = @"\\"; } + } - // Potential Windows path? - if (FullPath.Length == 2) + // Potential Windows path? + if (FullPath.Length == 2) + { + if (FullPath.EndsWith(":", StringComparison.OrdinalIgnoreCase)) { - if (FullPath.EndsWith(":", StringComparison.OrdinalIgnoreCase)) - { - FullPath = string.Concat(FullPath, Separator); - } + FullPath = string.Concat(FullPath, Separator); } + } - // Relative path? - IsRelative = !PathHelper.IsPathRooted(FullPath); + // Relative path? + IsRelative = !PathHelper.IsPathRooted(FullPath); - // Extract path segments. - Segments = FullPath.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries); - if (!IsUNC) + // Extract path segments. + Segments = FullPath.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries); + if (!IsUNC) + { + if (FullPath.StartsWith("/") && Segments.Length > 0) { - if (FullPath.StartsWith("/") && Segments.Length > 0) - { - Segments[0] = "/" + Segments[0]; - } + Segments[0] = "/" + Segments[0]; } - else + } + else + { + if (FullPath.StartsWith(@"\\")) { - if (FullPath.StartsWith(@"\\")) + if (Segments.Length > 0) + { + // Treat \\ as its own segment. + var segments = new string[Segments.Length + 1]; + segments[0] = @"\\"; + Segments.CopyTo(segments, 1); + Segments = segments; + } + else { - if (Segments.Length > 0) - { - // Treat \\ as its own segment. - var segments = new string[Segments.Length + 1]; - segments[0] = @"\\"; - Segments.CopyTo(segments, 1); - Segments = segments; - } - else - { - Segments = new[] { @"\\" }; - } + Segments = new[] { @"\\" }; } } } + } - /// - /// Returns a that represents this path. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - return FullPath; - } + /// + /// Returns a that represents this path. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return FullPath; } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/PathCollapser.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/PathCollapser.cs index 4407cdf..1c3f2c7 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/PathCollapser.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/PathCollapser.cs @@ -7,43 +7,38 @@ * ***************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +internal static class PathCollapser { - internal static class PathCollapser + public static string Collapse(Path path) { - public static string Collapse(Path path) + if (path == null) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - var stack = new Stack(); - var segments = path.FullPath.Split('/', '\\'); - foreach (string segment in segments) + throw new ArgumentNullException(nameof(path)); + } + var stack = new Stack(); + string[] segments = path.FullPath.Split('/', '\\'); + foreach (string segment in segments) + { + switch (segment) { - switch (segment) + case ".": + continue; + case "..": { - case ".": - continue; - case "..": + if (stack.Count > 1) { - if (stack.Count > 1) - { - stack.Pop(); - } - continue; + stack.Pop(); } - default: - stack.Push(segment); - break; + continue; } + default: + stack.Push(segment); + break; } - string collapsed = string.Join("/", stack.Reverse()); - return collapsed == string.Empty ? "." : collapsed; } + string collapsed = string.Join("/", stack.Reverse()); + return collapsed == string.Empty ? "." : collapsed; } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/PathHelper.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/PathHelper.cs index 6de26f9..54b24df 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/PathHelper.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/PathHelper.cs @@ -7,290 +7,280 @@ * ***************************************************************************************/ -using System; -using System.Linq; -using System.Runtime.InteropServices; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +internal static class PathHelper { - internal static class PathHelper + private const char Backslash = '\\'; + private const char Slash = '/'; + private const string UncPrefix = @"\\"; + + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + public static string Combine(params string[] paths) { - private const char Backslash = '\\'; - private const char Slash = '/'; - private const string UncPrefix = @"\\"; + if (paths.Length == 0) + { + return string.Empty; + } - private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + string current = paths[0]; + + for (var index = 1; index < paths.Length; index++) + { + current = PathHelper.Combine(current, paths[index]); + } + return current; + } - public static string Combine(params string[] paths) + public static string Combine(string first, string second) + { + if (first == null) { - if (paths.Length == 0) - { - return string.Empty; - } + throw new ArgumentNullException(nameof(first)); + } + if (second == null) + { + throw new ArgumentNullException(nameof(second)); + } - var current = paths[0]; - for (int index = 1; index < paths.Length; index++) - { - current = PathHelper.Combine(current, paths[index]); - } - return current; + // Both empty? + if (string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(second)) + { + return string.Empty; + } + // First empty? + if (string.IsNullOrWhiteSpace(first) && !string.IsNullOrWhiteSpace(second)) + { + return second; + } + // Second empty? + if (!string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(second)) + { + return first; } - public static string Combine(string first, string second) + bool isUnc = first.StartsWith(UncPrefix); + + // Trim separators. + first = first.TrimEnd(Backslash, Slash); + second = second.TrimStart(Backslash, Slash).TrimEnd(Backslash, Slash); + + // UNC root only? + if (isUnc && string.IsNullOrWhiteSpace(first)) { - if (first == null) - { - throw new ArgumentNullException(nameof(first)); - } - if (second == null) - { - throw new ArgumentNullException(nameof(second)); - } + return string.Concat(UncPrefix, second); + } + + char separator = isUnc ? Backslash : Slash; + return string.Concat(first, separator, second); + } - // Both empty? - if (string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(second)) + public static bool HasExtension(FilePath path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + for (int index = path.FullPath.Length - 1; index >= 0; index--) + { + if (path.FullPath[index] == '.') { - return string.Empty; + return true; } - // First empty? - if (string.IsNullOrWhiteSpace(first) && !string.IsNullOrWhiteSpace(second)) + + if (path.IsUNC && path.FullPath[index] == '\\') { - return second; + break; } - // Second empty? - if (!string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(second)) + if (path.FullPath[index] == '/') { - return first; + break; } + } - var isUnc = first.StartsWith(UncPrefix); - - // Trim separators. - first = first.TrimEnd(Backslash, Slash); - second = second.TrimStart(Backslash, Slash).TrimEnd(Backslash, Slash); + return false; + } - // UNC root only? - if (isUnc && string.IsNullOrWhiteSpace(first)) - { - return string.Concat(UncPrefix, second); - } + public static string GetDirectoryName(FilePath path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } - var separator = isUnc ? Backslash : Slash; - return string.Concat(first, separator, second); + switch (path.Segments.Length) + { + case 0: + return string.Empty; + case 1 when path.IsUNC: + return @"\\"; + case 1 when path.Segments[0].Length >= 1 && path.Segments[0][0] == '/': + return "/"; } - public static bool HasExtension(FilePath path) + if (!path.IsUNC) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } + return string.Join("/", path.Segments.Take(path.Segments.Length - 1)); + } - for (int index = path.FullPath.Length - 1; index >= 0; index--) - { - if (path.FullPath[index] == '.') - { - return true; - } + IEnumerable segments = path.Segments.Skip(1).Take(path.Segments.Length - 2); + return string.Concat(@"\\", string.Join("\\", segments)); - if (path.IsUNC && path.FullPath[index] == '\\') - { - break; - } - if (path.FullPath[index] == '/') - { - break; - } - } + } - return false; + public static string GetFileName(FilePath path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); } - public static string GetDirectoryName(FilePath path) + if (path.Segments.Length == 0) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } - - if (path.Segments.Length == 0) - { - return string.Empty; - } + return null; + } - if (path.Segments.Length == 1) + var filename = path.Segments[path.Segments.Length - 1]; + if (path.Segments.Length == 1 && !path.IsRelative) + { + if (path.Segments[0].StartsWith("/")) { - if (path.IsUNC) - { - return @"\\"; - } - if (path.Segments[0].Length >= 1 && path.Segments[0][0] == '/') - { - return "/"; - } + return filename.TrimStart('/'); } - if (path.IsUNC) { - var segments = path.Segments.Skip(1).Take(path.Segments.Length - 2); - return string.Concat(@"\\", string.Join("\\", segments)); + return filename.TrimStart('\\'); } - return string.Join("/", path.Segments.Take(path.Segments.Length - 1)); + return null; } - public static string? GetFileName(FilePath path) - { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } + return filename; + } - if (path.Segments.Length == 0) - { - return null; - } + public static string GetFileNameWithoutExtension(FilePath path) + { + var filename = PathHelper.GetFileName(path); + if (filename == null) + { + return null; + } - var filename = path.Segments[path.Segments.Length - 1]; - if (path.Segments.Length == 1 && !path.IsRelative) - { - if (path.Segments[0].StartsWith("/")) - { - return filename.TrimStart('/'); - } - if (path.IsUNC) - { - return filename.TrimStart('\\'); - } + var index = filename.LastIndexOf('.'); + if (index != -1) + { + return filename.Substring(0, index); + } - return null; - } + return filename; + } - return filename; + public static string ChangeExtension(FilePath path, string extension) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); } - public static string? GetFileNameWithoutExtension(FilePath path) + if (extension == null) { - var filename = PathHelper.GetFileName(path); - if (filename == null) - { - return null; - } - - var index = filename.LastIndexOf('.'); - if (index != -1) - { - return filename.Substring(0, index); - } + return RemoveExtension(path); + } + if (extension != null && string.IsNullOrWhiteSpace(extension)) + { + // Empty extension is an extension consisting of only a period. + extension = "."; + } - return filename; + // Make sure that the extension has a dot. + if (extension != null && !extension.StartsWith(".")) + { + extension = string.Concat(".", extension); } - public static string? ChangeExtension(FilePath path, string extension) + // Empty path? + var filename = path.FullPath; + if (string.IsNullOrWhiteSpace(filename)) { - if (path == null) - { - throw new ArgumentNullException(nameof(path)); - } + return null; + } - if (extension == null) + for (int index = path.FullPath.Length - 1; index >= 0; index--) + { + if (filename[index] == '/') { - return RemoveExtension(path); + // No extension found. + break; } - if (extension != null && string.IsNullOrWhiteSpace(extension)) + if (filename[index] == '.') { - // Empty extension is an extension consisting of only a period. - extension = "."; + // Replace the extension. + return string.Concat(filename.Substring(0, index), extension); } + } + + return string.Concat(filename, extension); + } + + public static string RemoveExtension(FilePath path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } - // Make sure that the extension has a dot. - if (extension != null && !extension.StartsWith(".")) + for (int index = path.FullPath.Length - 1; index >= 0; index--) + { + if (path.FullPath[index] == '.') { - extension = string.Concat(".", extension); + return path.FullPath.Substring(0, index); } - // Empty path? - var filename = path.FullPath; - if (string.IsNullOrWhiteSpace(filename)) + if (path.IsUNC && path.FullPath[index] == '\\') { - return null; + break; } - - for (int index = path.FullPath.Length - 1; index >= 0; index--) + if (path.FullPath[index] == '/') { - if (filename[index] == '/') - { - // No extension found. - break; - } - if (filename[index] == '.') - { - // Replace the extension. - return string.Concat(filename.Substring(0, index), extension); - } + break; } - - return string.Concat(filename, extension); } - public static string RemoveExtension(FilePath path) + return path.FullPath; + } + + public static bool IsPathRooted(string path) + { + var length = path.Length; + if (length >= 1) { - if (path == null) + // Root? + if (path[0] == '/') { - throw new ArgumentNullException(nameof(path)); + return true; } - for (int index = path.FullPath.Length - 1; index >= 0; index--) + if (path.Length >= 2) { - if (path.FullPath[index] == '.') + // UNC? + if (path[0] == '\\' && path[1] == '\\') { - return path.FullPath.Substring(0, index); - } - - if (path.IsUNC && path.FullPath[index] == '\\') - { - break; - } - if (path.FullPath[index] == '/') - { - break; + return true; } } - return path.FullPath; - } - - public static bool IsPathRooted(string path) - { - var length = path.Length; - if (length >= 1) + if (IsWindows) { - // Root? - if (path[0] == '/') + // Windows drive? + if (length >= 2 && path[1] == ':') { return true; } - - if (path.Length >= 2) - { - // UNC? - if (path[0] == '\\' && path[1] == '\\') - { - return true; - } - } - - if (_isWindows) - { - // Windows drive? - if (length >= 2 && path[1] == ':') - { - return true; - } - } } - - return false; } + + return false; } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/RelativePathResolver.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/RelativePathResolver.cs index b54cd3b..8b0f7c2 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/RelativePathResolver.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/RelativePathResolver.cs @@ -7,69 +7,65 @@ * ***************************************************************************************/ -using System; -using System.Linq; +namespace LocalStack.AwsLocal.ProcessCore.IO; -namespace LocalStack.AwsLocal.ProcessCore.IO +internal static class RelativePathResolver { - internal static class RelativePathResolver + public static DirectoryPath Resolve(DirectoryPath from, DirectoryPath to) { - public static DirectoryPath Resolve(DirectoryPath from, DirectoryPath to) + if (from == null) { - if (from == null) - { - throw new ArgumentNullException(nameof(from)); - } - if (to == null) - { - throw new ArgumentNullException(nameof(to)); - } - if (to.IsRelative) - { - throw new InvalidOperationException("Target path must be an absolute path."); - } - if (from.IsRelative) - { - throw new InvalidOperationException("Source path must be an absolute path."); - } - if (from.Segments.Length == 0 && to.Segments.Length == 0) - { - return new DirectoryPath("."); - } - if (from.Segments[0] != to.Segments[0]) - { - throw new InvalidOperationException("Paths must share a common prefix."); - } + throw new ArgumentNullException(nameof(from)); + } + if (to == null) + { + throw new ArgumentNullException(nameof(to)); + } + if (to.IsRelative) + { + throw new InvalidOperationException("Target path must be an absolute path."); + } + if (from.IsRelative) + { + throw new InvalidOperationException("Source path must be an absolute path."); + } + if (from.Segments.Length == 0 && to.Segments.Length == 0) + { + return new DirectoryPath("."); + } + if (from.Segments[0] != to.Segments[0]) + { + throw new InvalidOperationException("Paths must share a common prefix."); + } - if (string.CompareOrdinal(from.FullPath, to.FullPath) == 0) - { - return new DirectoryPath("."); - } + if (string.CompareOrdinal(from.FullPath, to.FullPath) == 0) + { + return new DirectoryPath("."); + } - var minimumSegmentsLength = Math.Min(from.Segments.Length, to.Segments.Length); - var numberOfSharedSegments = 1; + int minimumSegmentsLength = Math.Min(from.Segments.Length, to.Segments.Length); + var numberOfSharedSegments = 1; - for (var i = 1; i < minimumSegmentsLength; i++) + for (var i = 1; i < minimumSegmentsLength; i++) + { + if (string.CompareOrdinal(from.Segments[i], to.Segments[i]) != 0) { - if (string.CompareOrdinal(from.Segments[i], to.Segments[i]) != 0) - { - break; - } - - numberOfSharedSegments++; + break; } - var fromSegments = Enumerable.Repeat("..", from.Segments.Length - numberOfSharedSegments); - var toSegments = to.Segments.Skip(numberOfSharedSegments); + numberOfSharedSegments++; + } - var relativePath = PathHelper.Combine(fromSegments.Concat(toSegments).ToArray()); + IEnumerable fromSegments = Enumerable.Repeat("..", from.Segments.Length - numberOfSharedSegments); + IEnumerable toSegments = to.Segments.Skip(numberOfSharedSegments); - if (string.IsNullOrWhiteSpace(relativePath)) - { - relativePath = "."; - } + string relativePath = PathHelper.Combine(fromSegments.Concat(toSegments).ToArray()); - return new DirectoryPath(relativePath); + if (string.IsNullOrWhiteSpace(relativePath)) + { + relativePath = "."; } + + return new DirectoryPath(relativePath); } } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/IO/SearchScope.cs b/src/LocalStack.AwsLocal/ProcessCore/IO/SearchScope.cs index 93e4735..a30c434 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/IO/SearchScope.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/IO/SearchScope.cs @@ -7,21 +7,20 @@ * ***************************************************************************************/ -namespace LocalStack.AwsLocal.ProcessCore.IO +namespace LocalStack.AwsLocal.ProcessCore.IO; + +/// +/// Represents a search scope. +/// +public enum SearchScope { /// - /// Represents a search scope. + /// The current directory. /// - public enum SearchScope - { - /// - /// The current directory. - /// - Current, + Current, - /// - /// The current directory and child directories. - /// - Recursive - } + /// + /// The current directory and child directories. + /// + Recursive } \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/ProcessArgumentBuilder.cs b/src/LocalStack.AwsLocal/ProcessCore/ProcessArgumentBuilder.cs index 9903842..6b44536 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/ProcessArgumentBuilder.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/ProcessArgumentBuilder.cs @@ -8,149 +8,140 @@ ***************************************************************************************/ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using LocalStack.AwsLocal.Contracts; -using LocalStack.AwsLocal.ProcessCore.Arguments; -using LocalStack.AwsLocal.ProcessCore.IO; - -namespace LocalStack.AwsLocal.ProcessCore +namespace LocalStack.AwsLocal.ProcessCore; + +/// +/// Utility for building process arguments. +/// +public sealed class ProcessArgumentBuilder : IReadOnlyCollection { + private readonly List _tokens; + /// - /// Utility for building process arguments. + /// Gets the number of arguments contained in the . /// - public sealed class ProcessArgumentBuilder : IReadOnlyCollection - { - private readonly List _tokens; + public int Count => _tokens.Count; - /// - /// Gets the number of arguments contained in the . - /// - public int Count => _tokens.Count; + /// + /// Initializes a new instance of the class. + /// + public ProcessArgumentBuilder() + { + _tokens = new List(); + } - /// - /// Initializes a new instance of the class. - /// - public ProcessArgumentBuilder() - { - _tokens = new List(); - } + /// + /// Clears all arguments from the builder. + /// + public void Clear() + { + _tokens.Clear(); + } - /// - /// Clears all arguments from the builder. - /// - public void Clear() - { - _tokens.Clear(); - } + /// + /// Appends an argument. + /// + /// The argument. + public void Append(IProcessArgument argument) + { + _tokens.Add(argument); + } - /// - /// Appends an argument. - /// - /// The argument. - public void Append(IProcessArgument argument) - { - _tokens.Add(argument); - } + /// + /// Prepends an argument. + /// + /// The argument. + public void Prepend(IProcessArgument argument) + { + _tokens.Insert(0, argument); + } - /// - /// Prepends an argument. - /// - /// The argument. - public void Prepend(IProcessArgument argument) - { - _tokens.Insert(0, argument); - } + /// + /// Renders the arguments as a . + /// Sensitive information will be included. + /// + /// A string representation of the arguments. + public string Render() + { + return string.Join(" ", _tokens.Select(t => t.Render())); + } - /// - /// Renders the arguments as a . - /// Sensitive information will be included. - /// - /// A string representation of the arguments. - public string Render() - { - return string.Join(" ", _tokens.Select(t => t.Render())); - } + /// + /// Renders the arguments as a . + /// Sensitive information will be redacted. + /// + /// A safe string representation of the arguments. + public string RenderSafe() + { + return string.Join(" ", _tokens.Select(t => t.RenderSafe())); + } - /// - /// Renders the arguments as a . - /// Sensitive information will be redacted. - /// - /// A safe string representation of the arguments. - public string RenderSafe() + /// + /// Tries to filer any unsafe arguments from string + /// + /// unsafe source string. + /// Filtered string. + public string FilterUnsafe(string source) + { + if (string.IsNullOrWhiteSpace(source)) { - return string.Join(" ", _tokens.Select(t => t.RenderSafe())); + return source; } - /// - /// Tries to filer any unsafe arguments from string - /// - /// unsafe source string. - /// Filtered string. - public string FilterUnsafe(string source) - { - if (string.IsNullOrWhiteSpace(source)) + return _tokens + .Select(token => new { - return source; - } - - return _tokens - .Select(token => new - { - Safe = token.RenderSafe().Trim('"').Trim(), - Unsafe = token.Render().Trim('"').Trim() - }) - .Where(token => token.Safe != token.Unsafe) - .Aggregate( - new StringBuilder(source), - (sb, token) => sb.Replace(token.Unsafe, token.Safe), - sb => sb.ToString()); - } + Safe = token.RenderSafe().Trim('"').Trim(), + Unsafe = token.Render().Trim('"').Trim() + }) + .Where(token => token.Safe != token.Unsafe) + .Aggregate( + new StringBuilder(source), + (sb, token) => sb.Replace(token.Unsafe, token.Safe), + sb => sb.ToString()); + } - /// - /// Performs an implicit conversion from to . - /// - /// The text value to convert. - /// A . - public static implicit operator ProcessArgumentBuilder(string value) - { - return FromString(value); - } + /// + /// Performs an implicit conversion from to . + /// + /// The text value to convert. + /// A . + public static implicit operator ProcessArgumentBuilder(string value) + { + return FromString(value); + } - /// - /// Performs a conversion from to . - /// - /// The text value to convert. - /// A . - public static ProcessArgumentBuilder FromString(string value) - { - var builder = new ProcessArgumentBuilder(); - builder.Append(new TextArgument(value)); - return builder; - } + /// + /// Performs a conversion from to . + /// + /// The text value to convert. + /// A . + public static ProcessArgumentBuilder FromString(string value) + { + var builder = new ProcessArgumentBuilder(); + builder.Append(new TextArgument(value)); + return builder; + } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return _tokens.GetEnumerator(); - } + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return _tokens.GetEnumerator(); + } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)_tokens).GetEnumerator(); - } + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_tokens).GetEnumerator(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/ProcessHelper.cs b/src/LocalStack.AwsLocal/ProcessCore/ProcessHelper.cs index 5d70e92..08d22ec 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/ProcessHelper.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/ProcessHelper.cs @@ -7,18 +7,13 @@ * ***************************************************************************************/ -using System; -using System.Diagnostics; -using System.Linq; +namespace LocalStack.AwsLocal.ProcessCore; -namespace LocalStack.AwsLocal.ProcessCore +internal static class ProcessHelper { - internal static class ProcessHelper + public static void SetEnvironmentVariable(ProcessStartInfo info, string key, string value) { - public static void SetEnvironmentVariable(ProcessStartInfo info, string key, string value) - { - string envKey = info.Environment.Keys.FirstOrDefault(existingKey => StringComparer.OrdinalIgnoreCase.Equals(existingKey, key)) ?? key; - info.Environment[envKey] = value; - } + string envKey = info.Environment.Keys.FirstOrDefault(existingKey => StringComparer.OrdinalIgnoreCase.Equals(existingKey, key)) ?? key; + info.Environment[envKey] = value; } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/ProcessRunner.cs b/src/LocalStack.AwsLocal/ProcessCore/ProcessRunner.cs index 9e32005..c9870f1 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/ProcessRunner.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/ProcessRunner.cs @@ -1,119 +1,111 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using LocalStack.AwsLocal.Contracts; -using LocalStack.AwsLocal.Extensions; -using LocalStack.AwsLocal.ProcessCore.IO; - -namespace LocalStack.AwsLocal.ProcessCore -{ +namespace LocalStack.AwsLocal.ProcessCore; + /// - /// Responsible for starting processes. +/// Responsible for starting processes. +/// +public sealed class ProcessRunner : IProcessRunner +{ + /// + /// Starts a process using the specified information. /// - public sealed class ProcessRunner : IProcessRunner + /// The file name such as an application or document with which to start the process. + /// The information about the process to start. + /// A process handle. + public IProcess Start(FilePath filePath, ProcessSettings settings) { - /// - /// Starts a process using the specified information. - /// - /// The file name such as an application or document with which to start the process. - /// The information about the process to start. - /// A process handle. - public IProcess? Start(FilePath filePath, ProcessSettings settings) + if (filePath == null) + { + throw new ArgumentNullException(nameof(filePath)); + } + if (settings == null) { - if (filePath == null) - { - throw new ArgumentNullException(nameof(filePath)); - } - if (settings == null) - { - throw new ArgumentNullException(nameof(settings)); - } - - ProcessStartInfo info = GetProcessStartInfo(filePath, settings, out Func filterUnsafe); - - // Start and return the process. - var process = Process.Start(info); - if (process == null) - { - return null; - } - - var processWrapper = new ProcessWrapper(process, filterUnsafe, settings.RedirectedStandardOutputHandler, - filterUnsafe, settings.RedirectedStandardErrorHandler); - - if (settings.RedirectStandardOutput) - { - SubscribeStandardOutput(process, processWrapper); - } - if (settings.RedirectStandardError) - { - SubscribeStandardError(process, processWrapper); - } - - return processWrapper; + throw new ArgumentNullException(nameof(settings)); } - internal ProcessStartInfo GetProcessStartInfo(FilePath filePath, ProcessSettings settings, out Func filterUnsafe) + ProcessStartInfo info = GetProcessStartInfo(filePath, settings, out Func filterUnsafe); + + // Start and return the process. + var process = Process.Start(info); + if (process == null) { - // Get the fileName - var fileName = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? filePath.FullPath : filePath.FullPath.Quote(); - - // Get the arguments. - var arguments = settings.Arguments ?? new ProcessArgumentBuilder(); - filterUnsafe = arguments.FilterUnsafe; - - if (!settings.Silent) - { - // Log the filename and arguments. - var message = string.Concat(fileName, " ", arguments.RenderSafe().TrimEnd()); - Console.WriteLine("Executing: {0}", message); - } - - // Create the process start info. - var info = new ProcessStartInfo(fileName) - { - Arguments = arguments.Render(), - UseShellExecute = false, - RedirectStandardError = settings.RedirectStandardError, - RedirectStandardOutput = settings.RedirectStandardOutput - }; - - // Allow working directory? - if (!settings.NoWorkingDirectory) - { - DirectoryPath? workingDirectory = settings.WorkingDirectory; - info.WorkingDirectory = workingDirectory?.MakeAbsolute(workingDirectory).FullPath; - } - - if (settings.EnvironmentVariables == null) - { - return info; - } - - foreach ((string key, string value) in settings.EnvironmentVariables) - { - ProcessHelper.SetEnvironmentVariable(info, key, value); - } + return null; + } - return info; + var processWrapper = new ProcessWrapper(process, filterUnsafe, settings.RedirectedStandardOutputHandler, + filterUnsafe, settings.RedirectedStandardErrorHandler); + + if (settings.RedirectStandardOutput) + { + SubscribeStandardOutput(process, processWrapper); + } + if (settings.RedirectStandardError) + { + SubscribeStandardError(process, processWrapper); + } + + return processWrapper; + } + + internal ProcessStartInfo GetProcessStartInfo(FilePath filePath, ProcessSettings settings, out Func filterUnsafe) + { + // Get the fileName + var fileName = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? filePath.FullPath : filePath.FullPath.Quote(); + + // Get the arguments. + var arguments = settings.Arguments ?? new ProcessArgumentBuilder(); + filterUnsafe = arguments.FilterUnsafe; + + if (!settings.Silent) + { + // Log the filename and arguments. + var message = string.Concat(fileName, " ", arguments.RenderSafe().TrimEnd()); + Console.WriteLine("Executing: {0}", message); } - private static void SubscribeStandardError(Process process, ProcessWrapper processWrapper) + // Create the process start info. + var info = new ProcessStartInfo(fileName) { - process.ErrorDataReceived += (s, e) => - { - processWrapper.StandardErrorReceived(e.Data); - }; - process.BeginErrorReadLine(); + Arguments = arguments.Render(), + UseShellExecute = false, + RedirectStandardError = settings.RedirectStandardError, + RedirectStandardOutput = settings.RedirectStandardOutput + }; + + // Allow working directory? + if (!settings.NoWorkingDirectory) + { + DirectoryPath workingDirectory = settings.WorkingDirectory; + info.WorkingDirectory = workingDirectory?.MakeAbsolute(workingDirectory).FullPath; } - private static void SubscribeStandardOutput(Process process, ProcessWrapper processWrapper) + if (settings.EnvironmentVariables == null) { - process.OutputDataReceived += (s, e) => - { - processWrapper.StandardOutputReceived(e.Data); - }; - process.BeginOutputReadLine(); + return info; } + + foreach ((string key, string value) in settings.EnvironmentVariables) + { + ProcessHelper.SetEnvironmentVariable(info, key, value); + } + + return info; + } + + private static void SubscribeStandardError(Process process, ProcessWrapper processWrapper) + { + process.ErrorDataReceived += (s, e) => + { + processWrapper.StandardErrorReceived(e.Data); + }; + process.BeginErrorReadLine(); + } + + private static void SubscribeStandardOutput(Process process, ProcessWrapper processWrapper) + { + process.OutputDataReceived += (s, e) => + { + processWrapper.StandardOutputReceived(e.Data); + }; + process.BeginOutputReadLine(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/ProcessSettings.cs b/src/LocalStack.AwsLocal/ProcessCore/ProcessSettings.cs index f76a2b0..1943847 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/ProcessSettings.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/ProcessSettings.cs @@ -7,84 +7,79 @@ * ***************************************************************************************/ -using System; -using System.Collections.Generic; -using LocalStack.AwsLocal.ProcessCore.IO; +namespace LocalStack.AwsLocal.ProcessCore; -namespace LocalStack.AwsLocal.ProcessCore +/// +/// Specifies a set of values that are used to start a process. +/// +public sealed class ProcessSettings { /// - /// Specifies a set of values that are used to start a process. + /// Gets or sets the set of command-line arguments to use when starting the application. /// - public sealed class ProcessSettings - { - /// - /// Gets or sets the set of command-line arguments to use when starting the application. - /// - /// The set of command-line arguments to use when starting the application. - public ProcessArgumentBuilder? Arguments { get; set; } + /// The set of command-line arguments to use when starting the application. + public ProcessArgumentBuilder Arguments { get; set; } - /// - /// Gets or sets the working directory for the process to be started. - /// - /// The working directory for the process to be started. - public DirectoryPath? WorkingDirectory { get; set; } + /// + /// Gets or sets the working directory for the process to be started. + /// + /// The working directory for the process to be started. + public DirectoryPath WorkingDirectory { get; set; } - /// - /// Gets or sets a value indicating whether or not to opt out of using - /// an explicit working directory for the process. - /// - public bool NoWorkingDirectory { get; set; } + /// + /// Gets or sets a value indicating whether or not to opt out of using + /// an explicit working directory for the process. + /// + public bool NoWorkingDirectory { get; set; } - /// - /// Gets or sets a value indicating whether the error output of an application is written to the standard error stream. - /// - /// true if error output should be redirected; false if error output should be written to the standard error stream. The default is false. - public bool RedirectStandardError { get; set; } + /// + /// Gets or sets a value indicating whether the error output of an application is written to the standard error stream. + /// + /// true if error output should be redirected; false if error output should be written to the standard error stream. The default is false. + public bool RedirectStandardError { get; set; } - /// - /// Gets or sets a value indicating whether the output of an application is written to the standard output stream. - /// - /// true if output should be redirected; false if output should be written to the standard output stream. The default is false. - public bool RedirectStandardOutput { get; set; } + /// + /// Gets or sets a value indicating whether the output of an application is written to the standard output stream. + /// + /// true if output should be redirected; false if output should be written to the standard output stream. The default is false. + public bool RedirectStandardOutput { get; set; } - /// - /// Gets or sets a function that intercepts the error output before being redirected. Use in conjunction with - /// - public Func? RedirectedStandardErrorHandler { get; set; } + /// + /// Gets or sets a function that intercepts the error output before being redirected. Use in conjunction with + /// + public Func RedirectedStandardErrorHandler { get; set; } - /// - /// Gets or sets a function that intercepts the standard output before being redirected. Use in conjunction with - /// - public Func? RedirectedStandardOutputHandler { get; set; } + /// + /// Gets or sets a function that intercepts the standard output before being redirected. Use in conjunction with + /// + public Func RedirectedStandardOutputHandler { get; set; } - /// - /// Gets or sets optional timeout, in milliseconds, to wait for the associated process to exit. The maximum is the largest possible value of a 32-bit integer, which represents infinity to the operating system. - /// - public int? Timeout { get; set; } + /// + /// Gets or sets optional timeout, in milliseconds, to wait for the associated process to exit. The maximum is the largest possible value of a 32-bit integer, which represents infinity to the operating system. + /// + public int? Timeout { get; set; } - /// - /// Gets or sets a value indicating whether process output will be suppressed. - /// - /// - /// true if process output will be suppressed; otherwise, false. - /// - public bool Silent { get; set; } + /// + /// Gets or sets a value indicating whether process output will be suppressed. + /// + /// + /// true if process output will be suppressed; otherwise, false. + /// + public bool Silent { get; set; } - /// - /// Gets or sets search paths for files, directories for temporary files, application-specific options, and other similar information. - /// - /// - /// - /// StartProcess("cmd", new ProcessSettings{ - /// Arguments = "/c set", - /// EnvironmentVariables = new Dictionary<string, string>{ - /// { "CI", "True" }, - /// { "TEMP", MakeAbsolute(Directory("./Temp")).FullPath } - /// } - /// }); - /// - /// - public IDictionary? EnvironmentVariables { get; set; } - } -} + /// + /// Gets or sets search paths for files, directories for temporary files, application-specific options, and other similar information. + /// + /// + /// + /// StartProcess("cmd", new ProcessSettings{ + /// Arguments = "/c set", + /// EnvironmentVariables = new Dictionary<string, string>{ + /// { "CI", "True" }, + /// { "TEMP", MakeAbsolute(Directory("./Temp")).FullPath } + /// } + /// }); + /// + /// + public IDictionary EnvironmentVariables { get; set; } +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/ProcessCore/ProcessWrapper.cs b/src/LocalStack.AwsLocal/ProcessCore/ProcessWrapper.cs index c80ac35..aca200f 100644 --- a/src/LocalStack.AwsLocal/ProcessCore/ProcessWrapper.cs +++ b/src/LocalStack.AwsLocal/ProcessCore/ProcessWrapper.cs @@ -7,120 +7,114 @@ * ***************************************************************************************/ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using LocalStack.AwsLocal.Contracts; +namespace LocalStack.AwsLocal.ProcessCore; -namespace LocalStack.AwsLocal.ProcessCore +internal sealed class ProcessWrapper : IProcess { - internal sealed class ProcessWrapper : IProcess + private readonly System.Diagnostics.Process _process; + private readonly Func _filterError; + private readonly Func _filterOutput; + private readonly ConcurrentQueue _consoleErrorQueue; + private readonly ConcurrentQueue _consoleOutputQueue; + private readonly Func _standardOutputHandler; + private readonly Func _standardErrorHandler; + + public ProcessWrapper(System.Diagnostics.Process process, Func filterOutput, + Func standardOutputHandler, + Func filterError, Func standardErrorHandler) { - private readonly System.Diagnostics.Process _process; - private readonly Func _filterError; - private readonly Func _filterOutput; - private readonly ConcurrentQueue _consoleErrorQueue; - private readonly ConcurrentQueue _consoleOutputQueue; - private readonly Func _standardOutputHandler; - private readonly Func _standardErrorHandler; - - public ProcessWrapper(System.Diagnostics.Process process, Func filterOutput, - Func? standardOutputHandler, - Func filterError, Func? standardErrorHandler) + _process = process; + _filterOutput = filterOutput ?? (source => "[REDACTED]"); + _consoleOutputQueue = new ConcurrentQueue(); + _standardOutputHandler = standardOutputHandler ?? (output => output); + _filterError = filterError ?? (source => "[REDACTED]"); + _consoleErrorQueue = new ConcurrentQueue(); + _standardErrorHandler = standardErrorHandler ?? (output => output); + } + + public void WaitForExit() + { + _process.WaitForExit(); + } + + public bool WaitForExit(int milliseconds) + { + if (_process.WaitForExit(milliseconds)) { - _process = process; - _filterOutput = filterOutput ?? (source => "[REDACTED]"); - _consoleOutputQueue = new ConcurrentQueue(); - _standardOutputHandler = standardOutputHandler ?? (output => output); - _filterError = filterError ?? (source => "[REDACTED]"); - _consoleErrorQueue = new ConcurrentQueue(); - _standardErrorHandler = standardErrorHandler ?? (output => output); + return true; } - public void WaitForExit() + _process.Refresh(); + if (!_process.HasExited) { - _process.WaitForExit(); + _process.Kill(); } - public bool WaitForExit(int milliseconds) - { - if (_process.WaitForExit(milliseconds)) - { - return true; - } + return false; + } - _process.Refresh(); - if (!_process.HasExited) - { - _process.Kill(); - } + public int GetExitCode() + { + return _process.ExitCode; + } - return false; - } + internal void StandardErrorReceived(string standardError) + { + string redirectedError = _standardErrorHandler(standardError); - public int GetExitCode() + if (redirectedError != null) { - return _process.ExitCode; + _consoleErrorQueue.Enqueue(redirectedError); } + } - internal void StandardErrorReceived(string standardError) + public IEnumerable GetStandardError() + { + while (!_consoleErrorQueue.IsEmpty || !_process.HasExited) { - string redirectedError = _standardErrorHandler(standardError); - - if (redirectedError != null) + if (!_consoleErrorQueue.TryDequeue(out string line)) { - _consoleErrorQueue.Enqueue(redirectedError); + continue; } - } - - public IEnumerable GetStandardError() - { - while (!_consoleErrorQueue.IsEmpty || !_process.HasExited) - { - if (!_consoleErrorQueue.TryDequeue(out string line)) - { - continue; - } - Console.WriteLine("{0}", _filterError(line)); - yield return line; - } + Console.WriteLine("{0}", _filterError(line)); + yield return line; } + } - internal void StandardOutputReceived(string standardOutput) - { - string redirectedOutput = _standardOutputHandler(standardOutput); + internal void StandardOutputReceived(string standardOutput) + { + string redirectedOutput = _standardOutputHandler(standardOutput); - if (redirectedOutput != null) - { - _consoleOutputQueue.Enqueue(redirectedOutput); - } + if (redirectedOutput != null) + { + _consoleOutputQueue.Enqueue(redirectedOutput); } + } - public IEnumerable GetStandardOutput() + public IEnumerable GetStandardOutput() + { + while (!_consoleOutputQueue.IsEmpty || !_process.HasExited) { - while (!_consoleOutputQueue.IsEmpty || !_process.HasExited) + if (!_consoleOutputQueue.TryDequeue(out string line)) { - if (!_consoleOutputQueue.TryDequeue(out string line)) - { - continue; - } + continue; + } - Console.WriteLine("{0}", _filterOutput(line)); + Console.WriteLine("{0}", _filterOutput(line)); - yield return line; - } + yield return line; } + } - public void Kill() - { - _process.Kill(); - _process.WaitForExit(); - } + public void Kill() + { + _process.Kill(); + _process.WaitForExit(); + } - public void Dispose() - { - _process.Dispose(); - } + public void Dispose() + { + _process.Dispose(); } -} +} \ No newline at end of file diff --git a/src/LocalStack.AwsLocal/Program.cs b/src/LocalStack.AwsLocal/Program.cs index 2fd5cc4..22e114a 100644 --- a/src/LocalStack.AwsLocal/Program.cs +++ b/src/LocalStack.AwsLocal/Program.cs @@ -1,42 +1,34 @@ -using LocalStack.Client; -using System; -using LocalStack.AwsLocal.ProcessCore; -using LocalStack.AwsLocal.ProcessCore.IO; -using LocalStack.Client.Models; -using LocalStack.Client.Options; +namespace LocalStack.AwsLocal; -namespace LocalStack.AwsLocal +internal static class Program { - internal static class Program - { - private static readonly string? LocalStackHost = Environment.GetEnvironmentVariable("LOCALSTACK_HOST"); - private static readonly string? UseSsl = Environment.GetEnvironmentVariable("USE_SSL"); - private static readonly string? UseLegacyPorts = Environment.GetEnvironmentVariable("USE_LEGACY_PORTS"); - private static readonly string? UseEdgePort = Environment.GetEnvironmentVariable("EDGE_PORT"); + private static readonly string LocalStackHost = Environment.GetEnvironmentVariable("LOCALSTACK_HOST"); + private static readonly string UseSsl = Environment.GetEnvironmentVariable("USE_SSL"); + private static readonly string UseLegacyPorts = Environment.GetEnvironmentVariable("USE_LEGACY_PORTS"); + private static readonly string UseEdgePort = Environment.GetEnvironmentVariable("EDGE_PORT"); - private static void Main(string[] args) - { - //Console.WriteLine("Waiting for debugger to attach"); - //while (!Debugger.IsAttached) - //{ - // Thread.Sleep(100); - //} - //Console.WriteLine("Debugger attached"); + private static void Main(string[] args) + { + //Console.WriteLine("Waiting for debugger to attach"); + //while (!Debugger.IsAttached) + //{ + // Thread.Sleep(100); + //} + //Console.WriteLine("Debugger attached"); - string localStackHost = !string.IsNullOrEmpty(LocalStackHost) ? LocalStackHost : Constants.LocalStackHost; - bool useSsl = !string.IsNullOrEmpty(UseSsl) && (UseSsl == "1" || UseSsl == "true"); - bool useLegacyPorts = !string.IsNullOrEmpty(UseLegacyPorts) || (UseLegacyPorts == "1" || UseLegacyPorts == "true"); - int edgePort = int.TryParse(UseEdgePort, out int port) ? port : Constants.EdgePort; + string localStackHost = !string.IsNullOrEmpty(LocalStackHost) ? LocalStackHost : Constants.LocalStackHost; + bool useSsl = !string.IsNullOrEmpty(UseSsl) && UseSsl is "1" or "true"; + bool useLegacyPorts = !string.IsNullOrEmpty(UseLegacyPorts) || UseLegacyPorts is "1" or "true"; + int edgePort = int.TryParse(UseEdgePort, out int port) ? port : Constants.EdgePort; - var configOptions = new ConfigOptions(localStackHost, useSsl, useLegacyPorts, edgePort); + var configOptions = new ConfigOptions(localStackHost, useSsl, useLegacyPorts, edgePort); - var processRunner = new ProcessRunner(); - var config = new Config(configOptions); - var fileSystem = new FileSystem(); + var processRunner = new ProcessRunner(); + var config = new Config(configOptions); + var fileSystem = new FileSystem(); - var commandDispatcher = new CommandDispatcher(processRunner, config, fileSystem, args); + var commandDispatcher = new CommandDispatcher(processRunner, config, fileSystem, args); - commandDispatcher.Run(); - } + commandDispatcher.Run(); } } \ No newline at end of file diff --git a/src/LocalStack.sln b/src/LocalStack.sln index bc2b15c..27d3e60 100644 --- a/src/LocalStack.sln +++ b/src/LocalStack.sln @@ -1,14 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalStack.AwsLocal", "LocalStack.AwsLocal\LocalStack.AwsLocal.csproj", "{D5116356-24F8-4B01-AB33-64CCFC5F0713}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D9F1CEF9-248C-49EA-BD93-5B5E6FD02967}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalStack.AwsLocal.Tests", "..\tests\LocalStack.AwsLocal.Tests\LocalStack.AwsLocal.Tests.csproj", "{1109B4DD-BD82-4759-981B-6EB1D474A200}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{924DBE7D-09A6-4948-B616-3FA2025D5F94}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,7 +28,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {1109B4DD-BD82-4759-981B-6EB1D474A200} = {D9F1CEF9-248C-49EA-BD93-5B5E6FD02967} + {1109B4DD-BD82-4759-981B-6EB1D474A200} = {924DBE7D-09A6-4948-B616-3FA2025D5F94} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {479893D2-EC31-4B10-8F7C-DDA704071C4D} diff --git a/tests/LocalStack.AwsLocal.Tests/ArgumentExtensionsTests.cs b/tests/LocalStack.AwsLocal.Tests/ArgumentExtensionsTests.cs index cec75e9..b905ed9 100644 --- a/tests/LocalStack.AwsLocal.Tests/ArgumentExtensionsTests.cs +++ b/tests/LocalStack.AwsLocal.Tests/ArgumentExtensionsTests.cs @@ -1,83 +1,78 @@ -using System.Linq; -using LocalStack.AwsLocal.Extensions; -using Xunit; +namespace LocalStack.AwsLocal.Tests; -namespace LocalStack.AwsLocal.Tests +public class ArgumentExtensionsTests { - public class ArgumentExtensionsTests + [Fact] + public void ExtractServiceName_Should_Return_Empty_String_If_Arguments_Contains_Dash() { - [Fact] - public void ExtractServiceName_Should_Return_Empty_String_If_Arguments_Contains_Dash() - { - var args = new[] {"-foo", "-bar"}; + var args = new[] {"-foo", "-bar"}; - string serviceName = args.ExtractServiceName(); + string serviceName = args.ExtractServiceName(); - Assert.Equal(string.Empty, serviceName); - } + Assert.Equal(string.Empty, serviceName); + } - [Fact] - public void ExtractServiceName_Should_Return_S3_If_One_Of_The_Argument_Is_S3Api() - { - var args = new[] { "-foo", "-bar", "s3api" }; + [Fact] + public void ExtractServiceName_Should_Return_S3_If_One_Of_The_Argument_Is_S3Api() + { + var args = new[] { "-foo", "-bar", "s3api" }; - string serviceName = args.ExtractServiceName(); + string serviceName = args.ExtractServiceName(); - Assert.Equal("s3", serviceName); - } + Assert.Equal("s3", serviceName); + } - [Fact] - public void ExtractServiceName_Should_Extract_First_Valid_Argument_As_ServiceName_From_Arguments() - { - var args = new[] { "-foo", "-bar", "kinesis", "list-streams" }; + [Fact] + public void ExtractServiceName_Should_Extract_First_Valid_Argument_As_ServiceName_From_Arguments() + { + var args = new[] { "-foo", "-bar", "kinesis", "list-streams" }; - string serviceName = args.ExtractServiceName(); + string serviceName = args.ExtractServiceName(); - Assert.Equal("kinesis", serviceName); - } + Assert.Equal("kinesis", serviceName); + } - [Fact] - public void GetCliCommand_Should_Add_LocalStack_Service_EndPoint_As_Endpoint_Switch_To_Command() - { - var args = new[] { "kinesis", "list-streams" }; - const string serviceUrl = "http://localhost:1234"; + [Fact] + public void GetCliCommand_Should_Add_LocalStack_Service_EndPoint_As_Endpoint_Switch_To_Command() + { + var args = new[] { "kinesis", "list-streams" }; + const string serviceUrl = "http://localhost:1234"; - string cliCommand = args.GetCliCommand(serviceUrl); + string cliCommand = args.GetCliCommand(serviceUrl); - Assert.Contains($"--endpoint-url={serviceUrl}", cliCommand); - } + Assert.Contains($"--endpoint-url={serviceUrl}", cliCommand); + } - [Fact] - public void GetCliCommand_Should_Add_No_Verify_Ssl_Switch_To_Command() - { - var args = new[] { "kinesis", "list-streams" }; - const string serviceUrl = "https://localhost:1234"; + [Fact] + public void GetCliCommand_Should_Add_No_Verify_Ssl_Switch_To_Command() + { + var args = new[] { "kinesis", "list-streams" }; + const string serviceUrl = "https://localhost:1234"; - string cliCommand = args.GetCliCommand(serviceUrl); + string cliCommand = args.GetCliCommand(serviceUrl); - Assert.Contains("--no-verify-ssl", cliCommand); - } + Assert.Contains("--no-verify-ssl", cliCommand); + } - [Fact] - public void GetCliCommand_Should_Add_Aws_To_Command_As_First_Argument() - { - var args = new[] { "kinesis", "list-streams" }; - const string serviceUrl = "http://localhost:1234"; + [Fact] + public void GetCliCommand_Should_Add_Aws_To_Command_As_First_Argument() + { + var args = new[] { "kinesis", "list-streams" }; + const string serviceUrl = "http://localhost:1234"; - string cliCommand = args.GetCliCommand(serviceUrl); + string cliCommand = args.GetCliCommand(serviceUrl); - Assert.StartsWith("aws ", cliCommand); - } + Assert.StartsWith("aws ", cliCommand); + } - [Fact] - public void GetCliCommand_Should_Add_Arguments_To_Command() - { - var args = new[] { "-foo", "-bar", "kinesis", "list-streams" }; - const string serviceUrl = "http://localhost:1234"; + [Fact] + public void GetCliCommand_Should_Add_Arguments_To_Command() + { + var args = new[] { "-foo", "-bar", "kinesis", "list-streams" }; + const string serviceUrl = "http://localhost:1234"; - string cliCommand = args.GetCliCommand(serviceUrl); + string cliCommand = args.GetCliCommand(serviceUrl); - Assert.Contains(args, s => cliCommand.Split(" ").Contains(s)); - } + Assert.Contains(args, s => cliCommand.Split(" ").Contains(s)); } -} +} \ No newline at end of file diff --git a/tests/LocalStack.AwsLocal.Tests/CommandDispatcherTests.cs b/tests/LocalStack.AwsLocal.Tests/CommandDispatcherTests.cs index 9922b1e..38fd2f8 100644 --- a/tests/LocalStack.AwsLocal.Tests/CommandDispatcherTests.cs +++ b/tests/LocalStack.AwsLocal.Tests/CommandDispatcherTests.cs @@ -1,130 +1,120 @@ -using System.Collections.Generic; -using LocalStack.AwsLocal.AmbientContexts; -using LocalStack.AwsLocal.Extensions; -using LocalStack.AwsLocal.Tests.Mocks; -using LocalStack.Client.Enums; -using LocalStack.Client.Models; -using Moq; -using Xunit; - -namespace LocalStack.AwsLocal.Tests +namespace LocalStack.AwsLocal.Tests; + +public class CommandDispatcherTests { - public class CommandDispatcherTests + private readonly EnvironmentContextMock _environmentContextMock; + private readonly ConsoleContextMock _consoleContextMock; + + public CommandDispatcherTests() + { + _environmentContextMock = new EnvironmentContextMock(); + _consoleContextMock = new ConsoleContextMock(); + + EnvironmentContext.Current = _environmentContextMock; + ConsoleContext.Current = _consoleContextMock; + } + + [Fact] + public void Run_Should_Write_Help_Info_And_Exit_With_Zero_If_Argument_Count_Zero() + { + CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(Array.Empty()); + + commandDispatcher.Run(); + + Assert.Equal(0, _environmentContextMock.ExitValue); + Assert.NotNull(_consoleContextMock.Text); + Assert.NotEmpty(_consoleContextMock.Text); + } + + [Fact] + public void Run_Should_Write_Help_Info_And_Exit_With_Zero_If_The_First_Argument_Is_Help() + { + CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] {"-h"}); + + commandDispatcher.Run(); + + Assert.Equal(0, _environmentContextMock.ExitValue); + Assert.NotNull(_consoleContextMock.Text); + Assert.NotEmpty(_consoleContextMock.Text); + } + + [Fact] + public void Run_Should_Write_Error_And_Exit_With_One_If_The_Arguments_Does_Not_Contains_Valid_ServiceName() { - private readonly EnvironmentContextMock _environmentContextMock; - private readonly ConsoleContextMock _consoleContextMock; - - public CommandDispatcherTests() - { - _environmentContextMock = new EnvironmentContextMock(); - _consoleContextMock = new ConsoleContextMock(); - - EnvironmentContext.Current = _environmentContextMock; - ConsoleContext.Current = _consoleContextMock; - } - - [Fact] - public void Run_Should_Write_Help_Info_And_Exit_With_Zero_If_Argument_Count_Zero() - { - CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new string[0]); - - commandDispatcher.Run(); - - Assert.Equal(0, _environmentContextMock.ExitValue); - Assert.NotNull(_consoleContextMock.Text); - Assert.NotEmpty(_consoleContextMock.Text); - } - - [Fact] - public void Run_Should_Write_Help_Info_And_Exit_With_Zero_If_The_First_Argument_Is_Help() - { - CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] {"-h"}); - - commandDispatcher.Run(); - - Assert.Equal(0, _environmentContextMock.ExitValue); - Assert.NotNull(_consoleContextMock.Text); - Assert.NotEmpty(_consoleContextMock.Text); - } - - [Fact] - public void Run_Should_Write_Error_And_Exit_With_One_If_The_Arguments_Does_Not_Contains_Valid_ServiceName() - { - CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] { "-foo -bar" }); - - commandDispatcher.Run(); - - Assert.Equal(1, _environmentContextMock.ExitValue); - Assert.NotNull(_consoleContextMock.Text); - Assert.NotEmpty(_consoleContextMock.Text); - Assert.StartsWith("ERROR:", _consoleContextMock.Text); - } - - [Fact] - public void Run_Should_Write_Error_And_Exit_With_One_If_Given_ServiceName_Has_Not_Valid_LocalStack_Endpoint() - { - CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] { "hinesis", "list-streams" }); - - commandDispatcher.Config - .Setup(config => config.GetAwsServiceEndpoints()) - .Returns(() => new List()); - - commandDispatcher.Run(); - - Assert.Equal(1, _environmentContextMock.ExitValue); - Assert.NotNull(_consoleContextMock.Text); - Assert.NotEmpty(_consoleContextMock.Text); - Assert.StartsWith("ERROR:", _consoleContextMock.Text); - - commandDispatcher.Config - .Verify(config => config.GetAwsServiceEndpoints(), Times.Once); - } - - //[Fact] - //public void Run_Should_Run_Aws_Command_With_Generated_Command_And_Aws_Credentials() - //{ - // var args = new[] {"kinesis", "list-streams"}; - - // AwsServiceEndpointMetadata endpointMetadata = AwsServiceEndpointMetadata.Kinesis; - // var awsServiceEndpoint = new AwsServiceEndpoint( - // endpointMetadata.ServiceId, - // endpointMetadata.CliName, - // endpointMetadata.Enum, - // endpointMetadata.Port, - // "localhost", - // endpointMetadata.ToString("http", "localhost")); - - // string cliCommand = args.GetCliCommand(awsServiceEndpoint.ServiceUrl); - - // CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(args); - - // commandDispatcher.Config - // .Setup(config => config.GetAwsServiceEndpoints()) - // .Returns(() => new[] {awsServiceEndpoint}); - - // commandDispatcher.ProcessRunner.Setup(runner => runner.) - - // commandDispatcher.ProcessRunner - // .Setup(helper => helper.CmdExecute( - // It.IsAny(), - // It.IsAny(), - // It.IsAny(), - // It.IsAny(), - // It.IsAny>())) - // .Returns(0); - - // commandDispatcher.Run(); - - // commandDispatcher.Config - // .Verify(config => config.GetAwsServiceEndpoints(), Times.Once); - - // commandDispatcher.ProcessRunner - // .Verify(helper => helper.CmdExecute( - // It.Is(s => s == cliCommand), - // It.Is(s => s == null), - // It.Is(b => b), - // It.Is(b => b), - // It.IsAny>()), Times.Once); - //} + CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] { "-foo -bar" }); + + commandDispatcher.Run(); + + Assert.Equal(1, _environmentContextMock.ExitValue); + Assert.NotNull(_consoleContextMock.Text); + Assert.NotEmpty(_consoleContextMock.Text); + Assert.StartsWith("ERROR:", _consoleContextMock.Text); } -} + + [Fact] + public void Run_Should_Write_Error_And_Exit_With_One_If_Given_ServiceName_Has_Not_Valid_LocalStack_Endpoint() + { + CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(new[] { "hinesis", "list-streams" }); + + commandDispatcher.Config + .Setup(config => config.GetAwsServiceEndpoints()) + .Returns(() => new List()); + + commandDispatcher.Run(); + + Assert.Equal(1, _environmentContextMock.ExitValue); + Assert.NotNull(_consoleContextMock.Text); + Assert.NotEmpty(_consoleContextMock.Text); + Assert.StartsWith("ERROR:", _consoleContextMock.Text); + + commandDispatcher.Config + .Verify(config => config.GetAwsServiceEndpoints(), Times.Once); + } + + //[Fact] + //public void Run_Should_Run_Aws_Command_With_Generated_Command_And_Aws_Credentials() + //{ + // var args = new[] {"kinesis", "list-streams"}; + + // AwsServiceEndpointMetadata endpointMetadata = AwsServiceEndpointMetadata.Kinesis; + // var awsServiceEndpoint = new AwsServiceEndpoint( + // endpointMetadata.ServiceId, + // endpointMetadata.CliName, + // endpointMetadata.Enum, + // endpointMetadata.Port, + // "localhost", + // endpointMetadata.ToString("http", "localhost")); + + // string cliCommand = args.GetCliCommand(awsServiceEndpoint.ServiceUrl); + + // CommandDispatcherMock commandDispatcher = CommandDispatcherMock.Create(args); + + // commandDispatcher.Config + // .Setup(config => config.GetAwsServiceEndpoints()) + // .Returns(() => new[] {awsServiceEndpoint}); + + // commandDispatcher.ProcessRunner.Setup(runner => runner.) + + // commandDispatcher.ProcessRunner + // .Setup(helper => helper.CmdExecute( + // It.IsAny(), + // It.IsAny(), + // It.IsAny(), + // It.IsAny(), + // It.IsAny>())) + // .Returns(0); + + // commandDispatcher.Run(); + + // commandDispatcher.Config + // .Verify(config => config.GetAwsServiceEndpoints(), Times.Once); + + // commandDispatcher.ProcessRunner + // .Verify(helper => helper.CmdExecute( + // It.Is(s => s == cliCommand), + // It.Is(s => s == null), + // It.Is(b => b), + // It.Is(b => b), + // It.IsAny>()), Times.Once); + //} +} \ No newline at end of file diff --git a/tests/LocalStack.AwsLocal.Tests/GlobalUsings.cs b/tests/LocalStack.AwsLocal.Tests/GlobalUsings.cs new file mode 100644 index 0000000..dd5bb1c --- /dev/null +++ b/tests/LocalStack.AwsLocal.Tests/GlobalUsings.cs @@ -0,0 +1,14 @@ +global using LocalStack.AwsLocal.AmbientContexts; +global using LocalStack.AwsLocal.Contracts; +global using LocalStack.AwsLocal.Extensions; +global using LocalStack.AwsLocal.Tests.Mocks; +global using LocalStack.Client.Contracts; +global using LocalStack.Client.Models; + +global using Moq; + +global using System; +global using System.Collections.Generic; +global using System.Linq; + +global using Xunit; \ No newline at end of file diff --git a/tests/LocalStack.AwsLocal.Tests/Mocks/CommandDispatcherMock.cs b/tests/LocalStack.AwsLocal.Tests/Mocks/CommandDispatcherMock.cs index 7bc2349..17aad3b 100644 --- a/tests/LocalStack.AwsLocal.Tests/Mocks/CommandDispatcherMock.cs +++ b/tests/LocalStack.AwsLocal.Tests/Mocks/CommandDispatcherMock.cs @@ -1,31 +1,26 @@ -using LocalStack.AwsLocal.Contracts; -using LocalStack.Client.Contracts; -using Moq; +namespace LocalStack.AwsLocal.Tests.Mocks; -namespace LocalStack.AwsLocal.Tests.Mocks +public class CommandDispatcherMock : CommandDispatcher { - public class CommandDispatcherMock : CommandDispatcher + public CommandDispatcherMock(Mock processRunner, Mock config, Mock fileSystem, string[] args) + : base(processRunner.Object, config.Object, fileSystem.Object, args) { - public CommandDispatcherMock(Mock processRunner, Mock config, Mock fileSystem, string[] args) - : base(processRunner.Object, config.Object, fileSystem.Object, args) - { - ProcessRunner = processRunner; - Config = config; - } + ProcessRunner = processRunner; + Config = config; + } - public Mock ProcessRunner { get; } + public Mock ProcessRunner { get; } - public Mock Config { get; } + public Mock Config { get; } - public Mock FileSystem { get; } + public Mock FileSystem { get; } - public static CommandDispatcherMock Create(string[] args) - { - return new CommandDispatcherMock( - new Mock(MockBehavior.Strict), - new Mock(MockBehavior.Strict), - new Mock(MockBehavior.Strict), - args); - } + public static CommandDispatcherMock Create(string[] args) + { + return new CommandDispatcherMock( + new Mock(MockBehavior.Strict), + new Mock(MockBehavior.Strict), + new Mock(MockBehavior.Strict), + args); } -} +} \ No newline at end of file diff --git a/tests/LocalStack.AwsLocal.Tests/Mocks/ConsoleContextMock.cs b/tests/LocalStack.AwsLocal.Tests/Mocks/ConsoleContextMock.cs index 8254c49..a3c29e3 100644 --- a/tests/LocalStack.AwsLocal.Tests/Mocks/ConsoleContextMock.cs +++ b/tests/LocalStack.AwsLocal.Tests/Mocks/ConsoleContextMock.cs @@ -1,16 +1,13 @@ -using LocalStack.AwsLocal.AmbientContexts; +namespace LocalStack.AwsLocal.Tests.Mocks; -namespace LocalStack.AwsLocal.Tests.Mocks +public class ConsoleContextMock : ConsoleContext { - public class ConsoleContextMock : ConsoleContext - { - private string _text; - - public override void WriteLine(string text) - { - _text = text; - } + private string _text; - public string Text => _text; + public override void WriteLine(string text) + { + _text = text; } -} + + public string Text => _text; +} \ No newline at end of file diff --git a/tests/LocalStack.AwsLocal.Tests/Mocks/EnvironmentContextMock.cs b/tests/LocalStack.AwsLocal.Tests/Mocks/EnvironmentContextMock.cs index 990ff8f..0833df5 100644 --- a/tests/LocalStack.AwsLocal.Tests/Mocks/EnvironmentContextMock.cs +++ b/tests/LocalStack.AwsLocal.Tests/Mocks/EnvironmentContextMock.cs @@ -1,16 +1,13 @@ -using LocalStack.AwsLocal.AmbientContexts; +namespace LocalStack.AwsLocal.Tests.Mocks; -namespace LocalStack.AwsLocal.Tests.Mocks +public class EnvironmentContextMock : EnvironmentContext { - public class EnvironmentContextMock : EnvironmentContext - { - private int _exitValue; - - public override void Exit(int value) - { - _exitValue = value; - } + private int _exitValue; - public int ExitValue => _exitValue; + public override void Exit(int value) + { + _exitValue = value; } -} + + public int ExitValue => _exitValue; +} \ No newline at end of file