Esempio n. 1
0
        public static CommandLineApplication Create()
        {
            var app = new CommandLineApplication(throwOnUnexpectedArg: false)
            {
                Name     = "dotnet ef",
                FullName = "Entity Framework .NET Core CLI Commands"
            };

            // TODO better help output https://github.com/aspnet/EntityFramework/issues/5188
            // app.HelpOption("-h|--help");

            var targetProjectOption = app.Option(
                "-p|--project <PROJECT>",
                "The project to target (defaults to the project in the current directory). Can be a path to a project.json or a project directory.");
            var startupProjectOption = app.Option(
                "-s|--startup-project <PROJECT>",
                "The path to the project containing Startup (defaults to the target project). Can be a path to a project.json or a project directory.");
            var configurationOption = app.Option(
                "-c|--configuration <CONFIGURATION>",
                $"Configuration under which to load (defaults to {Constants.DefaultConfiguration})");
            var frameworkOption = app.Option(
                "-f|--framework <FRAMEWORK>",
                $"Target framework to load from the startup project (defaults to the framework most compatible with {FrameworkConstants.CommonFrameworks.NetCoreApp10}).");
            var buildBasePathOption = app.Option(
                "-b|--build-base-path <OUTPUT_DIR>",
                "Directory in which to find temporary outputs.");
            var outputOption = app.Option(
                "-o|--output <OUTPUT_DIR>",
                "Directory in which to find outputs");
            var noBuildOption = app.Option("--no-build", "Do not build before executing.");

            app.OnExecute(() =>
            {
                var targetProjectPath = targetProjectOption.HasValue()
                    ? targetProjectOption.Value()
                    : Directory.GetCurrentDirectory();

                Project targetProject;
                if (!ProjectReader.TryGetProject(targetProjectPath, out targetProject))
                {
                    throw new OperationException($"Could not load target project '{targetProjectPath}'");
                }

                Reporter.Verbose.WriteLine(ToolsStrings.LogUsingTargetProject(targetProject.Name));

                Project startupProject;
                if (startupProjectOption.HasValue())
                {
                    var startupPath = startupProjectOption.Value();
                    if (!ProjectReader.TryGetProject(startupPath, out startupProject))
                    {
                        throw new OperationException($"Could not load project '{startupPath}'");
                    }
                }
                else
                {
                    startupProject = targetProject;
                }

                Reporter.Verbose.WriteLine(ToolsStrings.LogUsingStartupProject(startupProject.Name));

                var startupFramework = frameworkOption.HasValue()
                    ? NuGetFramework.Parse(frameworkOption.Value())
                    : null;

                if (startupFramework == null)
                {
                    var frameworks   = startupProject.GetTargetFrameworks().Select(i => i.FrameworkName);
                    startupFramework = NuGetFrameworkUtility.GetNearest(frameworks, FrameworkConstants.CommonFrameworks.NetCoreApp10, f => f)
                                       ?? frameworks.FirstOrDefault();

                    Reporter.Verbose.WriteLine(ToolsStrings.LogUsingFramework(startupFramework.GetShortFolderName()));
                }

                var configuration = configurationOption.Value();

                if (configuration == null)
                {
                    configuration = Constants.DefaultConfiguration;

                    Reporter.Verbose.WriteLine(ToolsStrings.LogUsingConfiguration(configuration));
                }

                if (!noBuildOption.HasValue())
                {
                    var buildExitCode = BuildCommandFactory.Create(
                        startupProject.ProjectFilePath,
                        configuration,
                        startupFramework,
                        buildBasePathOption.Value(),
                        outputOption.Value())
                                        .ForwardStdErr()
                                        .ForwardStdOut()
                                        .Execute()
                                        .ExitCode;
                    if (buildExitCode != 0)
                    {
                        throw new OperationException(ToolsStrings.BuildFailed(startupProject.Name));
                    }
                }

                var startupProjectContext = ProjectContext.Create(
                    startupProject.ProjectFilePath,
                    startupFramework,
                    RuntimeEnvironmentRidExtensions.GetAllCandidateRuntimeIdentifiers());

                var startupOutputPaths = startupProjectContext
                                         .GetOutputPaths(configuration, buildBasePathOption.Value(), outputOption.Value());

                // TODO remove when https://github.com/dotnet/cli/issues/2645 is resolved
                Func <bool> isClassLibrary = () =>
                {
                    return(startupOutputPaths.RuntimeFiles == null ||
                           (
                               startupFramework.IsDesktop()
                                ? !Directory.Exists(startupOutputPaths.RuntimeFiles.BasePath)
                                : !File.Exists(startupOutputPaths.RuntimeFiles.RuntimeConfigJson) || !File.Exists(startupOutputPaths.RuntimeFiles.DepsJson)
                           ));
                };

                Reporter.Verbose.WriteLine(ToolsStrings.LogDataDirectory(startupOutputPaths.RuntimeOutputPath));

                // Workaround https://github.com/dotnet/cli/issues/3164
                var isExecutable = startupProject.GetCompilerOptions(startupFramework, configuration).EmitEntryPoint
                                   ?? startupProject.GetCompilerOptions(null, configuration).EmitEntryPoint.GetValueOrDefault();

                var startupAssembly = isExecutable
                    ? startupOutputPaths.RuntimeFiles.Executable
                    : startupOutputPaths.RuntimeFiles.Assembly;

                var targetAssembly = targetProject.ProjectFilePath.Equals(startupProject.ProjectFilePath)
                    ? startupAssembly
                                     // This assumes the target assembly is present in the startup project context and is a *.dll
                                     // TODO create a project context for target project as well to ensure filename is correct
                    : Path.Combine(startupOutputPaths.RuntimeOutputPath,
                                   targetProject.GetCompilerOptions(null, configuration).OutputName + FileNameSuffixes.DotNet.DynamicLib);

                Reporter.Verbose.WriteLine(ToolsStrings.LogBeginDispatch(ProjectDependencyToolName, startupProject.Name));

                try
                {
                    bool isVerbose;
                    bool.TryParse(Environment.GetEnvironmentVariable(CommandContext.Variables.Verbose), out isVerbose);
                    var dispatchArgs = CreateArgs(
                        assembly: targetAssembly,
                        startupAssembly: startupOutputPaths.RuntimeFiles.Assembly,
                        dispatcherVersion: ThisAssemblyVersion,
                        dataDir: startupOutputPaths.RuntimeOutputPath,
                        contentRootPath: startupProject.ProjectDirectory,
                        projectDir: targetProject.ProjectDirectory,
                        rootNamespace: targetProject.Name,
                        verbose: isVerbose)
                                       .Concat(app.RemainingArguments);

                    var buildBasePath = buildBasePathOption.Value();
                    if (buildBasePath != null && !Path.IsPathRooted(buildBasePath))
                    {
                        // ProjectDependenciesCommandFactory cannot handle relative build base paths.
                        buildBasePath = Path.Combine(Directory.GetCurrentDirectory(), buildBasePath);
                    }

                    return(new ProjectDependenciesCommandFactory(
                               startupFramework,
                               configuration,
                               outputOption.Value(),
                               buildBasePath,
                               startupProject.ProjectDirectory)
                           .Create(ProjectDependencyToolName, dispatchArgs, startupFramework, configuration)
                           .ForwardStdErr()
                           .ForwardStdOut()
                           .Execute()
                           .ExitCode);
                }
                catch (CommandUnknownException ex)
                {
                    Reporter.Verbose.WriteLine(ex.Message);

                    var fwlink = "http://go.microsoft.com/fwlink/?LinkId=798221";

                    if (isClassLibrary())
                    {
                        Reporter.Error.WriteLine(
                            ToolsStrings.ClassLibrariesNotSupportedInCli(startupProject.Name, fwlink).Bold().Red());
                    }
                    else if (startupFramework.IsDesktop() && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        Reporter.Error.WriteLine(
                            ToolsStrings.DesktopCommandsRequiresWindows(startupFramework.GetShortFolderName()).Bold().Red());
                    }
                    else
                    {
                        Reporter.Error.WriteLine(
                            ToolsStrings.ProjectDependencyCommandNotFound(
                                startupProject.Name,
                                ProjectDependencyToolName,
                                DispatcherToolName,
                                fwlink).Bold().Red());
                    }

                    return(1);
                }
            });

            return(app);
        }
Esempio n. 2
0
        private static IEnumerable <Package> GetUpdates(
            IEnumerable <Package> packages,
            ILookup <string, Tuple <NuGetVersion, VersionRange> > versionLookup,
            IEnumerable <NuGetFramework> targetFrameworkValues,
            bool includeAllVersions,
            string semVerLevel)
        {
            var isSemVerLevelCompliant = SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel).Compile();

            var updates = from p in packages.AsEnumerable()
                          let version = NuGetVersion.Parse(p.Version)
                                        where isSemVerLevelCompliant(p) &&
                                        versionLookup[p.PackageRegistration.Id].Any(versionTuple =>
            {
                NuGetVersion clientVersion     = versionTuple.Item1;
                var supportedPackageFrameworks = p.SupportedFrameworks.Select(f => f.FrameworkName);

                VersionRange versionConstraint = versionTuple.Item2;

                return(version > clientVersion &&
                       (targetFrameworkValues == null ||
                        !supportedPackageFrameworks.Any() ||
                        targetFrameworkValues.Any(s => supportedPackageFrameworks.Any(supported => NuGetFrameworkUtility.IsCompatibleWithFallbackCheck(s, supported)))) &&
                       (versionConstraint == null ||
                        versionConstraint.Satisfies(version)));
            })
                                        select p;

            if (!includeAllVersions)
            {
                updates = updates.GroupBy(p => p.PackageRegistration.Id)
                          .Select(g => g.OrderByDescending(p => NuGetVersion.Parse(p.Version)).First());
            }

            return(updates);
        }
        /// <summary>
        /// The lock file will get invalidated if one or more of the below are true
        ///     1. The target frameworks list of the current project was updated.
        ///     2. The runtime list of the current project waw updated.
        ///     3. The packages of the current project were updated.
        ///     4. The packages of the dependent projects were updated.
        ///     5. The framework list of the dependent projects were updated with frameworks incompatible with the main project framework.
        ///     6. If the version of the <paramref name="nuGetLockFile"/> is larger than the current tools <see cref="PackagesLockFileFormat.PackagesLockFileVersion"/>.
        /// </summary>
        /// <param name="dgSpec">The <see cref="DependencyGraphSpec"/> for the new project defintion.</param>
        /// <param name="nuGetLockFile">The current <see cref="PackagesLockFile"/>.</param>
        /// <returns>Returns LockFileValidityWithInvalidReasons object with IsValid set to true if the lock file is valid false otherwise.
        /// The second return type is a localized message that indicates in further detail the reason for the inconsistency.</returns>
        public static LockFileValidationResult IsLockFileValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)
        {
            if (dgSpec == null)
            {
                throw new ArgumentNullException(nameof(dgSpec));
            }

            if (nuGetLockFile == null)
            {
                throw new ArgumentNullException(nameof(nuGetLockFile));
            }

            List <string> invalidReasons = new List <string>();

            // Current tools know how to read only previous formats including the current
            if (PackagesLockFileFormat.PackagesLockFileVersion < nuGetLockFile.Version)
            {
                invalidReasons.Add(string.Format(
                                       CultureInfo.CurrentCulture,
                                       Strings.PackagesLockFile_IncompatibleLockFileVersion,
                                       PackagesLockFileFormat.PackagesLockFileVersion
                                       ));

                return(new LockFileValidationResult(false, invalidReasons));
            }

            var uniqueName = dgSpec.Restore.First();
            var project    = dgSpec.GetProjectSpec(uniqueName);

            // Validate all the direct dependencies
            NuGetFramework[] lockFileFrameworks = nuGetLockFile.Targets
                                                  .Where(t => t.TargetFramework != null)
                                                  .Select(t => t.TargetFramework)
                                                  .Distinct()
                                                  .ToArray();

            if (project.TargetFrameworks.Count != lockFileFrameworks.Length)
            {
                invalidReasons.Add(string.Format(
                                       CultureInfo.CurrentCulture,
                                       Strings.PackagesLockFile_MismatchedTargetFrameworks,
                                       string.Join(",", project.TargetFrameworks.Select(e => e.FrameworkName.GetShortFolderName())),
                                       string.Join(",", lockFileFrameworks.Select(e => e.GetShortFolderName()))
                                       ));
            }
            else
            {
                // Validate the runtimes for the current project did not change.
                var projectRuntimesKeys = project.RuntimeGraph.Runtimes.Select(r => r.Key).Where(k => k != null);
                var lockFileRuntimes    = nuGetLockFile.Targets.Select(t => t.RuntimeIdentifier).Where(r => r != null).Distinct();

                if (!projectRuntimesKeys.OrderedEquals(
                        lockFileRuntimes,
                        x => x,
                        StringComparer.InvariantCultureIgnoreCase,
                        StringComparer.InvariantCultureIgnoreCase))
                {
                    invalidReasons.Add(string.Format(
                                           CultureInfo.CurrentCulture,
                                           Strings.PackagesLockFile_RuntimeIdentifiersChanged,
                                           string.Join(";", projectRuntimesKeys.OrderBy(e => e)),
                                           string.Join(";", lockFileRuntimes.OrderBy(e => e))
                                           ));
                }

                foreach (var framework in project.TargetFrameworks)
                {
                    var target = nuGetLockFile.Targets.FirstOrDefault(
                        t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                    if (target == null)
                    {
                        // a new target found in the dgSpec so invalidate existing lock file.
                        invalidReasons.Add(string.Format(
                                               CultureInfo.CurrentCulture,
                                               Strings.PackagesLockFile_NewTargetFramework,
                                               framework.FrameworkName.GetShortFolderName())
                                           );

                        continue;
                    }

                    IEnumerable <LockFileDependency> directDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Direct);

                    (var hasProjectDependencyChanged, var pmessage) = HasDirectPackageDependencyChanged(framework.Dependencies, directDependencies, target.TargetFramework);
                    if (hasProjectDependencyChanged)
                    {
                        // lock file is out of sync
                        invalidReasons.Add(pmessage);
                    }

                    var transitiveDependenciesEnforcedByCentralVersions = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.CentralTransitive).ToList();
                    var transitiveDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Transitive).ToList();

                    (var hasTransitiveDependencyChanged, var tmessage) = HasProjectTransitiveDependencyChanged(framework.CentralPackageVersions, transitiveDependenciesEnforcedByCentralVersions, transitiveDependencies);
                    if (hasTransitiveDependencyChanged)
                    {
                        // lock file is out of sync
                        invalidReasons.Add(tmessage);
                    }
                }

                // Validate all P2P references
                foreach (var restoreMetadataFramework in project.RestoreMetadata.TargetFrameworks)
                {
                    var target = nuGetLockFile.Targets.FirstOrDefault(
                        t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, restoreMetadataFramework.FrameworkName));

                    if (target == null)
                    {
                        continue;
                    }

                    var queue = new Queue <Tuple <string, string> >();
                    var visitedP2PReference = new HashSet <string>();

                    foreach (var projectReference in restoreMetadataFramework.ProjectReferences)
                    {
                        if (visitedP2PReference.Add(projectReference.ProjectUniqueName))
                        {
                            PackageSpec spec = dgSpec.GetProjectSpec(projectReference.ProjectUniqueName);
                            queue.Enqueue(new Tuple <string, string>(spec.Name, projectReference.ProjectUniqueName));

                            while (queue.Count > 0)
                            {
                                var projectNames      = queue.Dequeue();
                                var p2pUniqueName     = projectNames.Item2;
                                var p2pProjectName    = projectNames.Item1;
                                var projectDependency = target.Dependencies.FirstOrDefault(
                                    dep => dep.Type == PackageDependencyType.Project &&
                                    StringComparer.OrdinalIgnoreCase.Equals(dep.Id, p2pProjectName));

                                if (projectDependency == null)
                                {
                                    // new direct project dependency.
                                    // If there are changes in the P2P2P references, they will be caught in HasP2PDependencyChanged.
                                    invalidReasons.Add(string.Format(
                                                           CultureInfo.CurrentCulture,
                                                           Strings.PackagesLockFile_ProjectReferenceAdded,
                                                           p2pProjectName,
                                                           target.TargetFramework.GetShortFolderName()
                                                           ));

                                    continue;
                                }

                                var p2pSpec = dgSpec.GetProjectSpec(p2pUniqueName);

                                if (p2pSpec != null)
                                {
                                    TargetFrameworkInformation p2pSpecTargetFrameworkInformation = default;
                                    if (p2pSpec.RestoreMetadata.ProjectStyle == ProjectStyle.PackagesConfig || p2pSpec.RestoreMetadata.ProjectStyle == ProjectStyle.Unknown)
                                    {
                                        // Skip compat check and dependency check for non PR projects.
                                        // Projects that are not PR do not undergo compat checks by NuGet and do not contribute anything transitively.
                                        p2pSpecTargetFrameworkInformation = p2pSpec.TargetFrameworks.FirstOrDefault();
                                    }
                                    else
                                    {
                                        // This does not consider ATF.
                                        p2pSpecTargetFrameworkInformation = NuGetFrameworkUtility.GetNearest(p2pSpec.TargetFrameworks, restoreMetadataFramework.FrameworkName, e => e.FrameworkName);
                                    }
                                    // No compatible framework found
                                    if (p2pSpecTargetFrameworkInformation != null)
                                    {
                                        // We need to compare the main framework only. Ignoring fallbacks.
                                        var p2pSpecProjectRestoreMetadataFrameworkInfo = p2pSpec.RestoreMetadata.TargetFrameworks.FirstOrDefault(
                                            t => NuGetFramework.Comparer.Equals(p2pSpecTargetFrameworkInformation.FrameworkName, t.FrameworkName));

                                        if (p2pSpecProjectRestoreMetadataFrameworkInfo != null)
                                        {
                                            (var hasChanged, var message) = HasP2PDependencyChanged(p2pSpecTargetFrameworkInformation.Dependencies, p2pSpecProjectRestoreMetadataFrameworkInfo.ProjectReferences, projectDependency, dgSpec);

                                            if (hasChanged)
                                            {
                                                // P2P transitive package dependencies have changed
                                                invalidReasons.Add(message);
                                            }

                                            foreach (var reference in p2pSpecProjectRestoreMetadataFrameworkInfo.ProjectReferences)
                                            {
                                                // Do not add private assets for processing.
                                                if (visitedP2PReference.Add(reference.ProjectUniqueName) && reference.PrivateAssets != LibraryIncludeFlags.All)
                                                {
                                                    var referenceSpec = dgSpec.GetProjectSpec(reference.ProjectUniqueName);
                                                    queue.Enqueue(new Tuple <string, string>(referenceSpec.Name, reference.ProjectUniqueName));
                                                }
                                            }
                                        }
                                        else // This should never happen.
                                        {
                                            throw new Exception(string.Format(CultureInfo.CurrentCulture, Strings.PackagesLockFile_RestoreMetadataMissingTfms));
                                        }
                                    }
                                    else
                                    {
                                        invalidReasons.Add(string.Format(
                                                               CultureInfo.CurrentCulture,
                                                               Strings.PackagesLockFile_ProjectReferenceHasNoCompatibleTargetFramework,
                                                               p2pProjectName,
                                                               restoreMetadataFramework.FrameworkName.GetShortFolderName()
                                                               ));
                                    }
                                }
                                else // This can't happen. When adding the queue, the referenceSpec HAS to be discovered. If the project is otherwise missing, it will be discovered in HasP2PDependencyChanged
                                {
                                    throw new Exception(string.Format(
                                                            CultureInfo.CurrentCulture,
                                                            Strings.PackagesLockFile_UnableToLoadPackagespec,
                                                            p2pUniqueName));
                                }
                            }
                        }
                    }
                }
            }

            bool isLockFileValid = invalidReasons.Count == 0;

            return(new LockFileValidationResult(isLockFileValid, invalidReasons));
        }
        /// <summary>
        /// Asynchronously gets reference items.
        /// </summary>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A task that represents the asynchronous operation.
        /// The task result (<see cref="Task{TResult}.Result" />) returns an
        /// <see cref="IEnumerable{FrameworkSpecificGroup}" />.</returns>
        /// <exception cref="OperationCanceledException">Thrown if <paramref name="cancellationToken" />
        /// is cancelled.</exception>
        public override async Task <IEnumerable <FrameworkSpecificGroup> > GetReferenceItemsAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var nuspecReader = await GetNuspecReaderAsync(cancellationToken).ConfigureAwait(false);

            var referenceGroups = nuspecReader.GetReferenceGroups();
            var fileGroups      = new List <FrameworkSpecificGroup>();

            // filter out non reference assemblies
            foreach (var group in await GetLibItemsAsync(cancellationToken).ConfigureAwait(false))
            {
                fileGroups.Add(new FrameworkSpecificGroup(group.TargetFramework, group.Items.Where(e => IsReferenceAssembly(e))));
            }

            // results
            var libItems = new List <FrameworkSpecificGroup>();

            if (referenceGroups.Any())
            {
                // the 'any' group from references, for pre2.5 nuspecs this will be the only group
                var fallbackGroup = referenceGroups.Where(g => g.TargetFramework.Equals(NuGetFramework.AnyFramework)).FirstOrDefault();

                foreach (var fileGroup in fileGroups)
                {
                    // check for a matching reference group to use for filtering
                    var referenceGroup = NuGetFrameworkUtility.GetNearest(
                        items: referenceGroups,
                        framework: fileGroup.TargetFramework,
                        frameworkMappings: FrameworkProvider,
                        compatibilityProvider: CompatibilityProvider);

                    if (referenceGroup == null)
                    {
                        referenceGroup = fallbackGroup;
                    }

                    if (referenceGroup == null)
                    {
                        // add the lib items without any filtering
                        libItems.Add(fileGroup);
                    }
                    else
                    {
                        var filteredItems = new List <string>();

                        foreach (var path in fileGroup.Items)
                        {
                            // reference groups only have the file name, not the path
                            var file = Path.GetFileName(path);

                            if (referenceGroup.Items.Any(s => StringComparer.OrdinalIgnoreCase.Equals(s, file)))
                            {
                                filteredItems.Add(path);
                            }
                        }

                        if (filteredItems.Any())
                        {
                            libItems.Add(new FrameworkSpecificGroup(fileGroup.TargetFramework, filteredItems));
                        }
                    }
                }
            }
            else
            {
                libItems.AddRange(fileGroups);
            }

            return(libItems);
        }
Esempio n. 5
0
 internal static T GetNearest <T>(IEnumerable <T> items) where T : IFrameworkSpecific
 {
     return(NuGetFrameworkUtility.GetNearest(items, NuGetFramework.Parse(_targetFramework)));
 }
Esempio n. 6
0
 internal static IFrameworkSpecific GetNearest(IEnumerable <string> items)
 {
     return(NuGetFrameworkUtility.GetNearest(items.Select(item => (IFrameworkSpecific)NuGetFramework.Parse(item)), NuGetFramework.Parse(_targetFramework)));
 }
Esempio n. 7
0
 private ProjectContext SelectCompatibleFramework(NuGetFramework target, IEnumerable <ProjectContext> contexts)
 {
     return(NuGetFrameworkUtility.GetNearest(contexts, target ?? FrameworkConstants.CommonFrameworks.NetCoreApp10,
                                             f => f.TargetFramework) ?? contexts.First());
 }
        private ITaskItem AssignNearestFrameworkForSingleReference(
            ITaskItem project,
            NuGetFramework projectNuGetFramework,
            IList <NuGetFramework> fallbackNuGetFrameworks,
            MSBuildLogger logger)
        {
            var itemWithProperties = new TaskItem(project);
            var referencedProjectFrameworkString = project.GetMetadata(TARGET_FRAMEWORKS);
            var referenceTargetFrameworkMonikers = project.GetMetadata(TARGET_FRAMEWORK_MONIKERS);
            var referencedProjectPlatformString  = project.GetMetadata(TARGET_PLATFORM_MONIKERS);

            var referencedProjectFile = project.GetMetadata(MSBUILD_SOURCE_PROJECT_FILE);

            if (string.IsNullOrEmpty(referencedProjectFrameworkString))
            {
                // No target frameworks set, nothing to do.
                return(itemWithProperties);
            }

            var referencedProjectFrameworks = MSBuildStringUtility.Split(referencedProjectFrameworkString);
            var referencedProjectTargetFrameworkMonikers = MSBuildStringUtility.Split(referenceTargetFrameworkMonikers);
            var referencedProjectTargetPlatformMonikers  = MSBuildStringUtility.Split(referencedProjectPlatformString);

            if (referencedProjectTargetFrameworkMonikers.Length > 0 &&
                (referencedProjectTargetFrameworkMonikers.Length != referencedProjectTargetPlatformMonikers.Length ||
                 referencedProjectTargetFrameworkMonikers.Length != referencedProjectFrameworks.Length))
            {
                logger.LogError($"Internal error for {CurrentProjectName}." +
                                $" Expected {TARGET_FRAMEWORKS}:{referencedProjectFrameworks}, " +
                                $"{TARGET_FRAMEWORK_MONIKERS}:{referenceTargetFrameworkMonikers}, " +
                                $"{TARGET_PLATFORM_MONIKERS}:{referencedProjectPlatformString} to have the same number of elements.");
                return(itemWithProperties);
            }
            // TargetFrameworks, TargetFrameworkMoniker, TargetPlatforMoniker
            var targetFrameworkInformations = new List <TargetFrameworkInformation>();
            var useTargetMonikers           = referencedProjectTargetFrameworkMonikers.Length > 0;

            for (int i = 0; i < referencedProjectFrameworks.Length; i++)
            {
                targetFrameworkInformations.Add(new TargetFrameworkInformation(
                                                    referencedProjectFrameworks[i],
                                                    useTargetMonikers ? referencedProjectTargetFrameworkMonikers[i] : null,
                                                    useTargetMonikers ? referencedProjectTargetPlatformMonikers[i] : null));
            }

            // try project framework
            var nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(targetFrameworkInformations, projectNuGetFramework, GetNuGetFramework);

            if (nearestNuGetFramework != null)
            {
                itemWithProperties.SetMetadata(NEAREST_TARGET_FRAMEWORK, nearestNuGetFramework._targetFrameworkAlias);
                return(itemWithProperties);
            }

            // try project fallback frameworks
            foreach (var currentProjectTargetFramework in fallbackNuGetFrameworks)
            {
                nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(targetFrameworkInformations, currentProjectTargetFramework, GetNuGetFramework);

                if (nearestNuGetFramework != null)
                {
                    var message = string.Format(CultureInfo.CurrentCulture,
                                                Strings.ImportsFallbackWarning,
                                                referencedProjectFile,
                                                currentProjectTargetFramework.DotNetFrameworkName,
                                                projectNuGetFramework.DotNetFrameworkName);

                    var warning = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1702, message);
                    warning.LibraryId   = referencedProjectFile;
                    warning.ProjectPath = CurrentProjectName;

                    // log NU1702 for ATF on project reference
                    logger.Log(warning);

                    itemWithProperties.SetMetadata(NEAREST_TARGET_FRAMEWORK, nearestNuGetFramework._targetFrameworkAlias);
                    return(itemWithProperties);
                }
            }

            // no match found
            logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.NoCompatibleTargetFramework, project.ItemSpec, projectNuGetFramework.DotNetFrameworkName, referencedProjectFrameworkString));
            return(itemWithProperties);
        }
        public static bool IsLockFileStillValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)
        {
            var uniqueName = dgSpec.Restore.First();
            var project    = dgSpec.GetProjectSpec(uniqueName);

            // Validate all the direct dependencies
            foreach (var framework in project.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var directDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Direct);

                if (HasProjectDependencyChanged(framework.Dependencies, directDependencies))
                {
                    // lock file is out of sync
                    return(false);
                }
            }

            // Validate all P2P references
            foreach (var framework in project.RestoreMetadata.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var queue = new Queue <Tuple <string, string> >();
                var visitedP2PReference = new HashSet <string>();

                foreach (var projectReference in framework.ProjectReferences)
                {
                    if (visitedP2PReference.Add(projectReference.ProjectUniqueName))
                    {
                        var spec = dgSpec.GetProjectSpec(projectReference.ProjectUniqueName);
                        queue.Enqueue(new Tuple <string, string>(spec.Name, projectReference.ProjectUniqueName));

                        while (queue.Count > 0)
                        {
                            var projectNames   = queue.Dequeue();
                            var p2pUniqueName  = projectNames.Item2;
                            var p2pProjectName = projectNames.Item1;

                            var projectDependency = target.Dependencies.FirstOrDefault(
                                dep => dep.Type == PackageDependencyType.Project &&
                                PathUtility.GetStringComparerBasedOnOS().Equals(dep.Id, p2pProjectName));

                            if (projectDependency == null)
                            {
                                // project dependency doesn't exist in lock file.
                                return(false);
                            }

                            var p2pSpec = dgSpec.GetProjectSpec(p2pUniqueName);

                            // The package spec not found in the dg spec. This could mean that the project does not exist anymore.
                            if (p2pSpec != null)
                            {
                                var p2pSpecTarget = NuGetFrameworkUtility.GetNearest(p2pSpec.TargetFrameworks, framework.FrameworkName, e => e.FrameworkName);

                                // No compatible framework found
                                if (p2pSpecTarget != null)
                                {
                                    var p2pSpecProjectRefTarget = p2pSpec.RestoreMetadata.TargetFrameworks.FirstOrDefault(
                                        t => EqualityUtility.EqualsWithNullCheck(p2pSpecTarget.FrameworkName, t.FrameworkName));

                                    if (p2pSpecProjectRefTarget != null) // This should never happen.
                                    {
                                        if (HasP2PDependencyChanged(p2pSpecTarget.Dependencies, p2pSpecProjectRefTarget.ProjectReferences, projectDependency, dgSpec))
                                        {
                                            // P2P transitive package dependencies have changed
                                            return(false);
                                        }

                                        foreach (var reference in p2pSpecProjectRefTarget.ProjectReferences)
                                        {
                                            if (visitedP2PReference.Add(reference.ProjectUniqueName))
                                            {
                                                var referenceSpec = dgSpec.GetProjectSpec(reference.ProjectUniqueName);
                                                queue.Enqueue(new Tuple <string, string>(referenceSpec.Name, reference.ProjectUniqueName));
                                            }
                                        }
                                    }
                                    else
                                    {
                                        return(false);
                                    }
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                            else
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 10
0
        /// <summary>
        /// The lock file will get invalidated if one or more of the below are true
        ///     1. The target frameworks list of the current project was updated.
        ///     2. The runtime list of the current project waw updated.
        ///     3. The packages of the current project were updated.
        ///     4. The packages of the dependent projects were updated.
        ///     5. The framework list of the dependent projects were updated with frameworks incompatible with the main project framework.
        ///     6. If the version of the <paramref name="nuGetLockFile"/> is larger than the current tools <see cref="PackagesLockFileFormat.PackagesLockFileVersion"/>.
        /// </summary>
        /// <param name="dgSpec">The <see cref="DependencyGraphSpec"/> for the new project defintion.</param>
        /// <param name="nuGetLockFile">The current <see cref="PackagesLockFile"/>.</param>
        /// <returns>True if the lock file is valid false otherwise. </returns>
        public static bool IsLockFileStillValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)
        {
            // Current tools know how to read only previous formats including the current
            if (PackagesLockFileFormat.PackagesLockFileVersion < nuGetLockFile.Version)
            {
                return(false);
            }

            var uniqueName = dgSpec.Restore.First();
            var project    = dgSpec.GetProjectSpec(uniqueName);

            // Validate all the direct dependencies
            var lockFileFrameworks = nuGetLockFile.Targets
                                     .Where(t => t.TargetFramework != null)
                                     .Select(t => t.TargetFramework)
                                     .Distinct();

            if (project.TargetFrameworks.Count != lockFileFrameworks.Count())
            {
                return(false);
            }

            foreach (var framework in project.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var directDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Direct);

                if (HasProjectDependencyChanged(framework.Dependencies, directDependencies))
                {
                    // lock file is out of sync
                    return(false);
                }

                var transitiveDependenciesEnforcedByCentralVersions = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.CentralTransitive).ToList();
                var transitiveDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Transitive).ToList();

                if (HasProjectTransitiveDependencyChanged(framework.CentralPackageVersions, transitiveDependenciesEnforcedByCentralVersions, transitiveDependencies))
                {
                    // lock file is out of sync
                    return(false);
                }
            }

            // Validate the runtimes for the current project did not change.
            var projectRuntimesKeys = project.RuntimeGraph.Runtimes.Select(r => r.Key).Where(k => k != null);
            var lockFileRuntimes    = nuGetLockFile.Targets.Select(t => t.RuntimeIdentifier).Where(r => r != null).Distinct();

            if (!projectRuntimesKeys.OrderedEquals(
                    lockFileRuntimes,
                    x => x,
                    StringComparer.InvariantCultureIgnoreCase,
                    StringComparer.InvariantCultureIgnoreCase))
            {
                return(false);
            }

            // Validate all P2P references
            foreach (var framework in project.RestoreMetadata.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var queue = new Queue <Tuple <string, string> >();
                var visitedP2PReference = new HashSet <string>();

                foreach (var projectReference in framework.ProjectReferences)
                {
                    if (visitedP2PReference.Add(projectReference.ProjectUniqueName))
                    {
                        var spec = dgSpec.GetProjectSpec(projectReference.ProjectUniqueName);
                        queue.Enqueue(new Tuple <string, string>(spec.Name, projectReference.ProjectUniqueName));

                        while (queue.Count > 0)
                        {
                            var projectNames      = queue.Dequeue();
                            var p2pUniqueName     = projectNames.Item2;
                            var p2pProjectName    = projectNames.Item1;
                            var projectDependency = target.Dependencies.FirstOrDefault(
                                dep => dep.Type == PackageDependencyType.Project &&
                                StringComparer.OrdinalIgnoreCase.Equals(dep.Id, p2pProjectName));

                            if (projectDependency == null)
                            {
                                // project dependency doesn't exist in lock file.
                                return(false);
                            }

                            var p2pSpec = dgSpec.GetProjectSpec(p2pUniqueName);

                            // The package spec not found in the dg spec. This could mean that the project does not exist anymore.
                            if (p2pSpec != null)
                            {
                                // This does not consider ATF.
                                var p2pSpecTargetFrameworkInformation = NuGetFrameworkUtility.GetNearest(p2pSpec.TargetFrameworks, framework.FrameworkName, e => e.FrameworkName);

                                // No compatible framework found
                                if (p2pSpecTargetFrameworkInformation != null)
                                {
                                    // We need to compare the main framework only. Ignoring fallbacks.
                                    var p2pSpecProjectRestoreMetadataFrameworkInfo = p2pSpec.RestoreMetadata.TargetFrameworks.FirstOrDefault(
                                        t => NuGetFramework.Comparer.Equals(p2pSpecTargetFrameworkInformation.FrameworkName, t.FrameworkName));

                                    if (p2pSpecProjectRestoreMetadataFrameworkInfo != null)
                                    {
                                        if (HasP2PDependencyChanged(p2pSpecTargetFrameworkInformation.Dependencies, p2pSpecProjectRestoreMetadataFrameworkInfo.ProjectReferences, projectDependency, dgSpec))
                                        {
                                            // P2P transitive package dependencies have changed
                                            return(false);
                                        }

                                        foreach (var reference in p2pSpecProjectRestoreMetadataFrameworkInfo.ProjectReferences)
                                        {
                                            // Do not add private assets for processing.
                                            if (visitedP2PReference.Add(reference.ProjectUniqueName) && reference.PrivateAssets != LibraryIncludeFlags.All)
                                            {
                                                var referenceSpec = dgSpec.GetProjectSpec(reference.ProjectUniqueName);
                                                queue.Enqueue(new Tuple <string, string>(referenceSpec.Name, reference.ProjectUniqueName));
                                            }
                                        }
                                    }
                                    else // This should never happen.
                                    {
                                        return(false);
                                    }
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                            else
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 11
0
        private MSBuildRestoreResult RestoreMSBuildFiles(PackageSpec project,
                                                         IEnumerable <RestoreTargetGraph> targetGraphs,
                                                         IReadOnlyList <NuGetv3LocalRepository> repositories,
                                                         RemoteWalkContext context)
        {
            // Get the project graph
            var projectFrameworks = project.TargetFrameworks.Select(f => f.FrameworkName).ToList();

            // Non-Msbuild projects should skip targets and treat it as success
            if (!context.IsMsBuildBased)
            {
                return(new MSBuildRestoreResult(project.Name, project.BaseDirectory, success: true));
            }

            // Invalid msbuild projects should write out an msbuild error target
            if (projectFrameworks.Count != 1 ||
                !targetGraphs.Any())
            {
                return(new MSBuildRestoreResult(project.Name, project.BaseDirectory, success: false));
            }

            // Gather props and targets to write out
            var graph = targetGraphs
                        .Single(g => g.Framework.Equals(projectFrameworks[0]) && string.IsNullOrEmpty(g.RuntimeIdentifier));

            var flattenedFlags = IncludeFlagUtils.FlattenDependencyTypes(_includeFlagGraphs, _request.Project, graph);

            var targets = new List <string>();
            var props   = new List <string>();

            foreach (var library in graph.Flattened
                     .Distinct()
                     .OrderBy(g => g.Data.Match.Library))
            {
                var includeLibrary = true;

                LibraryIncludeFlags libraryFlags;
                if (flattenedFlags.TryGetValue(library.Key.Name, out libraryFlags))
                {
                    includeLibrary = libraryFlags.HasFlag(LibraryIncludeFlags.Build);
                }

                // Skip libraries that do not include build files such as transitive packages
                if (includeLibrary)
                {
                    var            packageIdentity = new PackageIdentity(library.Key.Name, library.Key.Version);
                    IList <string> packageFiles;
                    context.PackageFileCache.TryGetValue(packageIdentity, out packageFiles);

                    if (packageFiles != null)
                    {
                        var contentItemCollection = new ContentItemCollection();
                        contentItemCollection.Load(packageFiles);

                        // Find MSBuild thingies
                        var groups = contentItemCollection.FindItemGroups(graph.Conventions.Patterns.MSBuildFiles);

                        // Find the nearest msbuild group, this can include the root level Any group.
                        var buildItems = NuGetFrameworkUtility.GetNearest(
                            groups,
                            graph.Framework,
                            group =>
                            group.Properties[ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker]
                            as NuGetFramework);

                        if (buildItems != null)
                        {
                            // We need to additionally filter to items that are named "{packageId}.targets" and "{packageId}.props"
                            // Filter by file name here and we'll filter by extension when we add things to the lists.
                            var items = buildItems.Items
                                        .Where(item =>
                                               Path.GetFileNameWithoutExtension(item.Path)
                                               .Equals(library.Key.Name, StringComparison.OrdinalIgnoreCase))
                                        .ToList();

                            var packageInfo  = NuGetv3LocalRepositoryUtility.GetPackage(repositories, library.Key.Name, library.Key.Version);
                            var pathResolver = packageInfo.Repository.PathResolver;

                            targets.AddRange(items
                                             .Where(c => Path.GetExtension(c.Path).Equals(".targets", StringComparison.OrdinalIgnoreCase))
                                             .Select(c =>
                                                     Path.Combine(pathResolver.GetInstallPath(library.Key.Name, library.Key.Version),
                                                                  c.Path.Replace('/', Path.DirectorySeparatorChar))));

                            props.AddRange(items
                                           .Where(c => Path.GetExtension(c.Path).Equals(".props", StringComparison.OrdinalIgnoreCase))
                                           .Select(c =>
                                                   Path.Combine(pathResolver.GetInstallPath(library.Key.Name, library.Key.Version),
                                                                c.Path.Replace('/', Path.DirectorySeparatorChar))));
                        }
                    }
                }
            }

            // Targets files contain a macro for the repository root. If only the user package folder was used
            // allow a replacement. If fallback folders were used the macro cannot be applied.
            // Do not use macros for fallback folders. Use only the first repository which is the user folder.
            var repositoryRoot = repositories.First().RepositoryRoot;

            return(new MSBuildRestoreResult(project.Name, project.BaseDirectory, repositoryRoot, props, targets));
        }
Esempio n. 12
0
        public static CommandLineApplication Create()
        {
            var app = new CommandLineApplication(throwOnUnexpectedArg: false)
            {
                Name     = "dotnet ef",
                FullName = "Entity Framework .NET Core CLI Commands Dispatcher"
            };

            var noBuildOption = app.Option("--no-build", "Do not build before executing");

            var configurationOption = app.Option(
                "-c|--configuration <CONFIGURATION>",
                "Configuration under which to load");
            var frameworkOption = app.Option(
                "-f|--framework <FRAMEWORK>",
                "Target framework to load");
            var buildBasePathOption = app.Option(
                "-b|--build-base-path <OUTPUT_DIR>",
                "Directory in which to find temporary outputs");
            var outputOption = app.Option(
                "-o|--output <OUTPUT_DIR>",
                "Directory in which to find outputs");

            app.OnExecute(() =>
            {
                var project = Directory.GetCurrentDirectory();

                Reporter.Verbose.WriteLine(ToolsStrings.LogUsingProject(project));

                var projectFile = ProjectReader.GetProject(project);

                var framework = frameworkOption.HasValue()
                    ? NuGetFramework.Parse(frameworkOption.Value())
                    : null;

                if (framework == null)
                {
                    var frameworks = projectFile.GetTargetFrameworks().Select(i => i.FrameworkName);
                    framework      = NuGetFrameworkUtility.GetNearest(frameworks, FrameworkConstants.CommonFrameworks.NetCoreApp10, f => f)
                                     ?? frameworks.FirstOrDefault();

                    Reporter.Verbose.WriteLine(ToolsStrings.LogUsingFramework(framework.GetShortFolderName()));
                }

                var configuration = configurationOption.Value();

                if (configuration == null)
                {
                    configuration = Constants.DefaultConfiguration;

                    Reporter.Verbose.WriteLine(ToolsStrings.LogUsingConfiguration(configuration));
                }

                if (!noBuildOption.HasValue())
                {
                    var buildExitCode = BuildCommandFactory.Create(
                        projectFile.ProjectFilePath,
                        configuration,
                        framework,
                        buildBasePathOption.Value(),
                        outputOption.Value())
                                        .ForwardStdErr()
                                        .ForwardStdOut()
                                        .Execute()
                                        .ExitCode;
                    if (buildExitCode != 0)
                    {
                        throw new OperationException(ToolsStrings.BuildFailed(projectFile.Name));
                    }
                }

                // TODO remove when https://github.com/dotnet/cli/issues/2645 is resolved
                Func <bool> isClassLibrary = () =>
                {
                    var projectContext = ProjectContext.Create(
                        projectFile.ProjectFilePath,
                        framework,
                        RuntimeEnvironmentRidExtensions.GetAllCandidateRuntimeIdentifiers());

                    var runtimeFiles = projectContext
                                       .GetOutputPaths(configuration, buildBasePathOption.Value(), outputOption.Value())
                                       ?.RuntimeFiles;

                    return(runtimeFiles == null ||
                           (
                               framework.IsDesktop()
                                ? !Directory.Exists(runtimeFiles.BasePath)
                                : !File.Exists(runtimeFiles.RuntimeConfigJson) || !File.Exists(runtimeFiles.DepsJson)
                           ));
                };

                Reporter.Verbose.WriteLine(ToolsStrings.LogBeginDispatch(ProjectDependencyToolName, projectFile.Name));

                try
                {
                    bool isVerbose;
                    bool.TryParse(Environment.GetEnvironmentVariable(CommandContext.Variables.Verbose), out isVerbose);
                    var dispatchArgs = ExecuteCommand
                                       .CreateArgs(framework, configuration, isVerbose)
                                       .Concat(app.RemainingArguments);

                    return(DotnetToolDispatcher.CreateDispatchCommand(
                               dispatchArgs,
                               framework,
                               configuration,
                               outputPath: outputOption.Value(),
                               buildBasePath: buildBasePathOption.Value(),
                               projectDirectory: projectFile.ProjectDirectory,
                               toolName: ProjectDependencyToolName)
                           .ForwardStdErr()
                           .ForwardStdOut()
                           .Execute()
                           .ExitCode);
                }
                catch (CommandUnknownException ex)
                {
                    Reporter.Verbose.WriteLine(ex.Message);

                    var fwlink = "http://go.microsoft.com/fwlink/?LinkId=798221";

                    if (isClassLibrary())
                    {
                        Reporter.Error.WriteLine(ToolsStrings.ClassLibrariesNotSupportedInCli(fwlink));
                    }
                    else
                    {
                        // intentionally put DispatcherToolName in error because "Microsoft.EntityFrameworkCore.Tools.Cli" is
                        // brought in automatically as a dependency of "Microsoft.EntityFrameworkCore.Tools"
                        Reporter.Error.WriteLine(ToolsStrings.ProjectDependencyCommandNotFound(DispatcherToolName, fwlink));
                    }

                    return(1);
                }
            });

            return(app);
        }
        public static bool IsLockFileStillValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)
        {
            var uniqueName = dgSpec.Restore.First();
            var project    = dgSpec.GetProjectSpec(uniqueName);

            // Validate all the direct dependencies
            foreach (var framework in project.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var directDependencies = target.Dependencies.Where(dep => dep.Type == PackageDependencyType.Direct);

                if (HasProjectDependencyChanged(framework.Dependencies, directDependencies))
                {
                    // lock file is out of sync
                    return(false);
                }
            }

            // Validate all P2P references
            foreach (var framework in project.RestoreMetadata.TargetFrameworks)
            {
                var target = nuGetLockFile.Targets.FirstOrDefault(
                    t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, framework.FrameworkName));

                if (target == null)
                {
                    // a new target found in the dgSpec so invalidate existing lock file.
                    return(false);
                }

                var queue = new Queue <string>();
                var visitedP2PReference = new HashSet <string>();

                foreach (var projectReference in framework.ProjectReferences)
                {
                    if (visitedP2PReference.Add(projectReference.ProjectUniqueName))
                    {
                        queue.Enqueue(projectReference.ProjectUniqueName);

                        while (queue.Count > 0)
                        {
                            var p2pUniqueName  = queue.Dequeue();
                            var p2pProjectName = Path.GetFileNameWithoutExtension(p2pUniqueName);

                            var projectDependency = target.Dependencies.FirstOrDefault(
                                dep => dep.Type == PackageDependencyType.Project &&
                                PathUtility.GetStringComparerBasedOnOS().Equals(dep.Id, p2pProjectName));

                            if (projectDependency == null)
                            {
                                // project dependency doesn't exist in lock file.
                                return(false);
                            }

                            var p2pSpec = dgSpec.GetProjectSpec(p2pUniqueName);

                            // ignore if this p2p packageSpec not found in DGSpec, It'll fail restore with different error at later stage
                            if (p2pSpec != null)
                            {
                                var p2pSpecTarget = NuGetFrameworkUtility.GetNearest(p2pSpec.TargetFrameworks, framework.FrameworkName, e => e.FrameworkName);

                                // ignore if compatible framework not found for p2p reference which means current project didn't
                                // get anything transitively from this p2p
                                if (p2pSpecTarget != null)
                                {
                                    if (HasP2PDependencyChanged(p2pSpecTarget.Dependencies, projectDependency))
                                    {
                                        // P2P transitive package dependencies has changed
                                        return(false);
                                    }

                                    var p2pSpecProjectRefTarget = p2pSpec.RestoreMetadata.TargetFrameworks.FirstOrDefault(
                                        t => PathUtility.GetStringComparerBasedOnOS().Equals(p2pSpecTarget.FrameworkName.GetShortFolderName(), t.FrameworkName.GetShortFolderName()));

                                    if (p2pSpecProjectRefTarget != null)
                                    {
                                        foreach (var reference in p2pSpecProjectRefTarget.ProjectReferences)
                                        {
                                            if (visitedP2PReference.Add(reference.ProjectUniqueName))
                                            {
                                                queue.Enqueue(reference.ProjectUniqueName);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(true);
        }