public async Task DotnetCliTool_BasicToolRestore()
        {
            // Arrange
            using (var pathContext = new SimpleTestPathContext())
            {
                var logger = new TestLogger();
                var dgFile = new DependencyGraphSpec();

                var spec = ToolRestoreUtility.GetSpec(
                    Path.Combine(pathContext.SolutionRoot, "fake.csproj"),
                    "a",
                    VersionRange.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"));

                dgFile.AddProject(spec);
                dgFile.AddRestore(spec.Name);

                var pathResolver = new ToolPathResolver(pathContext.UserPackagesFolder);
                var path         = pathResolver.GetLockFilePath(
                    "a",
                    NuGetVersion.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"));

                await SimpleTestPackageUtility.CreateFolderFeedV3(pathContext.PackageSource, new PackageIdentity("a", NuGetVersion.Parse("1.0.0")));

                // Act
                var result = await CommandsTestUtility.RunSingleRestore(dgFile, pathContext, logger);

                // Assert
                Assert.True(result.Success, "Failed: " + string.Join(Environment.NewLine, logger.Messages));
                Assert.True(File.Exists(path));
            }
        }
Exemple #2
0
        private string GetAssetsFilePath(LockFile lockFile)
        {
            var projectLockFilePath = _request.LockFilePath;

            if (string.IsNullOrEmpty(projectLockFilePath))
            {
                if (_request.ProjectStyle == ProjectStyle.PackageReference ||
                    _request.ProjectStyle == ProjectStyle.Standalone)
                {
                    projectLockFilePath = Path.Combine(_request.RestoreOutputPath, LockFileFormat.AssetsFileName);
                }
                else if (_request.ProjectStyle == ProjectStyle.DotnetCliTool)
                {
                    var toolName        = ToolRestoreUtility.GetToolIdOrNullFromSpec(_request.Project);
                    var lockFileLibrary = ToolRestoreUtility.GetToolTargetLibrary(lockFile, toolName);

                    if (lockFileLibrary != null)
                    {
                        var version = lockFileLibrary.Version;

                        var toolPathResolver = new ToolPathResolver(_request.PackagesDirectory);
                        projectLockFilePath = toolPathResolver.GetLockFilePath(
                            toolName,
                            version,
                            lockFile.Targets.First().TargetFramework);
                    }
                }
                else
                {
                    projectLockFilePath = Path.Combine(_request.Project.BaseDirectory, LockFileFormat.LockFileName);
                }
            }

            return(Path.GetFullPath(projectLockFilePath));
        }
        public async Task DotnetCliTool_BasicToolRestore_DifferentVersionRanges()
        {
            // Arrange
            using (var pathContext = new SimpleTestPathContext())
            {
                var logger = new TestLogger();
                var dgFile = new DependencyGraphSpec();

                var versions = new List <VersionRange>();

                var limit = 100;

                for (int i = 0; i < limit; i++)
                {
                    var version = VersionRange.Parse($"{i + 1}.0.0");
                    versions.Add(version);

                    var spec = ToolRestoreUtility.GetSpec(
                        Path.Combine(pathContext.SolutionRoot, $"fake{i}.csproj"),
                        "a",
                        version,
                        NuGetFramework.Parse("netcoreapp1.0"));

                    dgFile.AddProject(spec);
                    dgFile.AddRestore(spec.Name);
                }

                var pathResolver = new ToolPathResolver(pathContext.UserPackagesFolder);

                foreach (var version in versions)
                {
                    await SimpleTestPackageUtility.CreateFolderFeedV3(pathContext.PackageSource, new PackageIdentity("a", version.MinVersion));
                }

                // Act
                var results = await CommandsTestUtility.RunRestore(dgFile, pathContext, logger);

                // Assert
                Assert.Equal(limit, results.Count);

                foreach (var result in results)
                {
                    Assert.True(result.Success, "Failed: " + string.Join(Environment.NewLine, logger.Messages));
                }

                foreach (var version in versions)
                {
                    var path = pathResolver.GetLockFilePath(
                        "a",
                        version.MinVersion,
                        NuGetFramework.Parse("netcoreapp1.0"));

                    Assert.True(File.Exists(path));
                }
            }
        }
        public async Task DotnetCliTool_BasicToolRestore_WithDuplicates()
        {
            // Arrange
            using (var pathContext = new SimpleTestPathContext())
            {
                var logger = new TestLogger();
                var dgFile = new DependencyGraphSpec();

                for (int i = 0; i < 10; i++)
                {
                    var spec = ToolRestoreUtility.GetSpec(
                        Path.Combine(pathContext.SolutionRoot, "fake.csproj"),
                        "a",
                        VersionRange.Parse("1.0.0"),
                        NuGetFramework.Parse("netcoreapp1.0"),
                        pathContext.UserPackagesFolder,
                        new List <string>()
                    {
                        pathContext.FallbackFolder
                    },
                        new List <PackageSource>()
                    {
                        new PackageSource(pathContext.PackageSource)
                    },
                        projectWideWarningProperties: null);

                    dgFile.AddProject(spec);
                    dgFile.AddRestore(spec.Name);
                }

                var pathResolver = new ToolPathResolver(pathContext.UserPackagesFolder);
                var path         = pathResolver.GetLockFilePath(
                    "a",
                    NuGetVersion.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"));

                await SimpleTestPackageUtility.CreateFolderFeedV3Async(pathContext.PackageSource, new PackageIdentity("a", NuGetVersion.Parse("1.0.0")));

                // Act
                var results = await CommandsTestUtility.RunRestore(dgFile, pathContext, logger);

                // Assert
                // This should have been de-duplicated
                Assert.Equal(1, results.Count);
                var result = results.Single();

                Assert.True(result.Success, "Failed: " + string.Join(Environment.NewLine, logger.Messages));
                Assert.True(File.Exists(path));
            }
        }
        /// <summary>
        /// This method will resolve the cache/lock file paths for the tool if available in the cache
        /// This method will set the CacheFilePath and the LockFilePath in the RestoreMetadat if a matching tool is available
        /// </summary>
        public static void UpdateRequestBestMatchingToolPathsIfAvailable(RestoreRequest request)
        {
            if (request.ProjectStyle == ProjectStyle.DotnetCliTool)
            {
                // Resolve the lock file path if it exists
                var toolPathResolver = new ToolPathResolver(request.PackagesDirectory);
                var toolDirectory    = toolPathResolver.GetBestToolDirectoryPath(
                    ToolRestoreUtility.GetToolIdOrNullFromSpec(request.Project),
                    request.Project.TargetFrameworks.First().Dependencies.First().LibraryRange.VersionRange,
                    request.Project.TargetFrameworks.SingleOrDefault().FrameworkName);

                if (toolDirectory != null) // Only set the paths if a good enough match was found.
                {
                    request.Project.RestoreMetadata.CacheFilePath = NoOpRestoreUtilities.GetToolCacheFilePath(toolDirectory, ToolRestoreUtility.GetToolIdOrNullFromSpec(request.Project));
                    request.LockFilePath = toolPathResolver.GetLockFilePath(toolDirectory);
                }
            }
        }
Exemple #6
0
        internal static string GetToolCacheFilePath(RestoreRequest request, LockFile lockFile)
        {
            if (request.ProjectStyle != ProjectStyle.DotnetCliTool)
            {
                var toolName        = ToolRestoreUtility.GetToolIdOrNullFromSpec(request.Project);
                var lockFileLibrary = ToolRestoreUtility.GetToolTargetLibrary(lockFile, toolName);

                if (lockFileLibrary != null)
                {
                    var version = lockFileLibrary.Version;

                    var toolPathResolver = new ToolPathResolver(request.PackagesDirectory);
                    var projFileName     = Path.GetFileName(request.Project.RestoreMetadata.ProjectPath);
                    return(PathUtility.GetDirectoryName(toolPathResolver.GetLockFilePath(
                                                            toolName,
                                                            version,
                                                            lockFile.Targets.First().TargetFramework)) + $"{projFileName}.nuget.cache");
                }
            }
            return(null);
        }
        public void ToolPathResolver_BuildsOriginalCaseLockFilePath()
        {
            // Arrange
            var target   = new ToolPathResolver("packages", isLowercase: false);
            var expected = Path.Combine(
                "packages",
                ".tools",
                "PackageA",
                "3.1.4-BETA",
                "netstandard1.3",
                "project.assets.json");

            // Act
            var actual = target.GetLockFilePath(
                "PackageA",
                NuGetVersion.Parse("3.1.4-BETA"),
                FrameworkConstants.CommonFrameworks.NetStandard13);

            // Assert
            Assert.Equal(expected, actual);
        }
        private async Task <IEnumerable <ToolRestoreResult> > ExecuteToolRestoresAsync(
            NuGetv3LocalRepository localRepository,
            CancellationToken token)
        {
            var toolPathResolver = new ToolPathResolver(_request.PackagesDirectory);
            var results          = new List <ToolRestoreResult>();

            foreach (var tool in _request.Project.Tools)
            {
                _logger.LogMinimal(string.Format(
                                       CultureInfo.CurrentCulture,
                                       Strings.Log_RestoringToolPackages,
                                       tool.LibraryRange.Name,
                                       _request.Project.FilePath));

                // Build the fallback framework (which uses the "imports").
                var framework = LockFile.ToolFramework;
                if (tool.Imports.Any())
                {
                    framework = new FallbackFramework(framework, tool.Imports);
                }

                // Build a package spec in memory to execute the tool restore as if it were
                // its own project. For now, we always restore for a null runtime and a single
                // constant framework.
                var toolPackageSpec = new PackageSpec(new JObject())
                {
                    Name             = Guid.NewGuid().ToString(), // make sure this package never collides with a dependency
                    Dependencies     = new List <LibraryDependency>(),
                    Tools            = new List <ToolDependency>(),
                    TargetFrameworks =
                    {
                        new TargetFrameworkInformation
                        {
                            FrameworkName = framework,
                            Dependencies  = new List <LibraryDependency>
                            {
                                new LibraryDependency
                                {
                                    LibraryRange = tool.LibraryRange
                                }
                            }
                        }
                    }
                };

                // Try to find the existing lock file. Since the existing lock file is pathed under
                // a folder that includes the resolved tool's version, this is a bit of a chicken
                // and egg problem. That is, we need to run the restore operation in order to resolve
                // a tool version, but we need the tool version to find the existing project.lock.json
                // file which is required before executing the restore! Fortunately, this is solved by
                // looking at the tool's consuming project's lock file to see if the tool has been
                // restored before.
                LockFile existingToolLockFile = null;
                if (_request.ExistingLockFile != null)
                {
                    var existingTarget = _request
                                         .ExistingLockFile
                                         .Tools
                                         .Where(t => t.RuntimeIdentifier == null)
                                         .Where(t => t.TargetFramework.Equals(LockFile.ToolFramework))
                                         .FirstOrDefault();

                    var existingLibrary = existingTarget?.Libraries
                                          .Where(l => StringComparer.OrdinalIgnoreCase.Equals(l.Name, tool.LibraryRange.Name))
                                          .Where(l => tool.LibraryRange.VersionRange.Satisfies(l.Version))
                                          .FirstOrDefault();

                    if (existingLibrary != null)
                    {
                        var existingLockFilePath = toolPathResolver.GetLockFilePath(
                            existingLibrary.Name,
                            existingLibrary.Version,
                            existingTarget.TargetFramework);

                        existingToolLockFile = LockFileUtilities.GetLockFile(existingLockFilePath, _logger);
                    }
                }

                // Execute the restore.
                var toolSuccess = true; // success for this individual tool restore
                var runtimeIds  = new HashSet <string>();
                var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(toolPackageSpec, runtimeIds);
                var allInstalledPackages         = new HashSet <LibraryIdentity>();
                var contextForTool        = CreateRemoteWalkContext(_request);
                var walker                = new RemoteDependencyWalker(contextForTool);
                var projectRestoreRequest = new ProjectRestoreRequest(
                    _request,
                    toolPackageSpec,
                    existingToolLockFile,
                    new Dictionary <NuGetFramework, RuntimeGraph>(),
                    _runtimeGraphCacheByPackage);
                var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest);
                var result = await projectRestoreCommand.TryRestore(
                    tool.LibraryRange,
                    projectFrameworkRuntimePairs,
                    allInstalledPackages,
                    localRepository,
                    walker,
                    contextForTool,
                    writeToLockFile : true,
                    token : token);

                var graphs = result.Item2;
                if (!result.Item1)
                {
                    toolSuccess = false;
                    _success    = false;
                }

                // Create the lock file (in memory).
                var toolLockFile = BuildLockFile(
                    existingToolLockFile,
                    toolPackageSpec,
                    graphs,
                    localRepository,
                    contextForTool,
                    Enumerable.Empty <ToolRestoreResult>(),
                    false);

                // Build the path based off of the resolved tool. For now, we assume there is only
                // ever one target.
                var target            = toolLockFile.Targets.Single();
                var fileTargetLibrary = target
                                        .Libraries
                                        .FirstOrDefault(l => StringComparer.OrdinalIgnoreCase.Equals(tool.LibraryRange.Name, l.Name));
                string toolLockFilePath = null;
                if (fileTargetLibrary != null)
                {
                    toolLockFilePath = toolPathResolver.GetLockFilePath(
                        fileTargetLibrary.Name,
                        fileTargetLibrary.Version,
                        target.TargetFramework);
                }

                // Validate the results.
                if (!ValidateRestoreGraphs(graphs, _logger))
                {
                    toolSuccess = false;
                    _success    = false;
                }

                var checkResults = VerifyCompatibility(
                    toolPackageSpec,
                    new Dictionary <RestoreTargetGraph, Dictionary <string, LibraryIncludeFlags> >(),
                    localRepository,
                    toolLockFile,
                    graphs,
                    _logger);

                if (checkResults.Any(r => !r.Success))
                {
                    toolSuccess = false;
                    _success    = false;
                }

                results.Add(new ToolRestoreResult(
                                tool.LibraryRange.Name,
                                toolSuccess,
                                target,
                                fileTargetLibrary,
                                toolLockFilePath,
                                toolLockFile,
                                existingToolLockFile));
            }

            return(results);
        }
        public async Task DotnetCliTool_VerifyProjectsAreNotAllowed()
        {
            // Arrange
            using (var pathContext = new SimpleTestPathContext())
            {
                var logger = new TestLogger();
                var dgFile = new DependencyGraphSpec();

                var spec = ToolRestoreUtility.GetSpec(
                    Path.Combine(pathContext.SolutionRoot, "tool", "fake.csproj"),
                    "a",
                    VersionRange.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"),
                    pathContext.UserPackagesFolder,
                    new List <string>()
                {
                    pathContext.FallbackFolder
                },
                    new List <PackageSource>()
                {
                    new PackageSource(pathContext.PackageSource)
                },
                    projectWideWarningProperties: null);

                dgFile.AddProject(spec);
                dgFile.AddRestore(spec.Name);

                var pathResolver = new ToolPathResolver(pathContext.UserPackagesFolder);
                var path         = pathResolver.GetLockFilePath(
                    "a",
                    NuGetVersion.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"));

                var packageA = new SimpleTestPackageContext()
                {
                    Id      = "a",
                    Version = "1.0.0"
                };

                var packageB = new SimpleTestPackageContext()
                {
                    Id      = "b",
                    Version = "1.0.0"
                };

                packageA.Dependencies.Add(packageB);

                await SimpleTestPackageUtility.CreateFolderFeedV3Async(
                    pathContext.PackageSource,
                    PackageSaveMode.Defaultv3,
                    packageA,
                    packageB);

                var projectYRoot = Path.Combine(pathContext.SolutionRoot, "b");
                Directory.CreateDirectory(projectYRoot);
                var projectYJson = Path.Combine(projectYRoot, "project.json");

                var projectJsonContent = JObject.Parse(@"{
                                                    'dependencies': {
                                                    },
                                                    'frameworks': {
                                                        'netstandard1.0': {
                                                    }
                                                  }
                                               }");

                File.WriteAllText(projectYJson, projectJsonContent.ToString());

                // Act
                var result = await CommandsTestUtility.RunSingleRestore(dgFile, pathContext, logger);

                // Assert
                Assert.True(result.Success, "Failed: " + string.Join(Environment.NewLine, logger.Messages));
                Assert.True(File.Exists(path));

                var lockFormat = new LockFileFormat();
                var lockFile   = lockFormat.Read(path);

                // Verify only packages
                Assert.Empty(lockFile.Libraries.Where(e => e.Type != "package"));
            }
        }
        public async Task DotnetCliTool_ToolRestoreNoOpsRegardlessOfProject()
        {
            // Arrange
            using (var pathContext = new SimpleTestPathContext())
            {
                var logger1 = new TestLogger();
                var logger2 = new TestLogger();

                var spec1 = ToolRestoreUtility.GetSpec(
                    Path.Combine(pathContext.SolutionRoot, "fake1.csproj"),
                    "a",
                    VersionRange.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"),
                    pathContext.UserPackagesFolder,
                    new List <string>()
                {
                    pathContext.FallbackFolder
                },
                    new List <PackageSource>()
                {
                    new PackageSource(pathContext.PackageSource)
                },
                    projectWideWarningProperties: null);

                var spec2 = ToolRestoreUtility.GetSpec(
                    Path.Combine(pathContext.SolutionRoot, "fake2.csproj"),
                    "a",
                    VersionRange.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"),
                    pathContext.UserPackagesFolder,
                    new List <string>()
                {
                    pathContext.FallbackFolder
                },
                    new List <PackageSource>()
                {
                    new PackageSource(pathContext.PackageSource)
                },
                    projectWideWarningProperties: null);

                var dgFile1 = new DependencyGraphSpec();
                dgFile1.AddProject(spec1);
                dgFile1.AddRestore(spec1.Name);

                var dgFile2 = new DependencyGraphSpec();
                dgFile2.AddProject(spec2);
                dgFile2.AddRestore(spec2.Name);

                var pathResolver = new ToolPathResolver(pathContext.UserPackagesFolder);
                var path         = pathResolver.GetLockFilePath(
                    "a",
                    NuGetVersion.Parse("1.0.0"),
                    NuGetFramework.Parse("netcoreapp1.0"));

                await SimpleTestPackageUtility.CreateFolderFeedV3Async(pathContext.PackageSource, new PackageIdentity("a", NuGetVersion.Parse("1.0.0")));

                // Act
                var results1 = await CommandsTestUtility.RunRestore(dgFile1, pathContext, logger1);

                // Assert
                Assert.Equal(1, results1.Count);
                var result1 = results1.Single();

                Assert.True(result1.Success, "Failed: " + string.Join(Environment.NewLine, logger1.Messages));
                Assert.False(result1.NoOpRestore, "Should not no-op: " + string.Join(Environment.NewLine, logger1.Messages));
                Assert.True(File.Exists(path));

                // Act
                var results2 = await CommandsTestUtility.RunRestore(dgFile2, pathContext, logger2);

                // Assert
                Assert.Equal(1, results2.Count);
                var result2 = results2.Single();

                Assert.True(result2.Success, "Failed: " + string.Join(Environment.NewLine, logger2.Messages));
                Assert.True(result2.NoOpRestore, "Should no-op: " + string.Join(Environment.NewLine, logger2.Messages));
                Assert.True(File.Exists(path));
            }
        }