Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ForceOps.Benchmarks/ForceOps.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions ForceOps.Lib/ForceOps.Lib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="LockChecker" Version="0.9.33-gf4fccad662" />
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog" Version="4.3.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
</ItemGroup>
</Project>
8 changes: 4 additions & 4 deletions ForceOps.Test/ForceOps.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="System.Reactive" Version="6.1.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion ForceOps/ForceOps.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.CommandLine" Version="2.0.9" />
</ItemGroup>

<ItemGroup>
Expand Down
83 changes: 44 additions & 39 deletions ForceOps/src/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
using System.CommandLine;
using System.CommandLine.Help;
using System.Runtime.Versioning;

namespace ForceOps;
Expand All @@ -21,48 +20,46 @@ public ForceOpsRunner(ForceOps forceOps)

internal int Run()
{
var rootCommand = new RootCommand("By hook or by crook, perform operations on files and directories. If they are in use by a process, kill the process.")
{
Name = "forceops"
};
rootCommand.AddCommand(CreateDeleteCommand());
rootCommand.AddCommand(CreateListCommand());
// A named Command is used instead of RootCommand so the usage text shows
// "forceops" rather than the executable name ("ForceOps").
var rootCommand = new Command("forceops", "By hook or by crook, perform operations on files and directories. If they are in use by a process, kill the process.");
rootCommand.Options.Add(new HelpOption());
rootCommand.Options.Add(new VersionOption());
rootCommand.Subcommands.Add(CreateDeleteCommand());
rootCommand.Subcommands.Add(CreateListCommand());

var parser = new CommandLineBuilder(rootCommand)
.UseDefaults()
.AddMiddleware(async (context, next) =>
try
{
return rootCommand.Parse(_forceOps.args).Invoke(new InvocationConfiguration
{
try
{
await next(context);
}
catch (Exception ex)
{
_forceOps.caughtException = ex;

if (ex is FileNotFoundException fileNotFoundEx)
{
_forceOps.forceOpsContext.environmentExit.Exit((int)ExitCode.FileNotFound, ex.Message);
}
throw;
}
})
.Build();
EnableDefaultExceptionHandler = false
});
}
catch (Exception ex)
{
_forceOps.caughtException = ex;

return parser.Invoke(_forceOps.args);
if (ex is FileNotFoundException)
{
_forceOps.forceOpsContext.environmentExit.Exit((int)ExitCode.FileNotFound, ex.Message);
}
Console.Error.WriteLine(ex.ToString());
return 1;
}
}

Command CreateDeleteCommand()
{
var filesToDeleteArgument = new Argument<string[]>("files", "Files or directories to delete.")
var filesToDeleteArgument = new Argument<string[]>("files")
{
Description = "Files or directories to delete.",
Arity = ArgumentArity.OneOrMore
};

var forceOption = new Option<bool>(["-f", "--force"], "Ignore nonexistent files and arguments.");
var disableElevate = new Option<bool>(["-e", "--disable-elevate"], "Do not attempt to elevate if the file can't be deleted.");
var retryDelay = new Option<int>(["-d", "--retry-delay"], () => 50, "Delay when retrying to delete a file, after deleting processes holding a lock.");
var maxRetries = new Option<int>(["-n", "--max-retries"], () => 10, "Number of retries when deleting a locked file.");
var forceOption = new Option<bool>("--force", "-f") { Description = "Ignore nonexistent files and arguments." };
var disableElevate = new Option<bool>("--disable-elevate", "-e") { Description = "Do not attempt to elevate if the file can't be deleted." };
var retryDelay = new Option<int>("--retry-delay", "-d") { DefaultValueFactory = _ => 50, Description = "Delay when retrying to delete a file, after deleting processes holding a lock." };
var maxRetries = new Option<int>("--max-retries", "-n") { DefaultValueFactory = _ => 10, Description = "Number of retries when deleting a locked file." };

var deleteCommand = new Command("delete", "Delete files or a directories recursively.")
{
Expand All @@ -73,20 +70,28 @@ Command CreateDeleteCommand()
maxRetries
};

deleteCommand.AddAlias("rm");
deleteCommand.AddAlias("remove");
deleteCommand.SetHandler(_forceOps.DeleteCommand, filesToDeleteArgument, forceOption, disableElevate, retryDelay, maxRetries);
deleteCommand.Aliases.Add("rm");
deleteCommand.Aliases.Add("remove");
deleteCommand.SetAction(parseResult => _forceOps.DeleteCommand(
parseResult.GetValue(filesToDeleteArgument)!,
parseResult.GetValue(forceOption),
parseResult.GetValue(disableElevate),
parseResult.GetValue(retryDelay),
parseResult.GetValue(maxRetries)));
return deleteCommand;
}

Command CreateListCommand()
{
var fileOrDirectoryArgument = new Argument<string>("fileOrDirectory", "File or directory to get the locks of.");
var fileOrDirectoryArgument = new Argument<string>("fileOrDirectory")
{
Description = "File or directory to get the locks of."
};
var listCommand = new Command("list", "Uses LockCheck to output processes using a file or directory.")
{
fileOrDirectoryArgument
};
listCommand.SetHandler(_forceOps.ListCommand, fileOrDirectoryArgument);
listCommand.SetAction(parseResult => _forceOps.ListCommand(parseResult.GetValue(fileOrDirectoryArgument)!));
return listCommand;
}
}
Loading