public static void GenerateSolutionFile( ProjectCollection projectCollection, string solutionFileFullPath, string projectFileFullPath, IReadOnlyDictionary <string, Guid> customProjectTypeGuids, bool folders, IEnumerable <string> solutionItems, ISlnGenLogger logger) { if (string.IsNullOrWhiteSpace(solutionFileFullPath)) { solutionFileFullPath = Path.ChangeExtension(projectFileFullPath, ".sln"); } logger.LogMessageHigh($"Generating Visual Studio solution \"{solutionFileFullPath}\" ..."); if (customProjectTypeGuids.Count > 0) { logger.LogMessageLow("Custom Project Type GUIDs:"); foreach (KeyValuePair <string, Guid> item in customProjectTypeGuids) { logger.LogMessageLow(" {0} = {1}", item.Key, item.Value); } } SlnFile solution = new SlnFile(); solution.AddProjects(projectCollection, customProjectTypeGuids, projectFileFullPath); solution.AddSolutionItems(solutionItems); solution.Save(solutionFileFullPath, folders); }
public static void LaunchVisualStudio(string devEnvFullPath, bool useShellExecute, string solutionFileFullPath, ISlnGenLogger logger) { ProcessStartInfo processStartInfo; if (!string.IsNullOrWhiteSpace(devEnvFullPath)) { if (!File.Exists(devEnvFullPath)) { logger.LogError($"The specified path to Visual Studio ({devEnvFullPath}) does not exist or is inaccessible."); return; } processStartInfo = new ProcessStartInfo { FileName = devEnvFullPath, Arguments = $"\"{solutionFileFullPath}\"", }; } else if (!useShellExecute) { processStartInfo = new ProcessStartInfo { Arguments = $"/C start \"\" \"devenv.exe\" \"{solutionFileFullPath}\"", FileName = Environment.GetEnvironmentVariable("ComSpec"), WindowStyle = ProcessWindowStyle.Hidden, }; } else { processStartInfo = new ProcessStartInfo { FileName = solutionFileFullPath, UseShellExecute = true, }; } try { Process process = new Process { StartInfo = processStartInfo, }; logger.LogMessageHigh("Opening Visual Studio solution..."); logger.LogMessageLow(" FileName = {0}", processStartInfo.FileName); logger.LogMessageLow(" Arguments = {0}", processStartInfo.Arguments); logger.LogMessageLow(" UseShellExecute = {0}", processStartInfo.UseShellExecute); logger.LogMessageLow(" WindowStyle = {0}", processStartInfo.WindowStyle); if (!process.Start()) { logger.LogError("Failed to launch Visual Studio."); } } catch (Exception e) { logger.LogError($"Failed to launch Visual Studio. {e.Message}"); } }
private (string solutionFileFullPath, int customProjectTypeGuidCount, int solutionItemCount) GenerateSolutionFile(IEnumerable <Project> projects, ISlnGenLogger logger) { Project project = projects.First(); IReadOnlyDictionary <string, Guid> customProjectTypeGuids = SlnProject.GetCustomProjectTypeGuids(project); IReadOnlyCollection <string> solutionItems = SlnProject.GetSolutionItems(project, logger).ToList(); string solutionFileFullPath = _arguments.SolutionFileFullPath?.LastOrDefault(); if (solutionFileFullPath.IsNullOrWhiteSpace()) { string solutionDirectoryFullPath = _arguments.SolutionDirectoryFullPath?.LastOrDefault(); if (solutionDirectoryFullPath.IsNullOrWhiteSpace()) { solutionDirectoryFullPath = project.DirectoryPath; } string solutionFileName = Path.ChangeExtension(Path.GetFileName(project.FullPath), "sln"); solutionFileFullPath = Path.Combine(solutionDirectoryFullPath, solutionFileName); } logger.LogMessageHigh($"Generating Visual Studio solution \"{solutionFileFullPath}\" ..."); if (customProjectTypeGuids.Count > 0) { logger.LogMessageLow("Custom Project Type GUIDs:"); foreach (KeyValuePair <string, Guid> item in customProjectTypeGuids) { logger.LogMessageLow(" {0} = {1}", item.Key, item.Value); } } SlnFile solution = new SlnFile { Platforms = _arguments.GetPlatforms(), Configurations = _arguments.GetConfigurations(), }; if (SlnFile.TryParseExistingSolution(solutionFileFullPath, out Guid solutionGuid, out IReadOnlyDictionary <string, Guid> projectGuidsByPath)) { logger.LogMessageNormal("Updating existing solution file and reusing Visual Studio cache"); solution.SolutionGuid = solutionGuid; solution.ExistingProjectGuids = projectGuidsByPath; _arguments.LoadProjectsInVisualStudio = new[] { bool.TrueString }; } solution.AddProjects(projects, customProjectTypeGuids, project.FullPath); solution.AddSolutionItems(solutionItems); solution.Save(solutionFileFullPath, _arguments.EnableFolders(), _arguments.EnableCollapseFolders()); return(solutionFileFullPath, customProjectTypeGuids.Count, solutionItems.Count); }
public static void LogStatistics(MSBuildProjectLoader projectLoader, ISlnGenLogger logger) { logger.LogMessageLow("SlnGen Project Evaluation Performance Summary:"); foreach (KeyValuePair <string, TimeSpan> item in projectLoader.Statistics.ProjectLoadTimes.OrderByDescending(i => i.Value)) { logger.LogMessageLow($" {Math.Round(item.Value.TotalMilliseconds, 0)} ms {item.Key}", MessageImportance.Low); } }
/// <summary> /// Gets the solution items' full paths. /// </summary> /// <param name="items">The <see cref="IEnumerable{IMSBuildItem}" /> containing the solution items.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> /// <param name="fileExists">A <see cref="Func{String, Boolean}"/> to use when determining if a file exists.</param> /// <exception cref="ArgumentNullException"><paramref name="items" /> is <code>null</code> /// -or- /// <paramref name="logger" /> is <code>null</code> /// -or- /// <paramref name="fileExists" /> is <code>null</code>.</exception> /// <returns>An <see cref="IEnumerable{String}"/> of full paths to include as solution items.</returns> internal static IEnumerable <string> GetSolutionItems(IEnumerable <IMSBuildItem> items, ISlnGenLogger logger, Func <string, bool> fileExists) { if (items == null) { throw new ArgumentNullException(nameof(items)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (fileExists == null) { throw new ArgumentNullException(nameof(fileExists)); } foreach (string solutionItem in items.Select(i => i.GetMetadata("FullPath")).Where(i => !string.IsNullOrWhiteSpace(i))) { if (!fileExists(solutionItem)) { logger.LogMessageLow($"The solution item \"{solutionItem}\" does not exist and will not be added to the solution.", MessageImportance.Low); } else { yield return(solutionItem); } } }
/// <summary> /// Gets the solution items' full paths. /// </summary> /// <param name="project">The <see cref="Project" /> containing the solution items.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> /// <param name="fileExists">A <see cref="Func{String, Boolean}"/> to use when determining if a file exists.</param> /// <exception cref="ArgumentNullException"><paramref name="project" /> is null /// -or- /// <paramref name="logger" /> is null /// -or- /// <paramref name="fileExists" /> is null.</exception> /// <returns>An <see cref="IEnumerable{String}"/> of full paths to include as solution items.</returns> internal static IEnumerable <string> GetSolutionItems(Project project, ISlnGenLogger logger, Func <string, bool> fileExists = null) { if (project == null) { throw new ArgumentNullException(nameof(project)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } fileExists ??= File.Exists; foreach (string solutionItem in project.GetItems(MSBuildItemNames.SlnGenSolutionItem).Select(i => i.GetMetadataValue("FullPath")).Where(i => !i.IsNullOrWhiteSpace())) { if (!fileExists(solutionItem)) { logger.LogMessageLow($"The solution item \"{solutionItem}\" does not exist and will not be added to the solution.", MessageImportance.Low); } else { yield return(solutionItem); } } }
/// <summary> /// Launches Visual Studio. /// </summary> /// <param name="solutionFileFullPath">The full path to the solution file.</param> /// <param name="loadProjects">A value indicating whether to load projects in Visual Studio.</param> /// <param name="devEnvFullPath">An optional full path to devenv.exe.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> public static void Launch(string solutionFileFullPath, bool loadProjects, string devEnvFullPath, ISlnGenLogger logger) { if (solutionFileFullPath.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(solutionFileFullPath)); } CommandLineBuilder commandLineBuilder = new CommandLineBuilder(); ProcessStartInfo processStartInfo; if (!devEnvFullPath.IsNullOrWhiteSpace()) { if (!File.Exists(devEnvFullPath)) { logger.LogError($"The specified path to Visual Studio ({devEnvFullPath}) does not exist or is inaccessible."); return; } processStartInfo = new ProcessStartInfo { FileName = devEnvFullPath, UseShellExecute = false, }; commandLineBuilder.AppendFileNameIfNotNull(solutionFileFullPath); if (!loadProjects) { commandLineBuilder.AppendSwitch(DoNotLoadProjectsCommandLineArgument); } } else { processStartInfo = new ProcessStartInfo { FileName = solutionFileFullPath, UseShellExecute = true, }; } try { processStartInfo.Arguments = commandLineBuilder.ToString(); Process process = new Process { StartInfo = processStartInfo, }; logger.LogMessageHigh("Launching Visual Studio..."); logger.LogMessageLow(" FileName = {0}", processStartInfo.FileName); logger.LogMessageLow(" Arguments = {0}", processStartInfo.Arguments); logger.LogMessageLow(" UseShellExecute = {0}", processStartInfo.UseShellExecute); logger.LogMessageLow(" WindowStyle = {0}", processStartInfo.WindowStyle); if (!process.Start()) { logger.LogError("Failed to launch Visual Studio."); } } catch (Exception e) { logger.LogError($"Failed to launch Visual Studio. {e.Message}"); } }
/// <summary> /// Generates a solution file. /// </summary> /// <param name="arguments">The current <see cref="ProgramArguments" />.</param> /// <param name="projects">A <see cref="IEnumerable{String}" /> containing the entry projects.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> /// <returns>A <see cref="Tuple{String, Int32, Int32, Guid}" /> with the full path to the solution file, the count of custom project type GUIDs used, the count of solution items, and the solution GUID.</returns> public static (string solutionFileFullPath, int customProjectTypeGuidCount, int solutionItemCount, Guid solutionGuid) GenerateSolutionFile(ProgramArguments arguments, IEnumerable <Project> projects, ISlnGenLogger logger) { List <Project> projectList = projects.ToList(); Project firstProject = projectList.First(); IReadOnlyDictionary <string, Guid> customProjectTypeGuids = SlnProject.GetCustomProjectTypeGuids(firstProject); IReadOnlyCollection <string> solutionItems = SlnProject.GetSolutionItems(firstProject, logger).ToList(); string solutionFileFullPath = arguments.SolutionFileFullPath?.LastOrDefault(); if (solutionFileFullPath.IsNullOrWhiteSpace()) { string solutionDirectoryFullPath = arguments.SolutionDirectoryFullPath?.LastOrDefault(); if (solutionDirectoryFullPath.IsNullOrWhiteSpace()) { solutionDirectoryFullPath = firstProject.DirectoryPath; } string solutionFileName = Path.ChangeExtension(Path.GetFileName(firstProject.FullPath), "sln"); solutionFileFullPath = Path.Combine(solutionDirectoryFullPath !, solutionFileName); } logger.LogMessageHigh($"Generating Visual Studio solution \"{solutionFileFullPath}\" ..."); if (customProjectTypeGuids.Count > 0) { logger.LogMessageLow("Custom Project Type GUIDs:"); foreach (KeyValuePair <string, Guid> item in customProjectTypeGuids) { logger.LogMessageLow(" {0} = {1}", item.Key, item.Value); } } SlnFile solution = new SlnFile { Platforms = arguments.GetPlatforms(), Configurations = arguments.GetConfigurations(), }; if (SlnFile.TryParseExistingSolution(solutionFileFullPath, out Guid solutionGuid, out IReadOnlyDictionary <string, Guid> projectGuidsByPath)) { logger.LogMessageNormal("Updating existing solution file and reusing Visual Studio cache"); solution.SolutionGuid = solutionGuid; solution.ExistingProjectGuids = projectGuidsByPath; arguments.LoadProjectsInVisualStudio = new[] { bool.TrueString }; } solution.AddProjects(projectList, customProjectTypeGuids, arguments.IgnoreMainProject ? null : firstProject.FullPath); solution.AddSolutionItems(solutionItems); if (!arguments.EnableFolders()) { foreach (SlnProject project in solution._projects.Distinct(new EqualityComparer <SlnProject>((x, y) => string.Equals(x.SolutionFolder, y.SolutionFolder))) .Where(i => !string.IsNullOrWhiteSpace(i.SolutionFolder) && i.SolutionFolder.Contains(Path.DirectorySeparatorChar))) { logger.LogError($"The value of SlnGenSolutionFolder \"{project.SolutionFolder}\" cannot contain directory separators."); } } if (!logger.HasLoggedErrors) { solution.Save(solutionFileFullPath, arguments.EnableFolders(), arguments.EnableCollapseFolders()); } return(solutionFileFullPath, customProjectTypeGuids.Count, solutionItems.Count, solution.SolutionGuid); }
/// <summary> /// Launches Visual Studio. /// </summary> /// <param name="arguments">The current <see cref="ProgramArguments" />.</param> /// <param name="visualStudioInstance">A <see cref="VisualStudioInstance" /> object representing which instance of Visual Studio to launch.</param> /// <param name="solutionFileFullPath">The full path to the solution file.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> /// <returns>true if Visual Studio was launched, otherwise false.</returns> public static bool TryLaunch(ProgramArguments arguments, VisualStudioInstance visualStudioInstance, string solutionFileFullPath, ISlnGenLogger logger) { if (!arguments.ShouldLaunchVisualStudio()) { return(true); } if (!Utility.RunningOnWindows) { logger.LogWarning("Launching Visual Studio is not currently supported on your operating system."); return(true); } bool loadProjectsInVisualStudio = arguments.ShouldLoadProjectsInVisualStudio(); bool enableShellExecute = arguments.EnableShellExecute(); string devEnvFullPath = arguments.DevEnvFullPath?.LastOrDefault(); if (!enableShellExecute || !loadProjectsInVisualStudio || Program.CurrentDevelopmentEnvironment.IsCorext) { if (devEnvFullPath.IsNullOrWhiteSpace()) { if (visualStudioInstance == null) { logger.LogError( Program.CurrentDevelopmentEnvironment.IsCorext ? $"Could not find a Visual Studio {Environment.GetEnvironmentVariable("VisualStudioVersion")} installation. Please do one of the following:\n a) Specify a full path to devenv.exe via the -vs command-line argument\n b) Update your corext.config to specify a version of MSBuild.Corext that matches a Visual Studio version you have installed\n c) Install a version of Visual Studio that matches the version of MSBuild.Corext in your corext.config" : "Could not find a Visual Studio installation. Please specify the full path to devenv.exe via the -vs command-line argument"); return(false); } if (visualStudioInstance.IsBuildTools) { logger.LogError("Cannot use a BuildTools instance of Visual Studio."); return(false); } devEnvFullPath = Path.Combine(visualStudioInstance.InstallationPath, "Common7", "IDE", "devenv.exe"); } } if (solutionFileFullPath.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(solutionFileFullPath)); } CommandLineBuilder commandLineBuilder = new CommandLineBuilder(); ProcessStartInfo processStartInfo; if (!devEnvFullPath.IsNullOrWhiteSpace()) { if (!File.Exists(devEnvFullPath)) { logger.LogError($"The specified path to Visual Studio ({devEnvFullPath}) does not exist or is inaccessible."); return(false); } processStartInfo = new ProcessStartInfo { FileName = devEnvFullPath !, UseShellExecute = false, }; commandLineBuilder.AppendFileNameIfNotNull(solutionFileFullPath); if (!arguments.ShouldLoadProjectsInVisualStudio()) { commandLineBuilder.AppendSwitch(DoNotLoadProjectsCommandLineArgument); } } else { processStartInfo = new ProcessStartInfo { FileName = solutionFileFullPath, UseShellExecute = true, }; } try { processStartInfo.Arguments = commandLineBuilder.ToString(); Process process = new Process { StartInfo = processStartInfo, }; logger.LogMessageHigh("Launching Visual Studio..."); logger.LogMessageLow(" FileName = {0}", processStartInfo.FileName); logger.LogMessageLow(" Arguments = {0}", processStartInfo.Arguments); logger.LogMessageLow(" UseShellExecute = {0}", processStartInfo.UseShellExecute); logger.LogMessageLow(" WindowStyle = {0}", processStartInfo.WindowStyle); if (!process.Start()) { logger.LogError("Failed to launch Visual Studio."); } } catch (Exception e) { logger.LogError($"Failed to launch Visual Studio. {e.Message}"); } return(true); }
/// <summary> /// Launches Visual Studio. /// </summary> /// <param name="arguments">The current <see cref="ProgramArguments" />.</param> /// <param name="visualStudioInstance">A <see cref="VisualStudioInstance" /> object representing which instance of Visual Studio to launch.</param> /// <param name="solutionFileFullPath">The full path to the solution file.</param> /// <param name="logger">A <see cref="ISlnGenLogger" /> to use for logging.</param> /// <returns>true if Visual Studio was launched, otherwise false.</returns> public static bool TryLaunch(ProgramArguments arguments, VisualStudioInstance visualStudioInstance, string solutionFileFullPath, ISlnGenLogger logger) { if (!arguments.ShouldLaunchVisualStudio()) { return(true); } if (!Utility.RunningOnWindows) { logger.LogWarning("Launching Visual Studio is not currently supported on your operating system."); return(true); } string devEnvFullPath = arguments.GetDevEnvFullPath(visualStudioInstance); if (!devEnvFullPath.IsNullOrWhiteSpace()) { visualStudioInstance = VisualStudioConfiguration.GetInstanceForPath(devEnvFullPath); } if (visualStudioInstance == null) { logger.LogError( Program.CurrentDevelopmentEnvironment.IsCorext ? $"Could not find a Visual Studio {Environment.GetEnvironmentVariable("VisualStudioVersion")} installation. Please do one of the following:\n a) Specify a full path to devenv.exe via the -vs command-line argument\n b) Update your corext.config to specify a version of MSBuild.Corext that matches a Visual Studio version you have installed\n c) Install a version of Visual Studio that matches the version of MSBuild.Corext in your corext.config" : "Could not find a Visual Studio installation. Please run from a command window that has MSBuild.exe on the PATH or specify the full path to devenv.exe via the -vs command-line argument"); return(false); } if (visualStudioInstance.IsBuildTools) { logger.LogError("Cannot use a BuildTools instance of Visual Studio."); return(false); } if (!File.Exists(devEnvFullPath)) { logger.LogError($"The specified path to Visual Studio ({devEnvFullPath}) does not exist or is inaccessible."); return(false); } CommandLineBuilder commandLineBuilder = new CommandLineBuilder(); commandLineBuilder.AppendFileNameIfNotNull(solutionFileFullPath); if (!arguments.ShouldLoadProjectsInVisualStudio()) { commandLineBuilder.AppendSwitch(DoNotLoadProjectsCommandLineArgument); } try { Process process = new Process { StartInfo = new ProcessStartInfo { FileName = devEnvFullPath, Arguments = commandLineBuilder.ToString(), UseShellExecute = false, }, }; logger.LogMessageHigh("Launching Visual Studio..."); logger.LogMessageLow(" FileName = {0}", process.StartInfo.FileName); logger.LogMessageLow(" Arguments = {0}", process.StartInfo.Arguments); if (!process.Start()) { logger.LogError("Failed to launch Visual Studio."); } } catch (Exception e) { logger.LogError($"Failed to launch Visual Studio. {e.Message}"); } return(true); }