Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add subfolder reading, writing, deleting and deployment #553

Merged
merged 2 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Meadow.CLI.Commands.DeviceManagement;

internal static class AppTools
{
internal const string MeadowRootFolder = "meadow0";

internal static string ValidateAndSanitizeAppPath(string? path)
{
path ??= Directory.GetCurrentDirectory();
Expand Down Expand Up @@ -94,4 +96,32 @@ internal static async Task<bool> TrimApplication(string path,

return true;
}

internal static string SanitiseMeadowFilename(string fileName)
{
var folder = Path.GetDirectoryName(fileName);
if (string.IsNullOrWhiteSpace(folder))
{
folder = MeadowRootFolder;
}
else
{
if (folder.EndsWith('/') == false)
{
folder += "/";
}
if (folder.StartsWith('/') == false)
{
folder = $"/{folder}";
}
if (folder.Contains(MeadowRootFolder) == false)
{
folder = $"/{MeadowRootFolder}{folder}";
}
}

var meadowFileName = Path.Combine(folder, Path.GetFileName(fileName));

return meadowFileName!.Replace(Path.DirectorySeparatorChar, '/');
}
}
25 changes: 13 additions & 12 deletions Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ public class FileDeleteCommand : BaseDeviceCommand<FileDeleteCommand>
[CommandParameter(0, Name = "MeadowFile", IsRequired = true)]
public string MeadowFile { get; init; } = default!;

private const string MeadowRootFolder = "meadow0";

public FileDeleteCommand(MeadowConnectionManager connectionManager, ILoggerFactory loggerFactory)
: base(connectionManager, loggerFactory)
{ }
Expand All @@ -33,10 +31,10 @@ protected override async ValueTask ExecuteCommand()
var folder = Path.GetDirectoryName(MeadowFile)!.Replace(Path.DirectorySeparatorChar, '/');
if (string.IsNullOrWhiteSpace(folder))
{
folder = MeadowRootFolder;
folder = $"/{AppTools.MeadowRootFolder}/";
}

var fileList = await connection.GetFileList($"/{folder}/", false);
var fileList = await connection.GetFileList($"{folder}", false, CancellationToken);

if (fileList == null || fileList.Length == 0)
{
Expand All @@ -48,7 +46,7 @@ protected override async ValueTask ExecuteCommand()
{
foreach (var file in fileList)
{
await DeleteFileRecursive(device, file, CancellationToken);
await DeleteFileRecursive(device, folder, file, CancellationToken);
}
}
else
Expand All @@ -72,26 +70,29 @@ protected override async ValueTask ExecuteCommand()
}

Logger?.LogInformation($"Deleting file '{MeadowFile}' from device...");
await device.DeleteFile(MeadowFile, CancellationToken);
await device.DeleteFile(AppTools.SanitiseMeadowFilename(MeadowFile), CancellationToken);
}
}
}

private async Task DeleteFileRecursive(IMeadowDevice device, MeadowFileInfo fileInfo, CancellationToken cancellationToken)
private async Task DeleteFileRecursive(IMeadowDevice device, string directoryname, MeadowFileInfo fileInfo, CancellationToken cancellationToken)
{
var meadowFile = AppTools.SanitiseMeadowFilename(Path.Combine(directoryname, fileInfo.Name));
if (fileInfo.IsDirectory)
{
var subfolderFiles = await device.GetFileList(fileInfo.Name, false, cancellationToken);
// Add a backslash as we're a directory and not a file
meadowFile += "/";
var subfolderFiles = await device.GetFileList(meadowFile, false, cancellationToken);

foreach (var subfolderFile in subfolderFiles)
{
await DeleteFileRecursive(device, subfolderFile, cancellationToken);
await DeleteFileRecursive(device, meadowFile, subfolderFile, cancellationToken);
}
return;
}

var fileName = Path.GetFileName(fileInfo.Name);
Logger?.LogInformation($"Deleting file '{fileName}' from device...");
await device.DeleteFile(fileName, cancellationToken);
Logger?.LogInformation($"Deleting file '{meadowFile}' from device...");

await device.DeleteFile(meadowFile, cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protected override async ValueTask ExecuteCommand()

Logger?.LogInformation($"Reading file '{MeadowFile}' from device...\n");

var data = await device.ReadFileString(MeadowFile, CancellationToken);
var data = await device.ReadFileString(AppTools.SanitiseMeadowFilename(MeadowFile), CancellationToken);

if (data == null)
{
Expand Down
16 changes: 2 additions & 14 deletions Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public class FileListCommand : BaseDeviceCommand<FileListCommand>
{
public const int FileSystemBlockSize = 4096;

private const string MeadowRootFolder = "meadow0";
private const string FolderLabel = "[folder]";

[CommandOption("verbose", 'v', IsRequired = false)]
Expand All @@ -27,18 +26,7 @@ protected override async ValueTask ExecuteCommand()

if (Folder != null)
{
if (Folder.EndsWith('/') == false)
{
Folder += "/";
}
if (Folder.StartsWith('/') == false)
{
Folder = $"/{Folder}";
}
if (Folder.Contains(MeadowRootFolder) == false)
{
Folder = $"/{MeadowRootFolder}{Folder}";
}
Folder = AppTools.SanitiseMeadowFilename(Folder);

Logger?.LogInformation($"Getting file list from '{Folder}'...");
}
Expand All @@ -47,7 +35,7 @@ protected override async ValueTask ExecuteCommand()
Logger?.LogInformation($"Getting file list...");
}

var files = await device.GetFileList(Folder ?? $"/{MeadowRootFolder}/", Verbose, CancellationToken);
var files = await device.GetFileList(Folder ?? $"/{AppTools.MeadowRootFolder}/", Verbose, CancellationToken);

if (files == null || files.Length == 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected override async ValueTask ExecuteCommand()
await device.RuntimeDisable();
}

var success = await device.ReadFile(MeadowFile, LocalFile, CancellationToken);
var success = await device.ReadFile(AppTools.SanitiseMeadowFilename(MeadowFile), LocalFile, CancellationToken);

if (success)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected override async ValueTask ExecuteCommand()
}
else
{
var targetFileName = GetTargetFileName(i);
var targetFileName = AppTools.SanitiseMeadowFilename(GetTargetFileName(i));

Logger?.LogInformation(
$"Writing '{Files[i]}' as '{targetFileName}' to device");
Expand Down
27 changes: 25 additions & 2 deletions Source/v2/Meadow.Tooling.Core/App/AppManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static async Task DeployApplication(
dependencies.Add(Path.Combine(localBinaryDirectory, "App.pdb"));
}

var binaries = Directory.EnumerateFiles(localBinaryDirectory, "*.*", SearchOption.TopDirectoryOnly)
var binaries = Directory.EnumerateFiles(localBinaryDirectory, "*.*", SearchOption.AllDirectories)
.Where(s => new FileInfo(s).Extension != ".dll")
.Where(s => new FileInfo(s).Extension != ".pdb")
.Where(s => !s.Contains(".DS_Store")).ToList();
Expand Down Expand Up @@ -126,6 +126,20 @@ public static async Task DeployApplication(
// now send all files with differing CRCs
foreach (var localFile in localFiles)
{
string? meadowFilename = string.Empty;
if (!localFile.Key.Contains(MeadowLinker.PreLinkDirectoryName)
&& !localFile.Key.Contains(MeadowLinker.PostLinkDirectoryName))
{
meadowFilename = GetRelativePath(localBinaryDirectory, localFile.Key);
if (!meadowFilename.StartsWith("/meadow0/"))
{
meadowFilename = "/meadow0/" + meadowFilename;
}
}
else
{
meadowFilename = null;
}
var existing = deviceFiles.FirstOrDefault(f => Path.GetFileName(f.Name) == Path.GetFileName(localFile.Key));

if (existing != null && existing.Crc != null)
Expand All @@ -138,9 +152,10 @@ public static async Task DeployApplication(
}
}

logger?.LogInformation($"Sending '{localFile.Key}'");
send_file:

if (!await connection.WriteFile(localFile.Key, null, cancellationToken))
if (!await connection.WriteFile(localFile.Key, meadowFilename, cancellationToken))
{
logger?.LogWarning($"Error sending'{Path.GetFileName(localFile.Key)}' - retrying");
await Task.Delay(100);
Expand All @@ -151,4 +166,12 @@ public static async Task DeployApplication(
//on macOS, if we don't write a blank line we lose the writing notifcation for the last file
logger?.LogInformation(string.Empty);
}

// Path.GetRelativePath is only available in .NET 8 but we also need to support netstandard2.0, hence using this
static string GetRelativePath(string relativeTo, string path)
{
// Determine the difference
var relativePath = path.Substring(relativeTo.Length + 1);
return relativePath;
}
}
Loading