Minor refactoring, add enumeration of storage container by folder, by container, or by entire account

This commit is contained in:
Yaakov 2021-09-26 00:33:10 +10:00
parent a4f9f13780
commit 4743b1a74c
4 changed files with 123 additions and 43 deletions

View file

@ -0,0 +1,40 @@
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using CommandLine;
using CommandLine.Text;
using Microsoft.Extensions.DependencyInjection;
namespace Shamir.Console
{
public abstract class ParsedArgumentsCommand<TOptions> : ICommand
{
public abstract string Name { get; }
public abstract string Description { get; }
public ImmutableArray<string> Arguments { get; private set; }
public void Initialize(ReadOnlySpan<string> args)
{
Arguments = args.ToImmutableArray();
}
public async ValueTask<int> ExecuteAsync(IServiceProvider serviceProvider)
{
using var parser = serviceProvider.GetRequiredService<Parser>();
var result = parser.ParseArguments<TOptions>(Arguments);
return await result.MapResult(
options => ExecuteAsync(serviceProvider, options),
errors =>
{
var helpText = HelpText.AutoBuild(result);
helpText.Heading = string.Empty;
helpText.Copyright = string.Empty;
System.Console.Error.WriteLine(helpText);
return ValueTask.FromResult(1);
}
);
}
public abstract ValueTask<int> ExecuteAsync(IServiceProvider serviceProvider, TOptions options);
}
}

View file

@ -1,48 +1,20 @@
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using CommandLine;
using Microsoft.Extensions.DependencyInjection;
namespace Shamir.Console
{
public abstract class ParsedArgumentsCommand<TOptions> : ICommand
{
public abstract string Name { get; }
public abstract string Description { get; }
public ImmutableArray<string> Arguments { get; private set; }
public void Initialize(ReadOnlySpan<string> args)
{
var array = ImmutableArray.CreateBuilder<string>(args.Length);
foreach (var arg in args)
{
array.Add(arg);
}
Arguments = array.MoveToImmutable();
}
public async ValueTask<int> ExecuteAsync(IServiceProvider serviceProvider)
{
using var parser = serviceProvider.GetRequiredService<Parser>();
var result = parser.ParseArguments<TOptions>(Arguments);
return await result.MapResult(
options => ExecuteAsync(serviceProvider, options),
errors => ValueTask.FromResult(1)
);
}
public abstract ValueTask<int> ExecuteAsync(IServiceProvider serviceProvider, TOptions options);
}
public class StorageLsOptions
{
[Option("connection-string", Required = false)]
[Option("connection-string", Required = false, HelpText = "Azure Storage connection string for the Storage Account backing the CDN.")]
public string? ConnectionString { get; set; }
[Value(0)]
public string? ContainerName { get; set; }
[Option('a', "all", HelpText = "List all blobs in the container")]
public bool EnumerateAll { get; set; }
[Value(0, MetaName = "Path", HelpText = "Path to enumerate, starting with the Azure Storage container name.")]
public string? Path { get; set; }
}
public sealed class StorageLsCommand : ParsedArgumentsCommand<StorageLsOptions>
@ -55,7 +27,24 @@ namespace Shamir.Console
{
var connectionString = options.ConnectionString ?? Environment.GetEnvironmentVariable("AZURE_CONNECTION_STRING");
if (options.ContainerName is null)
if (options.Path is null)
{
if (options.EnumerateAll)
{
var client = new BlobServiceClient(connectionString);
await foreach (var container in client.GetBlobContainersAsync())
{
var containerClient = new BlobContainerClient(connectionString, container.Name);
await foreach (var blob in containerClient.GetBlobsAsync())
{
System.Console.Write(container.Name);
System.Console.Write('/');
System.Console.WriteLine(blob.Name);
}
}
}
else
{
var client = new BlobServiceClient(connectionString);
await foreach (var container in client.GetBlobContainersAsync())
@ -63,17 +52,45 @@ namespace Shamir.Console
System.Console.WriteLine(container.Name);
}
}
else
}
else if (options.EnumerateAll)
{
var client = new BlobContainerClient(connectionString, options.ContainerName);
var containerName = options.Path;
var client = new BlobContainerClient(connectionString, containerName);
await foreach (var blob in client.GetBlobsAsync())
{
System.Console.Write(options.ContainerName);
System.Console.Write(containerName);
System.Console.Write('/');
System.Console.WriteLine(blob.Name);
}
}
else
{
var delimiterIndex = options.Path.IndexOf('/');
var containerName = delimiterIndex > 0 ? options.Path[..delimiterIndex] : options.Path;
var client = new BlobContainerClient(connectionString, containerName);
var prefix = delimiterIndex > 0 ? options.Path[(delimiterIndex + 1)..] : string.Empty;
await foreach (var blob in client.GetBlobsByHierarchyAsync(default, default, delimiter: "/", prefix))
{
System.Console.Write(containerName);
System.Console.Write('/');
if (blob.IsPrefix)
{
System.Console.WriteLine(blob.Prefix);
}
else if (blob.IsBlob)
{
System.Console.WriteLine(blob.Blob.Name);
}
else
{
throw new NotImplementedException("Unknown result - neither a blob nor a prefix (folder).");
}
}
}
return 0;
}

View file

@ -0,0 +1,17 @@
namespace System.Collections.Immutable
{
public static class ImmutableArrayExtensions
{
public static ImmutableArray<T> ToImmutableArray<T>(this ReadOnlySpan<T> span)
{
var array = ImmutableArray.CreateBuilder<T>(span.Length);
foreach (var value in span)
{
array.Add(value);
}
return array.MoveToImmutable();
}
}
}

View file

@ -10,7 +10,13 @@ namespace Shamir.Console
public static async Task<int> Main(string[] args)
{
await using var serviceProvider = new ServiceCollection()
.AddTransient<Parser>(sp => new Parser(with => with.EnableDashDash = true))
.AddTransient<Parser>(sp => new Parser(with =>
{
with.AutoHelp = true;
with.AutoVersion = true;
with.EnableDashDash = true;
with.IgnoreUnknownArguments = false;
}))
.BuildServiceProvider();
var tree = new DefaultCommandTree(