tools/code/common/Workspace.cs (187 lines of code) (raw):

using Azure.Core.Pipeline; using Flurl; using LanguageExt; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; namespace common; public sealed record WorkspaceName : ResourceName, IResourceName<WorkspaceName> { private WorkspaceName(string value) : base(value) { } public static WorkspaceName From(string value) => new(value); } public sealed record WorkspacesUri : ResourceUri { public required ManagementServiceUri ServiceUri { get; init; } private static string PathSegment { get; } = "workspaces"; protected override Uri Value => ServiceUri.ToUri().AppendPathSegment(PathSegment).ToUri(); public static WorkspacesUri From(ManagementServiceUri serviceUri) => new() { ServiceUri = serviceUri }; } public sealed record WorkspaceUri : ResourceUri { public required WorkspacesUri Parent { get; init; } public required WorkspaceName Name { get; init; } protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri(); public static WorkspaceUri From(WorkspaceName name, ManagementServiceUri serviceUri) => new() { Parent = WorkspacesUri.From(serviceUri), Name = name }; } public sealed record WorkspacesDirectory : ResourceDirectory { public required ManagementServiceDirectory ServiceDirectory { get; init; } private static string Name { get; } = "workspaces"; protected override DirectoryInfo Value => ServiceDirectory.ToDirectoryInfo().GetChildDirectory(Name); public static WorkspacesDirectory From(ManagementServiceDirectory serviceDirectory) => new() { ServiceDirectory = serviceDirectory }; public static Option<WorkspacesDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) => directory is not null && directory.Name == Name && directory.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName ? new WorkspacesDirectory { ServiceDirectory = serviceDirectory } : Option<WorkspacesDirectory>.None; } public sealed record WorkspaceDirectory : ResourceDirectory { public required WorkspacesDirectory Parent { get; init; } public required WorkspaceName Name { get; init; } protected override DirectoryInfo Value => Parent.ToDirectoryInfo().GetChildDirectory(Name.Value); public static WorkspaceDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) => new() { Parent = WorkspacesDirectory.From(serviceDirectory), Name = name }; public static Option<WorkspaceDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) => directory is not null ? from parent in WorkspacesDirectory.TryParse(directory?.Parent, serviceDirectory) let name = WorkspaceName.From(directory!.Name) select new WorkspaceDirectory { Parent = parent, Name = name } : Option<WorkspaceDirectory>.None; } public sealed record WorkspaceInformationFile : ResourceFile { public required WorkspaceDirectory Parent { get; init; } public static string Name { get; } = "workspaceInformation.json"; protected override FileInfo Value => Parent.ToDirectoryInfo().GetChildFile(Name); public static WorkspaceInformationFile From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) => new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) }; public static Option<WorkspaceInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) => file is not null && file.Name == Name ? from parent in WorkspaceDirectory.TryParse(file.Directory, serviceDirectory) select new WorkspaceInformationFile { Parent = parent } : Option<WorkspaceInformationFile>.None; } public sealed record WorkspaceDto { [JsonPropertyName("properties")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public required WorkspaceContract Properties { get; init; } public sealed record WorkspaceContract { [JsonPropertyName("displayName")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string? DisplayName { get; init; } [JsonPropertyName("description")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string? Description { get; init; } } } public static class WorkspaceModule { public static async ValueTask DeleteAll(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) => await uri.ListNames(pipeline, cancellationToken) .IterParallel(async name => { var resourceUri = new WorkspaceUri { Parent = uri, Name = name }; await resourceUri.Delete(pipeline, cancellationToken); }, cancellationToken); public static IAsyncEnumerable<WorkspaceName> ListNames(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) { var exceptionHandler = (HttpRequestException exception) => exception.StatusCode == HttpStatusCode.BadRequest && exception.Message.Contains("MethodNotAllowedInPricingTier", StringComparison.OrdinalIgnoreCase) ? AsyncEnumerable.Empty<WorkspaceName>() : throw exception; return pipeline.ListJsonObjects(uri.ToUri(), cancellationToken) .Select(jsonObject => jsonObject.GetStringProperty("name")) .Select(WorkspaceName.From) .Catch(exceptionHandler); } public static IAsyncEnumerable<(WorkspaceName Name, WorkspaceDto Dto)> List(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) => uri.ListNames(pipeline, cancellationToken) .SelectAwait(async name => { var resourceUri = new WorkspaceUri { Parent = uri, Name = name }; var dto = await resourceUri.GetDto(pipeline, cancellationToken); return (name, dto); }); public static async ValueTask<Option<WorkspaceDto>> TryGetDto(this WorkspaceUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) { var contentOption = await pipeline.GetContentOption(uri.ToUri(), cancellationToken); return contentOption.Map(content => content.ToObjectFromJson<WorkspaceDto>()); } public static async ValueTask<WorkspaceDto> GetDto(this WorkspaceUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) { var content = await pipeline.GetContent(uri.ToUri(), cancellationToken); return content.ToObjectFromJson<WorkspaceDto>(); } public static async ValueTask Delete(this WorkspaceUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) => await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken); public static async ValueTask PutDto(this WorkspaceUri uri, WorkspaceDto dto, HttpPipeline pipeline, CancellationToken cancellationToken) { var content = BinaryData.FromObjectAsJson(dto); await pipeline.PutContent(uri.ToUri(), content, cancellationToken); } public static IEnumerable<WorkspaceDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory) { var workspacesDirectory = WorkspacesDirectory.From(serviceDirectory); return from workspacesDirectoryInfo in workspacesDirectory.ToDirectoryInfo().ListDirectories("*") let name = WorkspaceName.From(workspacesDirectoryInfo.Name) select new WorkspaceDirectory { Parent = workspacesDirectory, Name = name }; } public static IEnumerable<WorkspaceInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) => from workspaceDirectory in ListDirectories(serviceDirectory) let informationFile = new WorkspaceInformationFile { Parent = workspaceDirectory } where informationFile.ToFileInfo().Exists() select informationFile; public static async ValueTask WriteDto(this WorkspaceInformationFile file, WorkspaceDto dto, CancellationToken cancellationToken) { var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions); await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken); } public static async ValueTask<WorkspaceDto> ReadDto(this WorkspaceInformationFile file, CancellationToken cancellationToken) { var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken); return content.ToObjectFromJson<WorkspaceDto>(); } }