diff options
author | Mikayla Hutchinson <m.j.hutchinson@gmail.com> | 2016-07-14 00:56:42 +0300 |
---|---|---|
committer | Mikayla Hutchinson <m.j.hutchinson@gmail.com> | 2016-07-14 00:56:42 +0300 |
commit | 04bdab55d8de9edcf628694cfd2001561e8f8e60 (patch) | |
tree | 3a8a7f988896978153180765a9960e8151465ad7 | |
parent | 1f02d779052982aea7cecf4d56caf6ffff246830 (diff) | |
parent | 3a3aeb470862ce47e013bc31a2d1adc9e2829ee6 (diff) |
Merge remote-tracking branch 'upstream/dev' into dev
13 files changed, 231 insertions, 44 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..d55402c --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# NuGet.BuildTasks +The build tasks used to pick up package content from project.lock.json. +# Open Source Code of Conduct +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.Designer.cs b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.Designer.cs index 542db47..da6220a 100644 --- a/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.Designer.cs +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.Designer.cs @@ -149,6 +149,34 @@ namespace Microsoft.NuGet.Build.Tasks.Tests.Json { /// <summary> /// Looks up a localized string similar to { /// "locked": false, + /// "version": 2, + /// "targets": { + /// ".NETFramework,Version=v4.5": { + /// "Newtonsoft.Json/8.0.3": { + /// "type": "package", + /// "compile": { + /// "lib/net45/Newtonsoft.Json.dll": {} + /// }, + /// "runtime": { + /// "lib/net45/Newtonsoft.Json.dll": {} + /// } + /// } + /// } + /// }, + /// "libraries": { + /// "Newtonsoft.Json/8.0.3": { + /// "sha512": "KGsYQdS2zLH+H8x2cZaSI7e+YZ4SFIbyy1YJQYl6GYBWjf5o4H1A68nxyq+WTyVSOJQ4GqS/DiPE+UseUizgMg==", + /// "type": " [rest of string was truncated]";. + /// </summary> + internal static string LockFileWithWithSpecifiedPackageFolders { + get { + return ResourceManager.GetString("LockFileWithWithSpecifiedPackageFolders", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to { + /// "locked": false, /// "version": 1, /// "targets": { /// ".NETCore,Version=v5.0": { diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.resx b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.resx index 7656ea1..f569b2c 100644 --- a/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.resx +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/Json.resx @@ -139,4 +139,7 @@ <data name="nativeWinMD" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>nativeWinMD.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> </data> + <data name="LockFileWithWithSpecifiedPackageFolders" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>lockfilewithwithspecifiedpackagefolders.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> + </data> </root>
\ No newline at end of file diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/Json/LockFileWithWithSpecifiedPackageFolders.json b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/LockFileWithWithSpecifiedPackageFolders.json new file mode 100644 index 0000000..6df6a2a --- /dev/null +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/Json/LockFileWithWithSpecifiedPackageFolders.json @@ -0,0 +1,52 @@ +{ + "locked": false, + "version": 2, + "targets": { + ".NETFramework,Version=v4.5": { + "Newtonsoft.Json/8.0.3": { + "type": "package", + "compile": { + "lib/net45/Newtonsoft.Json.dll": {} + }, + "runtime": { + "lib/net45/Newtonsoft.Json.dll": {} + } + } + } + }, + "libraries": { + "Newtonsoft.Json/8.0.3": { + "sha512": "KGsYQdS2zLH+H8x2cZaSI7e+YZ4SFIbyy1YJQYl6GYBWjf5o4H1A68nxyq+WTyVSOJQ4GqS/DiPE+UseUizgMg==", + "type": "package", + "path": "newtonsoft.json/8.0.3", + "files": [ + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/portable-net40+sl5+wp80+win8+wpa81/Newtonsoft.Json.dll", + "lib/portable-net40+sl5+wp80+win8+wpa81/Newtonsoft.Json.xml", + "lib/portable-net45+wp80+win8+wpa81+dnxcore50/Newtonsoft.Json.dll", + "lib/portable-net45+wp80+win8+wpa81+dnxcore50/Newtonsoft.Json.xml", + "newtonsoft.json.8.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "tools/install.ps1" + ] + } + }, + "projectFileDependencyGroups": { + "": [ + "Newtonsoft.Json" + ], + ".NETFramework,Version=v4.5": [] + }, + "tools": {}, + "projectFileToolGroups": {}, + "packageFolders": { + "C:\\PackageFolder\\": {} + } +}
\ No newline at end of file diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/Microsoft.NuGet.Build.Tasks.Tests.csproj b/src/Microsoft.NuGet.Build.Tasks.Tests/Microsoft.NuGet.Build.Tasks.Tests.csproj index 80c7688..12878ba 100644 --- a/src/Microsoft.NuGet.Build.Tasks.Tests/Microsoft.NuGet.Build.Tasks.Tests.csproj +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/Microsoft.NuGet.Build.Tasks.Tests.csproj @@ -13,7 +13,7 @@ <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> <SignAssembly>true</SignAssembly> - <DelaySign>true</DelaySign> + <PublicSign>true</PublicSign> <AssemblyOriginatorKeyFile>..\..\build\PublicKey.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> @@ -55,6 +55,7 @@ <DependentUpon>Json.resx</DependentUpon> </Compile> <Compile Include="NuGetTestHelpers.cs" /> + <Compile Include="PackageFolderTests.cs" /> <Compile Include="PreprocessorTests.cs" /> <Compile Include="ProjectReferences\ProjectReferenceTests.cs" /> <Compile Include="ProjectReferences\Resources.Designer.cs"> @@ -73,10 +74,12 @@ </ProjectReference> </ItemGroup> <ItemGroup> + <None Include="app.config" /> <None Include="Json\analyzers.json" /> <None Include="Json\FluentAssertions.lock.json" /> <None Include="Json\FluentAssertionsAndWin10.lock.json" /> <None Include="Json\nativeWinMD.json" /> + <None Include="Json\LockFileWithWithSpecifiedPackageFolders.json" /> <None Include="Json\Win10.Edm.json" /> <None Include="Json\Win10.json" /> <None Include="Json\Win10.xunit.json" /> diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/NuGetTestHelpers.cs b/src/Microsoft.NuGet.Build.Tasks.Tests/NuGetTestHelpers.cs index 4a0391a..690a64d 100644 --- a/src/Microsoft.NuGet.Build.Tasks.Tests/NuGetTestHelpers.cs +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/NuGetTestHelpers.cs @@ -26,13 +26,13 @@ namespace Microsoft.NuGet.Build.Tasks.Tests TryGetRuntimeVersion tryGetRuntimeVersion = null, bool includeFrameworkReferences = true, string projectJsonFileContents = null, - IEnumerable<ITaskItem> projectReferencesCreatingPackages = null) + IEnumerable<ITaskItem> projectReferencesCreatingPackages = null, + bool createTemporaryFolderForPackages = true) { var rootDirectory = new TempRoot(); using (rootDirectory) { var projectDirectory = rootDirectory.CreateDirectory(); - var packagesDirectory = rootDirectory.CreateDirectory(); var projectLockJsonFile = projectDirectory.CreateFile("project.lock.json"); projectLockJsonFile.WriteAllText(projectLockJsonFileContents); @@ -43,21 +43,41 @@ namespace Microsoft.NuGet.Build.Tasks.Tests projectJsonFile.WriteAllText(projectJsonFileContents); } - var filesInPackages = new HashSet<string>( - GetFakeFileNamesFromPackages(projectLockJsonFileContents, packagesDirectory.Path), - StringComparer.OrdinalIgnoreCase); + var filesInPackages = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + DisposableDirectory packagesDirectory = null; + + if (createTemporaryFolderForPackages) + { + packagesDirectory = rootDirectory.CreateDirectory(); + + foreach (var fileInPackage in GetFakeFileNamesFromPackages(projectLockJsonFileContents, packagesDirectory.Path)) + { + filesInPackages.Add(fileInPackage); + } + } + else + { + // We will assume there is a location in the lock file we're using + var lockFile = JObject.Parse(projectLockJsonFileContents); + var firstLocation = ((JObject)lockFile["packageFolders"]).Properties().First().Name; + + foreach (var fileInPackage in GetFakeFileNamesFromPackages(projectLockJsonFileContents, firstLocation)) + { + filesInPackages.Add(fileInPackage); + } + } // Don't require the packages be restored on the machine - DirectoryExists directoryExists = path => path.StartsWith(packagesDirectory.Path) || Directory.Exists(path); + ResolveNuGetPackageAssets task = null; FileExists fileExists = path => filesInPackages.Contains(path) || File.Exists(path); - ResolveNuGetPackageAssets task = new ResolveNuGetPackageAssets(directoryExists, fileExists, tryGetRuntimeVersion); + task = new ResolveNuGetPackageAssets(fileExists, tryGetRuntimeVersion); var sw = new StringWriter(); task.BuildEngine = new MockBuildEngine(sw); task.AllowFallbackOnTargetSelection = allowFallbackOnTargetSelection; task.IncludeFrameworkReferences = includeFrameworkReferences; - task.NuGetPackagesDirectory = packagesDirectory.Path; + task.NuGetPackagesDirectory = packagesDirectory?.Path; task.RuntimeIdentifier = runtimeIdentifier; task.ProjectReferencesCreatingPackages = (projectReferencesCreatingPackages ?? Enumerable.Empty<ITaskItem>()).ToArray(); task.ProjectLockFile = projectLockJsonFile.Path; @@ -95,6 +115,10 @@ namespace Microsoft.NuGet.Build.Tasks.Tests yield return Path.Combine(packagesDirectory, library.Name, file).Replace('/', '\\'); } } + + // Some earlier versions of NuGet didn't include the hash file in the file list, so fake that + // in here. + yield return Path.Combine(packagesDirectory, library.Name.Replace('/', '\\'), library.Name.Replace('/', '.') + ".nupkg.sha512"); } } } diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/PackageFolderTests.cs b/src/Microsoft.NuGet.Build.Tasks.Tests/PackageFolderTests.cs new file mode 100644 index 0000000..d8ef819 --- /dev/null +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/PackageFolderTests.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.NuGet.Build.Tasks.Tests +{ + public class PackageFolderTests + { + [Fact] + public void ResolveWithLockFileWithPackageFolders() + { + var result = NuGetTestHelpers.ResolvePackagesWithJsonFileContents( + Json.Json.LockFileWithWithSpecifiedPackageFolders, + ".NETFramework,Version=v4.5", + runtimeIdentifier: null, + createTemporaryFolderForPackages: false); + + Assert.Equal(@"C:\PackageFolder\Newtonsoft.Json\8.0.3\lib\net45\Newtonsoft.Json.dll", result.References.Single().ItemSpec); + } + } +} diff --git a/src/Microsoft.NuGet.Build.Tasks.Tests/app.config b/src/Microsoft.NuGet.Build.Tasks.Tests/app.config new file mode 100644 index 0000000..845f164 --- /dev/null +++ b/src/Microsoft.NuGet.Build.Tasks.Tests/app.config @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <appSettings> + <add key="xunit.shadowCopy" value="false"/> + </appSettings> +</configuration>
\ No newline at end of file diff --git a/src/Microsoft.NuGet.Build.Tasks/Delegates.cs b/src/Microsoft.NuGet.Build.Tasks/Delegates.cs index 56a3dba..5eed529 100644 --- a/src/Microsoft.NuGet.Build.Tasks/Delegates.cs +++ b/src/Microsoft.NuGet.Build.Tasks/Delegates.cs @@ -3,7 +3,6 @@ namespace Microsoft.NuGet.Build.Tasks { - internal delegate bool DirectoryExists(string path); internal delegate bool FileExists(string path); internal delegate string TryGetRuntimeVersion(string path); }
\ No newline at end of file diff --git a/src/Microsoft.NuGet.Build.Tasks/Microsoft.NuGet.Build.Tasks.csproj b/src/Microsoft.NuGet.Build.Tasks/Microsoft.NuGet.Build.Tasks.csproj index 163ddec..8aba143 100644 --- a/src/Microsoft.NuGet.Build.Tasks/Microsoft.NuGet.Build.Tasks.csproj +++ b/src/Microsoft.NuGet.Build.Tasks/Microsoft.NuGet.Build.Tasks.csproj @@ -13,7 +13,7 @@ <FileAlignment>512</FileAlignment> <TargetFrameworkProfile /> <SignAssembly>true</SignAssembly> - <DelaySign>true</DelaySign> + <PublicSign>true</PublicSign> <AssemblyOriginatorKeyFile>..\..\build\PublicKey.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> @@ -80,4 +80,4 @@ <Target Name="AfterBuild"> </Target> --> -</Project>
\ No newline at end of file +</Project> diff --git a/src/Microsoft.NuGet.Build.Tasks/ResolveNuGetPackageAssets.cs b/src/Microsoft.NuGet.Build.Tasks/ResolveNuGetPackageAssets.cs index 657869f..e2afbc8 100644 --- a/src/Microsoft.NuGet.Build.Tasks/ResolveNuGetPackageAssets.cs +++ b/src/Microsoft.NuGet.Build.Tasks/ResolveNuGetPackageAssets.cs @@ -44,22 +44,18 @@ namespace Microsoft.NuGet.Build.Tasks private readonly List<ITaskItem> _contentItems = new List<ITaskItem>(); private readonly List<ITaskItem> _fileWrites = new List<ITaskItem>(); + private readonly List<string> _packageFolders = new List<string>(); + private readonly Dictionary<string, string> _projectReferencesToOutputBasePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); #region UnitTestSupport - private readonly DirectoryExists _directoryExists = new DirectoryExists(Directory.Exists); private readonly FileExists _fileExists = new FileExists(File.Exists); private readonly TryGetRuntimeVersion _tryGetRuntimeVersion = new TryGetRuntimeVersion(TryGetRuntimeVersion); private readonly bool _reportExceptionsToMSBuildLogger = true; - internal ResolveNuGetPackageAssets(DirectoryExists directoryExists, FileExists fileExists, TryGetRuntimeVersion tryGetRuntimeVersion) + internal ResolveNuGetPackageAssets(FileExists fileExists, TryGetRuntimeVersion tryGetRuntimeVersion) : this() { - if (directoryExists != null) - { - _directoryExists = directoryExists; - } - if (fileExists != null) { _fileExists = fileExists; @@ -72,6 +68,13 @@ namespace Microsoft.NuGet.Build.Tasks _reportExceptionsToMSBuildLogger = false; } + + // For unit testing. + internal IEnumerable<string> GetPackageFolders() + { + return _packageFolders; + } + #endregion /// <summary> @@ -233,6 +236,8 @@ namespace Microsoft.NuGet.Build.Tasks lockFile = JObject.Load(new JsonTextReader(streamReader)); } + PopulatePackageFolders(lockFile); + PopulateProjectReferenceMaps(); GetReferences(lockFile); GetCopyLocalItems(lockFile); @@ -241,6 +246,41 @@ namespace Microsoft.NuGet.Build.Tasks ProduceContentAssets(lockFile); } + private void PopulatePackageFolders(JObject lockFile) + { + // If we explicitly were given a path, let's use that + if (!string.IsNullOrEmpty(NuGetPackagesDirectory)) + { + _packageFolders.Add(NuGetPackagesDirectory); + } + + // Newer versions of NuGet can now specify the final list of locations in the lock file + var packageFolders = lockFile["packageFolders"] as JObject; + + if (packageFolders != null) + { + foreach (var packageFolder in packageFolders.Properties()) + { + _packageFolders.Add(packageFolder.Name); + } + } + + // If we didn't have any folders, let's fall back to the environment variable or user profile + if (_packageFolders.Count == 0) + { + string packagesFolder = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); + + if (!string.IsNullOrEmpty(packagesFolder)) + { + _packageFolders.Add(packagesFolder); + } + else + { + _packageFolders.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages")); + } + } + } + private void PopulateProjectReferenceMaps() { foreach (var projectReference in ProjectReferencesCreatingPackages ?? new ITaskItem[] { }) @@ -579,7 +619,7 @@ namespace Microsoft.NuGet.Build.Tasks private void ProduceContentAsset(NuGetPackageObject package, JProperty sharedAsset, IReadOnlyDictionary<string, string> preprocessorValues, string preprocessedOutputDirectory) { string pathToFinalAsset = package.GetFullPathToFile(sharedAsset.Name); - + if (sharedAsset.Value["ppOutputPath"] != null) { if (preprocessedOutputDirectory == null) @@ -775,7 +815,7 @@ namespace Microsoft.NuGet.Build.Tasks { targetPath = Path.Combine(culture, Path.GetFileName(file.Name)); } - + var item = CreateItem(package, package.GetFullPathToFile(file.Name), targetPath); item.SetMetadata("Private", "false"); @@ -857,32 +897,19 @@ namespace Microsoft.NuGet.Build.Tasks private string GetNuGetPackagePath(string packageId, string packageVersion) { - string packagesFolder = GetNuGetPackagesPath(); - string packagePath = Path.Combine(packagesFolder, packageId, packageVersion); - - if (!_directoryExists(packagePath)) - { - throw new ExceptionFromResource(nameof(Strings.PackageFolderNotFound), packageId, packageVersion, packagesFolder); - } - - return packagePath; - } - - private string GetNuGetPackagesPath() - { - if (!string.IsNullOrEmpty(NuGetPackagesDirectory)) + foreach (var packagesFolder in _packageFolders) { - return NuGetPackagesDirectory; - } - - string packagesFolder = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); + string packagePath = Path.Combine(packagesFolder, packageId, packageVersion); - if (!string.IsNullOrEmpty(packagesFolder)) - { - return packagesFolder; + // The proper way to check if a package is available is to look for the hash file, since that's the last + // file written as a part of the restore process. If it's not there, it means something failed part way through. + if (_fileExists(Path.Combine(packagePath, $"{packageId}.{packageVersion}.nupkg.sha512"))) + { + return packagePath; + } } - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); + throw new ExceptionFromResource(nameof(Strings.PackageFolderNotFound), packageId, packageVersion, string.Join(", ", _packageFolders)); } private IEnumerable<NuGetPackageObject> GetPackagesFromTarget(JObject lockFile, JObject target) @@ -898,6 +925,11 @@ namespace Microsoft.NuGet.Build.Tasks Func<string> fullPackagePathGenerator; + if (libraryObject == null) + { + throw new ExceptionFromResource(nameof(Strings.MissingPackageInTargetsSection), package.Key); + } + // If this is a project then we need to figure out it's relative output path if ((string)libraryObject["type"] == "project") { @@ -923,7 +955,7 @@ namespace Microsoft.NuGet.Build.Tasks }; } else - { + { fullPackagePathGenerator = () => GetNuGetPackagePath(id, version); } diff --git a/src/Microsoft.NuGet.Build.Tasks/Strings.Designer.cs b/src/Microsoft.NuGet.Build.Tasks/Strings.Designer.cs index 66ba930..6d71ed9 100644 --- a/src/Microsoft.NuGet.Build.Tasks/Strings.Designer.cs +++ b/src/Microsoft.NuGet.Build.Tasks/Strings.Designer.cs @@ -106,6 +106,15 @@ namespace Microsoft.NuGet.Build.Tasks { } /// <summary> + /// Looks up a localized string similar to The package '{0}' could not be found in the libraries section of the lock file. This may indicate your lock file is corrupted.. + /// </summary> + internal static string MissingPackageInTargetsSection { + get { + return ResourceManager.GetString("MissingPackageInTargetsSection", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to The project.json is referencing the project '{0}', but an output path was not specified on an item in the {1} property.. /// </summary> internal static string MissingProjectReference { diff --git a/src/Microsoft.NuGet.Build.Tasks/Strings.resx b/src/Microsoft.NuGet.Build.Tasks/Strings.resx index 8e42512..03a7fd1 100644 --- a/src/Microsoft.NuGet.Build.Tasks/Strings.resx +++ b/src/Microsoft.NuGet.Build.Tasks/Strings.resx @@ -132,6 +132,9 @@ <data name="MissingMSBuildPathInProjectPackage" xml:space="preserve"> <value>Your project is consuming assets from the project '{0}' but no MSBuild project is found in the project.lock.json. Check the project references in your project file, and re-run NuGet restore.</value> </data> + <data name="MissingPackageInTargetsSection" xml:space="preserve"> + <value>The package '{0}' could not be found in the libraries section of the lock file. This may indicate your lock file is corrupted.</value> + </data> <data name="MissingProjectReference" xml:space="preserve"> <value>The project.json is referencing the project '{0}', but an output path was not specified on an item in the {1} property.</value> </data> |