Skip to content

Commit

Permalink
Merge branch 'develop' into v2
Browse files Browse the repository at this point in the history
# Conflicts:
#	Source/v2/Meadow.Cli/Commands/Current/BaseCommand.cs
#	Source/v2/Meadow.Cli/Commands/Current/BaseDeviceCommand.cs
#	Source/v2/Meadow.Hcom/Connections/ConnectionBase.cs
#	Source/v2/Meadow.Hcom/Connections/SerialConnection.cs
#	Source/v2/Meadow.Hcom/Connections/TcpConnection.cs
#	Source/v2/Meadow.Hcom/IMeadowConnection.cs
#	Source/v2/Meadow.Hcom/IMeadowDevice.cs
#	Source/v2/Meadow.Hcom/MeadowDevice.cs
  • Loading branch information
ctacke committed Oct 4, 2023
2 parents eaa5d77 + d2bd257 commit 2ebf890
Show file tree
Hide file tree
Showing 58 changed files with 901 additions and 443 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public AppBuildCommand(IPackageManager packageManager, ILoggerFactory loggerFact
_packageManager = packageManager;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
protected override async ValueTask ExecuteCommand()
{
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
Expand Down
39 changes: 39 additions & 0 deletions Source/v2/Meadow.Cli/Commands/Current/App/AppDebugCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using CliFx.Attributes;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;

[Command("app debug", Description = "Debugs a running application")]
public class AppDebugCommand : BaseDeviceCommand<AppDebugCommand>
{
// VS 2019 - 4024
// VS 2017 - 4022
// VS 2015 - 4020
[CommandOption("Port", 'p', Description = "The port to run the debug server on")]
public int Port { get; init; } = 4024;

public AppDebugCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory)
: base(connectionManager, loggerFactory)
{
}

protected override async ValueTask ExecuteCommand()
{
if (CurrentConnection != null)
{
CurrentConnection.DeviceMessageReceived += (s, e) =>
{
Logger?.LogInformation(e.message);
};

using (var server = await CurrentConnection.StartDebuggingSession(Port, Logger, CancellationToken))
{
if (Console != null)
{
Logger?.LogInformation("Debugging server started. Press Enter to exit");
await Console.Input.ReadLineAsync();
}
}
}
}
}
113 changes: 58 additions & 55 deletions Source/v2/Meadow.Cli/Commands/Current/App/AppDeployCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,81 +20,84 @@ public AppDeployCommand(IPackageManager packageManager, MeadowConnectionManager
_packageManager = packageManager;
}

protected override async ValueTask ExecuteCommand(IMeadowConnection connection, Hcom.IMeadowDevice device, CancellationToken cancellationToken)
protected override async ValueTask ExecuteCommand()
{
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
: Path;

// is the path a file?
FileInfo file;

var lastFile = string.Empty;

// in order to deploy, the runtime must be disabled
var wasRuntimeEnabled = await connection.IsRuntimeEnabled();
if (wasRuntimeEnabled)
if (CurrentConnection != null)
{
Logger.LogInformation("Disabling runtime...");
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
: Path;

await connection.RuntimeDisable(cancellationToken);
}
// is the path a file?
FileInfo file;

connection.FileWriteProgress += (s, e) =>
{
var p = (e.completed / (double)e.total) * 100d;
var lastFile = string.Empty;

if (e.fileName != lastFile)
// in order to deploy, the runtime must be disabled
var wasRuntimeEnabled = await CurrentConnection.IsRuntimeEnabled();
if (wasRuntimeEnabled)
{
Console.Write("\n");
lastFile = e.fileName;
}

// Console instead of Logger due to line breaking for progress bar
Console.Write($"Writing {e.fileName}: {p:0}% \r");
};
Logger?.LogInformation("Disabling runtime...");

if (!File.Exists(path))
{
// is it a valid directory?
if (!Directory.Exists(path))
{
Logger.LogError($"Invalid application path '{path}'");
return;
await CurrentConnection.RuntimeDisable(CancellationToken);
}

// does the directory have an App.dll in it?
file = new FileInfo(System.IO.Path.Combine(path, "App.dll"));
if (!file.Exists)
CurrentConnection.FileWriteProgress += (s, e) =>
{
// it's a directory - we need to determine the latest build (they might have a Debug and a Release config)
var candidates = Cli.PackageManager.GetAvailableBuiltConfigurations(path, "App.dll");
var p = (e.completed / (double)e.total) * 100d;

if (e.fileName != lastFile)
{
Console?.Output.WriteAsync("\n");
lastFile = e.fileName;
}

// Console instead of Logger due to line breaking for progress bar
Console?.Output.WriteAsync($"Writing {e.fileName}: {p:0}% \r");
};

if (candidates.Length == 0)
if (!File.Exists(path))
{
// is it a valid directory?
if (!Directory.Exists(path))
{
Logger.LogError($"Cannot find a compiled application at '{path}'");
Logger?.LogError($"Invalid application path '{path}'");
return;
}

file = candidates.OrderByDescending(c => c.LastWriteTime).First();
// does the directory have an App.dll in it?
file = new FileInfo(System.IO.Path.Combine(path, "App.dll"));
if (!file.Exists)
{
// it's a directory - we need to determine the latest build (they might have a Debug and a Release config)
var candidates = Cli.PackageManager.GetAvailableBuiltConfigurations(path, "App.dll");

if (candidates.Length == 0)
{
Logger?.LogError($"Cannot find a compiled application at '{path}'");
return;
}

file = candidates.OrderByDescending(c => c.LastWriteTime).First();
}
}
else
{
// TODO: only deploy if it's App.dll
file = new FileInfo(path);
}
}
else
{
// TODO: only deploy if it's App.dll
file = new FileInfo(path);
}

var targetDirectory = file.DirectoryName;
var targetDirectory = file.DirectoryName;

await AppManager.DeployApplication(_packageManager, connection, targetDirectory, true, false, Logger, cancellationToken);
await AppManager.DeployApplication(_packageManager, CurrentConnection, targetDirectory, true, false, Logger, CancellationToken);

if (wasRuntimeEnabled)
{
// restore runtime state
Logger.LogInformation("Enabling runtime...");
if (wasRuntimeEnabled)
{
// restore runtime state
Logger.LogInformation("Enabling runtime...");

await connection.RuntimeEnable(cancellationToken);
await CurrentConnection.RuntimeEnable(CancellationToken);
}
}
}
}
113 changes: 58 additions & 55 deletions Source/v2/Meadow.Cli/Commands/Current/App/AppRunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,66 +26,69 @@ public AppRunCommand(IPackageManager packageManager, MeadowConnectionManager con
_packageManager = packageManager;
}

protected override async ValueTask ExecuteCommand(IMeadowConnection connection, Hcom.IMeadowDevice device, CancellationToken cancellationToken)
protected override async ValueTask ExecuteCommand()
{
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
: Path;

if (!Directory.Exists(path))
{
Logger.LogError($"Target directory '{path}' not found.");
return;
}

var lastFile = string.Empty;

// in order to deploy, the runtime must be disabled
var wasRuntimeEnabled = await connection.IsRuntimeEnabled();
if (wasRuntimeEnabled)
if (CurrentConnection != null)
{
Logger.LogInformation("Disabling runtime...");

await connection.RuntimeDisable(cancellationToken);
}

if (!await BuildApplication(path, cancellationToken))
{
return;
}
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
: Path;

if (!Directory.Exists(path))
{
Logger?.LogError($"Target directory '{path}' not found.");
return;
}

var lastFile = string.Empty;

// in order to deploy, the runtime must be disabled
var wasRuntimeEnabled = await CurrentConnection.IsRuntimeEnabled();
if (wasRuntimeEnabled)
{
Logger?.LogInformation("Disabling runtime...");

await CurrentConnection.RuntimeDisable(CancellationToken);
}

if (!await BuildApplication(path, CancellationToken))
{
return;
}

if (!await TrimApplication(path, CancellationToken))
{
return;
}

// illink returns before all files are actually written. That's not fun, but we must just wait a little while.
await Task.Delay(1000);

if (!await TrimApplication(path, cancellationToken))
{
return;
}
if (!await DeployApplication(CurrentConnection, path, CancellationToken))
{
return;
}

// illink returns before all files are actually written. That's not fun, but we must just wait a little while.
await Task.Delay(1000);
Logger?.LogInformation("Enabling the runtime...");
await CurrentConnection.RuntimeEnable(CancellationToken);

if (!await DeployApplication(connection, path, cancellationToken))
{
return;
}
Logger?.LogInformation("Listening for messages from Meadow...\n");
CurrentConnection.DeviceMessageReceived += OnDeviceMessageReceived;

Logger.LogInformation("Enabling the runtime...");
await connection.RuntimeEnable(cancellationToken);
while (!CancellationToken.IsCancellationRequested)
{
await Task.Delay(1000);
}

Logger.LogInformation("Listening for messages from Meadow...\n");
connection.DeviceMessageReceived += OnDeviceMessageReceived;

while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(1000);
Logger?.LogInformation("Listen cancelled...");
}

Logger.LogInformation("Listen cancelled...");
}

private Task<bool> BuildApplication(string path, CancellationToken cancellationToken)
{
if (Configuration == null) Configuration = "Debug";

Logger.LogInformation($"Building {Configuration} configuration of {path}...");
Logger?.LogInformation($"Building {Configuration} configuration of {path}...");

// TODO: enable cancellation of this call
return Task.FromResult(_packageManager.BuildApplication(path, Configuration));
Expand All @@ -98,14 +101,14 @@ private async Task<bool> TrimApplication(string path, CancellationToken cancella

if (candidates.Length == 0)
{
Logger.LogError($"Cannot find a compiled application at '{path}'");
Logger?.LogError($"Cannot find a compiled application at '{path}'");
return false;
}

var file = candidates.OrderByDescending(c => c.LastWriteTime).First();

// if no configuration was provided, find the most recently built
Logger.LogInformation($"Trimming {file.FullName} (this may take a few seconds)...");
Logger?.LogInformation($"Trimming {file.FullName} (this may take a few seconds)...");

await _packageManager.TrimApplication(file, false, null, cancellationToken);

Expand All @@ -120,15 +123,15 @@ private async Task<bool> DeployApplication(IMeadowConnection connection, string

if (candidates.Length == 0)
{
Logger.LogError($"Cannot find a compiled application at '{path}'");
Logger?.LogError($"Cannot find a compiled application at '{path}'");
return false;
}

var file = candidates.OrderByDescending(c => c.LastWriteTime).First();

Logger.LogInformation($"Deploying app from {file.DirectoryName}...");
Logger?.LogInformation($"Deploying app from {file.DirectoryName}...");

await AppManager.DeployApplication(_packageManager, connection, file.DirectoryName, true, false, Logger, cancellationToken);
await AppManager.DeployApplication(_packageManager, connection, file.DirectoryName, true, false, Logger, CancellationToken);

connection.FileWriteProgress -= OnFileWriteProgress;

Expand All @@ -141,23 +144,23 @@ private void OnFileWriteProgress(object? sender, (string fileName, long complete

if (e.fileName != _lastFile)
{
Console.Write("\n");
Console?.Output.Write("\n");
_lastFile = e.fileName;
}

// Console instead of Logger due to line breaking for progress bar
Console.Write($"Writing {e.fileName}: {p:0}% \r");
Console?.Output.Write($"Writing {e.fileName}: {p:0}% \r");
}

private void OnDeviceMessageReceived(object? sender, (string message, string? source) e)
{
if (NoPrefix)
{
Logger.LogInformation($"{e.message.TrimEnd('\n', '\r')}");
Logger?.LogInformation($"{e.message.TrimEnd('\n', '\r')}");
}
else
{
Logger.LogInformation($"{e.source}> {e.message.TrimEnd('\n', '\r')}");
Logger?.LogInformation($"{e.source}> {e.message.TrimEnd('\n', '\r')}");
}
}
}
4 changes: 2 additions & 2 deletions Source/v2/Meadow.Cli/Commands/Current/App/AppTrimCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public AppTrimCommand(IPackageManager packageManager, ILoggerFactory loggerFacto
_packageManager = packageManager;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
protected override async ValueTask ExecuteCommand()
{
string path = Path == null
? AppDomain.CurrentDomain.BaseDirectory
Expand Down Expand Up @@ -59,6 +59,6 @@ protected override async ValueTask ExecuteCommand(CancellationToken? cancellatio
// if no configuration was provided, find the most recently built
Logger?.LogInformation($"Trimming {file.FullName} (this may take a few seconds)...");

await _packageManager.TrimApplication(file, false, null, cancellationToken ?? default);
await _packageManager.TrimApplication(file, false, null, CancellationToken);
}
}
Loading

0 comments on commit 2ebf890

Please sign in to comment.