示例#1
0
        private void showDiscussionForm(DataCache dataCache, ILocalCommitStorage storage, User currentUser,
                                        MergeRequestKey mrk, IEnumerable <Discussion> discussions, string title, User author, string webUrl,
                                        string customActionFileName)
        {
            if (currentUser == null || discussions == null || author == null || currentUser.Id == 0)
            {
                return;
            }

            bool doesMatchTag(object tag) => tag != null && ((MergeRequestKey)(tag)).Equals(mrk);

            Form formExisting = WinFormsHelpers.FindFormByTag("DiscussionsForm", doesMatchTag);

            if (formExisting is DiscussionsForm existingDiscussionsForm)
            {
                existingDiscussionsForm.Restore();
                Trace.TraceInformation(String.Format("[MainForm] Activated an existing Discussions view for MR {0}", mrk.IId));
                return;
            }

            addOperationRecord("Rendering discussion contexts has started");
            labelOperationStatus.Refresh();

            DiscussionsForm form;

            try
            {
                IAsyncGitCommandService git = storage?.Git;

                AsyncDiscussionLoader discussionLoader = new AsyncDiscussionLoader(mrk, dataCache,
                                                                                   async(key, discussionsUpdated) =>
                {
                    if (storage != null && storage.Updater != null)
                    {
                        try
                        {
                            await storage.Updater.StartUpdate(new DiscussionBasedContextProvider(discussionsUpdated),
                                                              status => onStorageUpdateProgressChange(status, mrk), () => onStorageUpdateStateChange());
                        }
                        catch (LocalCommitStorageUpdaterException ex)
                        {
                            ExceptionHandlers.Handle("Cannot update a storage on refreshing discussions", ex);
                        }
                    }
                    else
                    {
                        Trace.TraceInformation("[MainForm] User tried to refresh Discussions without a storage");
                        MessageBox.Show("Cannot update a storage, some context code snippets may be missing. ",
                                        "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }, this);

                AsyncDiscussionHelper discussionHelper = new AsyncDiscussionHelper(mrk, title, currentUser, _shortcuts);

                IEnumerable <ICommand> getCommands(ICommandCallback callback) =>
                loadCustomCommands(customActionFileName, callback);

                DiscussionsForm discussionsForm = new DiscussionsForm(
                    git, currentUser, mrk, discussions, title, author, _colorScheme,
                    discussionLoader, discussionHelper, webUrl, _shortcuts, getCommands)
                {
                    Tag = mrk
                };
                form = discussionsForm;
            }
            catch (NoDiscussionsToShow)
            {
                MessageBox.Show("No discussions to show.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Trace.TraceInformation(String.Format("[MainForm] No discussions to show for MR IID {0}", mrk.IId));
                addOperationRecord("No discussions to show");
                return;
            }

            addOperationRecord("Opening Discussions view has started");
            labelOperationStatus.Refresh();

            form.Show();

            Trace.TraceInformation(String.Format("[MainForm] Opened Discussions for MR IId {0} (at {1})",
                                                 mrk.IId, (storage?.Path ?? "null")));

            addOperationRecord("Discussions view has opened");
            ensureMergeRequestInRecentDataCache(mrk);
        }
示例#2
0
        async private Task <IEnumerable <FileInternal> > fetchComparisonsAsync(bool isAwaitedUpdate,
                                                                               CommitStorageUpdateContext context)
        {
            bool                      cancelled   = _isDisposed;
            Exception                 exception   = null;
            List <FileInternal>       allFiles    = new List <FileInternal>();
            List <ComparisonInternal> comparisons = new List <ComparisonInternal>();

            async Task doFetch(BaseToHeadsCollection.FlatBaseToHeadInfo baseToHeadInfo)
            {
                if (cancelled)
                {
                    return;
                }

                await suspendProcessingOfNonAwaitedUpdate(isAwaitedUpdate);

                Comparison comparison = await fetchSingleComparisonAsync(baseToHeadInfo.Base.Sha, baseToHeadInfo.Head.Sha);

                if (comparison == null || _isDisposed)
                {
                    cancelled = true;
                    return;
                }

                try
                {
                    throwOnBadComparison(comparison);
                }
                catch (LocalCommitStorageUpdaterLimitException ex)
                {
                    if (baseToHeadInfo.Files?.Any() ?? false)
                    {
                        ExceptionHandlers.Handle("Bad Comparison object", ex);
                        traceInformation(String.Format(
                                             "[FileStorageUpdater] Applying manual file comparison for {0} files", baseToHeadInfo.Files.Count()));
                        foreach (BaseToHeadsCollection.RelativeFileInfo fileInfo in baseToHeadInfo.Files)
                        {
                            allFiles.Add(new FileInternal(fileInfo.OldPath, baseToHeadInfo.Base.Sha));
                            allFiles.Add(new FileInternal(fileInfo.NewPath, baseToHeadInfo.Head.Sha));
                        }
                        return;
                    }

                    exception = ex;
                    cancelled = true;
                    return;
                }

                IEnumerable <DiffStruct> filteredDiffs = filterDiffs(isAwaitedUpdate, comparison.Diffs,
                                                                     baseToHeadInfo.Base.Sha, baseToHeadInfo.Head.Sha, baseToHeadInfo.Files);

                if (filteredDiffs != null && filteredDiffs.Any())
                {
                    comparisons.Add(new ComparisonInternal(filteredDiffs, baseToHeadInfo.Base.Sha, baseToHeadInfo.Head.Sha));
                }
            }

            await TaskUtils.RunConcurrentFunctionsAsync(context.BaseToHeads.Flatten(), doFetch,
                                                        () => getComparisonBatchLimits(isAwaitedUpdate), () => cancelled);

            if (exception != null)
            {
                throw exception;
            }

            if (cancelled)
            {
                return(null);
            }

            Action <string> traceFunction = traceDebug;

            if (isAwaitedUpdate)
            {
                traceFunction = traceInformation;
            }

            traceFunction(String.Format("Got {0} comparisons, isAwaitedUpdate={1}",
                                        comparisons.Count(), isAwaitedUpdate.ToString()));
            foreach (ComparisonInternal comparison in comparisons)
            {
                traceFunction(String.Format("{0} vs {1} ({2} files)",
                                            comparison.BaseSha, comparison.HeadSha, comparison.Diffs.Count()));
            }

            allFiles.AddRange(comparisons.SelectMany(x => extractFilesFromComparison(x)));
            return(allFiles);
        }
示例#3
0
        private void processDiffQueue()
        {
            if (!_requestedDiff.Any())
            {
                return;
            }

            DiffRequest diffRequest = _requestedDiff.Peek();

            try
            {
                SnapshotSerializer serializer = new SnapshotSerializer();
                Snapshot           snapshot;
                try
                {
                    snapshot = serializer.DeserializeFromDisk(diffRequest.GitPID);
                }
                catch (Exception ex) // Any exception from de-serialization code
                {
                    ExceptionHandlers.Handle("Cannot read serialized Snapshot object", ex);
                    MessageBox.Show(
                        "Make sure that diff tool was launched from Merge Request Helper which is still running",
                        "Cannot create a discussion",
                        MessageBoxButtons.OK, MessageBoxIcon.Error,
                        MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }

                if (_storageFactory == null || _storageFactory.ParentFolder != snapshot.TempFolder)
                {
                    Trace.TraceWarning("[MainForm] File Storage folder was changed after launching diff tool");
                    MessageBox.Show("It seems that file storage folder was changed after launching diff tool. " +
                                    "Please restart diff tool.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning,
                                    MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }

                Core.Matching.MatchInfo matchInfo;
                try
                {
                    DiffArgumentParser diffArgumentParser = new DiffArgumentParser(diffRequest.DiffArguments);
                    matchInfo = diffArgumentParser.Parse(getDiffTempFolder(snapshot));
                    Debug.Assert(matchInfo != null);
                }
                catch (ArgumentException ex)
                {
                    ExceptionHandlers.Handle("Cannot parse diff tool arguments", ex);
                    MessageBox.Show("Bad arguments passed from diff tool", "Cannot create a discussion",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }

                ProjectKey          projectKey = new ProjectKey(snapshot.Host, snapshot.Project);
                ILocalCommitStorage storage    = getCommitStorage(projectKey, false);
                if (storage.Git == null)
                {
                    Trace.TraceError("[MainForm] storage.Git is null");
                    Debug.Assert(false);
                    return;
                }

                DataCache dataCache = getDataCacheByName(snapshot.DataCacheName);
                if (dataCache == null || getCurrentUser() == null)
                {
                    // It is unexpected to get here when we are not connected to a host
                    Debug.Assert(false);
                    return;
                }

                if ((dataCache.ConnectionContext?.GetHashCode() ?? 0) != snapshot.DataCacheHashCode)
                {
                    Trace.TraceWarning("[MainForm] Data Cache was changed after launching diff tool");
                    MessageBox.Show("It seems that data cache changed seriously after launching diff tool. " +
                                    "Please restart diff tool.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning,
                                    MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }

                DiffCallHandler handler = new DiffCallHandler(storage.Git, getCurrentUser(),
                                                              (mrk) => dataCache.DiscussionCache?.RequestUpdate(
                                                                  mrk, Constants.DiscussionCheckOnNewThreadFromDiffToolInterval, null),
                                                              (mrk) => dataCache.DiscussionCache?.GetDiscussions(mrk) ?? Array.Empty <Discussion>(),
                                                              _shortcuts);
                handler.Handle(matchInfo, snapshot);
            }
            finally
            {
                if (_requestedDiff.Any())
                {
                    _requestedDiff.Dequeue();
                    BeginInvoke(new Action(() => processDiffQueue()));
                }
            }
        }
示例#4
0
        private void addCustomActions()
        {
            CustomCommandLoader loader = new CustomCommandLoader(this);

            _customCommands = null;
            try
            {
                string CustomActionsFileName = "CustomActions.xml";
                _customCommands = loader.LoadCommands(CustomActionsFileName);
            }
            catch (CustomCommandLoaderException ex)
            {
                // If file doesn't exist the loader throws, leaving the app in an undesirable state.
                // Do not try to load custom actions if they don't exist.
                ExceptionHandlers.Handle("Cannot load custom actions", ex);
            }

            _keywords = _customCommands?
                        .Where(x => x is SendNoteCommand)
                        .Select(x => (x as SendNoteCommand).GetBody()) ?? null;

            if (_customCommands == null)
            {
                return;
            }

            int id = 0;

            foreach (ICommand command in _customCommands)
            {
                string name   = command.GetName();
                var    button = new System.Windows.Forms.Button
                {
                    Name     = "customAction" + id,
                    Location = new System.Drawing.Point {
                        X = 0, Y = 19
                    },
                    Size = new System.Drawing.Size {
                        Width = 72, Height = 32
                    },
                    MinimumSize = new System.Drawing.Size {
                        Width = 72, Height = 0
                    },
                    Text = name,
                    UseVisualStyleBackColor = true,
                    Enabled = false,
                    TabStop = false,
                    Tag     = command.GetDependency()
                };
                toolTip.SetToolTip(button, command.GetHint());
                button.Click += async(x, y) =>
                {
                    MergeRequestKey?mergeRequestKey = getMergeRequestKey(null);
                    if (!mergeRequestKey.HasValue)
                    {
                        return;
                    }

                    ITotalTimeCache totalTimeCache = getDataCache(!isSearchMode())?.TotalTimeCache;

                    labelWorkflowStatus.Text = "Command " + name + " is in progress";
                    try
                    {
                        await command.Run();
                    }
                    catch (Exception ex) // Whatever happened in Run()
                    {
                        string errorMessage = "Custom action failed";
                        ExceptionHandlers.Handle(errorMessage, ex);
                        MessageBox.Show(errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        labelWorkflowStatus.Text = "Command " + name + " failed";
                        return;
                    }

                    string statusMessage = String.Format("Command {0} completed for merge request !{1} in project {2}",
                                                         name, mergeRequestKey.Value.IId, mergeRequestKey.Value.ProjectKey.ProjectName);
                    labelWorkflowStatus.Text = statusMessage;
                    Trace.TraceInformation(String.Format("[MainForm] {0}", statusMessage));

                    if (command.GetStopTimer())
                    {
                        await onStopTimer(true);

                        onTimerStopped(totalTimeCache);
                    }

                    bool reload = command.GetReload();
                    if (reload)
                    {
                        requestUpdates(mergeRequestKey, new int[] {
                            Program.Settings.OneShotUpdateFirstChanceDelayMs,
                            Program.Settings.OneShotUpdateSecondChanceDelayMs
                        });
                    }
                };
                groupBoxActions.Controls.Add(button);
                id++;
            }
        }
示例#5
0
        private static void onLaunchFromDiffTool(LaunchOptions launchOptions)
        {
            LaunchContext context = (launchOptions.SpecialOptions as LaunchOptions.DiffToolModeOptions).LaunchContext;

            if (context.IsRunningSingleInstance)
            {
                Trace.TraceWarning("Merge Request Helper is not running");
                MessageBox.Show("Merge Request Helper is not running. Discussion cannot be created", "Warning",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            IntPtr concurrentDiscussionWindow = context.GetWindowByCaption(Constants.StartNewThreadCaption, false);

            if (concurrentDiscussionWindow != IntPtr.Zero)
            {
                Trace.TraceWarning(String.Format("Found a concurrent {0} window", Constants.StartNewThreadCaption));
                Win32Tools.ForceWindowIntoForeground(concurrentDiscussionWindow);
                return;
            }

            int parentToolPID = -1;

            try
            {
                string diffToolName = Path.GetFileNameWithoutExtension(createDiffTool().GetToolCommand());
                StorageSupport.LocalCommitStorageType type = ConfigurationHelper.GetPreferredStorageType(Program.Settings);
                string toolProcessName = type == StorageSupport.LocalCommitStorageType.FileStorage ? diffToolName : "git";
                parentToolPID = getParentProcessId(context.CurrentProcess, toolProcessName);
            }
            catch (Exception ex)
            {
                ExceptionHandlers.Handle("Cannot find parent diff tool process", ex);
            }

            if (parentToolPID == -1)
            {
                Trace.TraceError("Cannot find parent diff tool process");
                MessageBox.Show(
                    "Cannot find parent diff tool process. Discussion cannot be created. Is Merge Request Helper running?",
                    "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            string[] argumentsEx = new string[context.Arguments.Length + 1];
            Array.Copy(context.Arguments, 0, argumentsEx, 0, context.Arguments.Length);
            argumentsEx[argumentsEx.Length - 1] = parentToolPID.ToString();

            string message    = String.Join("|", argumentsEx);
            IntPtr mainWindow = context.GetWindowByCaption(Constants.MainWindowCaption, true);

            if (mainWindow == IntPtr.Zero)
            {
                Debug.Assert(false);

                Trace.TraceWarning("Cannot find Main Window");
                return;
            }

            Win32Tools.SendMessageToWindow(mainWindow, message);
        }
示例#6
0
        private static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var arguments = Environment.GetCommandLineArgs();

            if (arguments.Length < 2)
            {
                using (Mutex mutex = new Mutex(false, "Global\\" + mutex1_guid))
                {
                    if (!mutex.WaitOne(0, false))
                    {
                        return;
                    }

                    Application.ThreadException += (sender, e) => HandleUnhandledException(e.Exception);
                    setupTraceListener("mrHelper.main.log");

                    try
                    {
                        Application.Run(new MainForm());
                    }
                    catch (Exception ex) // whatever unhandled exception
                    {
                        HandleUnhandledException(ex);
                    }
                }
            }
            else if (arguments[1] == "diff")
            {
                using (Mutex mutex = new Mutex(false, "Global\\" + mutex2_guid))
                {
                    if (!mutex.WaitOne(0, false))
                    {
                        return;
                    }

                    Application.ThreadException += (sender, e) => HandleUnhandledException(e.Exception);
                    setupTraceListener("mrHelper.diff.log");

                    DiffArgumentParser diffArgumentParser = new DiffArgumentParser(arguments);
                    DiffToolInfo       diffToolInfo;
                    try
                    {
                        diffToolInfo = diffArgumentParser.Parse();
                    }
                    catch (ArgumentException ex)
                    {
                        ExceptionHandlers.Handle(ex, "Cannot parse diff tool arguments");
                        MessageBox.Show("Bad arguments, see details in logs", "Error",
                                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                    int gitPID = mrHelper.Core.Interprocess.Helpers.GetGitParentProcessId(Process.GetCurrentProcess().Id);

                    SnapshotSerializer serializer = new SnapshotSerializer();
                    Snapshot           snapshot;
                    try
                    {
                        snapshot = serializer.DeserializeFromDisk(gitPID);
                    }
                    catch (System.IO.IOException ex)
                    {
                        ExceptionHandlers.Handle(ex, "Cannot de-serialize snapshot");
                        MessageBox.Show("Cannot create a discussion. "
                                        + "Make sure that you use diff tool instance launched from mrHelper and mrHelper is still running.");
                        return;
                    }

                    IInterprocessCallHandler diffCallHandler = new DiffCallHandler(diffToolInfo);
                    try
                    {
                        diffCallHandler.Handle(snapshot);
                    }
                    catch (Exception ex) // whatever unhandled exception
                    {
                        HandleUnhandledException(ex);
                    }
                }
            }
        }