Skip to content

Commit

Permalink
Merge PR #37 (CLI) from felix-b/pr-cli
Browse files Browse the repository at this point in the history
Leftovers: #38, #39.
  • Loading branch information
felix-b authored Apr 6, 2017
2 parents 8eda429 + b6d137a commit d1fdf04
Show file tree
Hide file tree
Showing 30 changed files with 1,143 additions and 39 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
Expand Down
12 changes: 12 additions & 0 deletions Source/NWheels.Api/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,17 @@ public static string TrimSuffix(this string source, string suffix)

return source.Substring(startIndex: 0, length: source.Length - suffix.Length);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

public static string DefaultIfNullOrEmpty(this string source, string defaultValue)
{
if (string.IsNullOrEmpty(source))
{
return defaultValue;
}

return source;
}
}
}
1 change: 0 additions & 1 deletion Source/NWheels.Api/NWheels.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<RootNamespace>NWheels</RootNamespace>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<TargetFramework>netstandard1.6</TargetFramework>
<OutputPath>..\Bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
Expand Down
163 changes: 163 additions & 0 deletions Source/NWheels.Cli/CommandBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace NWheels.Cli
{
public abstract class CommandBase : ICommand
{
protected CommandBase(string name, string helpText)
{
this.Name = name;
this.HelpText = helpText;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

public abstract void DefineArguments(ArgumentSyntax syntax);
public abstract void ValidateArguments(ArgumentSyntax arguments);
public abstract void Execute();

//-----------------------------------------------------------------------------------------------------------------------------------------------------

public string Name { get; }
public string HelpText { get; }

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected int ExecuteProgram(
string nameOrFilePath,
string[] args = null,
string workingDirectory = null,
bool validateExitCode = true)
{
return ExecuteProgram(
out IEnumerable<string> output,
nameOrFilePath,
args,
workingDirectory,
validateExitCode,
shouldInterceptOutput: false);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected int ExecuteProgram(
out IEnumerable<string> output,
string nameOrFilePath,
string[] args = null,
string workingDirectory = null,
bool validateExitCode = true)
{
return ExecuteProgram(
out output,
nameOrFilePath,
args,
workingDirectory,
validateExitCode,
shouldInterceptOutput: true);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void Log(string message)
{
Console.WriteLine(message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void LogDebug(string message)
{
Program.LogMessageWithColor(ConsoleColor.DarkGray, message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void LogImportant(string message)
{
Program.LogMessageWithColor(ConsoleColor.Cyan, message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void LogSuccess(string message)
{
Program.LogMessageWithColor(ConsoleColor.Green, message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void LogWarning(string message)
{
Program.LogMessageWithColor(ConsoleColor.Yellow, message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void LogError(string message)
{
Program.LogMessageWithColor(ConsoleColor.Red, message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void ReportFatalError(Exception error)
{
Console.Error.WriteLine(error.ToString());
ReportFatalError(error.Message);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

protected void ReportFatalError(string message)
{
LogError("FATAL ERROR: " + message);
Environment.Exit(2);
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

private int ExecuteProgram(
out IEnumerable<string> output,
string nameOrFilePath,
string[] args,
string workingDirectory,
bool validateExitCode,
bool shouldInterceptOutput)
{
var info = new ProcessStartInfo() {
FileName = nameOrFilePath,
Arguments = (args != null ? string.Join(" ", args) : string.Empty),
WorkingDirectory = workingDirectory,
RedirectStandardOutput = shouldInterceptOutput
};

var process = Process.Start(info);
List<string> outputLines = null;

if (shouldInterceptOutput)
{
outputLines = new List<string>(capacity: 100);
string line;
while ((line = process.StandardOutput.ReadLine()) != null)
{
outputLines.Add(line);
}
}

process.WaitForExit();
output = outputLines;

if (validateExitCode && process.ExitCode != 0)
{
throw new Exception($"Program '{nameOrFilePath}' failed with code {process.ExitCode}.");
}

return process.ExitCode;
}
}
}
26 changes: 26 additions & 0 deletions Source/NWheels.Cli/ICommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.CommandLine;

namespace NWheels.Cli
{
public interface ICommand
{
void DefineArguments(ArgumentSyntax syntax);
void ValidateArguments(ArgumentSyntax arguments);
void Execute();
string Name { get; }
string HelpText { get; }
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------

public static class CommandExtensions
{
public static void BindToCommandLine(this ICommand command, ArgumentSyntax syntax)
{
var commandSyntax = syntax.DefineCommand(command.Name);
commandSyntax.Help = command.HelpText;
command.DefineArguments(syntax);
}
}
}
23 changes: 23 additions & 0 deletions Source/NWheels.Cli/NWheels.Cli.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyName>nwheels</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="0.1.0-e170329-6" />
<PackageReference Include="System.Xml.XPath.XDocument" Version="4.3.0" />
<!--
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" />
<PackageReference Include="Microsoft.NET.Sdk" Version="1.1.0-alpha-20170315-1" />
-->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NWheels.Api\NWheels.Api.csproj" />
<ProjectReference Include="..\NWheels.Implementation\NWheels.Implementation.csproj" />
</ItemGroup>

</Project>
81 changes: 81 additions & 0 deletions Source/NWheels.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.CommandLine;
using System.Linq;

namespace NWheels.Cli
{
class Program
{
private static readonly ICommand[] _s_commands = {
new Publish.PublishCommand(),
new Run.RunCommand()
};

//-----------------------------------------------------------------------------------------------------------------------------------------------------

static int Main(string[] args)
{
var arguments = ParseCommandLine(args); // will Environment.Exit with code 1 if not parsed
var activeCommand = FindActiveCommand(arguments); // will Environment.Exit with code 1 if not found
activeCommand.ValidateArguments(arguments); // will Environment.Exit with code 1 if not valid

var exitCode = 0;

try
{
activeCommand.Execute();
}
catch (Exception e)
{
LogMessageWithColor(ConsoleColor.Red, "FAILED: " + e.Message);
Console.Error.WriteLine(e.ToString());
exitCode = 2;
}

return exitCode;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

public static void LogMessageWithColor(ConsoleColor color, string message)
{
var saveColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = saveColor;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

private static ArgumentSyntax ParseCommandLine(string[] args)
{
return ArgumentSyntax.Parse(args, syntax => {
foreach (var command in _s_commands)
{
command.BindToCommandLine(syntax);
}
});
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------

private static ICommand FindActiveCommand(ArgumentSyntax arguments)
{
ICommand activeCommand = null;

if (arguments.ActiveCommand != null)
{
activeCommand = _s_commands
.FirstOrDefault(
c => string.Equals(c.Name, arguments.ActiveCommand.Name, StringComparison.OrdinalIgnoreCase));
}

if (activeCommand == null)
{
arguments.ReportError("Command not understood.");
}

return activeCommand;
}
}
}
9 changes: 9 additions & 0 deletions Source/NWheels.Cli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"profiles": {
"NWheels.Cli": {
"commandName": "Project",
"commandLineArgs": "run NWheels.Samples.FirstHappyPath --no-publish",
"workingDirectory": "$(SolutionDir)"
}
}
}
Loading

0 comments on commit d1fdf04

Please sign in to comment.