public static Task <Dictionary <string, EnvDTE.Project> > GetPathToDTEProjectLookupAsync(EnvDTE.DTE dte) { var pathToProject = new Dictionary <string, EnvDTE.Project>(StringComparer.OrdinalIgnoreCase); var supportedProjects = dte.Solution.Projects.Cast <EnvDTE.Project>(); foreach (var solutionProject in supportedProjects) { var solutionProjectPath = EnvDTEProjectUtility.GetFullProjectPath(solutionProject); if (!string.IsNullOrEmpty(solutionProjectPath) && !pathToProject.ContainsKey(solutionProjectPath)) { pathToProject.Add(solutionProjectPath, solutionProject); } } return(Task.FromResult(pathToProject)); }
private static Dictionary <string, EnvDTEProject> GetPathToDTEProjectLookup(EnvDTEProject project) { var pathToProject = new Dictionary <string, EnvDTEProject>(StringComparer.OrdinalIgnoreCase); foreach (var solutionProjectObj in project.DTE.Solution.Projects) { var solutionProject = solutionProjectObj as Project; if (solutionProject != null) { var solutionProjectPath = EnvDTEProjectUtility.GetFullProjectPath(solutionProject); if (!string.IsNullOrEmpty(solutionProjectPath) && !pathToProject.ContainsKey(solutionProjectPath)) { pathToProject.Add(solutionProjectPath, solutionProject); } } } return(pathToProject); }
public bool TryCreateNuGetProject(EnvDTE.Project envDTEProject, ProjectSystemProviderContext context, out NuGetProject result) { if (envDTEProject == null) { throw new ArgumentNullException(nameof(envDTEProject)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } ThreadHelper.ThrowIfNotOnUIThread(); result = null; var msBuildNuGetProjectSystem = MSBuildNuGetProjectSystemFactory.CreateMSBuildNuGetProjectSystem( envDTEProject, context.ProjectContext); var isWebSite = msBuildNuGetProjectSystem is WebSiteProjectSystem; // Web sites cannot have project.json if (!isWebSite) { // Find the project file path var projectFilePath = EnvDTEProjectUtility.GetFullProjectPath(envDTEProject); if (!string.IsNullOrEmpty(projectFilePath)) { var msbuildProjectFile = new FileInfo(projectFilePath); var projectNameFromMSBuildPath = Path.GetFileNameWithoutExtension(msbuildProjectFile.Name); // Treat projects with project.json as build integrated projects // Search for projectName.project.json first, then project.json // If the name cannot be determined, search only for project.json string projectJsonPath = null; if (string.IsNullOrEmpty(projectNameFromMSBuildPath)) { projectJsonPath = Path.Combine(msbuildProjectFile.DirectoryName, ProjectJsonPathUtilities.ProjectConfigFileName); } else { projectJsonPath = ProjectJsonPathUtilities.GetProjectConfigPath(msbuildProjectFile.DirectoryName, projectNameFromMSBuildPath); } if (File.Exists(projectJsonPath)) { result = new ProjectJsonBuildIntegratedProjectSystem( projectJsonPath, msbuildProjectFile.FullName, envDTEProject, EnvDTEProjectUtility.GetCustomUniqueName(envDTEProject)); } } } // Create a normal MSBuild project if no project.json was found if (result == null) { var folderNuGetProjectFullPath = context.PackagesPathFactory(); // Project folder path is the packages config folder path var packagesConfigFolderPath = EnvDTEProjectUtility.GetFullPath(envDTEProject); result = new VSMSBuildNuGetProject( envDTEProject, msBuildNuGetProjectSystem, folderNuGetProjectFullPath, packagesConfigFolderPath); } return(result != null); }
/// <summary> /// Returns the closure of all project to project references below this project. /// </summary> /// <remarks>This uses DTE and should be called from the UI thread.</remarks> public override async Task <IReadOnlyList <ExternalProjectReference> > GetProjectReferenceClosureAsync( ExternalProjectReferenceContext context) { var logger = context.Logger; var cache = context.Cache; // DTE calls need to be done from the main thread await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var results = new HashSet <ExternalProjectReference>(); // projects to walk - DFS var toProcess = new Stack <DTEReference>(); // keep track of found projects to avoid duplicates var rootProjectPath = EnvDTEProjectUtility.GetFullProjectPath(EnvDTEProject); // start with the current project toProcess.Push(new DTEReference(EnvDTEProject, rootProjectPath)); var itemsFactory = ServiceLocator.GetInstance <IVsEnumHierarchyItemsFactory>(); var uniqueNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // continue walking all project references until we run out while (toProcess.Count > 0) { var dteReference = toProcess.Pop(); // Find the path of the current project var projectFileFullPath = dteReference.Path; var project = dteReference.Project; if (string.IsNullOrEmpty(projectFileFullPath) || !uniqueNames.Add(projectFileFullPath)) { // This has already been processed or does not exist continue; } IReadOnlyList <ExternalProjectReference> cacheReferences; if (cache.TryGetValue(projectFileFullPath, out cacheReferences)) { // The cached value contains the entire closure, add it to the results and skip // all child references. results.UnionWith(cacheReferences); } else { // Get direct references var projectResult = GetDirectProjectReferences( dteReference.Project, projectFileFullPath, context, itemsFactory, rootProjectPath); // Add results to the closure results.UnionWith(projectResult.Processed); // Continue processing foreach (var item in projectResult.ToProcess) { toProcess.Push(item); } } } // Cache the results for this project and every child project which has not been cached foreach (var project in results) { if (!context.Cache.ContainsKey(project.UniqueName)) { var closure = BuildIntegratedRestoreUtility.GetExternalClosure(project.UniqueName, results); context.Cache.Add(project.UniqueName, closure.ToList()); } } return(cache[rootProjectPath]); }
/// <summary> /// Get the unique names of all references which have ReferenceOutputAssembly set to false. /// </summary> 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, Boolean.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 = EnvDTEProjectUtility .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); }
public bool TryCreateNuGetProject(EnvDTE.Project dteProject, ProjectSystemProviderContext context, out NuGetProject result) { if (dteProject == null) { throw new ArgumentNullException(nameof(dteProject)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } ThreadHelper.ThrowIfNotOnUIThread(); result = null; // The project must be an IVsHierarchy. var hierarchy = VsHierarchyUtility.ToVsHierarchy(dteProject); if (hierarchy == null) { return(false); } // Check if the project is not CPS capable or if it is CPS capable then it does not have TargetFramework(s), if so then return false if (!hierarchy.IsCapabilityMatch("CPS")) { return(false); } var buildPropertyStorage = hierarchy as IVsBuildPropertyStorage; // read MSBuild property RestoreProjectStyle, TargetFramework, and TargetFrameworks var restoreProjectStyle = VsHierarchyUtility.GetMSBuildProperty(buildPropertyStorage, RestoreProjectStyle); var targetFramework = VsHierarchyUtility.GetMSBuildProperty(buildPropertyStorage, TargetFramework); var targetFrameworks = VsHierarchyUtility.GetMSBuildProperty(buildPropertyStorage, TargetFrameworks); // check for RestoreProjectStyle property is set and if not set to PackageReference then return false if (!(string.IsNullOrEmpty(restoreProjectStyle) || restoreProjectStyle.Equals(ProjectStyle.PackageReference.ToString(), StringComparison.OrdinalIgnoreCase))) { return(false); } // check whether TargetFramework or TargetFrameworks property is set, else return false else if (string.IsNullOrEmpty(targetFramework) && string.IsNullOrEmpty(targetFrameworks)) { return(false); } // Lazy load the CPS enabled JoinableTaskFactory for the UI. NuGetUIThreadHelper.SetJoinableTaskFactoryFromService(ProjectServiceAccessor.Value as IProjectServiceAccessor); var projectNames = ProjectNames.FromDTEProject(dteProject); var fullProjectPath = EnvDTEProjectUtility.GetFullProjectPath(dteProject); var unconfiguredProject = GetUnconfiguredProject(dteProject); result = new CpsPackageReferenceProject( dteProject.Name, EnvDTEProjectUtility.GetCustomUniqueName(dteProject), fullProjectPath, _projectSystemCache, dteProject, unconfiguredProject, VsHierarchyUtility.GetProjectId(dteProject)); return(true); }
/// <summary> /// Get only the direct dependencies from a project /// </summary> public static async Task <IReadOnlyList <ProjectRestoreReference> > GetDirectProjectReferences( EnvDTEProject project, IEnumerable <string> resolvedProjects, ILogger log) { return(await NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(async() => { // DTE calls need to be done from the main thread await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var results = new List <ProjectRestoreReference>(); var itemsFactory = ServiceLocator.GetInstance <IVsEnumHierarchyItemsFactory>(); // Verify ReferenceOutputAssembly var excludedProjects = GetExcludedReferences(project, itemsFactory); var hasMissingReferences = false; // find all references in the project foreach (var childReference in GetProjectReferences(project)) { try { var reference3 = childReference as Reference3; // check if deferred projects resolved this reference, which means this is still not loaded so simply continue // We'll get this reference from deferred projects later if (reference3 != null && resolvedProjects.Contains(reference3.Name, StringComparer.OrdinalIgnoreCase)) { continue; } // Set missing reference if // 1. reference is null OR // 2. reference is not resolved which means project is not loaded or assembly not found. else 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 childProjectPath = EnvDTEProjectUtility.GetFullProjectPath(childReference.SourceProject); // Skip projects which have ReferenceOutputAssembly=false if (!string.IsNullOrEmpty(childProjectPath) && !excludedProjects.Contains(childProjectPath, StringComparer.OrdinalIgnoreCase)) { var restoreReference = new ProjectRestoreReference() { ProjectPath = childProjectPath, ProjectUniqueName = childProjectPath }; results.Add(restoreReference); } } } catch (Exception ex) { // Exceptions are expected in some scenarios for native projects, // ignore them and show a warning hasMissingReferences = true; log.LogDebug(ex.ToString()); Debug.Fail("Unable to find project dependencies: " + ex.ToString()); } } if (hasMissingReferences) { // Log a generic message once per project if any items could not be resolved. // In most cases this can be ignored, but in the rare case where the unresolved // item is actually a project the restore result will be incomplete. var message = string.Format( CultureInfo.CurrentCulture, Strings.UnresolvedItemDuringProjectClosureWalk, EnvDTEProjectUtility.GetUniqueName(project)); log.LogVerbose(message); } return results; })); }