Example #1
0
        private void UpdateCommandsForProjectOnDispatcher(IVsHierarchy project, bool onlyIfVcsSupportEnabled)
        {
            Logger.Info($"Dispatching update commands function call");

            JoinableTaskFactory.RunAsync(async delegate
            {
                // git branch and merge might lead to a race condition here.
                // If a branch is checkout where the json file differs, the
                // filewatcher will trigger an event which is dispatched here.
                // However, while the function call is queued VS may reopen the
                // solution due to changes. This will ultimately result in a
                // null ref exception because the project object is unloaded.
                // UpdateCommandsForProject() will skip such projects because
                // their guid is empty.

                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                if (onlyIfVcsSupportEnabled && !IsVcsSupportEnabled)
                {
                    return;
                }

                Logger.Info($"Dispatched update commands function call for project '{project.GetDisplayName()}'");

                if (project.GetGuid() == Guid.Empty)
                {
                    Logger.Info($"Race condition might occurred while dispatching update commands function call. Project is already unloaded.");
                }

                ToolWindowHistory.SaveState();

                UpdateCommandsForProject(project);
            });
        }
Example #2
0
        public void RenameProject(IVsHierarchy project, string oldProjectDir, string oldProjectName, Action hack)
        {
            if (cmdPackage.IsUseSolutionDirEnabled)
            {
                return;
            }

            var guid = project.GetGuid();

            if (projectFsWatchers.TryGetValue(guid, out FileSystemWatcher fsWatcher))
            {
                projectFsWatchers.Remove(guid);
                using (fsWatcher.TemporarilyDisable())
                {
                    var newFileName = FullFilenameForProjectJsonFileFromProject(project);
                    var oldFileName = FullFilenameForProjectJsonFileFromProjectPath(oldProjectDir, oldProjectName);

                    Logger.Info($"Renaming json-file '{oldFileName}' to new name '{newFileName}'");

                    if (File.Exists(newFileName))
                    {
                        File.Delete(oldFileName);

                        hack(); // TODO
                    }
                    else if (File.Exists(oldFileName))
                    {
                        File.Move(oldFileName, newFileName);
                    }
                    fsWatcher.Filter = Path.GetFileName(newFileName);
                }
                projectFsWatchers.Add(guid, fsWatcher);
            }
        }
        private void UpdateCommandsForProjectOnDispatcher(IVsHierarchy project)
        {
            Logger.Info($"Dispatching update commands function call for project '{project.GetDisplayName()}'");

            Application.Current.Dispatcher.BeginInvoke(
                DispatcherPriority.Normal,
                new Action(() =>
            {
                // git branch and merge might lead to a race condition here.
                // If a branch is checkout where the json file differs, the
                // filewatcher will trigger an event which is dispatched here.
                // However, while the function call is queued VS may reopen the
                // solution due to changes. This will ultimately result in a
                // null ref exception because the project object is unloaded.
                // UpdateCommandsForProject() will skip such projects because
                // their guid is empty.

                Logger.Info($"Dispatched update commands function call for project '{project.GetDisplayName()}'");

                if (project.GetGuid() == Guid.Empty)
                {
                    Logger.Info($"Race condition might occurred while dispatching update commands function call. Project is already unloaded.");
                }

                UpdateCommandsForProject(project);
            }));
        }
        int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
        {
            var project = ProjectForHierarchy(pHierarchy);

            if (!ProjectArguments.IsSupportedProject(project))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            Guid   projectGuid = pHierarchy.GetGuid();
            string projectPath = project.FullName;
            string projectName = project.UniqueName;
            bool   isLoaded    = pHierarchy.IsLoaded();

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

            ProjectStateMap[projectGuid] = new ProjectState {
                FilePath = projectPath, UniqueName = projectName, IsLoaded = isLoaded
            };

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

            return(S_OK);
        }
        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()}'.");
            }
        }
Example #6
0
        private void SaveJsonForProject(IVsHierarchy project)
        {
            if (!cmdPackage.IsVcsSupportEnabled || project == null)
            {
                return;
            }

            var               guid      = project.GetGuid();
            var               vm        = cmdPackage.ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(guid);
            string            filePath  = FullFilenameForProjectJsonFileFromProject(project);
            FileSystemWatcher fsWatcher = projectFsWatchers.GetValueOrDefault(guid);

            if (vm != null && vm.Items.Any())
            {
                using (fsWatcher?.TemporarilyDisable())
                {
                    // Tell VS that we're about to change this file
                    // This matters if the user has TFVC with server workpace (see #57)

                    if (!vsHelper.CanEditFile(filePath))
                    {
                        Logger.Error($"VS or the user did no let us edit our file :/");
                    }
                    else
                    {
                        try
                        {
                            using (Stream fileStream = File.Open(filePath, FileMode.Create, FileAccess.Write))
                            {
                                ProjectDataSerializer.Serialize(vm, fileStream);
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Warn($"Failed to write to file '{filePath}' with error '{e}'.");
                        }
                    }
                }
            }
            else if (File.Exists(filePath))
            {
                Logger.Info("Deleting json file because command list is empty but json-file exists.");

                try
                {
                    File.Delete(filePath);
                }
                catch (Exception e)
                {
                    Logger.Warn($"Failed to delete file '{filePath}' with error '{e}'.");
                }
            }
        }
        int IVsSolutionEvents.OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
        {
            if (!ProjectArguments.IsSupportedProject(pRealHierarchy))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            ProjectStateMap[pRealHierarchy.GetGuid()].IsLoaded = false;

            ProjectBeforeUnload?.Invoke(this, pRealHierarchy);

            return(S_OK);
        }
        int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
        {
            var project = ProjectForHierarchy(pRealHierarchy);

            if (!ProjectArguments.IsSupportedProject(project))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            ProjectStateMap[pRealHierarchy.GetGuid()].IsLoaded = true;

            ProjectAfterLoad?.Invoke(this, project);

            return(S_OK);
        }
        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 SaveJsonForProject(IVsHierarchy project)
        {
            if (!IsVcsSupportEnabled || project == null)
            {
                return;
            }

            var               guid      = project.GetGuid();
            var               vm        = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(guid);
            string            filePath  = FullFilenameForProjectJsonFileFromProject(project);
            FileSystemWatcher fsWatcher = projectFsWatchers.GetValueOrDefault(guid);

            if (vm != null && vm.Items.Any())
            {
                using (fsWatcher?.TemporarilyDisable())
                {
                    try
                    {
                        using (Stream fileStream = File.Open(filePath, FileMode.Create, FileAccess.Write))
                        {
                            Logic.ToolWindowProjectDataSerializer.Serialize(vm, fileStream);
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Warn($"Failed to write to file '{filePath}' with error '{e}'.");
                    }
                }
            }
            else if (File.Exists(filePath))
            {
                Logger.Info("Deleting json file because command list is empty but json-file exists.");

                try
                {
                    File.Delete(filePath);
                }
                catch (Exception e)
                {
                    Logger.Warn($"Failed to delete file '{filePath}' with error '{e}'.");
                }
            }
        }
        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);
        }
        int IVsSolutionEvents4.OnAfterRenameProject(IVsHierarchy pHierarchy)
        {
            var project = ProjectForHierarchy(pHierarchy);

            if (!ProjectArguments.IsSupportedProject(project))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            Guid projectGuid    = pHierarchy.GetGuid();
            var  oldFilePath    = ProjectStateMap[projectGuid].FilePath;
            var  oldProjectName = ProjectStateMap[projectGuid].UniqueName;

            ProjectStateMap[projectGuid].FilePath   = project.FullName;
            ProjectStateMap[projectGuid].UniqueName = project.UniqueName;

            ProjectAfterRename?.Invoke(this, new ProjectAfterRenameEventArgs {
                OldFilePath = oldFilePath, OldUniqueName = oldProjectName, Project = project
            });

            return(S_OK);
        }
        int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
        {
            if (!ProjectArguments.IsSupportedProject(pHierarchy))
            {
                return(LogIgnoringUnsupportedProjectType());
            }

            Guid projectGuid = pHierarchy.GetGuid();

            var isUloadProcess = ProjectStateMap.TryGetValue(projectGuid, out var state) && !state.IsLoaded;

            if (!isUloadProcess)
            {
                ProjectStateMap.Remove(projectGuid);
            }

            ProjectBeforeClose?.Invoke(this, new ProjectBeforeCloseEventArgs {
                Project = pHierarchy, IsUnloadProcess = isUloadProcess, IsSolutionCloseProcess = fRemoved == 0
            });

            return(S_OK);
        }
Example #14
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);
            }
        }
        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()}");
        }
        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()}'.");
        }
        private string CreateCommandLineArgsForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                return(null);
            }

            var projectCmd = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(project.GetGuid());

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

            string projConfig = project.GetProject()?.ConfigurationManager?.ActiveConfiguration?.ConfigurationName;

            string activeLaunchProfile = null;

            if (project.IsCpsProject())
            {
                activeLaunchProfile = SmartCmdArgs15.CpsProjectSupport.GetActiveLaunchProfileName(project.GetProject());
            }

            string MacroEvaluation(string arg)
            {
                if (!IsMacroEvaluationEnabled)
                {
                    return(arg);
                }

                return(msBuildPropertyRegex.Replace(arg,
                                                    match => vsHelper.GetMSBuildPropertyValueForActiveConfig(project, match.Groups["propertyName"].Value) ?? match.Value));
            }

            string JoinContainer(CmdContainer con)
            {
                IEnumerable <CmdBase> items = con.Items.Where(x => x.IsChecked != false);

                if (projConfig != null)
                {
                    items = items.Where(x => { var conf = x.UsedProjectConfig; return(conf == null || conf == projConfig); });
                }

                if (activeLaunchProfile != null)
                {
                    items = items.Where(x => { var prof = x.UsedLaunchProfile; return(prof == null || prof == activeLaunchProfile); });
                }

                return(string.Join(con.Delimiter, items.Select(x => x is CmdContainer c ? JoinContainer(c) : MacroEvaluation(x.Value))));
            }

            return(JoinContainer(projectCmd));
        }
        private string CreateCommandLineArgsForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                return(null);
            }

            IEnumerable <CmdArgument> checkedArgs = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(project.GetGuid())?.CheckedArguments;

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

            string projConfig = project.GetProject()?.ConfigurationManager?.ActiveConfiguration?.ConfigurationName;

            if (projConfig != null)
            {
                checkedArgs = checkedArgs.Where(x => { var conf = x.UsedProjectConfig; return(conf == null || conf == projConfig); });
            }

            if (project.IsCpsProject())
            {
                var activeLaunchProfile = SmartCmdArgs15.CpsProjectSupport.GetActiveLaunchProfileName(project.GetProject());
                if (activeLaunchProfile != null)
                {
                    checkedArgs = checkedArgs.Where(x => { var prof = x.UsedLaunchProfile; return(prof == null || prof == activeLaunchProfile); });
                }
            }

            IEnumerable <string> enabledEntries;

            if (IsMacroEvaluationEnabled)
            {
                enabledEntries = checkedArgs.Select(
                    e => msBuildPropertyRegex.Replace(e.Value,
                                                      match => vsHelper.GetMSBuildPropertyValueForActiveConfig(project, match.Groups["propertyName"].Value) ?? match.Value));
            }
            else
            {
                enabledEntries = checkedArgs.Select(e => e.Value);
            }
            return(string.Join(" ", enabledEntries));
        }
        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()}'.");
        }
Example #20
0
        private string GetWorkingDirForProject(IVsHierarchy project)
        {
            if (project == null)
            {
                return(null);
            }

            IEnumerable <CmdWorkingDir> checkedWorkingDirs = ToolWindowViewModel.TreeViewModel.Projects.GetValueOrDefault(project.GetGuid())?.CheckedWorkingDirs;

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

            string projConfig = project.GetProject()?.ConfigurationManager?.ActiveConfiguration?.ConfigurationName;

            if (projConfig != null)
            {
                checkedWorkingDirs = checkedWorkingDirs.Where(x => { var conf = x.UsedProjectConfig; return(conf == null || conf == projConfig); });
            }

            if (project.IsCpsProject())
            {
                var activeLaunchProfile = SmartCmdArgs15.CpsProjectSupport.GetActiveLaunchProfileName(project.GetProject());
                if (activeLaunchProfile != null)
                {
                    checkedWorkingDirs = checkedWorkingDirs.Where(x => { var prof = x.UsedLaunchProfile; return(prof == null || prof == activeLaunchProfile); });
                }
            }

            IEnumerable <string> enabledEntries;

            if (IsMacroEvaluationEnabled)
            {
                enabledEntries = checkedWorkingDirs.Select(
                    e => msBuildPropertyRegex.Replace(e.Value,
                                                      match => vsHelper.GetMSBuildPropertyValueForActiveConfig(project, match.Groups["propertyName"].Value) ?? match.Value));
            }
            else
            {
                enabledEntries = checkedWorkingDirs.Select(e => e.Value);
            }

            var list = enabledEntries.ToList();

            if (list.Count != 1)
            {
                Logger.Error("More than one working directory selected, fallback to default.");
                return(null);
            }

            return(list.First());
        }