diff --git a/Install/NuBuild.wxs b/Install/NuBuild.wxs index c2e8aef..fba6b1c 100644 --- a/Install/NuBuild.wxs +++ b/Install/NuBuild.wxs @@ -1,7 +1,7 @@ - + false + + true .NETFramework $(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion),Profile=$(TargetFrameworkProfile) $(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion) @@ -103,6 +108,7 @@ OutputPath="$(OutputPath)" ReferenceLibraries="@(__ReferenceLibraries)" AddBinariesToSubfolder="$(NuBuildAddBinariesToSubfolder)" + AutoGenerateDependencies="$(NuBuildAutoGenerateDependencies)" IncludePdbs="$(NuBuildIncludePdbs)"/> diff --git a/MSBuild/Tasks/NuPackage.cs b/MSBuild/Tasks/NuPackage.cs index bf782af..51e13df 100644 --- a/MSBuild/Tasks/NuPackage.cs +++ b/MSBuild/Tasks/NuPackage.cs @@ -21,10 +21,12 @@ // System References using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Versioning; +using System.Xml.Linq; using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; using Microsoft.Build.Framework; @@ -44,6 +46,7 @@ namespace NuBuild.MSBuild public sealed class NuPackage : Task, NuGet.IPropertyProvider { private Project propertyProject = null; + private const string PACKAGES_CONFIG = "packages.config"; #region Task Parameters /// @@ -72,6 +75,10 @@ public sealed class NuPackage : Task, NuGet.IPropertyProvider /// public Boolean AddBinariesToSubfolder { get; set; } /// + /// If nuspec dependencies is not defined, creates it based on project packages.config file. + /// + public Boolean AutoGenerateDependencies { get; set; } + /// /// Specifies whether to add PDB files for binaries /// automatically to the package /// @@ -127,11 +134,108 @@ private void BuildPackage (ITaskItem specItem) // add a new file to the folder for each project // referenced by the current project AddLibraries(builder); + + //auto generate package dependencies from packages.config file. + if (AutoGenerateDependencies && !builder.DependencySets.Any()) + AddDependencies(builder); + // write the configured package out to disk var pkgPath = specItem.GetMetadata("NuPackagePath"); using (var pkgFile = File.Create(pkgPath)) builder.Save(pkgFile); } + + /// + /// Go through each referenced project, and add any nuget dependencies from + /// their packages.config file. Ignores any that have developerDependency=true + /// + /// + private void AddDependencies(NuGet.PackageBuilder builder) + { + Dictionary NugetPackages = new Dictionary(); + + string projectRoot = Path.GetDirectoryName(this.ProjectPath); + + XElement root = XElement.Load(this.ProjectPath); + var ns = root.Name.Namespace; + var elems = (from el in root.Descendants(ns + "ProjectReference") + select el).ToList(); + + if (elems.Any()) + { + foreach (var item in elems) + { + string itemPath = item.Attribute("Include").Value; + string packagesPath = Path.GetFullPath(Path.Combine(projectRoot, Path.GetDirectoryName(itemPath))) + Path.DirectorySeparatorChar + PACKAGES_CONFIG; + GetNuGetDependencies(packagesPath, NugetPackages); + } + } + + if (NugetPackages.Any()) + AddNugetDependencies(builder, NugetPackages); + } + + /// + /// Inserts a dependency set into the packagebuilder object, based on a dictionary + /// containing Id/version pairs (Newtonsoft.json, 5.0.6 for example). + /// + /// + /// + private void AddNugetDependencies(NuGet.PackageBuilder builder, Dictionary packages) + { + //add dependencies + List dependencies = new List(); + foreach (var package in packages) + { + dependencies.Add(new PackageDependency(package.Key, new VersionSpec {MinVersion = new SemanticVersion(package.Value), IsMinInclusive = true})); + } + + var set = new PackageDependencySet(null, dependencies); + builder.DependencySets.Add(set); + } + + /// + /// opens a packages.config file (if exists) and parses the nuget packages into a dictionary. + /// dictionary key is the package id (ie, newtownsoft.json), and version is the semantic version string (ie 5.0.6) + /// if there are 2 csproj's linked to the same nuproj, this also verifies that any shared packages share the same version. + /// if they do not, throws an exception and stops. + /// + /// + /// + private void GetNuGetDependencies(string packagesPath, Dictionary packages) + { + if (!File.Exists(packagesPath)) return; //packages.config is not there, no nuget packages in project. + + XElement root = XElement.Load(packagesPath); + var elems = from el in root.Elements("package") + where el.Attribute("developmentDependency") == null || (string)el.Attribute("developmentDependency") == "false" + select el; + + foreach (var item in elems) + { + var id = item.Attribute("id").Value; + var version = item.Attribute("version").Value; + + if (packages.ContainsKey(id)) + { + //if version is the same, ok, but if different, then that means the same package + //is referenced with 2 different versions. (most likely from 2 different .csproj's linked in one nuproj, + //and not utilizing the same version of the nuget package. + if (packages[id] != version) + { + Log.LogError( + "package {0} is referenced twice, with different versions. Cannot proceed with the auto generation of dependencies. Please update to use the same version or manually create the dependencies in the nuspec file. Versions detected: {1}, {2}", + id, packages[id], version); + throw new Exception("Could not auto-generate dependencies due to multiple versions of same package."); + } + } + else + { + packages.Add(id, version); + } + } + } + /// /// Adds project references to the package lib section /// @@ -173,7 +277,7 @@ private void AddLibraries (NuGet.PackageBuilder builder) if (!String.IsNullOrWhiteSpace(targetFrameworkName)) tgtFolder = Path.Combine(tgtFolder, VersionUtility.GetShortFrameworkName(new FrameworkName(targetFrameworkName))); } - catch { } + catch { } // add the source library file to the package builder.Files.Add( new NuGet.PhysicalPackageFile() diff --git a/MSBuild/Tasks/NuPrepare.cs b/MSBuild/Tasks/NuPrepare.cs index e3fba67..1a786e5 100644 --- a/MSBuild/Tasks/NuPrepare.cs +++ b/MSBuild/Tasks/NuPrepare.cs @@ -108,7 +108,7 @@ public sealed class NuPrepare : Task public override Boolean Execute () { try - { + { // parepare the task for execution if (this.ReferenceLibraries == null) this.ReferenceLibraries = new ITaskItem[0]; @@ -129,7 +129,7 @@ public override Boolean Execute () PreparePackage(specItem); // return the list of build sources/targets this.Sources = this.sourceList.ToArray(); - this.Targets = this.targetList.ToArray(); + this.Targets = this.targetList.ToArray(); } catch (Exception e) { diff --git a/MSBuild/Tasks/Tasks.csproj b/MSBuild/Tasks/Tasks.csproj index 753e154..bc9bfd2 100644 --- a/MSBuild/Tasks/Tasks.csproj +++ b/MSBuild/Tasks/Tasks.csproj @@ -23,10 +23,12 @@ full false $(DefineConstants);DEBUG + true pdbonly true + false @@ -35,11 +37,12 @@ ..\..\packages\Microsoft.Web.Xdt.1.0.0\lib\net40\Microsoft.Web.XmlTransform.dll - + False - ..\..\packages\Nuget.Core.2.7.0\lib\net40-Client\NuGet.Core.dll + ..\..\packages\NuGet.Core.2.8.0\lib\net40-Client\NuGet.Core.dll + diff --git a/MSBuild/Tasks/packages.config b/MSBuild/Tasks/packages.config index 8ebc74b..1cd2e5a 100644 --- a/MSBuild/Tasks/packages.config +++ b/MSBuild/Tasks/packages.config @@ -1,5 +1,5 @@ - - + + - + \ No newline at end of file diff --git a/VS/Package/NuBuild/NuBuildPropertyPage.cs b/VS/Package/NuBuild/NuBuildPropertyPage.cs index dbe0a97..2208889 100644 --- a/VS/Package/NuBuild/NuBuildPropertyPage.cs +++ b/VS/Package/NuBuild/NuBuildPropertyPage.cs @@ -56,6 +56,7 @@ public sealed class NuBuildPropertyPage : SettingsPage private VersionSource versionSource; private Boolean versionFileName; private Boolean addBinariesToSubfolder; + private Boolean autoGenerateDependencies; private Boolean includePdbs; private TargetFramework targetFramework; @@ -128,6 +129,18 @@ public Boolean AddBinariesToSubfolder set { this.addBinariesToSubfolder = value; this.IsDirty = true; } } + /// + /// If nuspec dependencies is not defined, creates it based on project packages.config file. + /// + [Category("Advanced")] + [DisplayName("Auto Generate Dependencies")] + [Description(@"If nuspec dependencies is not defined, creates it based on project packages.config file.")] + public Boolean AutoGenerateDependencies + { + get { return this.autoGenerateDependencies; } + set { this.autoGenerateDependencies = value; this.IsDirty = true; } + } + /// /// Specifies whether to include PDBs for referenced assemblies /// @@ -165,6 +178,9 @@ protected override void BindProperties () this.addBinariesToSubfolder = Boolean.Parse( this.ProjectMgr.GetProjectProperty("NuBuildAddBinariesToSubfolder") ); + this.autoGenerateDependencies = Boolean.Parse( + this.ProjectMgr.GetProjectProperty("NuBuildAutoGenerateDependencies") + ); this.includePdbs = Boolean.Parse( this.ProjectMgr.GetProjectProperty("NuBuildIncludePdbs") ); @@ -207,6 +223,10 @@ protected override Int32 ApplyChanges () "NuBuildAddBinariesToSubfolder", this.addBinariesToSubfolder.ToString() ); + this.ProjectMgr.SetProjectProperty( + "NuBuildAutoGenerateDependencies", + this.autoGenerateDependencies.ToString() + ); this.ProjectMgr.SetProjectProperty( "NuBuildIncludePdbs", this.includePdbs.ToString() diff --git a/VS/ProjectTemplate/NuProj/NuProj.nuproj b/VS/ProjectTemplate/NuProj/NuProj.nuproj index bf7d926..3139357 100644 --- a/VS/ProjectTemplate/NuProj/NuProj.nuproj +++ b/VS/ProjectTemplate/NuProj/NuProj.nuproj @@ -7,6 +7,7 @@ library true false + true false diff --git a/Version.cs b/Version.cs index 5849840..aa2e276 100644 --- a/Version.cs +++ b/Version.cs @@ -21,5 +21,5 @@ // System References using System.Reflection; // Project References -[assembly:AssemblyVersion("1.9.0.0")] -[assembly:AssemblyFileVersion("1.9.0.0")] +[assembly:AssemblyVersion("1.9.1.0")] +[assembly:AssemblyFileVersion("1.9.1.0")]