private void UpdateConfigurationForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                return;
            }
            IEnumerable <CmdArgument> checkedArgs = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(project.GetGuid())?.CheckedArguments;

            if (checkedArgs == null)
            {
                return;
            }

            IEnumerable <string> enabledEntries;

            if (IsMacroEvaluationEnabled)
            {
                enabledEntries = checkedArgs.Select(
                    e => msBuildPropertyRegex.Replace(e.Value,
                                                      match => vsHelper.GetMSBuildPropertyValue(project, match.Groups["propertyName"].Value) ?? match.Value));
            }
            else
            {
                enabledEntries = checkedArgs.Select(e => e.Value);
            }
            string prjCmdArgs = string.Join(" ", enabledEntries);

            ProjectArguments.SetArguments(project, prjCmdArgs);
            Logger.Info($"Updated Configuration for Project: {project.GetName()}");
        }
        public string GetMSBuildPropertyValue(IVsHierarchy hierarchy, string propName)
        {
            var propStorage = hierarchy as IVsBuildPropertyStorage;

            if (propStorage == null)
            {
                return(null);
            }

            string configName;

            try
            {
                configName = hierarchy.GetProject()?.ConfigurationManager.ActiveConfiguration.ConfigurationName;
            }
            catch (Exception ex)
            {
                Logger.Warn($"Failed to get active configuration name for project '{hierarchy.GetName()}' with error '{ex}'");
                return(null);
            }

            if (configName != null)
            {
                if (ErrorHandler.Succeeded(propStorage.GetPropertyValue(propName, configName,
                                                                        (int)_PersistStorageType.PST_PROJECT_FILE,
                                                                        out string value)))
                {
                    return(value);
                }
            }

            return(null);
        }
        private void DetachFsWatcherFromProject(IVsHierarchy project)
        {
            var guid = project.GetGuid();

            if (projectFsWatchers.TryGetValue(guid, out FileSystemWatcher fsWatcher))
            {
                fsWatcher.Dispose();
                projectFsWatchers.Remove(guid);
                Logger.Info($"Detached FileSystemWatcher for project '{project.GetName()}'.");
            }
        }
        private void UpdateConfigurationForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                return;
            }

            var commandLineArgs = CreateCommandLineArgsForProject(project);

            if (commandLineArgs == null)
            {
                return;
            }

            ProjectArguments.SetArguments(project, commandLineArgs);
            Logger.Info($"Updated Configuration for Project: {project.GetName()}");
        }
        int IVsSolutionEvents4.OnAfterRenameProject(IVsHierarchy pHierarchy)
        {
            if (!ProjectArguments.IsSupportedProject(pHierarchy))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            Guid projectGuid    = pHierarchy.GetGuid();
            var  oldProjectDir  = ProjectStateMap[projectGuid].ProjectDir;
            var  oldProjectName = ProjectStateMap[projectGuid].ProjectName;

            ProjectStateMap[projectGuid].ProjectDir  = pHierarchy.GetProjectDir();
            ProjectStateMap[projectGuid].ProjectName = pHierarchy.GetName();

            ProjectAfterRename?.Invoke(this, new ProjectAfterRenameEventArgs {
                OldProjectDir = oldProjectDir, OldProjectName = oldProjectName, Project = pHierarchy
            });

            return(S_OK);
        }
        public string GetMSBuildPropertyValueForActiveConfig(IVsHierarchy hierarchy, string propName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            string configName = null;

            try
            {
                configName = hierarchy.GetProject()?.ConfigurationManager.ActiveConfiguration.ConfigurationName;
            }
            catch (Exception ex)
            {
                Logger.Warn($"Failed to get active configuration name for project '{hierarchy.GetName()}' with error '{ex}'");
                return(null);
            }

            if (configName == null)
            {
                return(null);
            }

            return(GetMSBuildPropertyValue(hierarchy, propName, configName));
        }
        int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
        {
            if (!ProjectArguments.IsSupportedProject(pHierarchy))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            Guid   projectGuid = pHierarchy.GetGuid();
            string projectDir  = pHierarchy.GetProjectDir();
            string projectName = pHierarchy.GetName();
            bool   isLoaded    = pHierarchy.IsLoaded();

            bool isLoadProcess = ProjectStateMap.TryGetValue(projectGuid, out var state) && state.IsLoaded;

            ProjectStateMap[projectGuid] = new ProjectState {
                ProjectDir = projectDir, ProjectName = projectName, IsLoaded = isLoaded
            };

            ProjectAfterOpen?.Invoke(this, new ProjectAfterOpenEventArgs {
                Project = pHierarchy, IsLoadProcess = isLoadProcess, IsSolutionOpenProcess = fAdded == 0
            });

            return(S_OK);
        }
        private string FullFilenameForProjectJsonFileFromProject(IVsHierarchy project)
        {
            var userFilename = vsHelper.GetMSBuildPropertyValue(project, "SmartCmdArgJsonFile");

            if (!string.IsNullOrEmpty(userFilename))
            {
                // It's recommended to use absolute paths for the json file in the first place...
                userFilename = Path.GetFullPath(userFilename); // ... but make it absolute in any case.

                Logger.Info($"'SmartCmdArgJsonFile' msbuild property present in project '{project.GetName()}' will use json file '{userFilename}'.");
                return(userFilename);
            }
            else
            {
                return(FullFilenameForProjectJsonFileFromProjectPath(project.GetProjectDir(), project.GetName()));
            }
        }
        private void UpdateCommandsForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            Logger.Info($"Update commands for project '{project?.GetName()}'. IsVcsSupportEnabled={IsVcsSupportEnabled}. SolutionData.Count={toolWindowStateLoadedFromSolution?.ProjectArguments?.Count}.");

            var projectGuid = project.GetGuid();

            if (projectGuid == Guid.Empty)
            {
                Logger.Info("Skipping project because guid euqals empty.");
                return;
            }

            var solutionData = toolWindowStateLoadedFromSolution ?? new ToolWindowStateSolutionData();

            ToolWindowViewModel.TreeViewModel.ShowAllProjects = solutionData.ShowAllProjects;

            // joins data from solution and project
            //  => overrides solution commands for a project if a project json file exists
            //  => keeps all data from the suo file for projects without a json
            //  => if we have data in our ViewModel we use this instad of the suo file

            // get project json data
            ToolWindowStateProjectData projectData = null;

            if (IsVcsSupportEnabled)
            {
                string filePath = FullFilenameForProjectJsonFileFromProject(project);

                if (File.Exists(filePath))
                {
                    try
                    {
                        using (Stream fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read))
                        {
                            projectData = Logic.ToolWindowProjectDataSerializer.Deserialize(fileStream);
                        }
                        Logger.Info($"Read {projectData?.Items?.Count} commands for project '{project.GetName()}' from json-file '{filePath}'.");
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to read file '{filePath}' with error '{e}'.");
                        projectData = null;
                    }
                }
                else
                {
                    Logger.Info($"Json-file '{filePath}' doesn't exists.");
                }
            }

            // project json overrides if it exists
            if (projectData != null)
            {
                Logger.Info($"Setting {projectData?.Items?.Count} commands for project '{project.GetName()}' from json-file.");

                var projectListViewModel = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(projectGuid);

                // update enabled state of the project json data (source prio: ViewModel > suo file)
                if (projectData.Items != null)
                {
                    var argumentDataFromProject = projectData.AllArguments;
                    var argumentDataFromLVM     = projectListViewModel?.AllArguments.ToDictionary(arg => arg.Id, arg => arg);
                    foreach (var dataFromProject in argumentDataFromProject)
                    {
                        if (argumentDataFromLVM != null && argumentDataFromLVM.TryGetValue(dataFromProject.Id, out CmdArgument argFromVM))
                        {
                            dataFromProject.Enabled = argFromVM.IsChecked;
                        }
                        else
                        {
                            dataFromProject.Enabled = solutionData.CheckedArguments.Contains(dataFromProject.Id);
                        }
                    }

                    var containerDataFromProject = projectData.AllContainer;
                    var containerDataFromLVM     = projectListViewModel?.AllContainer.ToDictionary(con => con.Id, con => con);
                    foreach (var dataFromProject in containerDataFromProject)
                    {
                        if (containerDataFromLVM != null && containerDataFromLVM.TryGetValue(dataFromProject.Id, out CmdContainer conFromVM))
                        {
                            dataFromProject.Expanded = conFromVM.IsExpanded;
                        }
                        else
                        {
                            dataFromProject.Expanded = solutionData.ExpandedContainer.Contains(dataFromProject.Id);
                        }
                    }

                    if (projectListViewModel != null)
                    {
                        projectData.Expanded = projectListViewModel.IsExpanded;
                    }
                    else
                    {
                        projectData.Expanded = solutionData.ExpandedContainer.Contains(projectData.Id);
                    }
                }
                else
                {
                    projectData = new ToolWindowStateProjectData();
                    Logger.Info($"DataCollection for project '{project.GetName()}' is null.");
                }
            }
            // if we have data in the ViewModel we keep it
            else if (ToolWindowViewModel.TreeViewModel.Projects.ContainsKey(projectGuid))
            {
                return;
            }
            else if (IsVcsSupportEnabled)
            {
                projectData = new ToolWindowStateProjectData();
                Logger.Info("Will clear all data because of missing json file and enabled VCS support.");
            }
            // we try to read the suo file data
            else if (solutionData.ProjectArguments.TryGetValue(projectGuid, out projectData))
            {
                Logger.Info($"Will use commands from suo file for project '{project.GetName()}'.");
                var argumentDataFromProject = projectData.AllArguments;
                foreach (var arg in argumentDataFromProject)
                {
                    arg.Enabled = solutionData.CheckedArguments.Contains(arg.Id);
                }

                var containerDataFromProject = projectData.AllContainer;
                foreach (var con in containerDataFromProject)
                {
                    con.Expanded = solutionData.ExpandedContainer.Contains(con.Id);
                }

                projectData.Expanded = solutionData.ExpandedContainer.Contains(projectData.Id);
            }
            else
            {
                Logger.Info($"Gathering commands from configurations for project '{project.GetName()}'.");
                // if we don't have suo file data we read cmd args from the project configs
                projectData = new ToolWindowStateProjectData();
                projectData.Items.AddRange(
                    ReadCommandlineArgumentsFromProject(project)
                    .Select(cmdLineArg => new ListEntryData {
                    Command = cmdLineArg
                }));
            }

            // push projectData to the ViewModel
            ToolWindowViewModel.PopulateFromProjectData(project, projectData);

            Logger.Info($"Updated Commands for project '{project.GetName()}'.");
        }
        private void AttachFsWatcherToProject(IVsHierarchy project)
        {
            string realProjectJsonFileFullName = SymbolicLinkUtils.GetRealPath(FullFilenameForProjectJsonFileFromProject(project));

            try
            {
                var projectJsonFileWatcher = new FileSystemWatcher();

                projectJsonFileWatcher.Path   = Path.GetDirectoryName(realProjectJsonFileFullName);
                projectJsonFileWatcher.Filter = Path.GetFileName(realProjectJsonFileFullName);

                projectJsonFileWatcher.EnableRaisingEvents = true;
                projectFsWatchers.Add(project.GetGuid(), projectJsonFileWatcher);

                projectJsonFileWatcher.Changed += (fsWatcher, args) => {
                    Logger.Info($"SystemFileWatcher file Change '{args.FullPath}'");
                    if (IsVcsSupportEnabled)
                    {
                        UpdateCommandsForProjectOnDispatcher(project);
                    }
                };
                projectJsonFileWatcher.Created += (fsWatcher, args) => {
                    Logger.Info($"SystemFileWatcher file Created '{args.FullPath}'");
                    if (IsVcsSupportEnabled)
                    {
                        UpdateCommandsForProjectOnDispatcher(project);
                    }
                };
                projectJsonFileWatcher.Renamed += (fsWatcher, args) =>
                {
                    Logger.Info($"FileWachter file Renamed '{args.FullPath}'. realProjectJsonFileFullName='{realProjectJsonFileFullName}'");
                    if (IsVcsSupportEnabled && realProjectJsonFileFullName == args.FullPath)
                    {
                        UpdateCommandsForProjectOnDispatcher(project);
                    }
                };

                Logger.Info($"Attached FileSystemWatcher to file '{realProjectJsonFileFullName}' for project '{project.GetName()}'.");
            }
            catch (Exception e)
            {
                Logger.Warn($"Failed to attach FileSystemWatcher to file '{realProjectJsonFileFullName}' for project '{project.GetName()}' with error '{e}'.");
            }
        }
        private void UpdateCommandsForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            Logger.Info($"Update commands for project '{project?.GetName()}'. IsVcsSupportEnabled={IsVcsSupportEnabled}. SolutionData.Count={toolWindowStateLoadedFromSolution?.ProjectArguments?.Count}.");

            var projectGuid = project.GetGuid();

            if (projectGuid == Guid.Empty)
            {
                Logger.Info("Skipping project because guid euqals empty.");
                return;
            }

            var solutionData = toolWindowStateLoadedFromSolution ?? new SuoDataJson();

            // joins data from solution and project
            //  => overrides solution commands for a project if a project json file exists
            //  => keeps all data from the suo file for projects without a json
            //  => if we have data in our ViewModel we use this instad of the suo file

            // get project json data
            ProjectDataJson projectData = null;

            if (IsVcsSupportEnabled)
            {
                projectData = fileStorage.ReadDataForProject(project);
            }

            // project json overrides if it exists
            if (projectData != null)
            {
                Logger.Info($"Setting {projectData?.Items?.Count} commands for project '{project.GetName()}' from json-file.");

                var projectListViewModel = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(projectGuid);

                var projHasSuoData = solutionData.ProjectArguments.ContainsKey(projectGuid);

                // update enabled state of the project json data (source prio: ViewModel > suo file)
                if (projectData.Items != null)
                {
                    var argumentDataFromProject = projectData.AllArguments;
                    var argumentDataFromLVM     = projectListViewModel?.AllArguments.ToDictionary(arg => arg.Id, arg => arg);
                    foreach (var dataFromProject in argumentDataFromProject)
                    {
                        if (argumentDataFromLVM != null && argumentDataFromLVM.TryGetValue(dataFromProject.Id, out CmdArgument argFromVM))
                        {
                            dataFromProject.Enabled = argFromVM.IsChecked;
                        }
                        else if (projHasSuoData)
                        {
                            dataFromProject.Enabled = solutionData.CheckedArguments.Contains(dataFromProject.Id);
                        }
                        else
                        {
                            dataFromProject.Enabled = dataFromProject.DefaultChecked;
                        }
                    }

                    var containerDataFromProject = projectData.AllContainer;
                    var containerDataFromLVM     = projectListViewModel?.AllContainer.ToDictionary(con => con.Id, con => con);
                    foreach (var dataFromProject in containerDataFromProject)
                    {
                        if (containerDataFromLVM != null && containerDataFromLVM.TryGetValue(dataFromProject.Id, out CmdContainer conFromVM))
                        {
                            dataFromProject.Expanded = conFromVM.IsExpanded;
                        }
                        else
                        {
                            dataFromProject.Expanded = solutionData.ExpandedContainer.Contains(dataFromProject.Id);
                        }
                    }

                    var itemDataFromProject = projectData.AllItems;
                    var itemDataFromLVM     = projectListViewModel?.ToDictionary(item => item.Id, item => item);
                    foreach (var dataFromProject in itemDataFromProject)
                    {
                        if (itemDataFromLVM != null && itemDataFromLVM.TryGetValue(dataFromProject.Id, out CmdBase itemFromVM))
                        {
                            dataFromProject.Selected = itemFromVM.IsSelected;
                        }
                        else
                        {
                            dataFromProject.Selected = solutionData.SelectedItems.Contains(dataFromProject.Id);
                        }
                    }

                    if (projectListViewModel != null)
                    {
                        projectData.Expanded = projectListViewModel.IsExpanded;
                        projectData.Selected = projectListViewModel.IsSelected;
                    }
                    else
                    {
                        projectData.Expanded = solutionData.ExpandedContainer.Contains(projectData.Id);
                        projectData.Selected = solutionData.SelectedItems.Contains(projectData.Id);
                    }
                }
                else
                {
                    projectData = new ProjectDataJson();
                    Logger.Info($"DataCollection for project '{project.GetName()}' is null.");
                }
            }
            // if we have data in the ViewModel we keep it
            else if (ToolWindowViewModel.TreeViewModel.Projects.ContainsKey(projectGuid))
            {
                return;
            }
            else if (IsVcsSupportEnabled)
            {
                projectData = new ProjectDataJson();
                Logger.Info("Will clear all data because of missing json file and enabled VCS support.");
            }
            // we try to read the suo file data
            else if (solutionData.ProjectArguments.TryGetValue(projectGuid, out projectData))
            {
                Logger.Info($"Will use commands from suo file for project '{project.GetName()}'.");
                var argumentDataFromProject = projectData.AllArguments;
                foreach (var arg in argumentDataFromProject)
                {
                    arg.Enabled = solutionData.CheckedArguments.Contains(arg.Id);
                }

                var containerDataFromProject = projectData.AllContainer;
                foreach (var con in containerDataFromProject)
                {
                    con.Expanded = solutionData.ExpandedContainer.Contains(con.Id);
                }

                var itemDataFromProject = projectData.AllItems;
                foreach (var item in itemDataFromProject)
                {
                    item.Selected = solutionData.SelectedItems.Contains(item.Id);
                }

                projectData.Expanded = solutionData.ExpandedContainer.Contains(projectData.Id);
                projectData.Selected = solutionData.SelectedItems.Contains(projectData.Id);
            }
            else
            {
                Logger.Info($"Gathering commands from configurations for project '{project.GetName()}'.");
                // if we don't have suo file data we read cmd args from the project configs
                projectData = new ProjectDataJson();
                projectData.Items.AddRange(ReadCommandlineArgumentsFromProject(project));
            }

            // push projectData to the ViewModel
            ToolWindowViewModel.PopulateFromProjectData(project, projectData);

            Logger.Info($"Updated Commands for project '{project.GetName()}'.");
        }
Exemple #12
0
        public ProjectDataJson ReadDataForProject(IVsHierarchy project)
        {
            ProjectDataJson result = null;

            if (!cmdPackage.IsUseSolutionDirEnabled)
            {
                string filePath = FullFilenameForProjectJsonFileFromProject(project);

                if (File.Exists(filePath))
                {
                    try
                    {
                        using (Stream fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read))
                        {
                            result = Logic.ProjectDataSerializer.Deserialize(fileStream);
                        }
                        Logger.Info($"Read {result?.Items?.Count} commands for project '{project.GetName()}' from json-file '{filePath}'.");
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to read file '{filePath}' with error '{e}'.");
                        result = null;
                    }
                }
                else
                {
                    Logger.Info($"Json-file '{filePath}' doesn't exists.");
                }

                return(result);
            }
            else
            {
                Guid   projectGui   = project.GetGuid();
                string slnFilename  = vsHelper.GetSolutionFilename();
                string jsonFilename = Path.ChangeExtension(slnFilename, "args.json");

                if (File.Exists(jsonFilename))
                {
                    try
                    {
                        using (Stream fileStream = File.Open(jsonFilename, FileMode.Open, FileAccess.Read))
                        {
                            SolutionDataJson slnData = SolutionDataSerializer.Deserialize(fileStream);

                            result = slnData.ProjectArguments.FirstOrDefault(p => p.Id == projectGui);
                        }
                        Logger.Info($"Read {result?.Items?.Count} commands for project '{project.GetName()}' from json-file '{jsonFilename}'.");
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to read file '{jsonFilename}' with error '{e}'.");
                        result = null;
                    }
                }
                else
                {
                    Logger.Info($"Json-file '{jsonFilename}' doesn't exists.");
                }

                return(result);
            }
        }