diff --git a/Packages.props b/Packages.props
index cbb091d..f0c566e 100644
--- a/Packages.props
+++ b/Packages.props
@@ -2,10 +2,13 @@
+
+
+
diff --git a/README.md b/README.md
index 1ea654e..5197265 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[](https://www.nuget.org/packages/MSBuild.ProjectCreation)
[](https://www.nuget.org/packages/MSBuild.ProjectCreation)
-This class library is a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) for generating MSBuild projects. Its primarily for unit tests that need MSBuild projects to do their testing.
+This class library is a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) for generating MSBuild projects and NuGet package repositories. Its primarily for unit tests that need MSBuild projects to do their testing.
## Example
You want to test a custom MSBuild task that you are building so your unit tests need to generate a project that you can build with MSBuild. The following code would generate the necessary project:
@@ -125,7 +125,7 @@ Your extension methods should extend the `ProjectCreatorTemplates` class so they
```C#
public static class ExtensionMethods
{
- public ProjectCreator LogsMessage(this ProjectCreatorTemplates template, string text, string path = null, MessageImportance ? importance = null, string condition = null)
+ public ProjectCreator LogsMessage(this ProjectCreatorTemplates template, string text, string path = null, MessageImportance ? importance = null, string condition = null)
{
return ProjectCreator.Create(path)
.TaskMessage(text, importance, condition);
@@ -158,3 +158,32 @@ And the resulting project would look like this:
```
+
+# Package Repositories
+NuGet and MSBuild are very tightly coupled and a lot of times you need packages available when building projects.
+
+## Example
+
+Create a package repository with a package that supports two target frameworks:
+
+```C#
+PackageRepository.Create(rootPath)
+ .Package("MyPackage", "1.2.3", out PackageIdentify package)
+ .Library("net472")
+ .Library("netstandard2.0");
+```
+
+The resulting package would have a `lib\net472\MyPackage.dll` and `lib\netstandard2.0\MyPackage.dll` class library. This allows you to restore and build projects that consume the packages
+
+```C#
+PackageRepository.Create(rootPath)
+ .Package("MyPackage", "1.0.0", out PackageIdentify package)
+ .Library("netstandard2.0");
+
+ProjectCreator.Templates.SdkCsproj()
+ .ItemPackageReference(package)
+ .Save(Path.Combine(rootPath, "ClassLibraryA", "ClassLibraryA.csproj"))
+ .TryBuild(restore: true, out bool result, out BuildOutput buildOutput);
+```
+
+The result would be a project that references the `MyPackage` package and would restore and build accordingly.
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/BuildTests.cs b/src/MSBuildProjectCreator.UnitTests/BuildTests.cs
index dc2bb2b..b99cfc4 100644
--- a/src/MSBuildProjectCreator.UnitTests/BuildTests.cs
+++ b/src/MSBuildProjectCreator.UnitTests/BuildTests.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT license.
using Microsoft.Build.Execution;
+using NuGet.Packaging.Core;
using Shouldly;
using System.Collections.Generic;
using System.IO;
@@ -13,6 +14,29 @@ namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests
{
public class BuildTests : TestBase
{
+#if NETCOREAPP
+ [Fact(Skip = "Does not work yet on .NET Core")]
+#else
+ [Fact]
+#endif
+ public void BuildCanConsumePackage()
+ {
+ PackageRepository packageRepository = PackageRepository.Create(TestRootPath)
+ .Package("PackageB", "1.0", out PackageIdentity packageB)
+ .Library("net45")
+ .Package("PackageA", "1.0.0", out PackageIdentity packageA)
+ .Dependency(packageB, "net45")
+ .Library("net45");
+
+ ProjectCreator.Templates.SdkCsproj(
+ targetFramework: "net45")
+ .ItemPackageReference(packageA)
+ .Save(Path.Combine(TestRootPath, "ClassLibraryA", "ClassLibraryA.csproj"))
+ .TryBuild(restore: true, out bool result, out BuildOutput buildOutput);
+
+ result.ShouldBeTrue(buildOutput.GetConsoleLog());
+ }
+
[Fact]
public void BuildTargetOutputsTest()
{
@@ -33,21 +57,6 @@ public void BuildTargetOutputsTest()
item.Value.Items.Select(i => i.ItemSpec).ShouldBe(new[] { "E32099C7AF4E481885B624E5600C718A", "7F38E64414104C6182F492B535926187" });
}
- [Fact]
- public void RestoreTargetCanBeRun()
- {
- ProjectCreator
- .Create(Path.Combine(TestRootPath, "project1.proj"))
- .Target("Restore")
- .TaskMessage("312D2E6ABDDC4735B437A016CED1A68E", Framework.MessageImportance.High, condition: "'$(MSBuildRestoreSessionId)' != ''")
- .TaskError("MSBuildRestoreSessionId was not defined", condition: "'$(MSBuildRestoreSessionId)' == ''")
- .TryRestore(out bool result, out BuildOutput buildOutput);
-
- result.ShouldBeTrue(buildOutput.GetConsoleLog());
-
- buildOutput.MessageEvents.High.ShouldContain(i => i.Message == "312D2E6ABDDC4735B437A016CED1A68E" && i.Importance == Framework.MessageImportance.High, buildOutput.GetConsoleLog());
- }
-
[Fact]
public void CanRestoreAndBuild()
{
@@ -66,5 +75,20 @@ public void CanRestoreAndBuild()
buildOutput.MessageEvents.High.ShouldContain(i => i.Message == "Building...", buildOutput.GetConsoleLog());
}
+
+ [Fact]
+ public void RestoreTargetCanBeRun()
+ {
+ ProjectCreator
+ .Create(Path.Combine(TestRootPath, "project1.proj"))
+ .Target("Restore")
+ .TaskMessage("312D2E6ABDDC4735B437A016CED1A68E", Framework.MessageImportance.High, condition: "'$(MSBuildRestoreSessionId)' != ''")
+ .TaskError("MSBuildRestoreSessionId was not defined", condition: "'$(MSBuildRestoreSessionId)' == ''")
+ .TryRestore(out bool result, out BuildOutput buildOutput);
+
+ result.ShouldBeTrue(buildOutput.GetConsoleLog());
+
+ buildOutput.MessageEvents.High.ShouldContain(i => i.Message == "312D2E6ABDDC4735B437A016CED1A68E" && i.Importance == Framework.MessageImportance.High, buildOutput.GetConsoleLog());
+ }
}
}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/ExtensionMethods.cs b/src/MSBuildProjectCreator.UnitTests/ExtensionMethods.cs
new file mode 100644
index 0000000..6da16ba
--- /dev/null
+++ b/src/MSBuildProjectCreator.UnitTests/ExtensionMethods.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Shouldly;
+using System.IO;
+
+namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests
+{
+ internal static class ExtensionMethods
+ {
+ public static FileInfo ShouldExist(this FileInfo fileInfo)
+ {
+ if (!fileInfo.Exists)
+ {
+ throw new ShouldAssertException($"The file \"{fileInfo.FullName}\" should exist but does not");
+ }
+
+ return fileInfo;
+ }
+
+ public static DirectoryInfo ShouldExist(this DirectoryInfo directoryInfo)
+ {
+ if (!directoryInfo.Exists)
+ {
+ throw new ShouldAssertException($"The directory \"{directoryInfo.FullName}\" should exist but does not");
+ }
+
+ return directoryInfo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/BuildLogicTests.cs b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/BuildLogicTests.cs
new file mode 100644
index 0000000..a9178f7
--- /dev/null
+++ b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/BuildLogicTests.cs
@@ -0,0 +1,114 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Microsoft.Build.Utilities.ProjectCreation.Resources;
+using Shouldly;
+using System;
+using System.IO;
+using Xunit;
+
+namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests.PackageRepositoryTests
+{
+ public class BuildLogicTests : TestBase
+ {
+ [Fact]
+ public void BuildLogicRequiresPackage()
+ {
+ InvalidOperationException exception;
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildMultiTargetingProps();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildMultiTargetingTargets();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildTransitiveProps();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildTransitiveTargets();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildProps();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+
+ exception = Should.Throw(() =>
+ {
+ PackageRepository.Create(TestRootPath)
+ .BuildTargets();
+ });
+
+ exception.Message.ShouldBe(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+ }
+
+ [Fact]
+ public void BuildMultiTargetingTest()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "2.0")
+ .BuildMultiTargetingProps(out ProjectCreator buildMultiTargetingPropsProject)
+ .BuildMultiTargetingTargets(out ProjectCreator buildMultiTargetingTargetsProject);
+
+ buildMultiTargetingPropsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\buildMultiTargeting\PackageA.props");
+ buildMultiTargetingTargetsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\buildMultiTargeting\PackageA.targets");
+
+ File.Exists(buildMultiTargetingPropsProject.FullPath).ShouldBeTrue();
+ File.Exists(buildMultiTargetingTargetsProject.FullPath).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void BuildPropsTest()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "2.0")
+ .BuildProps(out ProjectCreator buildPropsProject)
+ .BuildTargets(out ProjectCreator buildTargetsProject);
+
+ buildPropsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\build\PackageA.props");
+ buildTargetsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\build\PackageA.targets");
+
+ File.Exists(buildPropsProject.FullPath).ShouldBeTrue();
+ File.Exists(buildTargetsProject.FullPath).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void BuildTransitiveTest()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "2.0")
+ .BuildTransitiveProps(out ProjectCreator buildTransitivePropsProject)
+ .BuildTransitiveTargets(out ProjectCreator buildTransitiveTargetsProject);
+
+ buildTransitivePropsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\buildTransitive\PackageA.props");
+ buildTransitiveTargetsProject.FullPath.ShouldBe($@"{TestRootPath}\.nuget\packages\packagea\2.0.0\buildTransitive\PackageA.targets");
+
+ File.Exists(buildTransitivePropsProject.FullPath).ShouldBeTrue();
+ File.Exists(buildTransitiveTargetsProject.FullPath).ShouldBeTrue();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/DependencyTests.cs b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/DependencyTests.cs
new file mode 100644
index 0000000..c15c185
--- /dev/null
+++ b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/DependencyTests.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Frameworks;
+using NuGet.Packaging;
+using NuGet.Packaging.Core;
+using NuGet.Versioning;
+using Shouldly;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Xunit;
+
+namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests.PackageRepositoryTests
+{
+ public class DependencyTests : TestBase
+ {
+ [Fact]
+ public void CanAddDependenciesToMultipleGroups()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity package)
+ .Dependency("PackageB", "1.0.0", "net45")
+ .Dependency("PackageB", "1.0.0", "net46")
+ .Dependency("PackageB", "1.0.0", "netstandard2.0");
+
+ ValidatePackageDependencies(
+ package,
+ new List
+ {
+ new PackageDependencyGroup(
+ FrameworkConstants.CommonFrameworks.Net45,
+ new List
+ {
+ new PackageDependency("PackageB", VersionRange.Parse("1.0.0")),
+ }),
+ new PackageDependencyGroup(
+ FrameworkConstants.CommonFrameworks.Net46,
+ new List
+ {
+ new PackageDependency("PackageB", VersionRange.Parse("1.0.0")),
+ }),
+ new PackageDependencyGroup(
+ FrameworkConstants.CommonFrameworks.NetStandard20,
+ new List
+ {
+ new PackageDependency("PackageB", VersionRange.Parse("1.0.0")),
+ }),
+ });
+ }
+
+ [Fact]
+ public void CanAddMultipleDependenciesToSameGroup()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity package)
+ .Dependency("PackageB", "1.0.0", "net45")
+ .Dependency("PackageC", "1.1.0", "net45")
+ .Dependency("PackageD", "1.2.0", "net45");
+
+ ValidatePackageDependencies(
+ package,
+ new List
+ {
+ new PackageDependencyGroup(
+ FrameworkConstants.CommonFrameworks.Net45,
+ new List
+ {
+ new PackageDependency("PackageB", VersionRange.Parse("1.0.0")),
+ new PackageDependency("PackageC", VersionRange.Parse("1.1.0")),
+ new PackageDependency("PackageD", VersionRange.Parse("1.2.0")),
+ }),
+ });
+ }
+
+ private void ValidatePackageDependencies(PackageIdentity package, IEnumerable expectedDependencyGroups)
+ {
+ FileInfo nuspecFile = new FileInfo(VersionFolderPathResolver.GetManifestFilePath(package.Id, package.Version));
+
+ nuspecFile.ShouldExist();
+
+ using (FileStream stream = File.OpenRead(nuspecFile.FullName))
+ {
+ Manifest manifest = Manifest.ReadFrom(stream, validateSchema: false);
+
+ List dependencyGroups = manifest.Metadata.DependencyGroups.ToList();
+
+ dependencyGroups.ShouldBe(expectedDependencyGroups);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/LibraryTests.cs b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/LibraryTests.cs
new file mode 100644
index 0000000..89e23b2
--- /dev/null
+++ b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/LibraryTests.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Frameworks;
+using NuGet.Packaging.Core;
+using Shouldly;
+using System;
+using System.IO;
+using System.Reflection;
+using Xunit;
+
+namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests.PackageRepositoryTests
+{
+ public class LibraryTests : TestBase
+ {
+ [Fact]
+ public void BasicLibrary()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity packageA)
+ .Library(FrameworkConstants.CommonFrameworks.Net45);
+
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.Net45);
+ }
+
+ [Fact]
+ public void LibraryWithVersion()
+ {
+ const string assemblyVersion = "2.3.4.5";
+
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity packageA)
+ .Library(FrameworkConstants.CommonFrameworks.Net45, assemblyVersion: assemblyVersion);
+
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.Net45, version: "2.3.4.5");
+ }
+
+ [Fact]
+ public void MultipleLibrariesMultipleTargetFrameworks()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity packageA)
+ .Library(FrameworkConstants.CommonFrameworks.Net45)
+ .Library(FrameworkConstants.CommonFrameworks.NetStandard20);
+
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.Net45);
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.NetStandard20);
+ }
+
+ [Fact]
+ public void MultipleLibrariesSameTargetFramework()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageA", "1.0.0", out PackageIdentity packageA)
+ .Library(FrameworkConstants.CommonFrameworks.Net45, filename: null)
+ .Library(FrameworkConstants.CommonFrameworks.Net45, filename: "CustomAssembly.dll");
+
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.Net45);
+ VerifyAssembly(packageA, FrameworkConstants.CommonFrameworks.Net45, assemblyFileName: "CustomAssembly.dll");
+ }
+
+ private void VerifyAssembly(PackageIdentity packageIdentity, NuGetFramework targetFramework, string assemblyFileName = null, string version = null)
+ {
+ DirectoryInfo packageDirectory = new DirectoryInfo(VersionFolderPathResolver.GetInstallPath(packageIdentity.Id, packageIdentity.Version))
+ .ShouldExist();
+
+ DirectoryInfo libDirectory = new DirectoryInfo(Path.Combine(packageDirectory.FullName, "lib", targetFramework.GetShortFolderName()))
+ .ShouldExist();
+
+ FileInfo classLibrary = new FileInfo(Path.Combine(libDirectory.FullName, assemblyFileName ?? $"{packageIdentity.Id}.dll"))
+ .ShouldExist();
+
+ AssemblyName assemblyName = AssemblyName.GetAssemblyName(classLibrary.FullName);
+
+ assemblyName.Version.ShouldBe(version == null ? new Version(1, 0, 0, 0) : Version.Parse(version));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/PackageTests.cs b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/PackageTests.cs
new file mode 100644
index 0000000..715f600
--- /dev/null
+++ b/src/MSBuildProjectCreator.UnitTests/PackageRepositoryTests/PackageTests.cs
@@ -0,0 +1,117 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Packaging;
+using NuGet.Packaging.Core;
+using NuGet.Versioning;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Xunit;
+
+namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests.PackageRepositoryTests
+{
+ public class PackageTests : TestBase
+ {
+ [Fact]
+ public void BasicPackage()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package("PackageD", "1.2.3-beta", out PackageIdentity package);
+
+ package.ShouldNotBeNull();
+
+ package.Id.ShouldBe("PackageD");
+ package.Version.ShouldBe(NuGetVersion.Parse("1.2.3-beta"));
+
+ FileInfo manifestFilePath = new FileInfo(VersionFolderPathResolver.GetManifestFilePath(package.Id, package.Version))
+ .ShouldExist();
+
+ using (Stream stream = File.OpenRead(manifestFilePath.FullName))
+ {
+ Manifest manifest = Manifest.ReadFrom(stream, validateSchema: true);
+
+ manifest.Metadata.Authors.ShouldBe(new[] { "UserA" });
+ manifest.Metadata.Description.ShouldBe("Description");
+ manifest.Metadata.DevelopmentDependency.ShouldBeFalse();
+ manifest.Metadata.Id.ShouldBe("PackageD");
+ manifest.Metadata.RequireLicenseAcceptance.ShouldBeFalse();
+ }
+ }
+
+ [Fact]
+ public void CanSetAllPackageProperties()
+ {
+ PackageRepository.Create(TestRootPath)
+ .Package(
+ name: "PackageD",
+ version: "1.2.3",
+ package: out PackageIdentity package,
+ authors: "UserA;UserB",
+ description: "Custom description",
+ copyright: "Copyright 2000",
+ developmentDependency: true,
+#if !NET46
+ icon: @"some\icon.jpg",
+#endif
+ iconUrl: "https://icon.url",
+ language: "Pig latin",
+ licenseMetadata: new LicenseMetadata(LicenseType.Expression, "MIT", null, null, Version.Parse("1.0.0")),
+ owners: "Owner1;Owner2",
+ packageTypes: new List { PackageType.Dependency, PackageType.DotnetCliTool },
+ projectUrl: "https://project.url",
+ releaseNotes: "Release notes for PackageD",
+ repositoryType: "Git",
+ repositoryUrl: "https://repository.url",
+ repositoryBranch: "Branch1000",
+ repositoryCommit: "Commit14",
+ requireLicenseAcceptance: true,
+ serviceable: true,
+ summary: "Summary of PackageD",
+ tags: "Tag1 Tag2 Tag3",
+ title: "Title of PackageD");
+
+ package.ShouldNotBeNull();
+
+ package.Id.ShouldBe("PackageD");
+ package.Version.ShouldBe(NuGetVersion.Parse("1.2.3"));
+
+ FileInfo manifestFilePath = new FileInfo(VersionFolderPathResolver.GetManifestFilePath(package.Id, package.Version))
+ .ShouldExist();
+
+ using (Stream stream = File.OpenRead(manifestFilePath.FullName))
+ {
+ Manifest manifest = Manifest.ReadFrom(stream, validateSchema: true);
+
+ manifest.Metadata.Authors.ShouldBe(new[] { "UserA", "UserB" });
+ manifest.Metadata.Copyright.ShouldBe("Copyright 2000");
+ manifest.Metadata.Description.ShouldBe("Custom description");
+ manifest.Metadata.DevelopmentDependency.ShouldBeTrue();
+#if !NET46
+ manifest.Metadata.Icon.ShouldBe(@"some\icon.jpg");
+#endif
+ manifest.Metadata.IconUrl.ShouldBe(new Uri("https://icon.url"));
+ manifest.Metadata.Id.ShouldBe("PackageD");
+ manifest.Metadata.Language.ShouldBe("Pig latin");
+ manifest.Metadata.LicenseMetadata.License.ShouldBe("MIT");
+ manifest.Metadata.LicenseMetadata.Type.ShouldBe(LicenseType.Expression);
+ manifest.Metadata.LicenseMetadata.Version.ShouldBe(Version.Parse("1.0.0"));
+ manifest.Metadata.Owners.ShouldBe(new[] { "Owner1", "Owner2" });
+ manifest.Metadata.PackageTypes.ShouldBe(new[] { PackageType.Dependency, PackageType.DotnetCliTool });
+ manifest.Metadata.ProjectUrl.ShouldBe(new Uri("https://project.url"));
+ manifest.Metadata.ReleaseNotes.ShouldBe("Release notes for PackageD");
+ manifest.Metadata.Repository.Branch.ShouldBe("Branch1000");
+ manifest.Metadata.Repository.Commit.ShouldBe("Commit14");
+ manifest.Metadata.Repository.Type.ShouldBe("Git");
+ manifest.Metadata.Repository.Url.ShouldBe("https://repository.url");
+ manifest.Metadata.RequireLicenseAcceptance.ShouldBeTrue();
+ manifest.Metadata.Serviceable.ShouldBeTrue();
+ manifest.Metadata.Summary.ShouldBe("Summary of PackageD");
+ manifest.Metadata.Tags.ShouldBe("Tag1 Tag2 Tag3");
+ manifest.Metadata.Title.ShouldBe("Title of PackageD");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator.UnitTests/TestBase.cs b/src/MSBuildProjectCreator.UnitTests/TestBase.cs
index 102398e..14c749a 100644
--- a/src/MSBuildProjectCreator.UnitTests/TestBase.cs
+++ b/src/MSBuildProjectCreator.UnitTests/TestBase.cs
@@ -2,15 +2,23 @@
//
// Licensed under the MIT license.
+using NuGet.Packaging;
using System;
using System.IO;
namespace Microsoft.Build.Utilities.ProjectCreation.UnitTests
{
- public abstract class TestBase : MSBuildTestBase
+ public abstract class TestBase : MSBuildTestBase, IDisposable
{
+ private readonly Lazy _pathResolverLazy;
+
private readonly string _testRootPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ protected TestBase()
+ {
+ _pathResolverLazy = new Lazy(() => new VersionFolderPathResolver(Path.Combine(TestRootPath, ".nuget", "packages")));
+ }
+
public string TestRootPath
{
get
@@ -20,6 +28,8 @@ public string TestRootPath
}
}
+ public VersionFolderPathResolver VersionFolderPathResolver => _pathResolverLazy.Value;
+
public void Dispose()
{
Dispose(true);
diff --git a/src/MSBuildProjectCreator/MSBuildProjectCreator.csproj b/src/MSBuildProjectCreator/MSBuildProjectCreator.csproj
index f502351..5bfbe4b 100644
--- a/src/MSBuildProjectCreator/MSBuildProjectCreator.csproj
+++ b/src/MSBuildProjectCreator/MSBuildProjectCreator.csproj
@@ -35,6 +35,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
ResXFileCodeGenerator
diff --git a/src/MSBuildProjectCreator/PackageManifest.cs b/src/MSBuildProjectCreator/PackageManifest.cs
new file mode 100644
index 0000000..ca3048f
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageManifest.cs
@@ -0,0 +1,339 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Common;
+using NuGet.Frameworks;
+using NuGet.Packaging;
+using NuGet.Packaging.Core;
+using NuGet.Versioning;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ ///
+ /// Represents the manifest of a package.
+ ///
+ internal class PackageManifest : Manifest
+ {
+#if NET46
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The full path to the manifest file.
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+#else
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The full path to the manifest file.
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional path in the package that should be used for the icon of the package.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+#endif
+
+ public PackageManifest(
+ string fullPath,
+ string name,
+ string version,
+ string authors = null,
+ string description = null,
+ string copyright = null,
+ bool developmentDependency = false,
+#if !NET46
+ string icon = null,
+#endif
+ string iconUrl = null,
+ string language = null,
+ string licenseUrl = null,
+ LicenseMetadata licenseMetadata = null,
+ string owners = null,
+ IEnumerable packageTypes = null,
+ string projectUrl = null,
+ string releaseNotes = null,
+ string repositoryType = null,
+ string repositoryUrl = null,
+ string repositoryBranch = null,
+ string repositoryCommit = null,
+ bool requireLicenseAcceptance = false,
+ bool serviceable = false,
+ string summary = null,
+ string tags = null,
+ string title = null)
+ : base(
+ GetManifestMetadata(
+ name,
+ version,
+ authors,
+ description,
+ copyright,
+ developmentDependency,
+#if !NET46
+ icon,
+#endif
+ iconUrl,
+ language,
+ licenseUrl,
+ licenseMetadata,
+ owners,
+ packageTypes,
+ projectUrl,
+ releaseNotes,
+ repositoryType,
+ repositoryUrl,
+ repositoryBranch,
+ repositoryCommit,
+ requireLicenseAcceptance,
+ serviceable,
+ summary,
+ tags,
+ title))
+ {
+ if (string.IsNullOrWhiteSpace(fullPath))
+ {
+ throw new ArgumentNullException(nameof(fullPath));
+ }
+
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
+ if (string.IsNullOrWhiteSpace(version))
+ {
+ throw new ArgumentNullException(nameof(version));
+ }
+
+ FullPath = fullPath;
+
+ Directory = Path.GetDirectoryName(fullPath);
+
+ Save();
+
+ NupkgMetadataFileFormat.Write(
+ Path.Combine(Directory, PackagingCoreConstants.NupkgMetadataFileExtension),
+ new NupkgMetadataFile
+ {
+ ContentHash = string.Empty,
+ Version = NupkgMetadataFileFormat.Version,
+ });
+ }
+
+ ///
+ /// Gets the full path to the directory of the package.
+ ///
+ public string Directory { get; }
+
+ ///
+ /// Gets the full path to the package manifest file.
+ ///
+ public string FullPath { get; }
+
+ ///
+ /// Adds a to the package manifest.
+ ///
+ /// The of the package dependency group.
+ public void AddDependencyGroup(NuGetFramework targetFramework)
+ {
+ Metadata.DependencyGroups = Metadata.DependencyGroups.Concat(new List
+ {
+ new PackageDependencyGroup(targetFramework, Enumerable.Empty()),
+ });
+
+ Save();
+ }
+
+ ///
+ /// Saves the package manifest file.
+ ///
+ public void Save()
+ {
+ System.IO.Directory.CreateDirectory(Directory);
+
+ using (Stream stream = new FileStream(FullPath, FileMode.Create))
+ {
+ Save(stream);
+ }
+ }
+
+#if NET46
+ ///
+ /// Gets the for a package.
+ ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The for the package.
+#else
+ ///
+ /// Gets the for a package.
+ ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional path in the package that should be used for the icon of the package.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The for the package.
+#endif
+ private static ManifestMetadata GetManifestMetadata(
+ string name,
+ string version,
+ string authors = null,
+ string description = null,
+ string copyright = null,
+ bool developmentDependency = false,
+#if !NET46
+ string icon = null,
+#endif
+ string iconUrl = null,
+ string language = null,
+ string licenseUrl = null,
+ LicenseMetadata licenseMetadata = null,
+ string owners = null,
+ IEnumerable packageTypes = null,
+ string projectUrl = null,
+ string releaseNotes = null,
+ string repositoryType = null,
+ string repositoryUrl = null,
+ string repositoryBranch = null,
+ string repositoryCommit = null,
+ bool requireLicenseAcceptance = false,
+ bool serviceable = false,
+ string summary = null,
+ string tags = null,
+ string title = null)
+ {
+ ManifestMetadata metadata = new ManifestMetadata
+ {
+ Authors = MSBuildStringUtility.Split(authors ?? "UserA"),
+ Copyright = copyright,
+ Description = description ?? "Description",
+ DevelopmentDependency = developmentDependency,
+#if !NET46
+ Icon = icon,
+#endif
+ Id = name,
+ Language = language,
+ LicenseMetadata = licenseMetadata,
+ Owners = string.IsNullOrWhiteSpace(owners) ? null : MSBuildStringUtility.Split(owners),
+ PackageTypes = packageTypes ?? new[] { PackageType.Dependency },
+ ReleaseNotes = releaseNotes,
+ Repository = new RepositoryMetadata(repositoryType, repositoryUrl, repositoryBranch, repositoryCommit),
+ RequireLicenseAcceptance = requireLicenseAcceptance,
+ Serviceable = serviceable,
+ Summary = summary,
+ Tags = tags,
+ Title = title,
+ Version = NuGetVersion.Parse(version),
+ };
+
+ if (!string.IsNullOrWhiteSpace(iconUrl))
+ {
+ metadata.SetIconUrl(iconUrl);
+ }
+
+ if (!string.IsNullOrWhiteSpace(licenseUrl))
+ {
+ metadata.SetLicenseUrl(licenseUrl);
+ }
+
+ if (!string.IsNullOrWhiteSpace(projectUrl))
+ {
+ metadata.SetProjectUrl(projectUrl);
+ }
+
+ return metadata;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.BuildLogic.cs b/src/MSBuildProjectCreator/PackageRepository.BuildLogic.cs
new file mode 100644
index 0000000..82244c2
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.BuildLogic.cs
@@ -0,0 +1,316 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Microsoft.Build.Evaluation;
+using Microsoft.Build.Utilities.ProjectCreation.Resources;
+using System;
+using System.IO;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ public partial class PackageRepository
+ {
+ ///
+ /// Adds a .props file to the buildMultitargeting directory.
+ ///
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingProps(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingProps(null, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildMultitargeting directory.
+ ///
+ /// An to generate the .props file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingProps(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingProps(creator, out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildMultitargeting directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingProps(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingProps(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildMultitargeting directory.
+ ///
+ /// An to generate the .props file.
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingProps(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".props", "buildMultiTargeting", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ ///
+ /// Adds a .targets file to the buildMultitargeting directory.
+ ///
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingTargets(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingTargets(out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildMultitargeting directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingTargets(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingTargets(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildMultitargeting directory.
+ ///
+ /// An to generate the .targets file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingTargets(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildMultiTargetingTargets(creator, out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildMultitargeting directory.
+ ///
+ /// An to generate the .targets file.
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildMultiTargetingTargets(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".targets", "buildMultiTargeting", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ ///
+ /// Adds a .props file to the build directory.
+ ///
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildProps(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildProps(out ProjectCreator _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the build directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildProps(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildProps(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the build directory.
+ ///
+ /// An to generate the .props file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildProps(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildProps(creator, out ProjectCreator _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the build directory.
+ ///
+ /// An to generate the .props file.
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildProps(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".props", "build", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ ///
+ /// Adds a .targets file to the build directory.
+ ///
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTargets(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTargets(out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the build directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTargets(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTargets(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the build directory.
+ ///
+ /// An to generate the .targets file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTargets(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTargets(creator, out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the build directory.
+ ///
+ /// An to generate the .targets file.
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTargets(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".targets", "build", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ ///
+ /// Adds a .props file to the buildTransitive directory.
+ ///
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildTransitiveProps(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveProps(out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildTransitive directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildTransitiveProps(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveProps(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildTransitive directory.
+ ///
+ /// An to generate the .props file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildTransitiveProps(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveProps(creator, out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .props file to the buildTransitive directory.
+ ///
+ /// An to generate the .props file.
+ /// Receives the of the created project file.
+ /// Optional for the .props file.
+ /// The current .
+ public PackageRepository BuildTransitiveProps(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".props", "buildTransitive", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ ///
+ /// Adds a .targets file to the buildTransitive directory.
+ ///
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTransitiveTargets(NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveTargets(out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildTransitive directory.
+ ///
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTransitiveTargets(out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveTargets(null, out project, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildTransitive directory.
+ ///
+ /// An to generate the .targets file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTransitiveTargets(Action creator, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ return BuildTransitiveTargets(creator, out _, projectFileOptions);
+ }
+
+ ///
+ /// Adds a .targets file to the buildTransitive directory.
+ ///
+ /// An to generate the .targets file.
+ /// Receives the of the created project file.
+ /// Optional for the .targets file.
+ /// The current .
+ public PackageRepository BuildTransitiveTargets(Action creator, out ProjectCreator project, NewProjectFileOptions projectFileOptions = NewProjectFileOptions.IncludeAllOptions)
+ {
+ CreateBuildFile(".targets", "buildTransitive", creator, projectFileOptions, out project);
+
+ return this;
+ }
+
+ private void CreateBuildFile(string extension, string folderName, Action creator, NewProjectFileOptions projectFileOptions, out ProjectCreator project)
+ {
+ if (_packageManifest == null)
+ {
+ throw new InvalidOperationException(Strings.ErrorWhenAddingBuildLogicRequiresPackage);
+ }
+
+ if (string.IsNullOrWhiteSpace(extension))
+ {
+ throw new ArgumentNullException(extension);
+ }
+
+ if (string.IsNullOrWhiteSpace(folderName))
+ {
+ throw new ArgumentNullException(folderName);
+ }
+
+ project = ProjectCreator.Create(
+ path: Path.Combine(_packageManifest.Directory, folderName, $"{_packageManifest.Metadata.Id}{extension}"),
+ projectFileOptions: projectFileOptions);
+
+ creator?.Invoke(project);
+
+ project.Save();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.Dependency.cs b/src/MSBuildProjectCreator/PackageRepository.Dependency.cs
new file mode 100644
index 0000000..bac60f6
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.Dependency.cs
@@ -0,0 +1,117 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Common;
+using NuGet.Frameworks;
+using NuGet.LibraryModel;
+using NuGet.Packaging;
+using NuGet.Packaging.Core;
+using NuGet.Versioning;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ public partial class PackageRepository
+ {
+ ///
+ /// Adds a dependency to the current package.
+ ///
+ /// The of the dependency.
+ /// An optional target framework for the dependency.
+ /// An optional representing the assets to include for the dependency.
+ /// An optional representing the assets to exclude from the dependency.
+ /// The current .
+ public PackageRepository Dependency(PackageIdentity packageIdentity, string targetFramework, LibraryIncludeFlags? include = null, LibraryIncludeFlags? exclude = null)
+ {
+ return Dependency(
+ packageIdentity.Id,
+ new VersionRange(packageIdentity.Version),
+ targetFramework,
+ include,
+ exclude);
+ }
+
+ ///
+ /// Adds a dependency to the current package.
+ ///
+ /// The of the dependency.
+ /// The for the dependency.
+ /// An optional representing the assets to include for the dependency.
+ /// An optional representing the assets to exclude from the dependency.
+ /// The current .
+ public PackageRepository Dependency(PackageIdentity packageIdentity, NuGetFramework targetFramework, LibraryIncludeFlags? include = null, LibraryIncludeFlags? exclude = null)
+ {
+ return Dependency(packageIdentity.Id, new VersionRange(packageIdentity.Version), targetFramework, include, exclude);
+ }
+
+ ///
+ /// Adds a dependency to the current package.
+ ///
+ /// The identifier of the dependency.
+ /// The version of the dependency.
+ /// An optional target framework for the dependency.
+ /// An optional representing the assets to include for the dependency.
+ /// An optional representing the assets to exclude from the dependency.
+ /// The current .
+ public PackageRepository Dependency(string id, string version, string targetFramework, LibraryIncludeFlags? include = null, LibraryIncludeFlags? exclude = null)
+ {
+ return Dependency(
+ id,
+ VersionRange.Parse(version),
+ targetFramework,
+ include,
+ exclude);
+ }
+
+ ///
+ /// Adds a dependency to the current package.
+ ///
+ /// The identifier of the dependency.
+ /// The of the dependency.
+ /// An optional target framework for the dependency.
+ /// An optional representing the assets to include for the dependency.
+ /// An optional representing the assets to exclude from the dependency.
+ /// The current .
+ public PackageRepository Dependency(string id, VersionRange version, string targetFramework, LibraryIncludeFlags? include = null, LibraryIncludeFlags? exclude = null)
+ {
+ return Dependency(
+ id,
+ version,
+ string.IsNullOrWhiteSpace(targetFramework) ? null : NuGetFramework.Parse(targetFramework),
+ include,
+ exclude);
+ }
+
+ ///
+ /// Adds a dependency to the current package.
+ ///
+ /// The identifier of the dependency.
+ /// The of the dependency.
+ /// The for the dependency.
+ /// An optional representing the assets to include for the dependency.
+ /// An optional representing the assets to exclude from the dependency.
+ /// The current .
+ public PackageRepository Dependency(string id, VersionRange version, NuGetFramework targetFramework, LibraryIncludeFlags? include = null, LibraryIncludeFlags? exclude = null)
+ {
+ _packageManifest.Metadata.DependencyGroups = _packageManifest.Metadata.DependencyGroups.Concat(new List
+ {
+ new PackageDependencyGroup(
+ targetFramework ?? NuGetFramework.AnyFramework,
+ new List
+ {
+ new PackageDependency(
+ id,
+ version,
+ include == null ? null : MSBuildStringUtility.Split(include.ToString(), ','),
+ exclude == null ? null : MSBuildStringUtility.Split(exclude.ToString(), ',')),
+ }),
+ });
+
+ _packageManifest.Save();
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.File.cs b/src/MSBuildProjectCreator/PackageRepository.File.cs
new file mode 100644
index 0000000..b4dd8d7
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.File.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Microsoft.Build.Utilities.ProjectCreation.Resources;
+using System;
+using System.Globalization;
+using System.IO;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ public partial class PackageRepository
+ {
+ ///
+ /// Adds a text file to the package.
+ ///
+ /// The relative path of the text file within the package.
+ /// The contents of the text file.
+ /// The current .
+ public PackageRepository FileText(string relativePath, string contents)
+ {
+ return File(relativePath, file => System.IO.File.WriteAllText(file.FullName, contents));
+ }
+
+ private PackageRepository File(string relativePath, Action writeAction)
+ {
+ FileInfo fileInfo = new FileInfo(Path.Combine(_packageManifest.Directory, relativePath));
+
+ if (fileInfo.Exists)
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFileAlreadyCreated, relativePath));
+ }
+
+ if (fileInfo.Directory == null)
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFilePathMustBeInADirectory, relativePath));
+ }
+
+ fileInfo.Directory.Create();
+
+ writeAction(fileInfo);
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.Library.cs b/src/MSBuildProjectCreator/PackageRepository.Library.cs
new file mode 100644
index 0000000..1aea158
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.Library.cs
@@ -0,0 +1,118 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Microsoft.Build.Utilities.ProjectCreation.Resources;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Emit;
+using NuGet.Frameworks;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ public partial class PackageRepository
+ {
+ ///
+ /// Adds a library to the package.
+ ///
+ /// The target framework of the library.
+ /// An optional filename for the library. The default value is <PackageId>.dll.
+ /// An optional namespace for the library. The default value is <PackageId>.
+ /// An optional class name for the library. The default value is <PackageId>_Class.
+ /// An optional assembly version for the library. The default value is "1.0.0.0"
+ /// The current .
+ public PackageRepository Library(string targetFramework, string filename = null, string @namespace = null, string className = null, string assemblyVersion = "1.0.0.0")
+ {
+ return Library(NuGetFramework.Parse(targetFramework), filename, @namespace, className, assemblyVersion);
+ }
+
+ ///
+ /// Adds a library to the package.
+ ///
+ /// The of the library.
+ /// An optional filename for the library. The default value is <PackageId>.dll.
+ /// An optional namespace for the library. The default value is <PackageId>.
+ /// An optional class name for the library. The default value is <PackageId>_Class.
+ /// An optional assembly version for the library. The default value is "1.0.0.0"
+ /// The current .
+ public PackageRepository Library(NuGetFramework targetFramework, string filename = null, string @namespace = null, string className = null, string assemblyVersion = "1.0.0.0")
+ {
+ if (_packageManifest == null)
+ {
+ throw new InvalidOperationException(Strings.ErrorWhenAddingLibraryRequiresPackage);
+ }
+
+ if (string.IsNullOrWhiteSpace(filename))
+ {
+ filename = $"{_packageManifest.Metadata.Id}.dll";
+ }
+
+ if (string.IsNullOrWhiteSpace(className))
+ {
+ className = $"{_packageManifest.Metadata.Id}_Class";
+ }
+
+ _packageManifest.AddDependencyGroup(targetFramework);
+
+ return File(
+ Path.Combine("lib", targetFramework.GetShortFolderName(), filename),
+ fileInfo => CreateAssembly(fileInfo, @namespace, className, assemblyVersion, targetFramework.GetDotNetFrameworkName(DefaultFrameworkNameProvider.Instance)));
+ }
+
+ private void CreateAssembly(FileInfo fileInfo, string @namespace, string className, string version, string targetFramework)
+ {
+ if (fileInfo == null)
+ {
+ throw new ArgumentNullException(nameof(fileInfo));
+ }
+
+ if (fileInfo.Directory == null)
+ {
+ throw new ArgumentNullException(nameof(fileInfo.Directory));
+ }
+
+ fileInfo.Directory.Create();
+
+ string name = string.IsNullOrWhiteSpace(@namespace) ? Path.GetFileNameWithoutExtension(fileInfo.Name) : @namespace;
+
+ CreateAssembly(
+ fileInfo,
+ name,
+ $@"
+[assembly: System.Reflection.AssemblyVersionAttribute(""{version}"")]
+[assembly: System.Runtime.Versioning.TargetFramework(""{targetFramework}"")]
+namespace {name}
+{{
+ public class {className}
+ {{
+ }}
+}}",
+ new[]
+ {
+ typeof(object).Assembly.Location,
+ });
+ }
+
+ private void CreateAssembly(FileInfo fileInfo, string name, string code, IEnumerable references, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
+ {
+ CSharpCompilation compilation = CSharpCompilation.Create(
+ name,
+ new[]
+ {
+ CSharpSyntaxTree.ParseText(code),
+ },
+ references.Select(i => MetadataReference.CreateFromFile(i)),
+ new CSharpCompilationOptions(outputKind));
+
+ EmitResult result = compilation.Emit(fileInfo.FullName);
+
+ if (!result.Success)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.Package.cs b/src/MSBuildProjectCreator/PackageRepository.Package.cs
new file mode 100644
index 0000000..e170e2d
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.Package.cs
@@ -0,0 +1,289 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using Microsoft.Build.Utilities.ProjectCreation.Resources;
+using NuGet.Packaging;
+using NuGet.Packaging.Core;
+using NuGet.Versioning;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ public partial class PackageRepository
+ {
+ private readonly HashSet _packages = new HashSet();
+
+ ///
+ /// Gets the current packages in the repository.
+ ///
+ public IReadOnlyCollection Packages => _packages;
+
+ ///
+ public string GetInstallPath(string packageId, NuGetVersion version)
+ {
+ return _versionFolderPathResolver.GetInstallPath(packageId, version);
+ }
+
+#if NET46
+ ///
+ /// Creates a new package.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The current .
+#else
+ ///
+ /// Creates a new package.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional path in the package that should be used for the icon of the package.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The current .
+#endif
+
+ public PackageRepository Package(
+ string name,
+ string version,
+ string authors = null,
+ string description = null,
+ string copyright = null,
+ bool developmentDependency = false,
+#if !NET46
+ string icon = null,
+#endif
+ string iconUrl = null,
+ string language = null,
+ string licenseUrl = null,
+ LicenseMetadata licenseMetadata = null,
+ string owners = null,
+ IEnumerable packageTypes = null,
+ string projectUrl = null,
+ string releaseNotes = null,
+ string repositoryType = null,
+ string repositoryUrl = null,
+ string repositoryBranch = null,
+ string repositoryCommit = null,
+ bool requireLicenseAcceptance = false,
+ bool serviceable = false,
+ string summary = null,
+ string tags = null,
+ string title = null)
+ {
+ return Package(
+ name,
+ version,
+ out PackageIdentity _,
+ authors,
+ description,
+ copyright,
+ developmentDependency,
+#if !NET46
+ icon,
+#endif
+ iconUrl,
+ language,
+ licenseUrl,
+ licenseMetadata,
+ owners,
+ packageTypes,
+ projectUrl,
+ releaseNotes,
+ repositoryType,
+ repositoryUrl,
+ repositoryBranch,
+ repositoryCommit,
+ requireLicenseAcceptance,
+ serviceable,
+ summary,
+ tags,
+ title);
+ }
+
+#if NET46
+ ///
+ /// Creates a new package.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// Receives the of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The current .
+#else
+ ///
+ /// Creates a new package.
+ ///
+ /// The name or ID of the package.
+ /// The semantic version of the package.
+ /// Receives the of the package.
+ /// An optional semicolon delimited list of authors of the package. The default value is "UserA"
+ /// An optional description of the package. The default value is "Description"
+ /// An optional copyright of the package.
+ /// An optional value indicating whether or not the package is a development dependency. The default value is false.
+ /// An optional path in the package that should be used for the icon of the package.
+ /// An optional URL to the icon of the package.
+ /// An optional language of the package.
+ /// An optional URL to the license of the package.
+ /// An optional of the package.
+ /// An optional semicolon delimited list of owners of the package.
+ /// An optional containing the package types of the package.
+ /// An optional URL to the project of the package.
+ /// An optional value specifying release notes of the package.
+ /// An optional value specifying the type of source code repository of the package.
+ /// An optional value specifying the URL of the source code repository of the package.
+ /// An optional value specifying the branch of the source code repository of the package.
+ /// An optional value specifying the commit of the source code repository of the package.
+ /// An optional value indicating whether or not the package requires license acceptance The default value is false.
+ /// An option value indicating whether or not the package is serviceable. The default value is false.
+ /// An optional summary of the package.
+ /// An optional set of tags of the package.
+ /// An optional title of the package.
+ /// The current .
+#endif
+ public PackageRepository Package(
+ string name,
+ string version,
+ out PackageIdentity package,
+ string authors = null,
+ string description = null,
+ string copyright = null,
+ bool developmentDependency = false,
+#if !NET46
+ string icon = null,
+#endif
+ string iconUrl = null,
+ string language = null,
+ string licenseUrl = null,
+ LicenseMetadata licenseMetadata = null,
+ string owners = null,
+ IEnumerable packageTypes = null,
+ string projectUrl = null,
+ string releaseNotes = null,
+ string repositoryType = null,
+ string repositoryUrl = null,
+ string repositoryBranch = null,
+ string repositoryCommit = null,
+ bool requireLicenseAcceptance = false,
+ bool serviceable = false,
+ string summary = null,
+ string tags = null,
+ string title = null)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
+ if (string.IsNullOrWhiteSpace(version))
+ {
+ throw new ArgumentNullException(nameof(version));
+ }
+
+ package = new PackageIdentity(name, NuGetVersion.Parse(version));
+
+ string manifestFilePath = _versionFolderPathResolver.GetManifestFilePath(package.Id, package.Version);
+
+ if (System.IO.File.Exists(manifestFilePath))
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorPackageAlreadyCreated, name, version));
+ }
+
+ _packageManifest = new PackageManifest(
+ manifestFilePath,
+ name,
+ version,
+ authors,
+ description,
+ copyright,
+ developmentDependency,
+#if !NET46
+ icon,
+#endif
+ iconUrl,
+ language,
+ licenseUrl,
+ licenseMetadata,
+ owners,
+ packageTypes,
+ projectUrl,
+ releaseNotes,
+ repositoryType,
+ repositoryUrl,
+ repositoryBranch,
+ repositoryCommit,
+ requireLicenseAcceptance,
+ serviceable,
+ summary,
+ tags,
+ title);
+
+ _packages.Add(package);
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/PackageRepository.cs b/src/MSBuildProjectCreator/PackageRepository.cs
new file mode 100644
index 0000000..1e5667a
--- /dev/null
+++ b/src/MSBuildProjectCreator/PackageRepository.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Jeff Kluge. All rights reserved.
+//
+// Licensed under the MIT license.
+
+using NuGet.Configuration;
+using NuGet.Packaging;
+using System.IO;
+using System.Linq;
+
+namespace Microsoft.Build.Utilities.ProjectCreation
+{
+ ///
+ /// Represents a NuGet package repository.
+ ///
+ public partial class PackageRepository
+ {
+ private readonly VersionFolderPathResolver _versionFolderPathResolver;
+
+ private PackageManifest _packageManifest;
+
+ private PackageRepository(string rootPath)
+ {
+ GlobalPackagesFolder = Path.Combine(rootPath, ".nuget", SettingsUtility.DefaultGlobalPackagesFolderPath);
+
+ ISettings settings = new Settings(rootPath, Settings.DefaultSettingsFileName);
+
+ SettingsUtility.SetConfigValue(settings, ConfigurationConstants.GlobalPackagesFolder, GlobalPackagesFolder);
+
+ settings.Remove(ConfigurationConstants.PackageSources, settings.GetSection(ConfigurationConstants.PackageSources).Items.First());
+
+ settings.AddOrUpdate(ConfigurationConstants.PackageSources, new ClearItem());
+
+ settings.SaveToDisk();
+
+ _versionFolderPathResolver = new VersionFolderPathResolver(GlobalPackagesFolder);
+ }
+
+ ///
+ /// Gets the full path to the global packages folder.
+ ///
+ public string GlobalPackagesFolder { get; }
+
+ ///
+ /// Creates a new instance.
+ ///
+ /// The root directory to create a package repository directory in.
+ /// A object that is used to construct an NuGet package repository.
+ public static PackageRepository Create(string rootPath)
+ {
+ return new PackageRepository(rootPath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MSBuildProjectCreator/ProjectCreator.Items.cs b/src/MSBuildProjectCreator/ProjectCreator.Items.cs
index d8a97d1..528a697 100644
--- a/src/MSBuildProjectCreator/ProjectCreator.Items.cs
+++ b/src/MSBuildProjectCreator/ProjectCreator.Items.cs
@@ -4,6 +4,7 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
+using NuGet.Packaging.Core;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -164,6 +165,21 @@ public ProjectCreator ItemPackageReference(string include, string version = null
condition: condition);
}
+ ///
+ /// Adds a <PackageReference /> item to the current item group.
+ ///
+ /// The of the package to reference.
+ /// An optional value specifying which assets belonging to the package should be consumed.
+ /// An optional value specifying which assets belonging to the package should be not consumed.
+ /// An optional value specifying which assets belonging to the package should not flow to dependent projects.
+ /// An optional containing metadata for the item.
+ /// An optional condition to add to the item.
+ /// The current .
+ public ProjectCreator ItemPackageReference(PackageIdentity package, string includeAssets = null, string excludeAssets = null, string privateAssets = null, IDictionary metadata = null, string condition = null)
+ {
+ return ItemPackageReference(package.Id, package.Version.ToNormalizedString(), includeAssets, excludeAssets, privateAssets, metadata, condition);
+ }
+
///
/// Adds a <ProjectReference /> item to the current item group.
///
diff --git a/src/MSBuildProjectCreator/ProjectCreator.cs b/src/MSBuildProjectCreator/ProjectCreator.cs
index 5cb1f49..fbe558a 100644
--- a/src/MSBuildProjectCreator/ProjectCreator.cs
+++ b/src/MSBuildProjectCreator/ProjectCreator.cs
@@ -5,6 +5,7 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using System;
+using System.IO;
namespace Microsoft.Build.Utilities.ProjectCreation
{
@@ -143,6 +144,8 @@ public ProjectCreator Save()
/// The current .
public ProjectCreator Save(string path)
{
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
RootElement.Save(path);
return this;
diff --git a/src/MSBuildProjectCreator/Resources/Strings.Designer.cs b/src/MSBuildProjectCreator/Resources/Strings.Designer.cs
index ef824ef..bf46a10 100644
--- a/src/MSBuildProjectCreator/Resources/Strings.Designer.cs
+++ b/src/MSBuildProjectCreator/Resources/Strings.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.Build.Utilities.ProjectCreation.Resources {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Strings {
@@ -60,6 +60,24 @@ internal Strings() {
}
}
+ ///
+ /// Looks up a localized string similar to The file "{0}" has already been added to the package..
+ ///
+ internal static string ErrorFileAlreadyCreated {
+ get {
+ return ResourceManager.GetString("ErrorFileAlreadyCreated", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified file path "{0}" must have a parent directory..
+ ///
+ internal static string ErrorFilePathMustBeInADirectory {
+ get {
+ return ResourceManager.GetString("ErrorFilePathMustBeInADirectory", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to You can only add one Otherwise to a Choose..
///
@@ -78,6 +96,15 @@ internal static string ErrorOtherwiseRequresWhen {
}
}
+ ///
+ /// Looks up a localized string similar to The package "{0}" version "{1}" has already been created..
+ ///
+ internal static string ErrorPackageAlreadyCreated {
+ get {
+ return ResourceManager.GetString("ErrorPackageAlreadyCreated", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to You must add a Task by before you can add an output item..
///
@@ -123,6 +150,24 @@ internal static string ErrorUsingTaskParameterRequiresUsingTask {
}
}
+ ///
+ /// Looks up a localized string similar to You must add a package before adding build logic..
+ ///
+ internal static string ErrorWhenAddingBuildLogicRequiresPackage {
+ get {
+ return ResourceManager.GetString("ErrorWhenAddingBuildLogicRequiresPackage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You must add a package before adding a library..
+ ///
+ internal static string ErrorWhenAddingLibraryRequiresPackage {
+ get {
+ return ResourceManager.GetString("ErrorWhenAddingLibraryRequiresPackage", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to You must add a When before adding a When ItemGroup..
///
diff --git a/src/MSBuildProjectCreator/Resources/Strings.resx b/src/MSBuildProjectCreator/Resources/Strings.resx
index fe9b42e..883bbb4 100644
--- a/src/MSBuildProjectCreator/Resources/Strings.resx
+++ b/src/MSBuildProjectCreator/Resources/Strings.resx
@@ -117,12 +117,21 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ The file "{0}" has already been added to the package.
+
+
+ The specified file path "{0}" must have a parent directory.
+
You can only add one Otherwise to a Choose.
You must add a When before adding an Otherwise.
+
+ The package "{0}" version "{1}" has already been created.
+
You must add a Task by before you can add an output item.
@@ -138,6 +147,12 @@
You must add a UsingTask before adding a UsingTask parameter.
+
+ You must add a package before adding build logic.
+
+
+ You must add a package before adding a library.
+
You must add a When before adding a When ItemGroup.
diff --git a/version.json b/version.json
index 3bed904..930765a 100644
--- a/version.json
+++ b/version.json
@@ -1,5 +1,5 @@
{
- "version": "1.2",
+ "version": "1.3",
"assemblyVersion": "1.0",
"nugetPackageVersion": {
"semVer": 1