From 7d6227957b1b13bd84775f83d4d9a64041d7c825 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Tue, 13 Oct 2020 01:20:02 +0200 Subject: [PATCH] refactor: Extract gitree configuration from Project Model (#126) * refactor: Remove ProjectConfiguration, use C#9 'record' - cleanup ProjectModel by removing all ProjectConfiguration elements and moving those necessary to Gitree project - use C#9 records across ProjectModel and Workspaces - remove unncessary package references - remove Gitree support from Publish command in CliTool * fix: Suppress weird warnings * style: Fix whitespace issue --- Packages.props | 2 - .../Commands/ConvertXmlCommand.cs | 32 +++--- .../Commands/PublishCommand.cs | 50 +++------- .../AutoProjectConfigurationProvider.cs | 97 ------------------ .../WarHub.ArmouryModel.CliTool.csproj | 4 - .../Configuration/ProjectConfiguration.cs | 26 ----- .../Configuration/ProjectConfigurationInfo.cs | 12 --- .../Configuration/SourceFolder.cs | 15 --- .../DatafileInfo`1.cs | 10 +- .../IProjectConfigurationProvider.cs | 9 -- .../IWorkspace.cs | 5 - .../ProjectConfigurationExtensions.cs | 98 ------------------- .../ProjectConfigurationProviderBase.cs | 94 ------------------ .../ProjectFormatProviderType.cs | 13 --- .../RepoDistribution.cs | 11 +-- .../UnknownTypeDatafileInfo.cs | 6 +- .../WarHub.ArmouryModel.ProjectModel.csproj | 2 - .../Foundation/SourceExtensions.cs | 29 +++++- ...attleScribeProjectConfigurationProvider.cs | 15 --- ...rmouryModel.Workspaces.BattleScribe.csproj | 11 --- .../XmlDocument.cs | 35 ++++--- .../XmlWorkspace.cs | 28 +++--- .../XmlWorkspaceOptions.cs | 7 ++ .../GitreeListNode.cs | 8 +- .../GitreeNode.cs | 20 ++-- .../GitreeProjectConfigurationProvider.cs | 15 --- .../GitreeReader.cs | 16 ++- .../GitreeSourceFolder.cs | 15 +++ .../GitreeSourceFolderKind.cs} | 4 +- .../GitreeWorkspace.cs | 36 +++---- .../GitreeWorkspaceOptions.cs | 81 +++++++++++++++ .../GitreeWorkspaceOptionsExtensions.cs | 76 ++++++++++++++ .../GitreeWriter.cs | 3 +- ...gnoringEmptyCollectionsContractResolver.cs | 2 +- .../Serialization}/JsonUtilities.cs | 2 +- .../MultilineJsonStringConverter.cs | 4 +- .../SourceNodeToGitreeConverter.cs | 4 +- ...rHub.ArmouryModel.Workspaces.Gitree.csproj | 1 - .../Foundation/SourceKind.cs | 4 + ....CodeGeneration.Tests.GeneratedCode.csproj | 4 + 40 files changed, 331 insertions(+), 575 deletions(-) delete mode 100644 src/WarHub.ArmouryModel.CliTool/Utilities/AutoProjectConfigurationProvider.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfiguration.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfigurationInfo.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolder.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/IProjectConfigurationProvider.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationExtensions.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationProviderBase.cs delete mode 100644 src/WarHub.ArmouryModel.ProjectModel/ProjectFormatProviderType.cs delete mode 100644 src/WarHub.ArmouryModel.Workspaces.BattleScribe/BattleScribeProjectConfigurationProvider.cs create mode 100644 src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspaceOptions.cs delete mode 100644 src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeProjectConfigurationProvider.cs create mode 100644 src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolder.cs rename src/{WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolderKind.cs => WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolderKind.cs} (70%) create mode 100644 src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptions.cs create mode 100644 src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptionsExtensions.cs rename src/{WarHub.ArmouryModel.ProjectModel => WarHub.ArmouryModel.Workspaces.Gitree/Serialization}/IgnoringEmptyCollectionsContractResolver.cs (94%) rename src/{WarHub.ArmouryModel.ProjectModel => WarHub.ArmouryModel.Workspaces.Gitree/Serialization}/JsonUtilities.cs (91%) rename src/{WarHub.ArmouryModel.ProjectModel => WarHub.ArmouryModel.Workspaces.Gitree/Serialization}/MultilineJsonStringConverter.cs (93%) diff --git a/Packages.props b/Packages.props index f2e9d4b..c868f02 100644 --- a/Packages.props +++ b/Packages.props @@ -2,7 +2,6 @@ - @@ -31,7 +30,6 @@ Condition=" !$(IsTestingOnlyProject) " /> - diff --git a/src/WarHub.ArmouryModel.CliTool/Commands/ConvertXmlCommand.cs b/src/WarHub.ArmouryModel.CliTool/Commands/ConvertXmlCommand.cs index 7d11fe1..12514db 100644 --- a/src/WarHub.ArmouryModel.CliTool/Commands/ConvertXmlCommand.cs +++ b/src/WarHub.ArmouryModel.CliTool/Commands/ConvertXmlCommand.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.IO; using System.Threading.Tasks; -using WarHub.ArmouryModel.ProjectModel; using WarHub.ArmouryModel.Source; using WarHub.ArmouryModel.Workspaces.BattleScribe; using WarHub.ArmouryModel.Workspaces.Gitree; @@ -25,14 +24,14 @@ public async Task RunAsync(DirectoryInfo source, DirectoryInfo output, string ve await ConvertFilesAsync(configInfo, workspace); } - private async Task ConvertFilesAsync(ProjectConfigurationInfo configInfo, XmlWorkspace workspace) + private async Task ConvertFilesAsync(GitreeWorkspaceOptions gitreeOptions, XmlWorkspace workspace) { var treeWriter = new GitreeWriter(); foreach (var document in workspace.GetDocuments(SourceKind.Gamesystem, SourceKind.Catalogue)) { var sourceKind = document.Kind.GetSourceKindOrUnknown(); var filenameNoExt = Path.GetFileNameWithoutExtension(document.Filepath); - var folderPath = Path.Combine(configInfo.GetFullPath(sourceKind), filenameNoExt); + var folderPath = Path.Combine(gitreeOptions.GetFullPath(sourceKind), filenameNoExt); var folder = Directory.CreateDirectory(folderPath); Log.Information("Converting file {Name} into {Folder}", filenameNoExt, folder); Log.Verbose("- Reading..."); @@ -45,11 +44,17 @@ private async Task ConvertFilesAsync(ProjectConfigurationInfo configInfo, XmlWor } } - private static ProjectConfigurationInfo CreateDestinationProjectConfig(DirectoryInfo sourceDir, DirectoryInfo destDir) + private static GitreeWorkspaceOptions CreateDestinationProjectConfig(DirectoryInfo sourceDir, DirectoryInfo destDir) { - var configInfo = new ConvertedGitreeProjectConfigurationProvider().Create(sourceDir.FullName); - var destFilepath = Path.Combine(destDir.FullName, Path.GetFileName(configInfo.Filepath)); - return configInfo.WithFilepath(destFilepath); + var options = GitreeWorkspaceOptions.Create(sourceDir.FullName); + var destFilepath = Path.Combine(destDir.FullName, Path.GetFileName(options.Filepath)); + return options with + { + Filepath = destFilepath, + SourceDirectories = ImmutableArray.Create( + new GitreeSourceFolder(GitreeSourceFolderKind.Catalogues, "src/catalogues"), + new GitreeSourceFolder(GitreeSourceFolderKind.Gamesystems, "src/gamesystems")) + }; } private XmlWorkspace CreateXmlWorkspace(DirectoryInfo sourceDir) @@ -67,18 +72,5 @@ private XmlWorkspace CreateXmlWorkspace(DirectoryInfo sourceDir) return workspace; } - - private class ConvertedGitreeProjectConfigurationProvider : GitreeProjectConfigurationProvider - { - protected override ImmutableArray DefaultDirectoryReferences { get; } = - ImmutableArray.Create( - new SourceFolder(SourceFolderKind.Catalogues, "src/catalogues"), - new SourceFolder(SourceFolderKind.Gamesystems, "src/gamesystems")); - - protected override ProjectConfiguration CreateDefaultCore(string path) - { - return base.CreateDefaultCore(path).WithSourceDirectories(DefaultDirectoryReferences); - } - } } } diff --git a/src/WarHub.ArmouryModel.CliTool/Commands/PublishCommand.cs b/src/WarHub.ArmouryModel.CliTool/Commands/PublishCommand.cs index 3ce248f..f89939b 100644 --- a/src/WarHub.ArmouryModel.CliTool/Commands/PublishCommand.cs +++ b/src/WarHub.ArmouryModel.CliTool/Commands/PublishCommand.cs @@ -4,13 +4,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Amadevus.RecordGenerator; -using WarHub.ArmouryModel.CliTool.Utilities; using WarHub.ArmouryModel.ProjectModel; using WarHub.ArmouryModel.Source; using WarHub.ArmouryModel.Source.XmlFormat; using WarHub.ArmouryModel.Workspaces.BattleScribe; -using WarHub.ArmouryModel.Workspaces.Gitree; namespace WarHub.ArmouryModel.CliTool.Commands { @@ -18,17 +15,16 @@ public partial class PublishCommand : CommandBase { internal static readonly string[] ArtifactNames = new[] { "xml", "zip", "index", "bsi", "bsr" }; - [Record] - private partial class Options + private record Options { - public ImmutableArray Artifacts { get; } - public DirectoryInfo Source { get; } - public DirectoryInfo Output { get; } - public Uri Url { get; } - public ImmutableArray AdditionalUrls { get; } - public bool UrlOnlyIndex { get; } - public string RepoName { get; } - public string Filename { get; } + public ImmutableArray Artifacts { get; init; } + public DirectoryInfo Source { get; init; } + public DirectoryInfo Output { get; init; } + public Uri Url { get; init; } + public ImmutableArray AdditionalUrls { get; init; } + public bool UrlOnlyIndex { get; init; } + public string RepoName { get; init; } + public string Filename { get; init; } } public enum ArtifactType @@ -53,12 +49,6 @@ public enum ArtifactType string verbosity) { SetupLogger(verbosity); - var configInfo = new AutoProjectConfigurationProvider().Create(source.FullName); - Log.Debug("Using configuration: {@Config}", configInfo); - if (configInfo.Configuration.FormatProvider == ProjectFormatProviderType.Gitree) - { - Log.Warning("Gitree feature is a Work In Progress. It may not work as expected, or at all."); - } var artifactTypes = artifacts .Distinct() @@ -70,12 +60,12 @@ public enum ArtifactType Log.Information("Nothing to do."); return; } - output ??= new DirectoryInfo(configInfo.Configuration.OutputPath); + output ??= new DirectoryInfo("artifacts"); Log.Debug("Writing artifacts to: {Destination}", output); output.Create(); Log.Debug("Loading workspace..."); - var workspace = ReadWorkspaceFromConfig(configInfo); + var workspace = XmlWorkspace.CreateFromDirectory(source.FullName); Log.Debug( "Workspace loaded. {DatafileCount} datafiles discovered.", workspace.Datafiles.Count(x => x.DataKind.IsDataCatalogueKind())); @@ -87,7 +77,7 @@ public enum ArtifactType var resolvedFilename = string.IsNullOrWhiteSpace(filename) ? source.Name : filename; - var options = new Options.Builder + var options = new Options { Artifacts = artifactTypes, Source = source, @@ -97,7 +87,7 @@ public enum ArtifactType RepoName = resolvedRepoName, Filename = resolvedFilename, UrlOnlyIndex = urlOnlyIndex - }.ToImmutable(); + }; foreach (var artifactType in options.Artifacts) { @@ -156,7 +146,7 @@ private static async Task GetRepoNameFallbackAsync(IWorkspace workspace) var gst = (GamesystemNode)await workspace.Datafiles .FirstOrDefault(x => x.DataKind == SourceKind.Gamesystem) ?.GetDataAsync(); - return gst?.Name ?? workspace.Info.GetDirectoryInfo().Name; + return gst?.Name ?? new DirectoryInfo(workspace.RootPath).Name; } private async Task PublishArtifactRepoDistributionAsync(IWorkspace workspace, Options options) @@ -242,18 +232,6 @@ private async Task PublishXmlAsync(IWorkspace workspace, Options options) } } - private static IWorkspace ReadWorkspaceFromConfig(ProjectConfigurationInfo info) - { - return info.Configuration.FormatProvider switch - { - ProjectFormatProviderType.Gitree => GitreeWorkspace.CreateFromConfigurationInfo(info), - ProjectFormatProviderType.BattleScribeXml => XmlWorkspace.CreateFromConfigurationInfo(info), - _ => throw new InvalidOperationException( - $"Unknown {nameof(ProjectConfiguration.FormatProvider)}:" + - $" {info.Configuration.FormatProvider}"), - }; - } - private static ArtifactType ParseArtifactType(string name) { return name switch diff --git a/src/WarHub.ArmouryModel.CliTool/Utilities/AutoProjectConfigurationProvider.cs b/src/WarHub.ArmouryModel.CliTool/Utilities/AutoProjectConfigurationProvider.cs deleted file mode 100644 index 5131cf1..0000000 --- a/src/WarHub.ArmouryModel.CliTool/Utilities/AutoProjectConfigurationProvider.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using WarHub.ArmouryModel.ProjectModel; -using WarHub.ArmouryModel.Workspaces.BattleScribe; -using WarHub.ArmouryModel.Workspaces.Gitree; - -namespace WarHub.ArmouryModel.CliTool.Utilities -{ - internal class AutoProjectConfigurationProvider : IProjectConfigurationProvider - { - public ProjectConfigurationInfo Empty => new BattleScribeProjectConfigurationProvider().Empty; - - public ProjectConfigurationInfo Create(string path) - { - if (File.Exists(path)) - { - return ReadFile(path); - } - return ReadDirectory(path); - } - - private static ProjectConfigurationInfo ReadFile(string path) - { - if (!IsProjectConfituration(path)) - { - throw new ArgumentException($"Path '{path}' is not a project file ({ProjectConfiguration.FileExtension}) or directory."); - } - // we have configuration to read - return ReadConfigurationFile(path); - } - - private static ProjectConfigurationInfo ReadDirectory(string path) - { - var directory = string.IsNullOrEmpty(path) ? "." : path; - // search for single project configuration file in current directory - var files = Directory.EnumerateFiles(directory, "*" + ProjectConfiguration.FileExtension) - .ToImmutableArray(); - return files.Length switch - { - 0 => AutoGeneratedConfiguration(path), - 1 => ReadConfigurationFile(files[0]), - _ => throw new InvalidOperationException( - $"Cannot open project file ({ProjectConfiguration.FileExtension})" + - $" when there are {files.Length} such in directory {path}."), - }; - } - - private static ProjectConfigurationInfo AutoGeneratedConfiguration(string path) - { - var xmlWorkspace = XmlWorkspace.CreateFromDirectory(path); - if (xmlWorkspace.Documents.Any(x => x.Kind.GetSourceKindOrUnknown().IsDataCatalogueKind())) - { - // that's BattleScribe workspace - return new BattleScribeProjectConfigurationProvider().Create(path); - } - return new GitreeProjectConfigurationProvider().Create(path); - } - - private static ProjectConfigurationInfo ReadConfigurationFile(string path) - { - var raw = ProjectConfigurationProviderBase.ReadFromFile(path); - return raw.Configuration.FormatProvider switch - { - ProjectFormatProviderType.Gitree => new GitreeConfigurationSanitizingProvider().Sanitize(raw), - ProjectFormatProviderType.BattleScribeXml => new BattleScribeConfigurationSanitizingProvider().Sanitize(raw), - _ => raw, - }; - } - - private static bool IsProjectConfituration(string path) - { - var extension = Path.GetExtension(path); - return string.Equals( - extension, - ProjectConfiguration.FileExtension, - StringComparison.OrdinalIgnoreCase); - } - - private class GitreeConfigurationSanitizingProvider : GitreeProjectConfigurationProvider - { - public ProjectConfigurationInfo Sanitize(ProjectConfigurationInfo raw) - { - return raw.WithConfiguration(SanitizeConfiguration(raw.Configuration)); - } - } - - private class BattleScribeConfigurationSanitizingProvider : BattleScribeProjectConfigurationProvider - { - public ProjectConfigurationInfo Sanitize(ProjectConfigurationInfo raw) - { - return raw.WithConfiguration(SanitizeConfiguration(raw.Configuration)); - } - } - } -} diff --git a/src/WarHub.ArmouryModel.CliTool/WarHub.ArmouryModel.CliTool.csproj b/src/WarHub.ArmouryModel.CliTool/WarHub.ArmouryModel.CliTool.csproj index f30ae8e..14036a4 100644 --- a/src/WarHub.ArmouryModel.CliTool/WarHub.ArmouryModel.CliTool.csproj +++ b/src/WarHub.ArmouryModel.CliTool/WarHub.ArmouryModel.CliTool.csproj @@ -13,10 +13,6 @@ - - - - diff --git a/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfiguration.cs b/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfiguration.cs deleted file mode 100644 index 95818ea..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfiguration.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Immutable; -using Amadevus.RecordGenerator; -using Newtonsoft.Json; - -namespace WarHub.ArmouryModel.ProjectModel -{ - [Record] - public partial class ProjectConfiguration - { - public const string FileExtension = ".whamproj"; - - public const string DefaultOutputPath = "artifacts"; - - [JsonProperty("toolset")] - public string ToolsetVersion { get; } - - [JsonProperty("src")] - public ImmutableArray SourceDirectories { get; } - - [JsonProperty("out")] - public string OutputPath { get; } - - [JsonProperty("format")] - public ProjectFormatProviderType FormatProvider { get; } - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfigurationInfo.cs b/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfigurationInfo.cs deleted file mode 100644 index 28153da..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/Configuration/ProjectConfigurationInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Amadevus.RecordGenerator; - -namespace WarHub.ArmouryModel.ProjectModel -{ - [Record] - public partial class ProjectConfigurationInfo - { - public string Filepath { get; } - - public ProjectConfiguration Configuration { get; } - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolder.cs b/src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolder.cs deleted file mode 100644 index e9e6e6c..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolder.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Amadevus.RecordGenerator; -using Newtonsoft.Json; - -namespace WarHub.ArmouryModel.ProjectModel -{ - [Record] - public partial class SourceFolder - { - [JsonProperty("kind")] - public SourceFolderKind Kind { get; } - - [JsonProperty("path")] - public string Subpath { get; } - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/DatafileInfo`1.cs b/src/WarHub.ArmouryModel.ProjectModel/DatafileInfo`1.cs index 568ceb5..cc08045 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/DatafileInfo`1.cs +++ b/src/WarHub.ArmouryModel.ProjectModel/DatafileInfo`1.cs @@ -1,20 +1,12 @@ using System.IO; using System.Threading.Tasks; -using Amadevus.RecordGenerator; using WarHub.ArmouryModel.Source; namespace WarHub.ArmouryModel.ProjectModel { - [Record] - public sealed partial class DatafileInfo : IDatafileInfo + public sealed record DatafileInfo(string Filepath, TData Data) : IDatafileInfo where TData : SourceNode { - // TODO internal ctor - - public string Filepath { get; } - - public TData Data { get; } - public SourceKind DataKind => Data.Kind; public string GetStorageName() => Path.GetFileNameWithoutExtension(Filepath); diff --git a/src/WarHub.ArmouryModel.ProjectModel/IProjectConfigurationProvider.cs b/src/WarHub.ArmouryModel.ProjectModel/IProjectConfigurationProvider.cs deleted file mode 100644 index 1c8cc2c..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/IProjectConfigurationProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace WarHub.ArmouryModel.ProjectModel -{ - public interface IProjectConfigurationProvider - { - ProjectConfigurationInfo Create(string path); - - ProjectConfigurationInfo Empty { get; } - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/IWorkspace.cs b/src/WarHub.ArmouryModel.ProjectModel/IWorkspace.cs index cd9446a..d7ca38a 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/IWorkspace.cs +++ b/src/WarHub.ArmouryModel.ProjectModel/IWorkspace.cs @@ -17,10 +17,5 @@ public interface IWorkspace /// Gets a collection of datafile info objects that belong in this workspace. /// ImmutableArray Datafiles { get; } - - /// - /// Gets project configuration info. - /// - ProjectConfigurationInfo Info { get; } } } diff --git a/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationExtensions.cs b/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationExtensions.cs deleted file mode 100644 index 10c61c2..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationExtensions.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using WarHub.ArmouryModel.Source; - -namespace WarHub.ArmouryModel.ProjectModel -{ - public static class ProjectConfigurationExtensions - { - static ProjectConfigurationExtensions() - { - DataCatalogueKinds = - ImmutableHashSet.Create( - SourceKind.Gamesystem, - SourceKind.Catalogue); - - FolderKindsBySourceKinds = - new Dictionary> - { - [SourceKind.Catalogue] = ImmutableHashSet.Create(SourceFolderKind.All, SourceFolderKind.Catalogues), - [SourceKind.Gamesystem] = ImmutableHashSet.Create(SourceFolderKind.All, SourceFolderKind.Gamesystems) - } - .ToImmutableDictionary(); - - DataIndexKinds = - new Dictionary - { - [SourceKind.Catalogue] = DataIndexEntryKind.Catalogue, - [SourceKind.Gamesystem] = DataIndexEntryKind.Gamesystem - } - .ToImmutableDictionary(); - - SourceKindsByDataIndexKinds = DataIndexKinds.ToImmutableDictionary(x => x.Value, x => x.Key); - - SourceKindsByFolderKinds = FolderKindsBySourceKinds - .SelectMany(x => x.Value.Select(folderKind => (folderKind, sourceKind: x.Key))) - .GroupBy(x => x.folderKind, x => x.sourceKind) - .ToImmutableDictionary(x => x.Key, x => x.ToImmutableHashSet()); - } - - public static ImmutableHashSet DataCatalogueKinds { get; } - public static ImmutableDictionary> FolderKindsBySourceKinds { get; } - public static ImmutableDictionary DataIndexKinds { get; } - public static ImmutableDictionary SourceKindsByDataIndexKinds { get; } - public static ImmutableDictionary> SourceKindsByFolderKinds { get; } - - public static ImmutableHashSet FolderKinds(this SourceKind sourceKind) - => FolderKindsBySourceKinds[sourceKind]; - - public static ImmutableHashSet SourceKinds(this SourceFolderKind folderKind) - => SourceKindsByFolderKinds[folderKind]; - - public static DataIndexEntryKind GetIndexEntryKindOrUnknown(this SourceKind sourceKind) - => DataIndexKinds.TryGetValue(sourceKind, out var kind) ? kind : DataIndexEntryKind.Unknown; - - public static IEnumerable GetSourceFolders(this ProjectConfiguration config, SourceKind kind) - { - var folderKinds = kind.FolderKinds(); - return config.SourceDirectories.Where(x => folderKinds.Contains(x.Kind)); - } - - public static bool IsDataCatalogueKind(this SourceKind kind) => DataCatalogueKinds.Contains(kind); - - public static SourceFolder GetSourceFolder(this ProjectConfiguration config, SourceKind kind) - { - return config.GetSourceFolders(kind).First(); - } - - public static void WriteFile(this ProjectConfigurationInfo configInfo) - { - using var stream = File.OpenWrite(configInfo.Filepath); - configInfo.Configuration.Serialize(stream); - } - - public static void Serialize(this ProjectConfiguration configuration, Stream stream) - { - var serializer = JsonUtilities.CreateSerializer(); - using var textWriter = new StreamWriter(stream); - serializer.Serialize(textWriter, configuration); - } - - public static string GetFullPath(this ProjectConfigurationInfo configInfo, SourceKind kind) - => configInfo.GetFullPath(configInfo.Configuration.GetSourceFolder(kind)); - - public static string GetFullPath(this ProjectConfigurationInfo configInfo, SourceFolder folder) - => Path.Combine(Path.GetDirectoryName(configInfo.Filepath) ?? "", folder.Subpath); - - public static DirectoryInfo GetDirectoryInfo(this ProjectConfigurationInfo configInfo) - => new DirectoryInfo(Path.GetDirectoryName(configInfo.Filepath) ?? ""); - - public static string GetFilename(this ProjectConfigurationInfo configInfo) - => Path.GetFileName(configInfo.Filepath); - - public static DirectoryInfo GetDirectoryInfoFor(this ProjectConfigurationInfo configInfo, SourceFolder folder) - => new DirectoryInfo(configInfo.GetFullPath(folder)); - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationProviderBase.cs b/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationProviderBase.cs deleted file mode 100644 index bf1b6fa..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/ProjectConfigurationProviderBase.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Collections.Immutable; -using System.IO; -using Newtonsoft.Json; - -namespace WarHub.ArmouryModel.ProjectModel -{ - public abstract class ProjectConfigurationProviderBase : IProjectConfigurationProvider - { - private ProjectConfigurationInfo? empty; - - public virtual ProjectConfigurationInfo Empty => empty ??= new ProjectConfigurationInfo.Builder - { - Filepath = ".", - Configuration = new ProjectConfiguration.Builder - { - FormatProvider = ProviderType, - OutputPath = ProjectConfiguration.DefaultOutputPath, - SourceDirectories = ImmutableArray.Empty, - ToolsetVersion = ProjectToolset.Version - }.ToImmutable() - }.ToImmutable(); - - public ProjectConfigurationInfo Create(string path) - { - return CreateCore(path); - } - - protected virtual ProjectConfigurationInfo CreateCore(string path) - { - // TODO version check - var raw = CreateRaw(); - var sanitized = SanitizeConfiguration(raw.Configuration); - return raw.WithConfiguration(sanitized); - - ProjectConfigurationInfo CreateRaw() - { - return File.Exists(path) - ? ReadFromFile(path) - : CreateDefault(path); - } - } - - private static ProjectConfiguration ReadText(TextReader reader) - { - var serializer = JsonUtilities.CreateSerializer(); - using var jsonReader = new JsonTextReader(reader); - return serializer.Deserialize(jsonReader); - } - - public static ProjectConfigurationInfo ReadFromFile(string filepath) - { - using var streamReader = File.OpenText(filepath); - var config = ReadText(streamReader); - return new ProjectConfigurationInfo(filepath, config); - } - - protected virtual ProjectConfigurationInfo CreateDefault(string directory) - { - var config = CreateDefaultCore(directory); - var filepath = Path.Combine(directory, CreateDefaultFilename(directory)); - return new ProjectConfigurationInfo(filepath, config); - } - - protected static string CreateDefaultFilename(string directory) - { - var dir = new DirectoryInfo(directory); - var folderName = dir.Parent != null ? dir.Name : "project"; - var filename = folderName + ProjectConfiguration.FileExtension; - return filename; - } - - protected virtual ProjectConfiguration CreateDefaultCore(string directory) - { - return new ProjectConfiguration( - ProjectToolset.Version, - DefaultDirectoryReferences, - ProjectConfiguration.DefaultOutputPath, - ProviderType); - } - - public abstract ProjectFormatProviderType ProviderType { get; } - - protected abstract ImmutableArray DefaultDirectoryReferences { get; } - - protected virtual ProjectConfiguration SanitizeConfiguration(ProjectConfiguration raw) - { - return raw.Update( - raw.ToolsetVersion ?? ProjectToolset.Version, - raw.SourceDirectories.IsDefaultOrEmpty ? DefaultDirectoryReferences : raw.SourceDirectories, - string.IsNullOrWhiteSpace(raw.OutputPath) ? ProjectConfiguration.DefaultOutputPath : raw.OutputPath, - raw.FormatProvider); - } - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/ProjectFormatProviderType.cs b/src/WarHub.ArmouryModel.ProjectModel/ProjectFormatProviderType.cs deleted file mode 100644 index 93cbfba..0000000 --- a/src/WarHub.ArmouryModel.ProjectModel/ProjectFormatProviderType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace WarHub.ArmouryModel.ProjectModel -{ - public enum ProjectFormatProviderType - { - [JsonProperty("gitree")] - Gitree = 0, - - [JsonProperty("bsxml")] - BattleScribeXml = 1, - } -} diff --git a/src/WarHub.ArmouryModel.ProjectModel/RepoDistribution.cs b/src/WarHub.ArmouryModel.ProjectModel/RepoDistribution.cs index 8830e57..d6a53f6 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/RepoDistribution.cs +++ b/src/WarHub.ArmouryModel.ProjectModel/RepoDistribution.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using Amadevus.RecordGenerator; using WarHub.ArmouryModel.Source; namespace WarHub.ArmouryModel.ProjectModel @@ -7,11 +6,7 @@ namespace WarHub.ArmouryModel.ProjectModel /// /// This represents contents of the .bsr file. /// - [Record] - public partial class RepoDistribution - { - public IDatafileInfo Index { get; } - - public ImmutableArray> Datafiles { get; } - } + public record RepoDistribution( + IDatafileInfo Index, + ImmutableArray> Datafiles); } diff --git a/src/WarHub.ArmouryModel.ProjectModel/UnknownTypeDatafileInfo.cs b/src/WarHub.ArmouryModel.ProjectModel/UnknownTypeDatafileInfo.cs index 78efb81..50ec093 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/UnknownTypeDatafileInfo.cs +++ b/src/WarHub.ArmouryModel.ProjectModel/UnknownTypeDatafileInfo.cs @@ -1,17 +1,13 @@ using System.IO; using System.Threading.Tasks; -using Amadevus.RecordGenerator; using WarHub.ArmouryModel.Source; namespace WarHub.ArmouryModel.ProjectModel { - [Record] - public sealed partial class UnknownTypeDatafileInfo : IDatafileInfo, IDatafileInfo + public record UnknownTypeDatafileInfo(string Filepath) : IDatafileInfo, IDatafileInfo { private static readonly Task nullTask = Task.FromResult(null); - public string Filepath { get; } - public SourceKind DataKind => SourceKind.Unknown; public SourceNode? Data => null; diff --git a/src/WarHub.ArmouryModel.ProjectModel/WarHub.ArmouryModel.ProjectModel.csproj b/src/WarHub.ArmouryModel.ProjectModel/WarHub.ArmouryModel.ProjectModel.csproj index 033618f..1045d06 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/WarHub.ArmouryModel.ProjectModel.csproj +++ b/src/WarHub.ArmouryModel.ProjectModel/WarHub.ArmouryModel.ProjectModel.csproj @@ -12,8 +12,6 @@ - - diff --git a/src/WarHub.ArmouryModel.Source/Foundation/SourceExtensions.cs b/src/WarHub.ArmouryModel.Source/Foundation/SourceExtensions.cs index cc61d17..da287ef 100644 --- a/src/WarHub.ArmouryModel.Source/Foundation/SourceExtensions.cs +++ b/src/WarHub.ArmouryModel.Source/Foundation/SourceExtensions.cs @@ -1,9 +1,31 @@ -using System.Linq; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; namespace WarHub.ArmouryModel.Source { public static class SourceExtensions { + static SourceExtensions() + { + DataCatalogueKinds = + ImmutableHashSet.Create( + SourceKind.Gamesystem, + SourceKind.Catalogue); + + DataIndexKinds = + new Dictionary + { + [SourceKind.Catalogue] = DataIndexEntryKind.Catalogue, + [SourceKind.Gamesystem] = DataIndexEntryKind.Gamesystem + } + .ToImmutableDictionary(); + } + + public static ImmutableHashSet DataCatalogueKinds { get; } + + public static ImmutableDictionary DataIndexKinds { get; } + public static bool IsKind(this SourceNode @this, SourceKind kind) => @this.Kind == kind; /// @@ -15,5 +37,10 @@ public static class SourceExtensions { return node.Parent?.ChildrenInfos().ElementAt(node.IndexInParent); } + + public static DataIndexEntryKind GetIndexEntryKindOrUnknown(this SourceKind sourceKind) + => DataIndexKinds.TryGetValue(sourceKind, out var kind) ? kind : DataIndexEntryKind.Unknown; + + public static bool IsDataCatalogueKind(this SourceKind kind) => DataCatalogueKinds.Contains(kind); } } diff --git a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/BattleScribeProjectConfigurationProvider.cs b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/BattleScribeProjectConfigurationProvider.cs deleted file mode 100644 index 5ca1128..0000000 --- a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/BattleScribeProjectConfigurationProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Immutable; -using WarHub.ArmouryModel.ProjectModel; - -namespace WarHub.ArmouryModel.Workspaces.BattleScribe -{ - public class BattleScribeProjectConfigurationProvider : ProjectConfigurationProviderBase - { - public const string DefaultSourcePath = "."; - - public override ProjectFormatProviderType ProviderType => ProjectFormatProviderType.BattleScribeXml; - - protected override ImmutableArray DefaultDirectoryReferences { get; } = - ImmutableArray.Create(new SourceFolder(SourceFolderKind.All, DefaultSourcePath)); - } -} diff --git a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/WarHub.ArmouryModel.Workspaces.BattleScribe.csproj b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/WarHub.ArmouryModel.Workspaces.BattleScribe.csproj index c14e244..9219709 100644 --- a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/WarHub.ArmouryModel.Workspaces.BattleScribe.csproj +++ b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/WarHub.ArmouryModel.Workspaces.BattleScribe.csproj @@ -4,20 +4,9 @@ net5 Implementations of wham ProjectModel for BattleScribe format files: .cat(z), .gst(z), .bsi, .bsr. - - - 8669;$(NoWarn) - - - diff --git a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlDocument.cs b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlDocument.cs index a60acdc..cefeb4d 100644 --- a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlDocument.cs +++ b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlDocument.cs @@ -1,38 +1,37 @@ using System.IO; using System.Threading.Tasks; -using Amadevus.RecordGenerator; using WarHub.ArmouryModel.ProjectModel; using WarHub.ArmouryModel.Source; namespace WarHub.ArmouryModel.Workspaces.BattleScribe { - [Record] - public partial class XmlDocument - { +#pragma warning disable CS1587 // XML comment is not placed on a valid language element +#pragma warning disable CA1801 // Parameter x of method .ctor is never used. Remove the parameter or use it in the method body. + public record XmlDocument( /// - /// Gets the filepath of this document. + /// Gets the kind of this document. /// - public string Filepath => DatafileInfo.Filepath; - + IDatafileInfo DatafileInfo, /// - /// Gets the filename without file extension. + /// Gets the underlying datafile info. /// - public string Name => Path.GetFileNameWithoutExtension(Filepath); - + XmlDocumentKind Kind, /// - /// Gets the kind of this document. + /// Gets the parent workspace of this document. /// - public XmlDocumentKind Kind { get; } - + XmlWorkspace? Workspace = null) + { +#pragma warning restore CS1587 +#pragma warning restore CA1801 /// - /// Gets the underlying datafile info. + /// Gets the filepath of this document. /// - public IDatafileInfo DatafileInfo { get; } + public string Filepath => DatafileInfo.Filepath; /// - /// Gets the parent workspace of this document. + /// Gets the filename without file extension. /// - public XmlWorkspace? Workspace { get; } + public string Name => Path.GetFileNameWithoutExtension(Filepath); /// /// Gets the root node of the document. May cause deserialization. @@ -42,7 +41,7 @@ public partial class XmlDocument public static XmlDocument Create(IDatafileInfo datafileInfo, XmlWorkspace? workspace = null) { - return new XmlDocument(datafileInfo.Filepath.GetXmlDocumentKind(), datafileInfo, workspace); + return new XmlDocument(datafileInfo, datafileInfo.Filepath.GetXmlDocumentKind(), workspace); } } } diff --git a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspace.cs b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspace.cs index dcc241d..8c9dd53 100644 --- a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspace.cs +++ b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspace.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.IO; using System.Linq; using WarHub.ArmouryModel.ProjectModel; @@ -9,17 +10,17 @@ namespace WarHub.ArmouryModel.Workspaces.BattleScribe /// public sealed class XmlWorkspace : IWorkspace { - private XmlWorkspace(ProjectConfigurationInfo info, ImmutableArray documents) + private XmlWorkspace(XmlWorkspaceOptions info, ImmutableArray documents) { - Info = info; - Documents = documents.Select(x => x.WithWorkspace(this)).ToImmutableArray(); + Options = info; + Documents = documents.Select(x => x with { Workspace = this }).ToImmutableArray(); } private string? rootPath; private ImmutableArray? datafiles; private ImmutableDictionary>? documentsByKind; - public ProjectConfigurationInfo Info { get; } + public XmlWorkspaceOptions Options { get; } public ImmutableArray Documents { get; } @@ -28,7 +29,7 @@ private XmlWorkspace(ProjectConfigurationInfo info, ImmutableArray group => group.Key, group => group.ToImmutableArray()); - public string RootPath => rootPath ??= Info.GetDirectoryInfo().FullName; + public string RootPath => rootPath ??= new DirectoryInfo(Options.SourceDirectory).FullName; public ImmutableArray Datafiles => datafiles ??= Documents.Select(x => x.DatafileInfo).ToImmutableArray(); @@ -39,22 +40,23 @@ private XmlWorkspace(ProjectConfigurationInfo info, ImmutableArray /// Workspace created from the directory with all files with well-known extensions. public static XmlWorkspace CreateFromDirectory(string path) { - var info = new BattleScribeProjectConfigurationProvider().Create(path); - return CreateFromConfigurationInfo(info); + return Create(new XmlWorkspaceOptions + { + SourceDirectory = path + }); } public static XmlWorkspace CreateFromDocuments(ImmutableArray documents) { - return new XmlWorkspace(new BattleScribeProjectConfigurationProvider().Empty, documents); + return new XmlWorkspace(new XmlWorkspaceOptions(), documents); } - public static XmlWorkspace CreateFromConfigurationInfo(ProjectConfigurationInfo info) + public static XmlWorkspace Create(XmlWorkspaceOptions options) { - var files = info.Configuration.SourceDirectories - .SelectMany(x => info.GetDirectoryInfoFor(x).EnumerateFiles()); + var files = new DirectoryInfo(options.SourceDirectory).EnumerateFiles(); var datafiles = files.Select(XmlFileExtensions.GetDatafileInfo).ToImmutableArray(); - var documents = datafiles.Select(file => new XmlDocument(file.Filepath.GetXmlDocumentKind(), file, null)).ToImmutableArray(); - return new XmlWorkspace(info, documents); + var documents = datafiles.Select(file => new XmlDocument(file, file.Filepath.GetXmlDocumentKind())).ToImmutableArray(); + return new XmlWorkspace(options, documents); } } } diff --git a/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspaceOptions.cs b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspaceOptions.cs new file mode 100644 index 0000000..431bb08 --- /dev/null +++ b/src/WarHub.ArmouryModel.Workspaces.BattleScribe/XmlWorkspaceOptions.cs @@ -0,0 +1,7 @@ +namespace WarHub.ArmouryModel.Workspaces.BattleScribe +{ + public record XmlWorkspaceOptions + { + public string SourceDirectory { get; init; } = "."; + } +} diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeListNode.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeListNode.cs index 3881a5d..3e9142e 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeListNode.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeListNode.cs @@ -1,15 +1,11 @@ using System.Collections.Immutable; -using Amadevus.RecordGenerator; using System.Diagnostics; namespace WarHub.ArmouryModel.Workspaces.Gitree { - [Record] [DebuggerDisplay("{" + nameof(Name) + "}, Count = {" + nameof(Items) + ".Length}")] - public partial class GitreeListNode + public record GitreeListNode(string Name) { - public string Name { get; } - - public ImmutableArray Items { get; } + public ImmutableArray Items { get; init; } = ImmutableArray.Empty; } } diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeNode.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeNode.cs index 715ce04..74e292a 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeNode.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeNode.cs @@ -1,25 +1,25 @@ using System.Collections.Immutable; using System.Diagnostics; -using Amadevus.RecordGenerator; using WarHub.ArmouryModel.Source; namespace WarHub.ArmouryModel.Workspaces.Gitree { - [Record] [DebuggerDisplay("{" + nameof(WrappedNode) + ".Kind}, Lists = {" + nameof(Lists) + ".Length}")] - public partial class GitreeNode + public record GitreeNode( + DatablobNode Datablob, + SourceNode WrappedNode) { - public DatablobNode Datablob { get; } + public bool IsLeaf { get; init; } - public SourceNode WrappedNode { get; } - - public bool IsLeaf { get; } - - public ImmutableArray Lists { get; } + public ImmutableArray Lists { get; init; } = ImmutableArray.Empty; public static GitreeNode Create(DatablobNode datablob, SourceNode node, ImmutableArray lists) { - return new GitreeNode(datablob, node, lists.IsEmpty, lists); + return new GitreeNode(datablob, node) + { + IsLeaf = lists.IsEmpty, + Lists = lists + }; } } } diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeProjectConfigurationProvider.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeProjectConfigurationProvider.cs deleted file mode 100644 index 51ce626..0000000 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeProjectConfigurationProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Immutable; -using WarHub.ArmouryModel.ProjectModel; - -namespace WarHub.ArmouryModel.Workspaces.Gitree -{ - public class GitreeProjectConfigurationProvider : ProjectConfigurationProviderBase - { - public const string DefaultSourcePath = "src"; - - public override ProjectFormatProviderType ProviderType => ProjectFormatProviderType.Gitree; - - protected override ImmutableArray DefaultDirectoryReferences { get; } = - ImmutableArray.Create(new SourceFolder(SourceFolderKind.All, DefaultSourcePath)); - } -} diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeReader.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeReader.cs index 9343361..67c883d 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeReader.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeReader.cs @@ -14,7 +14,11 @@ public GitreeNode ReadItemFolder(GitreeStorageFolderNode folder) var children = folder.GetFolders().Select(ReadListFolder).ToImmutableArray(); var nodeDocument = folder.GetDocuments().Single(); var (node, wrappedNode) = ReadDocumentNodes(nodeDocument); - var blobItem = new GitreeNode(node, wrappedNode, false, children); + var blobItem = new GitreeNode(node, wrappedNode) + { + IsLeaf = false, + Lists = children + }; return blobItem; } @@ -22,14 +26,20 @@ private GitreeListNode ReadListFolder(GitreeStorageFolderNode folder) { var documentItems = folder.GetDocuments().Select(ReadDocument).ToImmutableArray(); var folderItems = folder.GetFolders().Select(ReadItemFolder).ToImmutableArray(); - var blobList = new GitreeListNode(folder.Name, documentItems.AddRange(folderItems)); + var blobList = new GitreeListNode(folder.Name) + { + Items = documentItems.AddRange(folderItems) + }; return blobList; } private GitreeNode ReadDocument(GitreeStorageFileNode document) { var (node, wrappedNode) = ReadDocumentNodes(document); - var item = new GitreeNode(node, wrappedNode, true, ImmutableArray.Empty); + var item = new GitreeNode(node, wrappedNode) + { + IsLeaf = true + }; return item; } diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolder.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolder.cs new file mode 100644 index 0000000..e74bfa7 --- /dev/null +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolder.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace WarHub.ArmouryModel.Workspaces.Gitree +{ +#pragma warning disable CA1801 // Parameter x of method .ctor is never used. Remove the parameter or use it in the method body. + public record GitreeSourceFolder + ( + [property: JsonProperty("kind")] + GitreeSourceFolderKind Kind, + + [property: JsonProperty("path")] + string Subpath + ); +#pragma warning restore CA1801 +} diff --git a/src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolderKind.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolderKind.cs similarity index 70% rename from src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolderKind.cs rename to src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolderKind.cs index 53d630b..285b435 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/Configuration/SourceFolderKind.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeSourceFolderKind.cs @@ -1,8 +1,8 @@ using Newtonsoft.Json; -namespace WarHub.ArmouryModel.ProjectModel +namespace WarHub.ArmouryModel.Workspaces.Gitree { - public enum SourceFolderKind + public enum GitreeSourceFolderKind { [JsonProperty("all")] All, diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspace.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspace.cs index 7a7a5ac..164b5a2 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspace.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspace.cs @@ -8,19 +8,20 @@ using Optional; using Optional.Collections; using WarHub.ArmouryModel.ProjectModel; +using WarHub.ArmouryModel.Workspaces.Gitree.Serialization; namespace WarHub.ArmouryModel.Workspaces.Gitree { public sealed class GitreeWorkspace : IWorkspace { - private GitreeWorkspace(ProjectConfigurationInfo info) + private GitreeWorkspace(GitreeWorkspaceOptions options) { Serializer = JsonUtilities.CreateSerializer(); - Info = info; + Options = options; // TOD validate configuration, handle not-found paths - var documentFindingVisitor = new GitreeRootFindingVisitor(info, this); + var documentFindingVisitor = new GitreeRootFindingVisitor(this); Datafiles = - info.Configuration.SourceDirectories + options.SourceDirectories .SelectMany(documentFindingVisitor.GetRootDocuments) .Select(x => (IDatafileInfo)new GitreeDatafileInfo(x)) .ToImmutableArray(); @@ -28,10 +29,11 @@ private GitreeWorkspace(ProjectConfigurationInfo info) internal JsonSerializer Serializer { get; } - public string RootPath => Info.GetDirectoryInfo().FullName; + public string RootPath => Options.GetDirectoryInfo().FullName; public ImmutableArray Datafiles { get; } - public ProjectConfigurationInfo Info { get; } + + public GitreeWorkspaceOptions Options { get; } public static GitreeWorkspace CreateFromPath(string path) { @@ -43,43 +45,41 @@ public static GitreeWorkspace CreateFromPath(string path) } public static GitreeWorkspace CreateFromConfigurationFile(string path) - => new GitreeWorkspace(new GitreeProjectConfigurationProvider().Create(path)); + => new GitreeWorkspace(GitreeWorkspaceOptions.Create(path)); - public static GitreeWorkspace CreateFromConfigurationInfo(ProjectConfigurationInfo info) - => new GitreeWorkspace(info); + public static GitreeWorkspace Create(GitreeWorkspaceOptions options) + => new GitreeWorkspace(options); public static GitreeWorkspace CreateFromDirectory(string path) { var configFiles = new DirectoryInfo(path) - .EnumerateFiles("*" + ProjectConfiguration.FileExtension) + .EnumerateFiles("*" + GitreeWorkspaceOptions.FileExtension) .ToList(); - var configProvider = new GitreeProjectConfigurationProvider(); return configFiles.Count switch { - 0 => new GitreeWorkspace(configProvider.Create(path)), - 1 => new GitreeWorkspace(configProvider.Create(configFiles[0].FullName)), + 0 => new GitreeWorkspace(GitreeWorkspaceOptions.Create(path)), + 1 => new GitreeWorkspace(GitreeWorkspaceOptions.Create(configFiles[0].FullName)), _ => throw new InvalidOperationException("There's more than one project file in the directory"), }; } private class GitreeRootFindingVisitor { - public GitreeRootFindingVisitor(ProjectConfigurationInfo info, GitreeWorkspace workspace) + public GitreeRootFindingVisitor(GitreeWorkspace workspace) { - Info = info; Workspace = workspace; } - public ProjectConfigurationInfo Info { get; } + public GitreeWorkspaceOptions Options => Workspace.Options; public GitreeWorkspace Workspace { get; } private Queue FoldersToVisit { get; } = new Queue(); - public IEnumerable GetRootDocuments(SourceFolder sourceFolder) + public IEnumerable GetRootDocuments(GitreeSourceFolder sourceFolder) { - var initialDir = Info.GetDirectoryInfoFor(sourceFolder); + var initialDir = Options.GetDirectoryInfoFor(sourceFolder); var initialFolder = new GitreeStorageFolderNode(initialDir, null, Workspace); FoldersToVisit.Enqueue(initialFolder); diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptions.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptions.cs new file mode 100644 index 0000000..ee26ebb --- /dev/null +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptions.cs @@ -0,0 +1,81 @@ +using System.Collections.Immutable; +using System.IO; +using Newtonsoft.Json; +using WarHub.ArmouryModel.ProjectModel; +using WarHub.ArmouryModel.Workspaces.Gitree.Serialization; + +namespace WarHub.ArmouryModel.Workspaces.Gitree +{ + public record GitreeWorkspaceOptions + { + public const string DefaultSourcePath = "src"; + + public const string DefaultOutputPath = "artifacts"; + + public const string FileExtension = ".whamproj"; + + private static ImmutableArray DefaultDirectoryReferences { get; } = + ImmutableArray.Create(new GitreeSourceFolder(GitreeSourceFolderKind.All, DefaultSourcePath)); + + [JsonIgnore] + public string Filepath { get; init; } = "project" + FileExtension; + + [JsonProperty("toolset")] + public string ToolsetVersion { get; init; } = ProjectToolset.Version; + + [JsonProperty("src")] + public ImmutableArray SourceDirectories { get; init; } = ImmutableArray.Empty; + + [JsonProperty("out")] + public string OutputPath { get; init; } = DefaultOutputPath; + + public static GitreeWorkspaceOptions Create(string path) + { + // TODO version check + var raw = CreateRaw(); + return SanitizeConfiguration(raw); + + GitreeWorkspaceOptions CreateRaw() + { + return File.Exists(path) + ? ReadFromFile(path) + : CreateDefault(path); + } + static GitreeWorkspaceOptions CreateDefault(string directory) + { + return new GitreeWorkspaceOptions + { + Filepath = Path.Combine(directory, CreateDefaultFilename()) + }; + string CreateDefaultFilename() + { + var dir = new DirectoryInfo(directory); + var folderName = dir.Parent != null ? dir.Name : "project"; + var filename = folderName + FileExtension; + return filename; + } + } + static GitreeWorkspaceOptions SanitizeConfiguration(GitreeWorkspaceOptions raw) + { + return raw with + { + ToolsetVersion = raw.ToolsetVersion ?? ProjectToolset.Version, + SourceDirectories = raw.SourceDirectories.IsDefaultOrEmpty ? DefaultDirectoryReferences : raw.SourceDirectories, + OutputPath = string.IsNullOrWhiteSpace(raw.OutputPath) ? DefaultOutputPath : raw.OutputPath + }; + } + static GitreeWorkspaceOptions ReadFromFile(string filepath) + { + return ReadText() with { Filepath = filepath }; + + GitreeWorkspaceOptions ReadText() + { + using var streamReader = File.OpenText(filepath); + var serializer = JsonUtilities.CreateSerializer(); + using var jsonReader = new JsonTextReader(streamReader); + return serializer.Deserialize(jsonReader); + } + } + } + } +} diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptionsExtensions.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptionsExtensions.cs new file mode 100644 index 0000000..10a6eb5 --- /dev/null +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWorkspaceOptionsExtensions.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using WarHub.ArmouryModel.Source; +using WarHub.ArmouryModel.Workspaces.Gitree.Serialization; + +namespace WarHub.ArmouryModel.Workspaces.Gitree +{ + public static class GitreeWorkspaceOptionsExtensions + { + static GitreeWorkspaceOptionsExtensions() + { + FolderKindsBySourceKinds = + new Dictionary> + { + [SourceKind.Catalogue] = ImmutableHashSet.Create(GitreeSourceFolderKind.All, GitreeSourceFolderKind.Catalogues), + [SourceKind.Gamesystem] = ImmutableHashSet.Create(GitreeSourceFolderKind.All, GitreeSourceFolderKind.Gamesystems) + } + .ToImmutableDictionary(); + + SourceKindsByFolderKinds = FolderKindsBySourceKinds + .SelectMany(x => x.Value.Select(folderKind => (folderKind, sourceKind: x.Key))) + .GroupBy(x => x.folderKind, x => x.sourceKind) + .ToImmutableDictionary(x => x.Key, x => x.ToImmutableHashSet()); + } + + public static ImmutableDictionary> FolderKindsBySourceKinds { get; } + public static ImmutableDictionary> SourceKindsByFolderKinds { get; } + + public static ImmutableHashSet FolderKinds(this SourceKind sourceKind) + => FolderKindsBySourceKinds[sourceKind]; + + public static ImmutableHashSet SourceKinds(this GitreeSourceFolderKind folderKind) + => SourceKindsByFolderKinds[folderKind]; + + public static IEnumerable GetSourceFolders(this GitreeWorkspaceOptions config, SourceKind kind) + { + var folderKinds = kind.FolderKinds(); + return config.SourceDirectories.Where(x => folderKinds.Contains(x.Kind)); + } + + public static GitreeSourceFolder GetSourceFolder(this GitreeWorkspaceOptions config, SourceKind kind) + { + return config.GetSourceFolders(kind).First(); + } + + public static void WriteFile(this GitreeWorkspaceOptions options) + { + using var stream = File.OpenWrite(options.Filepath); + options.Serialize(stream); + } + + public static void Serialize(this GitreeWorkspaceOptions options, Stream stream) + { + var serializer = JsonUtilities.CreateSerializer(); + using var textWriter = new StreamWriter(stream); + serializer.Serialize(textWriter, options); + } + + public static string GetFullPath(this GitreeWorkspaceOptions configInfo, SourceKind kind) + => configInfo.GetFullPath(configInfo.GetSourceFolder(kind)); + + public static string GetFullPath(this GitreeWorkspaceOptions configInfo, GitreeSourceFolder folder) + => Path.Combine(Path.GetDirectoryName(configInfo.Filepath) ?? "", folder.Subpath); + + public static DirectoryInfo GetDirectoryInfo(this GitreeWorkspaceOptions configInfo) + => new DirectoryInfo(Path.GetDirectoryName(configInfo.Filepath) ?? ""); + + public static string GetFilename(this GitreeWorkspaceOptions configInfo) + => Path.GetFileName(configInfo.Filepath); + + public static DirectoryInfo GetDirectoryInfoFor(this GitreeWorkspaceOptions configInfo, GitreeSourceFolder folder) + => new DirectoryInfo(configInfo.GetFullPath(folder)); + } +} diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWriter.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWriter.cs index f47a959..67d8d6e 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWriter.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/GitreeWriter.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using Optional; using WarHub.ArmouryModel.Source; +using WarHub.ArmouryModel.Workspaces.Gitree.Serialization; namespace WarHub.ArmouryModel.Workspaces.Gitree { @@ -16,7 +17,7 @@ public class GitreeWriter private const string Extension = ".json"; private const string ExtensionPattern = "*.json"; - private JsonSerializer Serializer { get; } = ProjectModel.JsonUtilities.CreateSerializer(); + private JsonSerializer Serializer { get; } = JsonUtilities.CreateSerializer(); public string WriteItem(GitreeNode blobItem, DirectoryInfo directory) { diff --git a/src/WarHub.ArmouryModel.ProjectModel/IgnoringEmptyCollectionsContractResolver.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/IgnoringEmptyCollectionsContractResolver.cs similarity index 94% rename from src/WarHub.ArmouryModel.ProjectModel/IgnoringEmptyCollectionsContractResolver.cs rename to src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/IgnoringEmptyCollectionsContractResolver.cs index 39328b7..71012c5 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/IgnoringEmptyCollectionsContractResolver.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/IgnoringEmptyCollectionsContractResolver.cs @@ -4,7 +4,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -namespace WarHub.ArmouryModel.ProjectModel +namespace WarHub.ArmouryModel.Workspaces.Gitree.Serialization { /// /// Ignores collections with no elements. diff --git a/src/WarHub.ArmouryModel.ProjectModel/JsonUtilities.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/JsonUtilities.cs similarity index 91% rename from src/WarHub.ArmouryModel.ProjectModel/JsonUtilities.cs rename to src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/JsonUtilities.cs index 744c5b8..23f84cb 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/JsonUtilities.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/JsonUtilities.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace WarHub.ArmouryModel.ProjectModel +namespace WarHub.ArmouryModel.Workspaces.Gitree.Serialization { public static class JsonUtilities { diff --git a/src/WarHub.ArmouryModel.ProjectModel/MultilineJsonStringConverter.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/MultilineJsonStringConverter.cs similarity index 93% rename from src/WarHub.ArmouryModel.ProjectModel/MultilineJsonStringConverter.cs rename to src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/MultilineJsonStringConverter.cs index b6e89d6..ebaf66d 100644 --- a/src/WarHub.ArmouryModel.ProjectModel/MultilineJsonStringConverter.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/Serialization/MultilineJsonStringConverter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace WarHub.ArmouryModel.ProjectModel +namespace WarHub.ArmouryModel.Workspaces.Gitree.Serialization { /// /// Converts multiline strings into arrays of strings. @@ -17,7 +17,7 @@ public override bool CanConvert(Type objectType) return objectType == typeof(string); } - public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null || (reader.TokenType != JsonToken.StartArray && reader.TokenType != JsonToken.String)) { diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/SourceNodeToGitreeConverter.cs b/src/WarHub.ArmouryModel.Workspaces.Gitree/SourceNodeToGitreeConverter.cs index f915ef5..1870894 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/SourceNodeToGitreeConverter.cs +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/SourceNodeToGitreeConverter.cs @@ -41,7 +41,7 @@ Option CreateListOption(ChildInfo info) var treeNodes = CreateList(list.NodeList); var name = Gitree.ChildListAliases.TryGetValue(info.Name, out var alias) ? alias : info.Name; - return new GitreeListNode(name, treeNodes).Some(); + return new GitreeListNode(name) { Items = treeNodes }.Some(); } return default; } @@ -67,7 +67,7 @@ GitreeNode AssignIdentifiers(GitreeNode prevTreeNode, GitreeNode treeNode) var newMeta = blob.Meta .WithIdentifier(identifier) .WithPrevIdentifier(prevTreeNode?.Datablob.Meta.Identifier); - return treeNode.WithDatablob(blob.WithMeta(newMeta)); + return treeNode with { Datablob = blob.WithMeta(newMeta) }; } string GetUniqueIdentifier(SourceNode node) diff --git a/src/WarHub.ArmouryModel.Workspaces.Gitree/WarHub.ArmouryModel.Workspaces.Gitree.csproj b/src/WarHub.ArmouryModel.Workspaces.Gitree/WarHub.ArmouryModel.Workspaces.Gitree.csproj index 01fcd99..c86c007 100644 --- a/src/WarHub.ArmouryModel.Workspaces.Gitree/WarHub.ArmouryModel.Workspaces.Gitree.csproj +++ b/src/WarHub.ArmouryModel.Workspaces.Gitree/WarHub.ArmouryModel.Workspaces.Gitree.csproj @@ -9,7 +9,6 @@ - diff --git a/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/Foundation/SourceKind.cs b/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/Foundation/SourceKind.cs index 9b4b5b3..9a4e220 100644 --- a/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/Foundation/SourceKind.cs +++ b/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/Foundation/SourceKind.cs @@ -4,6 +4,10 @@ public enum SourceKind { Unknown, + Gamesystem, GamesystemList, + + Catalogue, CatalogueList, + Class1, Class1List, Container, ContainerList, diff --git a/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode.csproj b/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode.csproj index 5fe3e0d..79e82a2 100644 --- a/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode.csproj +++ b/tests/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode/WarHub.ArmouryModel.Source.CodeGeneration.Tests.GeneratedCode.csproj @@ -11,6 +11,10 @@ + + + +