Skip to content

Commit 895823b

Browse files
committed
Add process command and rework test commands
1 parent df8272b commit 895823b

File tree

10 files changed

+86
-27
lines changed

10 files changed

+86
-27
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using System;
2+
using InEngine.Core;
23
using InEngine.Core.Exceptions;
34

4-
namespace InEngine.Core.Commands
5+
namespace InEngine.Commands
56
{
67
/// <summary>
78
/// Dummy command for testing and sample code.

src/InEngine.Core/Commands/AlwaysSucceed.cs renamed to src/InEngine.Commands/AlwaysSucceed.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace InEngine.Core.Commands
1+
using InEngine.Core;
2+
3+
namespace InEngine.Commands
24
{
35
/// <summary>
46
/// Dummy command for testing and sample code.

src/InEngine.Commands/Options.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
using CommandLine;
2-
using InEngine.Commands.Sample;
2+
using CommandLine.Text;
33
using InEngine.Core;
44

55
namespace InEngine.Commands
66
{
77
public class Options : IOptions
88
{
9-
[VerbOption("sample:minimal")]
10-
public Minimal Minimal { get; set; }
9+
[VerbOption("fail", HelpText = "Always fail. Useful for end-to-end testing.")]
10+
public AlwaysFail AlwaysFail { get; set; }
1111

12+
[VerbOption("succeed", HelpText = "A null operation command. Literally does nothing.")]
13+
public AlwaysSucceed Null { get; set; }
14+
15+
[HelpVerbOption]
1216
public string GetUsage(string verb)
1317
{
14-
return "\tsample:minimal \t\tA minimal implementation of a command.";
18+
return HelpText.AutoBuild(this, verb);
1519
}
1620
}
1721
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public class MoreOptions : IOptions
1313
[VerbOption("sample:say-hello", HelpText = "A sample command to say \"hello\".")]
1414
public SayHello SayHello { get; set; }
1515

16+
[VerbOption("sample:minimal")]
17+
public Minimal Minimal { get; set; }
18+
19+
[HelpVerbOption]
1620
public string GetUsage(string verb)
1721
{
1822
return HelpText.AutoBuild(this, verb);

src/InEngine.Core.Test/Queue/Commands/ConsumeTest.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
using System.Collections.Generic;
2-
using System.Linq;
3-
using BeekmanLabs.UnitTesting;
4-
using InEngine.Core.Commands;
5-
using InEngine.Core.Exceptions;
1+
using BeekmanLabs.UnitTesting;
2+
using InEngine.Commands;
63
using InEngine.Core.Queue.Commands;
74
using Moq;
85
using NUnit.Framework;

src/InEngine.Core.Test/Queue/Commands/PublishTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Linq;
43
using BeekmanLabs.UnitTesting;
4+
using InEngine.Commands;
55
using InEngine.Core.Commands;
66
using InEngine.Core.Exceptions;
77
using InEngine.Core.Queue.Commands;

src/InEngine.Core/Commands/Options.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,16 @@ namespace InEngine.Core.Commands
55
{
66
public class Options : IOptions
77
{
8-
[VerbOption("fail", HelpText = "Always fail. Useful for end-to-end testing.")]
9-
public AlwaysFail AlwaysFail { get; set; }
10-
118
[VerbOption("echo", HelpText= "Echo some text to the console. Useful for end-to-end testing.")]
129
public Echo Echo { get; set; }
1310

14-
[VerbOption("succeed", HelpText = "A null operation command. Literally does nothing.")]
15-
public AlwaysSucceed Null { get; set; }
11+
[VerbOption("process", HelpText = "Launch an arbitrary process.")]
12+
public RuntimeProcess Process { get; set; }
1613

14+
[HelpVerbOption]
1715
public string GetUsage(string verb)
1816
{
19-
return null;
17+
return HelpText.AutoBuild(this, verb);
2018
}
2119
}
2220
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.IO;
4+
using CommandLine;
5+
using InEngine.Core.Exceptions;
6+
7+
namespace InEngine.Core.Commands
8+
{
9+
public class RuntimeProcess : AbstractCommand
10+
{
11+
[Option('c', "command", Required = true, HelpText = "The name of the CLI program/command to run.")]
12+
public string Command { get; set; }
13+
14+
[Option('a', "args", HelpText = "Arguments for the CLI program/command.")]
15+
public string Arguments { get; set; }
16+
17+
[Option('t', "timeout", DefaultValue = 900, HelpText = "The number of seconds to wait before killing the runnin process.")]
18+
public int Timeout { get; set; }
19+
20+
public override void Run()
21+
{
22+
if (!File.Exists(Command))
23+
throw new CommandFailedException($"Cannot run {Command}. It either does not exist or is inaccessible. Exiting...");
24+
var process = new Process() {
25+
StartInfo = new ProcessStartInfo(Command, Arguments) {
26+
UseShellExecute = false,
27+
ErrorDialog = false,
28+
RedirectStandardError = false,
29+
RedirectStandardInput = false,
30+
RedirectStandardOutput = false,
31+
}
32+
};
33+
var commandWithArguments = $"{Command} {Arguments}";
34+
Logger.Debug($"Starting process for command: {commandWithArguments}");
35+
process.Start();
36+
Logger.Debug($"Command ({commandWithArguments}) started with process ID {process.Id}.");
37+
if (process.WaitForExit(Timeout * 1000)) {
38+
Logger.Debug($"Process for command {commandWithArguments} with PID {process.Id} ended with exit code {process.ExitCode}.");
39+
return;
40+
}
41+
Logger.Debug($"The command ({commandWithArguments}) has timed out and is about to be killed...");
42+
process.Kill();
43+
Logger.Debug($"The command ({commandWithArguments}) has been killed.");
44+
throw new CommandFailedException($"The command timed out after {Timeout} second(s).");
45+
}
46+
}
47+
}

src/InEngine.Core/ExitCodes.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace InEngine.Core
2+
{
3+
public static class ExitCodes
4+
{
5+
public static readonly int success = 0;
6+
public static readonly int fail = 1;
7+
}
8+
}

src/InEngine/ArgumentInterpreter.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void Interpret(string[] args)
4343
if (parser.ParseArguments(args, options))
4444
{
4545
if (options == null)
46-
Environment.Exit(Parser.DefaultExitCodeFail);
46+
ExitWithFailure("Could not parse arguments.");
4747

4848
if (!args.Any())
4949
PrintInEngineHelpTextAndExit(plugins, options);
@@ -53,6 +53,7 @@ public void Interpret(string[] args)
5353
if (options.ShouldRunScheduler)
5454
{
5555
Write.Info(CliLogo);
56+
Write.Line("Starting the scheduler...").Newline();
5657
Program.RunScheduler();
5758
ExitWithSuccess();
5859
}
@@ -87,22 +88,22 @@ public void ExitWithSuccess(string message = null)
8788
if (string.IsNullOrWhiteSpace(message))
8889
message = "success";
8990
Logger.Debug($"✔ {message}");
90-
Environment.Exit(0);
91+
Environment.Exit(ExitCodes.success);
9192
}
9293

9394
public void ExitWithFailure(string message = null)
9495
{
9596
Logger.Error(MakeErrorMessage(message));
9697
Write.Error(message);
97-
Environment.Exit(Parser.DefaultExitCodeFail);
98+
Environment.Exit(ExitCodes.fail);
9899
}
99100

100101
public void ExitWithFailure(Exception exception = null)
101102
{
102103
var ex = exception ?? new Exception("Unspecified failure");
103104
Logger.Error(ex, MakeErrorMessage(ex.Message));
104105
Write.Error(ex.Message);
105-
Environment.Exit(Parser.DefaultExitCodeFail);
106+
Environment.Exit(ExitCodes.fail);
106107
}
107108

108109
protected string MakeErrorMessage(string message = null)
@@ -121,13 +122,10 @@ public void InterpretPluginArguments(string[] pluginArgs, IOptions pluginOptions
121122
if (subOptions == null && (lastArg == "-h" || lastArg == "--help"))
122123
ExitWithSuccess();
123124
else if (subOptions == null)
124-
ExitWithFailure(new CommandFailedException("Could not parse plugin options"));
125-
125+
ExitWithFailure(new CommandFailedException("Could not parse plugin arguments. Use -h, --help for usage."));
126126
var command = subOptions as ICommand;
127-
128127
if (command is AbstractCommand)
129128
(command as AbstractCommand).Name = verb.Normalize();
130-
131129
command.Run();
132130
ExitWithSuccess();
133131
}
@@ -138,7 +136,7 @@ public void InterpretPluginArguments(string[] pluginArgs, IOptions pluginOptions
138136
});
139137

140138
if (!isSuccessful)
141-
ExitWithFailure("Could not parse plugin arguments");
139+
ExitWithFailure(new CommandFailedException("Could not parse plugin arguments. Use -h, --help for usage."));
142140
}
143141

144142
public void PrintPluginHelpTextAndExit(Plugin plugin, List<IOptions> pluginOptionList, string[] pluginArgs)

0 commit comments

Comments
 (0)