Ejemplo n.º 1
0
        // recursive
        static void ReportProjectReferences(ProjectReferenceNode source, PackageSpec project, NuGetFramework rootNuGetFramework,
                                            DependencyGraphSpec dependencyGraph, int indentLevel, HashSet <Node> vertices, HashSet <Edge> edges)
        {
            const int INDENT_SIZE = 2;

            NuGetFramework nearest = project.GetNearestFrameworkMatching(rootNuGetFramework);

            // TODO: This is done be caller....delete
            //var projectReference = new ProjectReferenceNode(project.FilePath, project.Version.ToString(), nearest);
            //projects.Add(projectReference);

            // indent shows levels of the graph
            Console.Write(new string(' ', indentLevel * INDENT_SIZE));
            Console.WriteLine($"{project.RestoreMetadata.ProjectUniqueName}, v{project.Version}, ({nearest.GetShortFolderName()})");

            ProjectRestoreMetadataFrameworkInfo resolvedTargetFramework =
                project.RestoreMetadata.TargetFrameworks.Single(tf => nearest.Equals(tf.FrameworkName));

            // project references of a targetFramework
            foreach (ProjectRestoreReference projectRestoreReference in resolvedTargetFramework.ProjectReferences)
            {
                // TODO: PrivateAssets, ExcludeAssets, IncludeAssets
                //dependency.ProjectPath
                //dependency.ProjectUniqueName
                PackageSpec projectDependency = dependencyGraph.GetProjectSpec(projectRestoreReference.ProjectUniqueName);

                var projectDependencyReference = new ProjectReferenceNode(
                    projectDependency.FilePath,
                    projectDependency.Version.ToString(),
                    projectDependency.GetNearestFrameworkMatching(rootNuGetFramework));

                vertices.Add(projectDependencyReference);

                edges.Add(new Edge(source, projectDependencyReference));

                //Console.WriteLine($"({projectDependency.Name}, {Path.GetFileName(projectDependency.FilePath)}) is a project reference of ({project.Name}, {Path.GetFileName(project.FilePath)}");

                // recursive
                ReportProjectReferences(projectDependencyReference, projectDependency, rootNuGetFramework,
                                        dependencyGraph, indentLevel + 1, vertices, edges);
            }
        }
Ejemplo n.º 2
0
        // TODO: Should we use framework here
        //
        // 1. Create dgspec.json via .NET Core CLI: GenerateRestoreGraphFile target
        // 2. Load dgspec.json into DependencyGraphSpec instance/object
        // For each SDK project (ProjectStyle.PackageReference) in the graph spec
        // 3. Get assets file (project.assets.json) for the project
        // 4. Construct LockFile from assets file for the project
        static void AnalyzeProject(string projectPath, string framework)
        {
            // Graph input
            var vertices = new HashSet <Node>();
            var edges    = new HashSet <Edge>();

            var rootNuGetFramework = NuGetFramework.ParseFolder(framework); // TODO: optional filter

            // TODO: HACK...kan fjernes
            if (string.IsNullOrEmpty(projectPath))
            {
                var rootPath = GetRepoRootPath();

                //projectPath = Path.Combine(rootPath, "DotnetDependencies.sln");
                projectPath = Path.Combine(
                    Path.Combine(
                        Path.Combine(rootPath, "src"), "Deps.CLI"), "Deps.CLI.csproj");
            }

            // 'package graph' is a better word
            // Load dependency graph via nuget client tools build into msbuild (.NET Core CLI, .NET Core SDK)
            // TODO: opsatning af packageSources
            var dependencyGraphService = new DependencyGraphService();
            var dependencyGraph        = dependencyGraphService.GenerateDependencyGraph(projectPath);

            // We only support MSBuild style <PackageReference> SDK projects, where project.assets.json (lock file) is
            // generated in the RestoreOutputPath folder
            if (dependencyGraph.Projects.Any(p => p.RestoreMetadata.ProjectStyle != ProjectStyle.PackageReference))
            {
                throw new InvalidOperationException("Only SDK projects are supported.");
            }

            PackageSpec projectRoot = dependencyGraph.Projects.Single(p => Path.GetFileName(p.FilePath) == Path.GetFileName(projectPath));

            var rootNode = new ProjectReferenceNode(projectPath, projectRoot.Version.ToString(), rootNuGetFramework);

            vertices.Add(rootNode);

            var projectRootTargetFramework = projectRoot.TargetFrameworks.FirstOrDefault(tf => rootNuGetFramework.Equals(tf.FrameworkName));

            if (projectRootTargetFramework == null)
            {
                throw new InvalidOperationException(
                          $"The root project does not define the TargetFramework {rootNuGetFramework}");
            }

            //Console.WriteLine($"project: {Path.GetFileName(project.FilePath)}");
            //Console.WriteLine($"project.BaseDirectory: {Path.GetFileName(project.BaseDirectory)}");
            //Console.WriteLine($"project.Name: {project.Name}");
            //Console.WriteLine($"project.TargetFrameworks: {string.Join(", ", project.TargetFrameworks.Select(tfm => tfm.FrameworkName.GetShortFolderName()))}");
            //Console.WriteLine($"project.Version: {project.Version}");
            //Console.WriteLine($"project.RestoreMetadata.ProjectName: {project.RestoreMetadata.ProjectName}");
            //Console.WriteLine($"project.RestoreMetadata.Sources: {string.Join(", ", project.RestoreMetadata.Sources)}");
            //Console.WriteLine($"project.Dependencies: {string.Join(", ", project.Dependencies)}");


            // TODO: Path. Unique name etc...
            Console.WriteLine($"Name: {projectRoot.Name}");
            Console.WriteLine($"Version: {projectRoot.Version} ({rootNuGetFramework.GetShortFolderName()})");
            Console.WriteLine($"Framework: {rootNuGetFramework.DotNetFrameworkName}");
            Console.WriteLine($"Framework moniker: {rootNuGetFramework.GetShortFolderName()}");
            Console.WriteLine();

            Console.WriteLine("resolve project reference dependency graph");
            Console.WriteLine();

            // TODO: Path. Unique name etc...
            Console.WriteLine($"{projectRoot.Name}, v{projectRoot.Version} ({rootNuGetFramework.GetShortFolderName()})");

            //
            // First resolve project reference dependency graph
            //

            foreach (ProjectRestoreMetadataFrameworkInfo targetFramework in projectRoot.RestoreMetadata.TargetFrameworks)
            {
                // only want project references defined for the TargetFramework
                if (!rootNuGetFramework.Equals(targetFramework.FrameworkName))
                {
                    continue;
                }

                // project references of a targetFramework
                foreach (var projectRestoreReference in targetFramework.ProjectReferences)
                {
                    // TODO: PrivateAssets, ExcludeAssets, IncludeAssets
                    //dependency.ProjectPath
                    //dependency.ProjectUniqueName
                    PackageSpec projectDependency = dependencyGraph.GetProjectSpec(projectRestoreReference.ProjectUniqueName);

                    //Console.WriteLine($"({project.Name}, {Path.GetFileName(project.FilePath)}) is a project reference of ({projectRoot.Name}, {Path.GetFileName(projectRoot.FilePath)}");

                    NuGetFramework nearest          = projectDependency.GetNearestFrameworkMatching(rootNuGetFramework);
                    var            projectReference = new ProjectReferenceNode(projectDependency.FilePath, projectDependency.Version.ToString(), nearest);

                    vertices.Add(projectReference);

                    edges.Add(new Edge(rootNode, projectReference));

                    ReportProjectReferences(rootNode, projectDependency, rootNuGetFramework, dependencyGraph, 1,
                                            vertices, edges);
                }
            }

            // TODO: What about ProjectReferences...are project references converted to package specs in dgspec file??? YES,
            // and available via dependencyGraph.Projects and dependencyGraph.GetProjectSpec

            // TODO: project Closure is part of graph all ready
            // closure[0] is the root
            // closure[1..m] contains project references
            IReadOnlyList <PackageSpec> projectClosure = dependencyGraph.GetClosure(projectRoot.RestoreMetadata.ProjectUniqueName);

            Debug.Assert(ReferenceEquals(projectRoot, projectClosure[0]));

            //
            // Second, resolve package reference dependency graph of each project
            //

            Console.WriteLine();
            Console.WriteLine("resolve package reference dependency graph");
            Console.WriteLine();

            // for each csproj with PackageReference style (i.e. SDK csproj)
            foreach (PackageSpec project in dependencyGraph.Projects)
            {
                // TODO: Maybe just use the project.assets.json created by .NET Core SDK tooling
                // Generate lock file: A lock file has the package dependency graph for the project/solution/repo
                // that includes both the direct as well as transitive dependencies.
                var      lockFileService = new LockFileService();
                LockFile lockFile        = lockFileService.GetLockFile(project.FilePath, project.RestoreMetadata.OutputPath);

                // TODO: This could change our code...we can get at the project references inside one single loop
                //{
                //    // TODO: For debugging
                //    var projectDirectory = Path.GetDirectoryName(lockFile.PackageSpec.RestoreMetadata.ProjectPath);
                //    // full path to the referenced msbuild files (csproj files)
                //    var projectReferences = lockFile.Libraries
                //        .Where(library => library.MSBuildProject != null)
                //        .Select(library => Path.GetFullPath(Path.Combine(projectDirectory, library.MSBuildProject)))
                //        .ToArray();

                //    if (projectReferences.Length > 0)
                //    {
                //        Console.WriteLine($"project references {string.Join(", ", projectReferences)}");
                //    }
                //}

                NuGetFramework nearest = project.GetNearestFrameworkMatching(rootNuGetFramework);

                TargetFrameworkInformation resolvedTargetFramework =
                    project.TargetFrameworks.Single(tf => nearest.Equals(tf.FrameworkName));

                // for the root should this resolve to the rootNuGetFramework
                Console.WriteLine($"{project.Name}, v{project.Version}, ({resolvedTargetFramework.FrameworkName.GetShortFolderName()})");

                // Find the transitive closure for this tfm
                LockFileTarget lockFileTargetFramework =
                    lockFile.Targets.FirstOrDefault(t => t.TargetFramework.Equals(resolvedTargetFramework.FrameworkName));

                if (lockFileTargetFramework != null)
                {
                    // For each direct dependency
                    foreach (LibraryDependency directDependency in resolvedTargetFramework.Dependencies)
                    {
                        // Find the _resolved_ package reference
                        LockFileTargetLibrary resolvedPackageReference =
                            lockFileTargetFramework.Libraries.FirstOrDefault(library =>
                                                                             library.Name == directDependency.Name);

                        // Show transitive dependencies of this direct dependency
                        ReportLockFilePackageDependencies(resolvedPackageReference, lockFileTargetFramework, 1);
                    }
                }
            }
        }