Esempio n. 1
0
        protected override void Initialize()
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            base.Initialize();

            // Now retrieve all needed services
            _enumHierarchyItemsFactory = Package.GetGlobalService(typeof(SVsEnumHierarchyItemsFactory)) as IVsEnumHierarchyItemsFactory;
            _solutionService           = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution;
        }
        private static List <string> GetExcludedReferences(
            EnvDTEProject project,
            IVsEnumHierarchyItemsFactory itemsFactory)
        {
            var excludedReferences = new List <string>();

            var hierarchy = VsHierarchyUtility.ToVsHierarchy(project);

            // Get all items in the hierarchy, this includes project references, files, and everything else.
            IEnumHierarchyItems items;

            if (ErrorHandler.Succeeded(itemsFactory.EnumHierarchyItems(
                                           hierarchy,
                                           (uint)__VSEHI.VSEHI_Leaf,
                                           (uint)VSConstants.VSITEMID.Root,
                                           out items)))
            {
                var buildPropertyStorage = (IVsBuildPropertyStorage)hierarchy;

                // Loop through all items
                uint fetched;
                VSITEMSELECTION[] item = new VSITEMSELECTION[1];
                while (ErrorHandler.Succeeded(items.Next(1, item, out fetched)) && fetched == 1)
                {
                    // Check if the item has ReferenceOutputAssembly. This will
                    // return null for the vast majority of items.
                    string value;
                    if (ErrorHandler.Succeeded(buildPropertyStorage.GetItemAttribute(
                                                   item[0].itemid,
                                                   "ReferenceOutputAssembly",
                                                   out value)) &&
                        value != null)
                    {
                        // We only need to go farther if the flag exists and is not true
                        if (!string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase))
                        {
                            // Get the DTE Project reference for the item id. This checks for nulls incase this is
                            // somehow not a project reference that had the ReferenceOutputAssembly flag.
                            object childObject;
                            if (ErrorHandler.Succeeded(hierarchy.GetProperty(
                                                           item[0].itemid,
                                                           (int)__VSHPROPID.VSHPROPID_ExtObject,
                                                           out childObject)))
                            {
                                // 1. Verify that this is a project reference
                                // 2. Check that it is valid and resolved
                                // 3. Follow the reference to the DTE project and get the unique name
                                var reference = childObject as Reference3;

                                if (reference != null && reference.Resolved && reference.SourceProject != null)
                                {
                                    var childPath = EnvDTEProjectInfoUtility
                                                    .GetFullProjectPath(reference.SourceProject);

                                    excludedReferences.Add(childPath);
                                }
                            }
                        }
                    }
                }
            }

            return(excludedReferences);
        }
        /// <summary>
        /// Get only the direct dependencies from a project
        /// </summary>
        private DirectReferences GetDirectProjectReferences(
            EnvDTEProject project,
            string projectFileFullPath,
            ExternalProjectReferenceContext context,
            IVsEnumHierarchyItemsFactory itemsFactory,
            string rootProjectPath)
        {
            var logger = context.Logger;
            var cache  = context.Cache;

            var result = new DirectReferences();

            // Find a project.json in the project
            // This checks for files on disk to match how BuildIntegratedProjectSystem checks at creation time.
            // NuGet.exe also uses disk paths and not the project file.
            var projectName = Path.GetFileNameWithoutExtension(projectFileFullPath);

            var projectDirectory = Path.GetDirectoryName(projectFileFullPath);

            // Check for projectName.project.json and project.json
            string jsonConfigItem =
                ProjectJsonPathUtilities.GetProjectConfigPath(
                    directoryPath: projectDirectory,
                    projectName: projectName);

            var hasProjectJson = true;

            // Verify the file exists, otherwise clear it
            if (!File.Exists(jsonConfigItem))
            {
                jsonConfigItem = null;
                hasProjectJson = false;
            }

            // Verify ReferenceOutputAssembly
            var excludedProjects = GetExcludedReferences(project, itemsFactory);

            var childReferences      = new HashSet <string>(StringComparer.Ordinal);
            var hasMissingReferences = false;

            // find all references in the project
            foreach (var childReference in GetProjectReferences(project))
            {
                try
                {
                    var reference3 = childReference as Reference3;

                    if (reference3 != null && !reference3.Resolved)
                    {
                        // Skip missing references and show a warning
                        hasMissingReferences = true;
                        continue;
                    }

                    // Skip missing references
                    if (childReference.SourceProject != null)
                    {
                        if (EnvDTEProjectUtility.HasUnsupportedProjectCapability(childReference.SourceProject))
                        {
                            // Skip this shared project
                            continue;
                        }

                        var childName = EnvDTEProjectUtility.GetFullProjectPath(childReference.SourceProject);

                        // Skip projects which have ReferenceOutputAssembly=false
                        if (!string.IsNullOrEmpty(childName) &&
                            !excludedProjects.Contains(childName, StringComparer.OrdinalIgnoreCase))
                        {
                            childReferences.Add(childName);

                            result.ToProcess.Add(new DTEReference(childReference.SourceProject, childName));
                        }
                    }
                    else if (hasProjectJson)
                    {
                        // SDK references do not have a SourceProject or child references,
                        // but they can contain project.json files, and should be part of the closure
                        // SDKs are not projects, only the project.json name is checked here
                        var possibleSdkPath = childReference.Path;

                        if (!string.IsNullOrEmpty(possibleSdkPath) &&
                            !possibleSdkPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) &&
                            Directory.Exists(possibleSdkPath))
                        {
                            var possibleProjectJson = Path.Combine(
                                possibleSdkPath,
                                ProjectJsonPathUtilities.ProjectConfigFileName);

                            if (File.Exists(possibleProjectJson))
                            {
                                childReferences.Add(possibleProjectJson);

                                // add the sdk to the results here
                                result.Processed.Add(new ExternalProjectReference(
                                                         possibleProjectJson,
                                                         childReference.Name,
                                                         possibleProjectJson,
                                                         msbuildProjectPath: null,
                                                         projectReferences: Enumerable.Empty <string>()));
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Exceptions are expected in some scenarios for native projects,
                    // ignore them and show a warning
                    hasMissingReferences = true;

                    logger.LogDebug(ex.ToString());

                    Debug.Fail("Unable to find project closure: " + ex.ToString());
                }
            }

            if (hasMissingReferences)
            {
                // Log a warning message once per project
                // This warning contains only the names of the root project and the project with the
                // broken reference. Attempting to display more details on the actual reference
                // that has the problem may lead to another exception being thrown.
                var warning = string.Format(
                    CultureInfo.CurrentCulture,
                    Strings.Warning_ErrorDuringProjectClosureWalk,
                    projectName,
                    rootProjectPath);

                logger.LogWarning(warning);
            }

            // For the xproj -> xproj -> csproj scenario find all xproj-> xproj references.
            if (projectFileFullPath.EndsWith(XProjUtility.XProjExtension, StringComparison.OrdinalIgnoreCase))
            {
                // All xproj paths, these are already checked for project.json
                var xprojFiles = XProjUtility.GetProjectReferences(projectFileFullPath);

                if (xprojFiles.Count > 0)
                {
                    var pathToProject = GetPathToDTEProjectLookup(project);

                    foreach (var xProjPath in xprojFiles)
                    {
                        // Only add projects that we can find in the solution, otherwise they will
                        // end up causing failures. If this is an actual failure the resolver will
                        // fail when resolving the dependency from project.json
                        Project xProjDTE;
                        if (pathToProject.TryGetValue(xProjPath, out xProjDTE))
                        {
                            var xProjFullPath = EnvDTEProjectUtility.GetFullProjectPath(xProjDTE);

                            if (!string.IsNullOrEmpty(xProjFullPath))
                            {
                                childReferences.Add(xProjFullPath);

                                // Continue walking this project if it has not been walked already
                                result.ToProcess.Add(new DTEReference(xProjDTE, xProjFullPath));
                            }
                        }
                    }
                }
            }

            // Only set a package spec project name if a package spec exists
            var packageSpecProjectName = jsonConfigItem == null ? null : projectName;

            // Add the parent project to the results
            result.Processed.Add(new ExternalProjectReference(
                                     projectFileFullPath,
                                     packageSpecProjectName,
                                     jsonConfigItem,
                                     projectFileFullPath,
                                     childReferences));

            return(result);
        }