From 2bb64636aee5a27ec33dd17c08cb4a1f36d44a4d Mon Sep 17 00:00:00 2001 From: Yaakov Date: Sun, 26 Sep 2021 13:39:45 +1000 Subject: [PATCH] Add command to copy file to Azure Storage --- .../Commands/Cdn/StorageCopyCommand.cs | 62 +++++++++++++++++++ src/console/Program.cs | 3 +- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/console/Commands/Cdn/StorageCopyCommand.cs diff --git a/src/console/Commands/Cdn/StorageCopyCommand.cs b/src/console/Commands/Cdn/StorageCopyCommand.cs new file mode 100644 index 0000000..9f949e9 --- /dev/null +++ b/src/console/Commands/Cdn/StorageCopyCommand.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Models; +using CommandLine; + +namespace Shamir.Console +{ + public class StorageCopyOptions + { + [Option("connection-string", Required = false, HelpText = "Azure Storage connection string for the Storage Account backing the CDN.")] + public string? ConnectionString { get; set; } + + [Value(0, Required = true, MetaName = "LocalPath", HelpText = "The local path to the file to copy.")] + public string? LocalPath { get; set; } + + [Value(1, Required = true, MetaName = "RemotePath", HelpText = "The destination path in Azure Storage.")] + public string? RemotePath { get; set; } + } + + public sealed class StorageCopyCommand : ParsedArgumentsCommand + { + public override string Name => "cp"; + + public override string Description => "Copy a file to an Azure Storage account."; + + public override async ValueTask ExecuteAsync(IServiceProvider serviceProvider, StorageCopyOptions options) + { + var connectionString = options.ConnectionString ?? Environment.GetEnvironmentVariable("AZURE_CONNECTION_STRING"); + + Debug.Assert(options.LocalPath != null, "LocalPath should be set."); + Debug.Assert(options.RemotePath != null, "RemotePath should be set."); + + var delimiterIndex = options.RemotePath.IndexOf('/'); + var (containerName, path) = delimiterIndex > 0 + ? (options.RemotePath[..delimiterIndex], options.RemotePath[(delimiterIndex + 1)..]) + : (options.RemotePath, string.Empty); + + var inputIsStdInputStream = options.LocalPath == "-"; + + if (string.IsNullOrEmpty(path)) + { + if (inputIsStdInputStream) + { + throw new NotSupportedException("The remote path must include a name for the blob, as it cannot be derived from the local file name."); + } + + path = Path.GetFileName(options.LocalPath); + } + + var client = new BlobContainerClient(connectionString, containerName); + await client.CreateIfNotExistsAsync(PublicAccessType.Blob); + + using var blobStream = inputIsStdInputStream ? System.Console.OpenStandardInput() : File.OpenRead(options.LocalPath); + var response = await client.UploadBlobAsync(path, blobStream); + + return 0; + } + } +} \ No newline at end of file diff --git a/src/console/Program.cs b/src/console/Program.cs index 0fa3077..2f5ea58 100644 --- a/src/console/Program.cs +++ b/src/console/Program.cs @@ -28,7 +28,8 @@ namespace Shamir.Console "Browse and add new data to a CDN backed by Azure Storage", ImmutableArray.Empty, ImmutableArray.Create( - new StorageLsCommand() + new StorageLsCommand(), + new StorageCopyCommand() )) ), ImmutableArray.Empty