/// <summary> /// Gets the project file of the project with the given unique identifier. /// </summary> /// <param name="projectGuid">The unique identifier of the project for which the project file should be retrieves.</param> /// <returns> /// The project file of the project with the given unique identifier. /// </returns> /// <exception cref="BuildException">No project with unique identifier <paramref name="projectGuid" /> could be located.</exception> public string GetProjectFileFromGuid(string projectGuid) { // locate project entry using the project guid ProjectEntry projectEntry = ProjectEntries[projectGuid]; // TODO : as an emergency patch throw a build error when a GUID fails // to return a project file. This should be sanity checked when the // HashTable is populated and not at usage time to avoid internal // errors during build. if (projectEntry == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Project with GUID '{0}' must be included for the build to" + " work.", projectGuid), Location.UnknownLocation); } return(projectEntry.Path); }
/// <summary> /// Adds a <see cref="ProjectEntry"/> to the end of the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> to be added to the end of the collection.</param> /// <returns> /// The position into which the new element was inserted. /// </returns> public int Add(ProjectEntry item) { if (item == null) { throw new ArgumentNullException("item"); } // fail if a project with the same GUID exists in the collection ProjectEntry existingEntry = this[item.Guid]; if (existingEntry != null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The GUIDs of projects \"{0}\" and \"{1}\" are identical." + " Please correct this manually.", item.Path, existingEntry.Path), Location.UnknownLocation); } return(base.List.Add(item)); }
protected void LoadProjectGuids(ArrayList projects, bool isReferenceProject) { foreach (string projectFileName in projects) { string projectGuid = _solutionTask.ProjectFactory.LoadGuid(projectFileName); // locate project entry using the project guid ProjectEntry projectEntry = ProjectEntries[projectGuid]; if (projectEntry != null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Error loading project {0}. " + " Project GUID {1} already exists! Conflicting project is {2}.", projectFileName, projectGuid, projectEntry.Path)); } ProjectEntries.Add(new ProjectEntry(projectGuid, projectFileName)); if (isReferenceProject) { _htReferenceProjects[projectGuid] = null; } } }
protected virtual void SetProjectBuildConfiguration(ProjectEntry projectEntry) { if (projectEntry.BuildConfigurations == null) { // project was not loaded from solution file, and as a result // there's no project configuration section available, so we'll // consider all project configurations as valid build // configurations ProjectBase project = projectEntry.Project; project.BuildConfigurations.Clear(); foreach (ConfigurationDictionaryEntry ce in project.ProjectConfigurations) { project.BuildConfigurations[ce.Name] = ce.Config; } } else { // project was loaded from solution file, so only add build // configurations that were listed in project configuration // section ProjectBase project = projectEntry.Project; foreach (ConfigurationMapEntry ce in projectEntry.BuildConfigurations) { Configuration solutionConfig = ce.Key; Configuration projectConfig = ce.Value; ConfigurationBase conf = project.ProjectConfigurations [projectConfig]; if (conf != null) { project.BuildConfigurations[solutionConfig] = conf; } } } }
/// <summary> /// Inserts a <see cref="ProjectEntry"/> into the collection at the specified index. /// </summary> /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param> /// <param name="item">The <see cref="ProjectEntry"/> to insert.</param> public void Insert(int index, ProjectEntry item) { base.List.Insert(index, item); }
/// <summary> /// Copies the entire collection to a compatible one-dimensional array, starting at the specified index of the target array. /// </summary> /// <param name="array">The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing.</param> /// <param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param> public void CopyTo(ProjectEntry[] array, int index) { base.List.CopyTo(array, index); }
/// <summary> /// Retrieves the index of a specified <see cref="ProjectEntry"/> object in the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> object for which the index is returned.</param> /// <returns> /// The index of the specified <see cref="ProjectEntry"/>. If the <see cref="ProjectEntry"/> is not currently a member of the collection, it returns -1. /// </returns> public int IndexOf(ProjectEntry item) { return base.List.IndexOf(item); }
/// <summary> /// Adds the elements of a <see cref="ProjectEntry"/> array to the end of the collection. /// </summary> /// <param name="items">The array of <see cref="ProjectEntry"/> elements to be added to the end of the collection.</param> public void AddRange(ProjectEntry[] items) { for (int i = 0; (i < items.Length); i = (i + 1)) { Add(items[i]); } }
/// <summary> /// Determines whether a <see cref="ProjectEntry"/> is in the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> to locate in the collection.</param> /// <returns> /// <see langword="true" /> if <paramref name="item"/> is found in the /// collection; otherwise, <see langword="false" />. /// </returns> public bool Contains(ProjectEntry item) { return base.List.Contains(item); }
/// <summary> /// Initializes a new instance of the <see cref="ProjectEntryCollection"/> class /// with the specified array of <see cref="ProjectEntry"/> instances. /// </summary> public ProjectEntryCollection(ProjectEntry[] value) { AddRange(value); }
/// <summary> /// Adds a <see cref="ProjectEntry"/> to the end of the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> to be added to the end of the collection.</param> /// <returns> /// The position into which the new element was inserted. /// </returns> public int Add(ProjectEntry item) { if (item == null) { throw new ArgumentNullException("item"); } // fail if a project with the same GUID exists in the collection ProjectEntry existingEntry = this[item.Guid]; if (existingEntry != null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The GUIDs of projects \"{0}\" and \"{1}\" are identical." + " Please correct this manually.", item.Path, existingEntry.Path), Location.UnknownLocation); } return base.List.Add(item); }
/// <summary> /// Removes a member from the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> to remove from the collection.</param> public void Remove(ProjectEntry item) { base.List.Remove(item); }
/// <summary> /// Determines whether a <see cref="ProjectEntry"/> is in the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> to locate in the collection.</param> /// <returns> /// <see langword="true" /> if <paramref name="item"/> is found in the /// collection; otherwise, <see langword="false" />. /// </returns> public bool Contains(ProjectEntry item) { return(base.List.Contains(item)); }
protected void GetDependenciesFromProjects(Configuration solutionConfiguration) { Log(Level.Verbose, "Gathering additional dependencies..."); // first get all of the output files foreach (ProjectEntry projectEntry in ProjectEntries) { ProjectBase project = projectEntry.Project; if (project == null) { // skip projects that are not loaded/supported continue; } foreach (ConfigurationBase projectConfig in project.ProjectConfigurations.Values) { string projectOutputFile = projectConfig.OutputPath; if (projectOutputFile != null) { _htOutputFiles[projectOutputFile] = project.Guid; } } } // if one of output files resides in reference search path - circle began // we must build project with that outputFile before projects referencing it // (similar to project dependency) VS.NET 7.0/7.1 do not address this problem // build list of output which reside in such folders Hashtable outputsInAssemblyFolders = CollectionsUtil.CreateCaseInsensitiveHashtable(); foreach (DictionaryEntry de in _htOutputFiles) { string outputfile = (string)de.Key; string folder = Path.GetDirectoryName(outputfile); if (_solutionTask.AssemblyFolderList.Contains(folder)) { outputsInAssemblyFolders[Path.GetFileName(outputfile)] = (string)de.Value; } } // build the dependency list foreach (ProjectEntry projectEntry in ProjectEntries) { ProjectBase project = projectEntry.Project; if (project == null) { // skip projects that are not loaded/supported continue; } // check if project actually supports the build configuration ConfigurationBase projectConfig = project.BuildConfigurations[solutionConfiguration]; if (projectConfig == null) { continue; } // ensure output directory exists. VS creates output directories // before it starts compiling projects if (!projectConfig.OutputDir.Exists) { projectConfig.OutputDir.Create(); projectConfig.OutputDir.Refresh(); } foreach (ReferenceBase reference in project.References) { ProjectReferenceBase projectReference = reference as ProjectReferenceBase; if (projectReference != null) { project.ProjectDependencies.Add(projectReference.Project); } else { string outputFile = reference.GetPrimaryOutputFile( solutionConfiguration); // if we reference an assembly in an AssemblyFolder // that is an output directory of another project, // then add dependency on that project if (outputFile == null) { continue; } string dependencyGuid = (string)outputsInAssemblyFolders[Path.GetFileName(outputFile)]; if (dependencyGuid == null) { continue; } ProjectEntry dependencyEntry = ProjectEntries[dependencyGuid]; if (dependencyEntry != null && dependencyEntry.Project != null) { project.ProjectDependencies.Add(dependencyEntry.Project); } } } } }
/// <summary> /// Loads the projects from the file system and stores them in an /// instance variable. /// </summary> /// <param name="gacCache"><see cref="GacCache" /> instance to use to determine whether an assembly is located in the Global Assembly Cache.</param> /// <param name="refResolver"><see cref="ReferencesResolver" /> instance to use to determine location and references of assemblies.</param> /// <param name="explicitProjectDependencies">TODO</param> /// <exception cref="BuildException">A project GUID in the solution file does not match the actual GUID of the project in the project file.</exception> protected void LoadProjects(GacCache gacCache, ReferencesResolver refResolver, Hashtable explicitProjectDependencies) { Log(Level.Verbose, "Loading projects..."); FileSet excludes = _solutionTask.ExcludeProjects; foreach (ProjectEntry projectEntry in ProjectEntries) { string projectPath = projectEntry.Path; string projectGuid = projectEntry.Guid; // determine whether project is on case-sensitive filesystem, bool caseSensitive = PlatformHelper.IsVolumeCaseSensitive(projectPath); // indicates whether the project should be skipped (excluded) bool skipProject = false; // check whether project should be excluded from build foreach (string excludedProjectFile in excludes.FileNames) { if (string.Compare(excludedProjectFile, projectPath, !caseSensitive, CultureInfo.InvariantCulture) == 0) { Log(Level.Verbose, "Excluding project '{0}'.", projectPath); // do not load project skipProject = true; // we have a match, so quit looking break; } } if (skipProject) { // remove dependencies for excluded projects if (explicitProjectDependencies.ContainsKey(projectGuid)) { explicitProjectDependencies.Remove(projectGuid); } // project was excluded, move on to next project continue; } Log(Level.Verbose, "Loading project '{0}'.", projectPath); ProjectBase p = _solutionTask.ProjectFactory.LoadProject(this, _solutionTask, _tfc, gacCache, refResolver, _outputDir, projectPath); if (p == null) { Log(Level.Warning, "Project '{0}' is of unsupported type. Skipping.", projectPath); // skip the project continue; } if (p.Guid == null || p.Guid.Length == 0) { p.Guid = FindGuidFromPath(projectPath); } // add project to entry projectEntry.Project = p; // set project build configuration SetProjectBuildConfiguration(projectEntry); } // add explicit dependencies (as set in VS.NET) to individual projects foreach (DictionaryEntry dependencyEntry in explicitProjectDependencies) { string projectGuid = (string)dependencyEntry.Key; Hashtable dependencies = (Hashtable)dependencyEntry.Value; ProjectEntry projectEntry = ProjectEntries[projectGuid]; if (projectEntry == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Dependencies for project \'{0}\' could not be analyzed." + " Project is not included.", projectGuid), Location.UnknownLocation); } ProjectBase project = projectEntry.Project; // make sure project is loaded if (project == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Dependencies for project \'{0}\' could not be analyzed." + " Project is not loaded.", projectGuid), Location.UnknownLocation); } foreach (string dependentProjectGuid in dependencies.Keys) { ProjectEntry dependentEntry = ProjectEntries[dependentProjectGuid]; if (dependentEntry == null || dependentEntry.Project == null) { Log(Level.Warning, "Project \"{0}\": ignored dependency" + " on project \"{1}\", which is not included.", project.Name, dependentProjectGuid); continue; } project.ProjectDependencies.Add(dependentEntry.Project); } } }
/// <summary> /// Retrieves the index of a specified <see cref="ProjectEntry"/> object in the collection. /// </summary> /// <param name="item">The <see cref="ProjectEntry"/> object for which the index is returned.</param> /// <returns> /// The index of the specified <see cref="ProjectEntry"/>. If the <see cref="ProjectEntry"/> is not currently a member of the collection, it returns -1. /// </returns> public int IndexOf(ProjectEntry item) { return(base.List.IndexOf(item)); }
public WhidbeySolution(string solutionContent, SolutionTask solutionTask, TempFileCollection tfc, GacCache gacCache, ReferencesResolver refResolver) : base(solutionTask, tfc, gacCache, refResolver) { Regex reProjects = new Regex(@"Project\(\""(?<package>\{.*?\})\"".*?\""(?<name>.*?)\"".*?\""(?<project>.*?)\"".*?\""(?<guid>.*?)\""(?<all>[\s\S]*?)EndProject", RegexOptions.Multiline); MatchCollection projectMatches = reProjects.Matches(solutionContent); Hashtable explicitProjectDependencies = CollectionsUtil.CreateCaseInsensitiveHashtable(); foreach (Match projectMatch in projectMatches) { string project = projectMatch.Groups["project"].Value; string guid = projectMatch.Groups["guid"].Value; string package = projectMatch.Groups["package"].Value; // bug #1732361: skip solution folders if (package == SolutionFolder_GUID) { continue; } // translate partial project path or URL to absolute path string fullProjectPath = TranslateProjectPath(solutionTask.SolutionFile.DirectoryName, project); if (ManagedProjectBase.IsEnterpriseTemplateProject(fullProjectPath)) { RecursiveLoadTemplateProject(fullProjectPath); } else { // add project entry to collection ProjectEntries.Add(new ProjectEntry(guid, fullProjectPath)); } // set-up project dependencies Regex reDependencies = new Regex(@"^\s+(?<guid>\{[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}\})\s+=\s+(?<dep>\{[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}\})", RegexOptions.Multiline); MatchCollection dependencyMatches = reDependencies.Matches(projectMatch.Value); foreach (Match dependencyMatch in dependencyMatches) { string dependency = dependencyMatch.Groups["dep"].Value; if (!explicitProjectDependencies.ContainsKey(guid)) { explicitProjectDependencies[guid] = CollectionsUtil.CreateCaseInsensitiveHashtable(); } ((Hashtable)explicitProjectDependencies[guid])[dependency] = null; } // set-up project configuration Regex reProjectBuildConfig = new Regex(@"^\s+" + Regex.Escape(guid) + @"\.(?<solutionConfiguration>[^|]+)\|(?<solutionPlatform>[^.]+)\.Build\.0\s*=\s*(?<projectConfiguration>[^|]+)\|(?<projectPlatform>[\.\w ]+)\s*", RegexOptions.Multiline); MatchCollection projectBuildMatches = reProjectBuildConfig.Matches(solutionContent); ProjectEntry projectEntry = ProjectEntries [guid]; if (projectEntry == null) { // TODO: determine if we should report an error if a build // configuration is defined for a project that does not // exist in the solution continue; } // holds mapping between project configuration(s) and solution(s) ConfigurationMap buildConfigurations = new ConfigurationMap( projectBuildMatches.Count); for (int i = 0; i < projectBuildMatches.Count; i++) { Match projectBuildMatch = projectBuildMatches [i]; string solutionConfigName = projectBuildMatch.Groups["solutionConfiguration"].Value; string solutionPlatform = projectBuildMatch.Groups["solutionPlatform"].Value; string projectConfigName = projectBuildMatch.Groups["projectConfiguration"].Value; string projectPlatform = projectBuildMatch.Groups["projectPlatform"].Value; Configuration solutionConfig = new Configuration( solutionConfigName, solutionPlatform); Configuration projectConfig = new Configuration( projectConfigName, projectPlatform); buildConfigurations [solutionConfig] = projectConfig; } // add map to corresponding project entry projectEntry.BuildConfigurations = buildConfigurations; } LoadProjectGuids(new ArrayList(solutionTask.Projects.FileNames), false); LoadProjectGuids(new ArrayList(solutionTask.ReferenceProjects.FileNames), true); LoadProjects(gacCache, refResolver, explicitProjectDependencies); }