Skip to content

Commit

Permalink
renaming status context to environment and adding environment variabl…
Browse files Browse the repository at this point in the history
…e functionality

adding commands for setting and displaying environment variables
  • Loading branch information
AC-4 committed May 21, 2024
1 parent 5459ca3 commit dc950ab
Show file tree
Hide file tree
Showing 23 changed files with 584 additions and 114 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,4 @@ MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/
/src.bak
21 changes: 15 additions & 6 deletions src/Xcaciv.Command.FileLoader/Crawler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO.Abstractions;
using Xcaciv.Command.Interface;
using Xcaciv.Command.Interface.Attributes;
using Xcaciv.Command.Interface.Exceptions;
using Xcaciv.Loader;

Expand Down Expand Up @@ -62,13 +64,20 @@ public IDictionary<string, PackageDescription> LoadPackageDescriptions(string ba
{
if (commandType == null) continue; // not sure why it could be null, but the compiler says so
var command = context.CreateInstance<ICommandDelegate>(commandType);
commands[command.BaseCommand] = new CommandDescription()
// required to have BaseCommandAttribute,
if (Attribute.GetCustomAttribute(commandType, typeof(BaseCommandAttribute)) is BaseCommandAttribute attributes)
{
BaseCommand = command.BaseCommand,
FullTypeName = command.GetType().FullName ?? String.Empty,
PackageDescription = packagDesc
};
commands[attributes.Command] = new CommandDescription()
{
BaseCommand = attributes.Command,
FullTypeName = commandType.FullName ?? String.Empty,
PackageDescription = packagDesc
};
}
else
{
Debug.WriteLine($"{commandType.FullName} implements ICommandDelegate but does not have BaseCommandAttribute. Unable to automatically register.");
}
}
packagDesc.Commands = commands;
Expand Down
43 changes: 43 additions & 0 deletions src/Xcaciv.Command.Interface/Attributes/BaseCommandAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Xcaciv.Command.Interface.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class BaseCommandAttribute : Attribute
{
private string _command;
/// <summary>
/// define how this command is to be called
/// </summary>
/// <param name="command"></param>
/// <param name="description"></param>
public BaseCommandAttribute(string command = "", string description = "")
{
this._command = command.ToUpper();
this.Description = description;
}
/// <summary>
/// the base command string
/// </summary>
/// <example>DIR</example>
public string Command {
get
{ return this._command; }
set
{ this._command = value.ToUpper(); }
}
/// <summary>
/// What does this command do
/// </summary>
public string Description { get; set; } = "TODO";
/// <summary>
/// Prototype/example of how to call the command with parameters parameters
/// </summary>
/// <example>CMD [-A | -U] [-Q] [-D] [-E ON | OFF]</example>
public string Prototype { get; set; } = "TODO";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Xcaciv.Command.Interface.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public class CommandHelpRemarksAttribute : Attribute
{
/// <summary>
/// add remarks to help output
/// </summary>
/// <param name="remarks"></param>
public CommandHelpRemarksAttribute(string remarks)
{
this.Remarks = remarks;
}
/// <summary>
/// further explination to be displayed in help
/// </summary>
public string Remarks { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Xcaciv.Command.Interface.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public class CommandParameterAttribute : Attribute
{
private string _valueName = "TODO";

public CommandParameterAttribute(string name, string description = "")
{
this.ValueName = name;
}

public CommandParameterAttribute(string flagname, string name, string description = "")
{
this.FlagName = flagname;
this.ValueName = name;
}

public CommandParameterAttribute(string abbrFlag, string flagname, string name, string description = "")
{
this.AbbrFlagName = abbrFlag;
this.FlagName = flagname;
this.ValueName = name;
}

public string AbbrFlagName { get; } = "";
public string FlagName { get; set; } = "";

public string ValueName
{
get { return _valueName; }
set { _valueName = String.Format(@"<{0}>", value.Trim('>').Trim(']')); }
}

public string ValueDescription { get; set; } = "";

public override string ToString()
{
return $"{AbbrFlagName} {FlagName} \t {_valueName} \t {ValueDescription}".Trim();
}
}
}
4 changes: 4 additions & 0 deletions src/Xcaciv.Command.Interface/CommandDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ public class CommandDescription
/// full path to containing assembly
/// </summary>
public PackageDescription PackageDescription { get; set; } = new PackageDescription();
/// <summary>
/// explicitly indicates if a command modifes the environment
/// </summary>
public bool ModifiesEnvironment { get; set; }
}
10 changes: 1 addition & 9 deletions src/Xcaciv.Command.Interface/ICommandDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,13 @@ namespace Xcaciv.Command.Interface
/// </summary>
public interface ICommandDelegate : IAsyncDisposable
{
/// <summary>
/// unique typed command - alphanumeric with dash or underscore
/// </summary>
string BaseCommand { get; }
/// <summary>
/// Display name - may contain special characters
/// </summary>
string FriendlyName { get; }
/// <summary>
/// primary command execution method
/// </summary>
/// <param name="parameters"></param>
/// <param name="messageContext">used for progress and status messages</param>
/// <returns></returns>
IAsyncEnumerable<string> Main(IInputContext input, IStatusContext statusContext);
IAsyncEnumerable<string> Main(IInputContext input, IEnvironment statusContext);
/// <summary>
/// output usage instructions via message context
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Xcaciv.Command.Interface
{
public interface IStatusContext
public interface IEnvironment
{
/// <summary>
/// replace status text with new text
Expand Down Expand Up @@ -37,5 +37,33 @@ public interface IStatusContext
/// <param name="message"></param>
/// <returns></returns>
Task Complete(string? message);
/// <summary>
/// add a value to the environment, across commands
/// the storage mechanism should be apropriate to the running environment
/// probably a ConcurrentDictionary<TKey,TValue>
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
void SetValue(string key, string value);
/// <summary>
/// retrieve global environment value
/// </summary>
/// <param name="key"></param>
/// <returns>String.Empty if not found</returns>
string GetValue(string key);
/// <summary>
/// captures the environment values and returns them
/// </summary>
/// <returns></returns>
Dictionary<string, string> GetEnvinronment();
/// <summary>
/// indicates that the environment variables has changed
/// </summary>
bool ValuesChanged { get; }
/// <summary>
/// sync values in envronment
/// </summary>
/// <param name="dictionary"></param>
void UpdateEnvironment(Dictionary<string, string> dictionary);
}
}
5 changes: 3 additions & 2 deletions src/Xcaciv.Command.Interface/ITextIoContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Xcaciv.Command.Interface;
/// to a particular bound output, but should prioritise the pipeline when channels
/// are available.
/// </summary>
public interface ITextIoContext : IStatusContext, IInputContext, IOutputContext, IAsyncDisposable
public interface ITextIoContext : IEnvironment, IInputContext, IOutputContext, IAsyncDisposable
{
/// <summary>
/// current message context identifier
Expand All @@ -31,10 +31,11 @@ public interface ITextIoContext : IStatusContext, IInputContext, IOutputContext,
Guid? Parent { get; }
/// <summary>
/// create a child output context
/// MUST pass down expected Environment values
/// may track the instance for later use
/// </summary>
/// <param name="childArguments">arguments to pass to child context</param>
/// <param name="pipeline">specify we are dealing with a pipeline</param>
/// <returns></returns>
Task<ITextIoContext> GetChild(string[]? childArguments = null);
Task<ITextIoContext> GetChild(string[]? childArguments = null);
}
4 changes: 2 additions & 2 deletions src/Xcaciv.Command.Interface/Xcaciv.Command.Interface.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.4</Version>
<Version>1.1.11</Version>
<IsPublishable>True</IsPublishable>
<AssemblyName>Xcaciv.Command.Interface</AssemblyName>
<RootNamespace>Xcaciv.Command.Interface</RootNamespace>
Expand Down
62 changes: 62 additions & 0 deletions src/Xcaciv.Command.Tests/Commands/SayCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Text;
using System.Threading.Tasks;
using Xcaciv.Command.FileLoader;
using Xcaciv.Command.Commands;
using Xcaciv.Command.Interface.Attributes;

namespace Xcaciv.Command.Tests.Commands
{
Expand All @@ -25,5 +27,65 @@ public async Task HandleExecutionTest()
// by looking at the output of the second output line
Assert.Equal("what is up", textio.Children.First().Output.First());
}

[Fact()]
public void ProcessEnvValuesTest()
{
var textio = new TestImpementations.TestTextIo();
textio.SetValue("direction", "up");

var actual = SayCommand.ProcessEnvValues("what is %direction%!", textio);

Assert.Equal("what is up!", actual);
}

[Fact()]
public async Task HandleExecutionWithEnvTest()
{
var commands = new CommandController(new Crawler(), "");
commands.EnableDefaultCommands();

var textio = new TestImpementations.TestTextIo();
textio.SetValue("direction", "up");
// simulate user input
await commands.Run(@"say ""what is %direction%!""", textio);

// verify the output of the first run
// by looking at the output of the second output line
Assert.Equal("what is up!", textio.Children.First().Output.First());
}

[Fact()]
public void BaseAttributeTest()
{

//var actual = SayCommand.ProcessEnvValues("what is %direction%!", textio);

var attributes = Attribute.GetCustomAttribute(typeof(SayCommand), typeof(BaseCommandAttribute)) as BaseCommandAttribute;

Assert.NotNull(attributes);
Assert.Equal("Like echo but more valley.", attributes.Description);
}

[Fact()]
public void ParameterAttributeTest()
{

var attributes = Attribute.GetCustomAttribute(typeof(SayCommand), typeof(CommandParameterAttribute)) as CommandParameterAttribute;

Assert.NotNull(attributes);
Assert.Equal("<thing to output>", attributes.ValueName);
}

[Fact()]
public void MultipleParameterAttributeTest()
{

var attributes = Attribute.GetCustomAttributes(typeof(SayCommand), typeof(CommandHelpRemarksAttribute)) as CommandHelpRemarksAttribute[];

Assert.NotNull(attributes);
Assert.NotEmpty(attributes);
Assert.Equal(2, attributes.Length);
}
}
}
Loading

0 comments on commit dc950ab

Please sign in to comment.