diff --git a/Sources/Directory.Packages.props b/Sources/Directory.Packages.props index 0814660..20cebdb 100644 --- a/Sources/Directory.Packages.props +++ b/Sources/Directory.Packages.props @@ -4,11 +4,12 @@ - - + + - - + + + @@ -28,15 +29,15 @@ - + - + - - - + + + \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem.Tests/Kysect.DotnetProjectSystem.Tests.csproj b/Sources/Kysect.DotnetProjectSystem.Tests/Kysect.DotnetProjectSystem.Tests.csproj index f5024e8..8c89745 100644 --- a/Sources/Kysect.DotnetProjectSystem.Tests/Kysect.DotnetProjectSystem.Tests.csproj +++ b/Sources/Kysect.DotnetProjectSystem.Tests/Kysect.DotnetProjectSystem.Tests.csproj @@ -15,6 +15,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Sources/Kysect.DotnetProjectSystem.Tests/Projects/DirectoryBuildTargetFileTests.cs b/Sources/Kysect.DotnetProjectSystem.Tests/Projects/DirectoryBuildTargetFileTests.cs new file mode 100644 index 0000000..1d50f18 --- /dev/null +++ b/Sources/Kysect.DotnetProjectSystem.Tests/Projects/DirectoryBuildTargetFileTests.cs @@ -0,0 +1,27 @@ +using Kysect.DotnetProjectSystem.Projects; +using Microsoft.Language.Xml; + +namespace Kysect.DotnetProjectSystem.Tests.Projects; + +public class DirectoryBuildTargetFileTests +{ + [Fact] + public void Create_FileWithTarget_ReturnFileWithTarget() + { + var content = """ + + + + false + + + + """; + + var dotnetBuildTargetFile = DirectoryBuildTargetFile.Create(content); + + IReadOnlyCollection targets = dotnetBuildTargetFile.GetTargets(); + + targets.Should().HaveCount(1); + } +} \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierFactoryTests.cs b/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierFactoryTests.cs index 808c6da..75301f8 100644 --- a/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierFactoryTests.cs +++ b/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierFactoryTests.cs @@ -109,4 +109,48 @@ public void Create_ForSolutionWithoutDirectoryFiles_DirectoryFileMustBeCreatedOn .ToXmlString(_syntaxFormatter) .Should().Be(directoryPackagesPropsContent); } + + [Fact] + public void Create_SolutionWithDirectoryBuildTargets_ReturnTargetFileContent() + { + string directoryBuildTargetContent = """ + + + + false + + + + """; + + _solutionFileStructureBuilderFactory.Create("Solution") + .AddDirectoryBuildTargets(directoryBuildTargetContent) + .Save(_currentPath); + + DotnetSolutionModifier solutionModifier = _solutionModifierFactory.Create("Solution.sln"); + + solutionModifier + .GetOrCreateDirectoryBuildTargetFile() + .ToXmlString(_syntaxFormatter) + .Should().Be(directoryBuildTargetContent); + } + + [Fact] + public void Create_SolutionWithoutDirectoryBuildTargets_ReturnEmptyTargetFileContent() + { + string directoryBuildTargetContent = """ + + + """; + + _solutionFileStructureBuilderFactory.Create("Solution") + .Save(_currentPath); + + DotnetSolutionModifier solutionModifier = _solutionModifierFactory.Create("Solution.sln"); + + solutionModifier + .GetOrCreateDirectoryBuildTargetFile() + .ToXmlString(_syntaxFormatter) + .Should().Be(directoryBuildTargetContent); + } } \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierTests.cs b/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierTests.cs index b2ecef7..bb8277e 100644 --- a/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierTests.cs +++ b/Sources/Kysect.DotnetProjectSystem.Tests/SolutionModification/DotnetSolutionModifierTests.cs @@ -1,9 +1,11 @@ using Kysect.DotnetProjectSystem.FileStructureBuilding; using Kysect.DotnetProjectSystem.Parsing; +using Kysect.DotnetProjectSystem.Projects; using Kysect.DotnetProjectSystem.SolutionModification; using Kysect.DotnetProjectSystem.Tests.Asserts; using Kysect.DotnetProjectSystem.Tools; using Kysect.DotnetProjectSystem.Xml; +using Microsoft.Language.Xml; using System.IO.Abstractions.TestingHelpers; namespace Kysect.DotnetProjectSystem.Tests.SolutionModification; @@ -83,4 +85,31 @@ public void Save_AfterAddingValueToDirectoryBuildProps_FileSaved() .ShouldExists() .ShouldHaveContent(expectedContent); } + + [Fact] + public void Save_AfterModifyDirectoryBuildTargets_FileSaved() + { + var expectedContent = """ + + + + """; + + _solutionFileStructureBuilderFactory.Create("Solution") + .AddDirectoryBuildTargets(DirectoryBuildTargetFile.CreateEmpty()) + .Save(_currentPath); + + DotnetSolutionModifier solutionModifier = _solutionModifierFactory.Create("Solution.sln"); + solutionModifier + .GetOrCreateDirectoryBuildTargetFile() + .UpdateDocument(d => d.ReplaceNode( + d.Root.AsSyntaxElement.AsNode, + d.Root.AsSyntaxElement.AddChild(ExtendedSyntaxFactory.XmlElement("NewNode")).AsNode)); + solutionModifier.Save(); + + _fileSystemAsserts + .File(SolutionItemNameConstants.DirectoryBuildTargets) + .ShouldExists() + .ShouldHaveContent(expectedContent); + } } \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem/FileStructureBuilding/SolutionFileStructureBuilder.cs b/Sources/Kysect.DotnetProjectSystem/FileStructureBuilding/SolutionFileStructureBuilder.cs index 5a04a91..36ba653 100644 --- a/Sources/Kysect.DotnetProjectSystem/FileStructureBuilding/SolutionFileStructureBuilder.cs +++ b/Sources/Kysect.DotnetProjectSystem/FileStructureBuilding/SolutionFileStructureBuilder.cs @@ -16,6 +16,7 @@ public class SolutionFileStructureBuilder private readonly List _files; private DirectoryBuildPropsFile? _directoryBuildPropsFile; private DirectoryPackagesPropsFile? _directoryPackagesPropsFile; + private DirectoryBuildTargetFile? _directoryBuildTargetFile; public SolutionFileStructureBuilder(IFileSystem fileSystem, XmlDocumentSyntaxFormatter syntaxFormatter, string solutionName) { @@ -66,11 +67,22 @@ public SolutionFileStructureBuilder AddDirectoryPackagesProps(DirectoryPackagesP return this; } + public SolutionFileStructureBuilder AddDirectoryBuildTargets(string content) + { + return AddDirectoryBuildTargets(DirectoryBuildTargetFile.Create(content)); + } + + public SolutionFileStructureBuilder AddDirectoryBuildTargets(DirectoryBuildTargetFile directoryBuildTargetFile) + { + _directoryBuildTargetFile = directoryBuildTargetFile; + return this; + } + public void Save(string solutionDirectory) { string solutionFileContent = CreateSolutionFile(_fileSystem); - DirectoryExtensions.EnsureDirectoryExists(_fileSystem, solutionDirectory); + _fileSystem.EnsureDirectoryExists(solutionDirectory); _fileSystem.File.WriteAllText(_fileSystem.Path.Combine(solutionDirectory, $"{_solutionName}.sln"), solutionFileContent); if (_directoryBuildPropsFile is not null) @@ -79,6 +91,9 @@ public void Save(string solutionDirectory) if (_directoryPackagesPropsFile is not null) AddFile([SolutionItemNameConstants.DirectoryPackagesProps], _directoryPackagesPropsFile.File.ToXmlString(_syntaxFormatter)); + if (_directoryBuildTargetFile is not null) + AddFile([SolutionItemNameConstants.DirectoryBuildTargets], _directoryBuildTargetFile.ToXmlString(_syntaxFormatter)); + foreach (SolutionStructureElement? solutionFileInfo in _files) { string partialFilePath = _fileSystem.Path.Combine(solutionFileInfo.Path.ToArray()); diff --git a/Sources/Kysect.DotnetProjectSystem/Projects/DirectoryBuildTargetFile.cs b/Sources/Kysect.DotnetProjectSystem/Projects/DirectoryBuildTargetFile.cs new file mode 100644 index 0000000..2d5ab8c --- /dev/null +++ b/Sources/Kysect.DotnetProjectSystem/Projects/DirectoryBuildTargetFile.cs @@ -0,0 +1,58 @@ +using Kysect.CommonLib.BaseTypes.Extensions; +using Kysect.DotnetProjectSystem.Xml; +using Microsoft.Language.Xml; + +namespace Kysect.DotnetProjectSystem.Projects; + +public class DirectoryBuildTargetFile +{ + private XmlDocumentSyntax _content; + + public static DirectoryBuildTargetFile CreateEmpty() + { + string contentTemplate = + """ + + + """; + + return Create(contentTemplate); + } + + public static DirectoryBuildTargetFile Create(string content) + { + XmlDocumentSyntax xmlDocumentSyntax = Parser.ParseText(content); + if (xmlDocumentSyntax.RootSyntax is null) + return CreateEmpty(); + + return new DirectoryBuildTargetFile(xmlDocumentSyntax); + } + + public DirectoryBuildTargetFile(XmlDocumentSyntax content) + { + _content = content; + } + + public IReadOnlyCollection GetTargets() + { + return GetNodesByName("Target"); + } + + public IReadOnlyCollection GetNodesByName(string name) + { + return _content.GetNodesByName(name); + } + + public void UpdateDocument(Func morphism) + { + morphism.ThrowIfNull(); + _content = morphism(_content); + } + + public string ToXmlString(XmlDocumentSyntaxFormatter formatter) + { + formatter.ThrowIfNull(); + + return formatter.Format(_content).ToFullString(); + } +} \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifier.cs b/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifier.cs index 42b5420..586be92 100644 --- a/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifier.cs +++ b/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifier.cs @@ -13,6 +13,7 @@ public class DotnetSolutionModifier private readonly IFileSystem _fileSystem; private DirectoryBuildPropsFile? _directoryBuildPropsModifier; private DirectoryPackagesPropsFile? _directoryPackagePropsModifier; + private DirectoryBuildTargetFile? _directoryBuildTargetFile; private readonly Dictionary _projects; public IReadOnlyCollection> Projects => _projects; @@ -29,10 +30,17 @@ public DirectoryPackagesPropsFile GetOrCreateDirectoryPackagePropsModifier() return _directoryPackagePropsModifier; } + public DirectoryBuildTargetFile GetOrCreateDirectoryBuildTargetFile() + { + _directoryBuildTargetFile ??= DirectoryBuildTargetFile.CreateEmpty(); + return _directoryBuildTargetFile; + } + public DotnetSolutionModifier( Dictionary projects, DirectoryBuildPropsFile? directoryBuildPropsModifier, DirectoryPackagesPropsFile? directoryPackagePropsModifier, + DirectoryBuildTargetFile? directoryBuildTargetsFile, IFileSystem fileSystem, IFileInfo solutionPath, XmlDocumentSyntaxFormatter syntaxFormatter) @@ -40,6 +48,7 @@ public DotnetSolutionModifier( _projects = projects; _directoryBuildPropsModifier = directoryBuildPropsModifier; _directoryPackagePropsModifier = directoryPackagePropsModifier; + _directoryBuildTargetFile = directoryBuildTargetsFile; _fileSystem = fileSystem; _solutionPath = solutionPath; _syntaxFormatter = syntaxFormatter; @@ -61,6 +70,12 @@ public void Save() _fileSystem.File.WriteAllText(directoryPackagesPropsPath, _directoryPackagePropsModifier.File.ToXmlString(_syntaxFormatter)); } + if (_directoryBuildTargetFile is not null) + { + string directoryPackagesPropsPath = _fileSystem.Path.Combine(_solutionPath.Directory.FullName, SolutionItemNameConstants.DirectoryBuildTargets); + _fileSystem.File.WriteAllText(directoryPackagesPropsPath, _directoryBuildTargetFile.ToXmlString(_syntaxFormatter)); + } + foreach (KeyValuePair projectModifier in _projects) { _fileSystem.File.WriteAllText(projectModifier.Key, projectModifier.Value.File.ToXmlString(_syntaxFormatter)); diff --git a/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifierFactory.cs b/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifierFactory.cs index 30a40a7..b5ed994 100644 --- a/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifierFactory.cs +++ b/Sources/Kysect.DotnetProjectSystem/SolutionModification/DotnetSolutionModifierFactory.cs @@ -28,12 +28,14 @@ public DotnetSolutionModifier Create(string solutionPath) DirectoryBuildPropsFile? directoryBuildPropsModifier = TryCreateDirectoryBuildPropsFile(solutionFileInfo); DirectoryPackagesPropsFile? directoryPackagesPropsFile = TryCreateDirectoryPackagesPropsFile(solutionFileInfo); + DirectoryBuildTargetFile? directoryBuildTargetsFile = TryCreateDirectoryBuildTargetsFile(solutionFileInfo); Dictionary projects = CreateProjectModifiers(solutionFileInfo); return new DotnetSolutionModifier( projects, directoryBuildPropsModifier, directoryPackagesPropsFile, + directoryBuildTargetsFile, _fileSystem, solutionFileInfo, _syntaxFormatter); @@ -63,6 +65,22 @@ public DotnetSolutionModifier Create(string solutionPath) return new DirectoryPackagesPropsFile(dotnetProjectFile); } + private DirectoryBuildTargetFile? TryCreateDirectoryBuildTargetsFile(IFileInfo solutionFileInfo) + { + solutionFileInfo.Directory.ThrowIfNull(); + + string path = _fileSystem.Path.Combine(solutionFileInfo.Directory.FullName, SolutionItemNameConstants.DirectoryBuildTargets); + if (!_fileSystem.File.Exists(path)) + return null; + + string fileContent = + _fileSystem.File.Exists(path) + ? _fileSystem.File.ReadAllText(path) + : string.Empty; + + return DirectoryBuildTargetFile.Create(fileContent); + } + private Dictionary CreateProjectModifiers(IFileInfo solutionFileInfo) { solutionFileInfo.Directory.ThrowIfNull(); diff --git a/Sources/Kysect.DotnetProjectSystem/Tools/SolutionItemNameConstants.cs b/Sources/Kysect.DotnetProjectSystem/Tools/SolutionItemNameConstants.cs index 41caaf7..6a7b27f 100644 --- a/Sources/Kysect.DotnetProjectSystem/Tools/SolutionItemNameConstants.cs +++ b/Sources/Kysect.DotnetProjectSystem/Tools/SolutionItemNameConstants.cs @@ -4,4 +4,5 @@ public static class SolutionItemNameConstants { public const string DirectoryBuildProps = "Directory.Build.props"; public const string DirectoryPackagesProps = "Directory.Packages.props"; + public const string DirectoryBuildTargets = "Directory.Build.targets"; } \ No newline at end of file diff --git a/Sources/Kysect.DotnetProjectSystem/Xml/XmlElementSyntaxExtensions.cs b/Sources/Kysect.DotnetProjectSystem/Xml/XmlElementSyntaxExtensions.cs deleted file mode 100644 index aded487..0000000 --- a/Sources/Kysect.DotnetProjectSystem/Xml/XmlElementSyntaxExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Kysect.CommonLib.BaseTypes.Extensions; -using Microsoft.Language.Xml; - -namespace Kysect.DotnetProjectSystem.Xml; - -public static class XmlElementSyntaxExtensions -{ - public static IXmlElementSyntax RemoveAllChild(this IXmlElementSyntax xmlElementSyntax) - { - xmlElementSyntax.ThrowIfNull(); - - IXmlElementSyntax? child = xmlElementSyntax.Elements.FirstOrDefault(); - - while (child is not null) - { - xmlElementSyntax = xmlElementSyntax.RemoveChild(child); - child = xmlElementSyntax.Elements.FirstOrDefault(); - } - - return xmlElementSyntax; - } -} \ No newline at end of file