Skip to content

Commit

Permalink
finished up cloud commands
Browse files Browse the repository at this point in the history
  • Loading branch information
ctacke committed Oct 3, 2023
1 parent 9324cbf commit 8e391ef
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 53 deletions.
41 changes: 41 additions & 0 deletions Source/v2/Meadow.Cli/Commands/Current/BaseCloudCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Meadow.CLI.Commands.DeviceManagement;

public abstract class BaseCloudCommand<T> : BaseCommand<T>
{
public const string DefaultHost = "https://www.meadowcloud.co";

protected IdentityManager IdentityManager { get; }
protected UserService UserService { get; }
protected DeviceService DeviceService { get; }
Expand All @@ -24,4 +26,43 @@ public BaseCloudCommand(
DeviceService = deviceService;
CollectionService = collectionService;
}

protected async Task<UserOrg?> ValidateOrg(string host, string? orgNameOrId = null, CancellationToken? cancellationToken = null)
{
UserOrg? org = null;

try
{
Logger?.LogInformation("Retrieving your user and organization information...");

var userOrgs = await UserService.GetUserOrgs(host, cancellationToken).ConfigureAwait(false);
if (!userOrgs.Any())
{
Logger?.LogInformation($"Please visit {host} to register your account.");
}
else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(orgNameOrId))
{
Logger?.LogInformation($"You are a member of more than 1 organization. Please specify the desired orgId for this device provisioning.");
}
else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(orgNameOrId))
{
orgNameOrId = userOrgs.First().Id;
}
else
{
org = userOrgs.FirstOrDefault(o => o.Id == orgNameOrId || o.Name == orgNameOrId);
if (org == null)
{
Logger?.LogInformation($"Unable to find an organization with a Name or ID matching '{orgNameOrId}'");
}
}
}
catch (MeadowCloudAuthException)
{
Logger?.LogError($"You must be signed in to execute this command.");
Logger?.LogError($"Please run \"meadow cloud login\" to sign in to Meadow.Cloud.");
}

return org;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ namespace Meadow.CLI.Commands.DeviceManagement;
[Command("cloud collection list", Description = "List Meadow Collections")]
public class CloudCollectionListCommand : BaseCloudCommand<CloudCollectionListCommand>
{
public const string DefaultHost = "https://www.meadowcloud.co";

[CommandOption("host", 'h', Description = $"Optionally set a host (default is {DefaultHost})", IsRequired = false)]
public string? Host { get; set; }
[CommandOption("orgId", 'o', Description = "Organization Id", IsRequired = false)]
Expand All @@ -27,43 +25,10 @@ public CloudCollectionListCommand(

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
{
UserOrg? org;

try
{
if (Host == null) Host = DefaultHost;

Logger?.LogInformation("Retrieving your user and organization information...");

var userOrgs = await UserService.GetUserOrgs(Host, cancellationToken).ConfigureAwait(false);
if (!userOrgs.Any())
{
Logger?.LogInformation($"Please visit {Host} to register your account.");
return;
}
else if (userOrgs.Count() > 1 && string.IsNullOrEmpty(OrgId))
{
Logger?.LogInformation($"You are a member of more than 1 organization. Please specify the desired orgId for this device provisioning.");
return;
}
else if (userOrgs.Count() == 1 && string.IsNullOrEmpty(OrgId))
{
OrgId = userOrgs.First().Id;
}
if (Host == null) Host = DefaultHost;
var org = await ValidateOrg(Host, OrgId, cancellationToken);

org = userOrgs.FirstOrDefault(o => o.Id == OrgId || o.Name == OrgId);
if (org == null)
{
Logger?.LogInformation($"Unable to find an organization with a Name or ID matching '{OrgId}'");
return;
}
}
catch (MeadowCloudAuthException)
{
Logger?.LogError($"You must be signed in to execute this command.");
Logger?.LogError($"Please run \"meadow cloud login\" to sign in to Meadow.Cloud.");
return;
}
if (org == null) return;

var collections = await CollectionService.GetOrgCollections(org.Id, Host, cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Meadow.Cli;
using Meadow.Cloud;
using Meadow.Cloud.Identity;
using Meadow.Software;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;
Expand All @@ -23,17 +24,20 @@ public class CloudPackageCreateCommand : BaseCloudCommand<CloudPackageCreateComm
public string Filter { get; init; } = "*";

private IPackageManager _packageManager;
private FileManager _fileManager;

public CloudPackageCreateCommand(
IdentityManager identityManager,
UserService userService,
DeviceService deviceService,
CollectionService collectionService,
IPackageManager packageManager,
FileManager fileManager,
ILoggerFactory? loggerFactory)
: base(identityManager, userService, deviceService, collectionService, loggerFactory)
{
_packageManager = packageManager;
_fileManager = fileManager;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
Expand All @@ -50,24 +54,28 @@ protected override async ValueTask ExecuteCommand(CancellationToken? cancellatio
return;
}

var candidates = PackageManager.GetAvailableBuiltConfigurations(ProjectPath, "App.dll");
var candidates = Cli.PackageManager.GetAvailableBuiltConfigurations(ProjectPath, "App.dll");

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

var store = _fileManager.Firmware["Meadow F7"];
await store.Refresh();
var osVersion = store?.DefaultPackage?.Version ?? "unknown";

var file = candidates.OrderByDescending(c => c.LastWriteTime).First(); // trim
Logger?.LogInformation($"Trimming application...");
await _packageManager.TrimApplication(file, cancellationToken: cancellationToken);

// package
var packageDir = Path.Combine(file.Directory?.FullName ?? string.Empty, PackageManager.PackageOutputDirectoryName);
var postlinkDir = Path.Combine(file.Directory?.FullName ?? string.Empty, PackageManager.PostLinkDirectoryName);
var packageDir = Path.Combine(file.Directory?.FullName ?? string.Empty, Cli.PackageManager.PackageOutputDirectoryName);
var postlinkDir = Path.Combine(file.Directory?.FullName ?? string.Empty, Cli.PackageManager.PostLinkDirectoryName);

Logger?.LogInformation($"Assembling the MPAK...");
var packagePath = await _packageManager.AssemblePackage(postlinkDir, packageDir, Filter, true, cancellationToken);
var packagePath = await _packageManager.AssemblePackage(postlinkDir, packageDir, osVersion, Filter, true, cancellationToken);

if (packagePath != null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using CliFx.Attributes;
using Meadow.Cloud;
using Meadow.Cloud.Identity;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;

[Command("cloud package list", Description = "Lists all Meadow Packages (MPAK)")]
public class CloudPackageListCommand : BaseCloudCommand<CloudPackageListCommand>
{
private PackageService _packageService;

[CommandOption("orgId", 'o', Description = "Optional organization ID", IsRequired = false)]
public string? OrgId { get; set; }

[CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)]
public string Host { get; set; }

public CloudPackageListCommand(
IdentityManager identityManager,
UserService userService,
DeviceService deviceService,
CollectionService collectionService,
PackageService packageService,
ILoggerFactory? loggerFactory)
: base(identityManager, userService, deviceService, collectionService, loggerFactory)
{
_packageService = packageService;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
{
if (Host == null) Host = DefaultHost;
var org = await ValidateOrg(Host, OrgId, cancellationToken);

if (org == null) return;

var packages = await _packageService.GetOrgPackages(org.Id, Host, cancellationToken);

if (packages == null || packages.Count == 0)
{
Logger?.LogInformation("No packages found.");
}
else
{
Logger?.LogInformation("packages:");
foreach (var package in packages)
{
Logger?.LogInformation($" {package.Id} | {package.Name}");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using CliFx.Attributes;
using Meadow.Cloud;
using Meadow.Cloud.Identity;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;

[Command("cloud package publish", Description = "Publishes a Meadow Package (MPAK)")]
public class CloudPackagePublishCommand : BaseCloudCommand<CloudPackagePublishCommand>
{
private PackageService _packageService;

[CommandParameter(0, Name = "PackageID", Description = "ID of the package to publish", IsRequired = true)]
public string PackageId { get; init; }

[CommandOption("collectionId", 'c', Description = "The target collection for publishing", IsRequired = true)]
public string CollectionId { get; set; }

[CommandOption("metadata", 'm', Description = "Pass through metadata", IsRequired = false)]
public string Metadata { get; set; }

[CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)]
public string Host { get; set; }

public CloudPackagePublishCommand(
IdentityManager identityManager,
UserService userService,
DeviceService deviceService,
CollectionService collectionService,
PackageService packageService,
ILoggerFactory? loggerFactory)
: base(identityManager, userService, deviceService, collectionService, loggerFactory)
{
_packageService = packageService;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
{
if (Host == null) Host = DefaultHost;

try
{
Logger?.LogInformation($"Publishing package {PackageId} to collection {CollectionId}...");

await _packageService.PublishPackage(PackageId, CollectionId, Metadata, Host, cancellationToken);
Logger?.LogInformation("Publish successful.");
}
catch (MeadowCloudException mex)
{
Logger?.LogError($"Publish failed: {mex.Message}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using CliFx.Attributes;
using Meadow.Cloud;
using Meadow.Cloud.Identity;
using Microsoft.Extensions.Logging;

namespace Meadow.CLI.Commands.DeviceManagement;

[Command("cloud package upload", Description = "Upload a Meadow Package (MPAK) to Meadow.Cloud")]
public class CloudPackageUploadCommand : BaseCloudCommand<CloudPackageUploadCommand>
{
[CommandParameter(0, Name = "MpakPath", Description = "The full path of the mpak file", IsRequired = true)]
public string MpakPath { get; init; }

[CommandOption("orgId", 'o', Description = "OrgId to upload to", IsRequired = false)]
public string? OrgId { get; set; }

[CommandOption("description", 'd', Description = "Description of the package", IsRequired = false)]
public string? Description { get; set; }

[CommandOption("host", Description = "Optionally set a host (default is https://www.meadowcloud.co)", IsRequired = false)]
public string? Host { get; set; }

private PackageService _packageService;

public CloudPackageUploadCommand(
IdentityManager identityManager,
UserService userService,
DeviceService deviceService,
CollectionService collectionService,
PackageService packageService,
ILoggerFactory? loggerFactory)
: base(identityManager, userService, deviceService, collectionService, loggerFactory)
{
_packageService = packageService;
}

protected override async ValueTask ExecuteCommand(CancellationToken? cancellationToken)
{
if (!File.Exists(MpakPath))
{
Logger?.LogError($"Package {MpakPath} does not exist");
return;
}

if (Host == null) Host = DefaultHost;
var org = await ValidateOrg(Host, OrgId, cancellationToken);

if (org == null) return;

try
{
Logger?.LogInformation($"Uploading package {Path.GetFileName(MpakPath)}...");

var package = await _packageService.UploadPackage(MpakPath, org.Id, Description, Host, cancellationToken);
Logger?.LogInformation($"Upload complete. Package Id: {package.Id}");
}
catch (MeadowCloudException mex)
{
Logger?.LogError($"Upload failed: {mex.Message}");
}

}
}
6 changes: 3 additions & 3 deletions Source/v2/Meadow.Cli/Commands/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
| debug | TODO |
| device provision | device provision | - |
| package create | cloud package create | n |
| package list | TODO |
| package publish | TODO |
| package upload | TODO |
| package list | cloud package list |
| package publish | cloud package publish |
| package upload | cloud package upload |
| collection list | cloud collection list | - |
| cloud login | cloud login | - |
| cloud logout | cloud logout | - |
Expand Down
1 change: 1 addition & 0 deletions Source/v2/Meadow.Cli/IPackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Task TrimApplication(
Task<string> AssemblePackage(
string contentSourceFolder,
string outputFolder,
string osVersion,
string filter = "*",
bool overwrite = false,
CancellationToken? cancellationToken = null);
Expand Down
3 changes: 3 additions & 0 deletions Source/v2/Meadow.Cli/PackageManager.AssemblyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ private string? MeadowAssembliesPath
if (store.DefaultPackage != null)
{
var defaultPackage = store.DefaultPackage;

if (defaultPackage.BclFolder != null)
{
_meadowAssembliesPath = defaultPackage.GetFullyQualifiedPath(defaultPackage.BclFolder);
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions Source/v2/Meadow.Cli/PackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ await TrimDependencies(
public Task<string> AssemblePackage(
string contentSourceFolder,
string outputFolder,
string osVersion,
string filter = "*",
bool overwrite = false,
CancellationToken? cancellationToken = null)
Expand Down Expand Up @@ -204,8 +205,8 @@ public Task<string> AssemblePackage(
// TODO: we need to see what is necessary and meaningful here and pass it in via param (or the entire file via param?)
PackageInfo info = new PackageInfo()
{
Version = "1",
OsVersion = "1"
Version = "1.0",
OsVersion = osVersion
};

var infoJson = JsonSerializer.Serialize(info);
Expand Down
Loading

0 comments on commit 8e391ef

Please sign in to comment.