public bool ShouldEnableSecondItemDiff(FileStatusItem item, bool isSecondRevision)
 {
     // Git reference in this revision or work tree file existing on the file system
     return(item is not null &&
            !item.Item.IsSubmodule &&
            (isSecondRevision ? !item.Item.IsDeleted : !item.Item.IsNew));
 }
        public FileStatusItem CreateFileStatusItem(string name, GitRevision rev)
        {
            var gis = new GitItemStatus {
                IsNew = true, Name = name
            };
            var fsi = new FileStatusItem(null, rev, gis);

            return(fsi);
        }
        public void RememberFile_GetGitCommit_SecondWorkTree()
        {
            var rev      = new GitRevision(ObjectId.Random());
            var workTree = new GitRevision(ObjectId.WorkTreeId);
            var name     = "WorkTreeFile";
            var item     = new FileStatusItem(
                firstRev: rev,
                secondRev: workTree,
                item: new GitItemStatus(name));

            _rememberFileContextMenuController.GetGitCommit(null, item, true).Should().Be(name);
        }
        public void RememberFile_GetGitCommit_CommitNoOld(bool isSecondRev)
        {
            var          id      = ObjectId.Random();
            var          rev     = new GitRevision(id);
            const string newName = "newName";
            var          item    = new FileStatusItem(
                firstRev: rev,
                secondRev: rev,
                item: new GitItemStatus(name: newName));
            var expected = $"{id}:{newName}";

            _rememberFileContextMenuController.GetGitCommit(null, item, isSecondRev).Should().Be(expected);
        }
        public void RememberFile_ShouldEnableSecondRemember_WorkTree(bool isSubmodule, bool isDeleted, bool isSecondRev, bool result)
        {
            var rev  = new GitRevision(ObjectId.Random());
            var item = new FileStatusItem(
                firstRev: rev,
                secondRev: new GitRevision(ObjectId.WorkTreeId),
                item: new GitItemStatus("file1")
            {
                IsSubmodule = isSubmodule,
                IsDeleted   = isDeleted
            });

            _rememberFileContextMenuController.ShouldEnableSecondItemDiff(item, isSecondRev).Should().Be(result);
        }
        public void RememberFile_GetGitCommit_null()
        {
            var rev      = new GitRevision(ObjectId.Random());
            var workTree = new GitRevision(ObjectId.WorkTreeId);

            _rememberFileContextMenuController.GetGitCommit(null, null, false).Should().BeNull();

            var item = new FileStatusItem(
                firstRev: null,
                secondRev: rev,
                item: new GitItemStatus("file"));

            _rememberFileContextMenuController.GetGitCommit(null, item, false).Should().BeNull();
        }
        public void RememberFile_GetGitCommit_Index_GetBlob()
        {
            var          rev   = new GitRevision(ObjectId.Random());
            var          index = new GitRevision(ObjectId.IndexId);
            const string name  = "File";
            var          item  = new FileStatusItem(
                firstRev: rev,
                secondRev: index,
                item: new GitItemStatus {
                Name = name, TreeGuid = null
            });

            _rememberFileContextMenuController.GetGitCommit(GetFileBlobHash, item, true).Should().Be(ObjectId.IndexId.ToString());
        }
        public void RememberFile_GetGitCommit_Index_Tree()
        {
            var          rev   = new GitRevision(ObjectId.Random());
            var          index = new GitRevision(ObjectId.IndexId);
            const string name  = "File";
            var          item  = new FileStatusItem(
                firstRev: rev,
                secondRev: index,
                item: new GitItemStatus(name)
            {
                TreeGuid = ObjectId.Random()
            });

            _rememberFileContextMenuController.GetGitCommit(null, item, true).Should().Be(item.Item.TreeGuid?.ToString());
        }
        /// <summary>
        /// View the changes between the revisions, if possible as a diff
        /// </summary>
        /// <param name="fileViewer">Current FileViewer</param>
        /// <param name="item">The FileStatusItem to present changes for</param>
        /// <param name="defaultText">default text if no diff is possible</param>
        /// <param name="openWithDiffTool">The difftool command to open with</param>
        /// <returns>Task to view</returns>
        public static Task ViewChangesAsync(this FileViewer fileViewer,
                                            [CanBeNull] FileStatusItem item,
                                            [NotNull] string defaultText        = "",
                                            [CanBeNull] Action openWithDiffTool = null)
        {
            if (!string.IsNullOrWhiteSpace(item?.Item?.ErrorMessage))
            {
                // Present error (e.g. parsing Git)
                return(fileViewer.ViewTextAsync(item.Item.Name, item.Item.ErrorMessage));
            }

            if (item?.Item == null || item.SecondRevision?.ObjectId == null)
            {
                if (!string.IsNullOrWhiteSpace(defaultText))
                {
                    return(fileViewer.ViewTextAsync(item?.Item?.Name, defaultText));
                }

                fileViewer.Clear();
                return(Task.CompletedTask);
            }

            var firstId = item.FirstRevision?.ObjectId ?? item.SecondRevision.FirstParentGuid;

            openWithDiffTool ??= OpenWithDiffTool;

            if (item.Item.IsNew || firstId == null || FileHelper.IsImage(item.Item.Name))
            {
                // View blob guid from revision, or file for worktree
                return(fileViewer.ViewGitItemRevisionAsync(item.Item, item.SecondRevision.ObjectId, openWithDiffTool));
            }

            string selectedPatch = GetSelectedPatch(fileViewer, firstId, item.SecondRevision.ObjectId, item.Item);

            return(item.Item.IsSubmodule || selectedPatch == null
                ? fileViewer.ViewTextAsync(item.Item.Name, text : selectedPatch ?? defaultText, openWithDifftool : openWithDiffTool)
                : fileViewer.ViewPatchAsync(item.Item.Name, text: selectedPatch, openWithDifftool: openWithDiffTool));

            void OpenWithDiffTool()
            {
                fileViewer.Module.OpenWithDifftool(
                    item.Item.Name,
                    item.Item.OldName,
                    firstId?.ToString(),
                    item.SecondRevision.ToString(),
                    "",
                    item.Item.IsTracked);
            }
        // Executes GET requsts for all files
        private static ActionResult GetHandler(IFileHandler handler)
        {
            IFileStatus status = new FileStatus();

            using (FilesModel db = new FilesModel())
            {
                foreach (var row in db.Files)
                {
                    string url = handler.Context.Request.Url.OriginalString + "?fileName=" + row.Id.ToString();

                    IFileStatusItem file = new FileStatusItem()
                    {
                        ContentType  = row.Type,
                        DeleteType   = "DELETE",
                        FileName     = row.Name,
                        FileSize     = row.Size,
                        OriginalName = row.Original,
                        Progress     = "100",
                        Success      = true,
                        ThumbnailUrl = row.Preview,

                        // Set an identifier for GET and DELETE requests
                        DeleteUrl = url,
                        FileUrl   = url
                    };

                    status.Files.Add(file);
                }
            }

            handler.FileStatus = status;

            // Create client plugin specific result and return an ActionResult
            IBackloadResult result = handler.Services.Core.CreatePluginResult();

            return(ResultCreator.Create((IFileStatusResult)result));
        }
Exemple #11
0
        /// <summary>
        /// View the changes between the revisions, if possible as a diff
        /// </summary>
        /// <param name="fileViewer">Current FileViewer</param>
        /// <param name="item">The FileStatusItem to present changes for</param>
        /// <param name="defaultText">default text if no diff is possible</param>
        /// <param name="openWithDiffTool">The difftool command to open with</param>
        /// <returns>Task to view</returns>
        public static Task ViewChangesAsync(this FileViewer fileViewer,
                                            [CanBeNull] FileStatusItem item,
                                            [NotNull] string defaultText        = "",
                                            [CanBeNull] Action openWithDiffTool = null)
        {
            if (item?.Item?.IsStatusOnly ?? false)
            {
                // Present error (e.g. parsing Git)
                return(fileViewer.ViewTextAsync(item.Item.Name, item.Item.ErrorMessage));
            }

            if (item?.Item is null || item.SecondRevision?.ObjectId is null)
            {
                if (!string.IsNullOrWhiteSpace(defaultText))
                {
                    return(fileViewer.ViewTextAsync(item?.Item?.Name, defaultText));
                }

                fileViewer.Clear();
                return(Task.CompletedTask);
            }

            var firstId = item.FirstRevision?.ObjectId ?? item.SecondRevision.FirstParentId;

            openWithDiffTool ??= OpenWithDiffTool;

            if (item.Item.IsNew || firstId is null || FileHelper.IsImage(item.Item.Name))
            {
                // View blob guid from revision, or file for worktree
                return(fileViewer.ViewGitItemRevisionAsync(item.Item, item.SecondRevision.ObjectId, openWithDiffTool));
            }

            if (item.Item.IsRangeDiff)
            {
                // This command may take time, give an indication of what is going on
                // The sha are incorrect if baseA/baseB is set, to simplify the presentation
                fileViewer.ViewText("range-diff.sh", $"git range-diff {firstId}...{item.SecondRevision.ObjectId}");

                string output = fileViewer.Module.GetRangeDiff(
                    firstId,
                    item.SecondRevision.ObjectId,
                    item.BaseA,
                    item.BaseB,
                    fileViewer.GetExtraDiffArguments(isRangeDiff: true));

                // Try set highlighting from first found filename
                var match    = new Regex(@"\n\s*(@@|##)\s+(?<file>[^#:\n]+)").Match(output ?? "");
                var filename = match.Groups["file"].Success ? match.Groups["file"].Value : item.Item.Name;

                return(fileViewer.ViewRangeDiffAsync(filename, output ?? defaultText));
            }

            string selectedPatch = GetSelectedPatch(fileViewer, firstId, item.SecondRevision.ObjectId, item.Item)
                                   ?? defaultText;

            return(item.Item.IsSubmodule
                ? fileViewer.ViewTextAsync(item.Item.Name, text: selectedPatch, openWithDifftool: openWithDiffTool)
                : fileViewer.ViewPatchAsync(item, text: selectedPatch, openWithDifftool: openWithDiffTool));

            void OpenWithDiffTool()
            {
                fileViewer.Module.OpenWithDifftool(
                    item.Item.Name,
                    item.Item.OldName,
                    firstId?.ToString(),
                    item.SecondRevision.ToString(),
                    isTracked: item.Item.IsTracked);
            }
        private void UpdateSelectedFileViewers(bool force = false)
        {
            var selectedRevisions = FileChanges.GetSelectedRevisions();

            if (selectedRevisions.Count == 0)
            {
                return;
            }

            GitRevision revision = selectedRevisions[0];
            var         children = FileChanges.GetRevisionChildren(revision.ObjectId);

            var fileName = revision.Name;

            if (string.IsNullOrEmpty(fileName))
            {
                fileName = FileName;
            }

            SetTitle(fileName);

            if (revision.IsArtificial)
            {
                tabControl1.SelectedTab = DiffTab;

                CommitInfoTabPage.Parent = null;
                BlameTab.Parent          = null;
                ViewTab.Parent           = null;
            }
            else
            {
                if (CommitInfoTabPage.Parent == null)
                {
                    tabControl1.TabPages.Insert(0, CommitInfoTabPage);
                }

                if (ViewTab.Parent == null)
                {
                    var index = tabControl1.TabPages.IndexOf(DiffTab);
                    Debug.Assert(index != -1, "TabControl should contain diff tab page");
                    tabControl1.TabPages.Insert(index + 1, ViewTab);
                }

                if (BlameTab.Parent == null)
                {
                    var index = tabControl1.TabPages.IndexOf(ViewTab);
                    Debug.Assert(index != -1, "TabControl should contain view tab page");
                    tabControl1.TabPages.Insert(index + 1, BlameTab);
                }
            }

            if (tabControl1.SelectedTab == BlameTab)
            {
                Blame.LoadBlame(revision, children, fileName, FileChanges, BlameTab, Diff.Encoding, force: force);
            }
            else if (tabControl1.SelectedTab == ViewTab)
            {
                View.Encoding = Diff.Encoding;
                var file = new GitItemStatus
                {
                    IsTracked   = true,
                    Name        = fileName,
                    IsSubmodule = GitModule.IsValidGitWorkingDir(_fullPathResolver.Resolve(fileName))
                };
                View.ViewGitItemRevisionAsync(file, revision.ObjectId);
            }
            else if (tabControl1.SelectedTab == DiffTab)
            {
                var file = new GitItemStatus
                {
                    IsTracked   = true,
                    Name        = fileName,
                    IsSubmodule = GitModule.IsValidGitWorkingDir(_fullPathResolver.Resolve(fileName))
                };
                var revisions = FileChanges.GetSelectedRevisions();
                var item      = new FileStatusItem(firstRev: revisions.Skip(1).LastOrDefault(), secondRev: revisions.FirstOrDefault(), file);
                Diff.ViewChangesAsync(item, defaultText: "You need to select at least one revision to view diff.");
            }
            else if (tabControl1.SelectedTab == CommitInfoTabPage)
            {
                CommitDiff.SetRevision(revision.ObjectId, fileName);
            }

            if (_buildReportTabPageExtension == null)
            {
                _buildReportTabPageExtension = new BuildReportTabPageExtension(() => Module, tabControl1, _buildReportTabCaption.Text);
            }

            _buildReportTabPageExtension.FillBuildReport(selectedRevisions.Count == 1 ? revision : null);
        }
        public string GetGitCommit([CanBeNull] Func <string, ObjectId, ObjectId> getFileBlobHash, [CanBeNull] FileStatusItem item, bool isSecondRevision)
        {
            if (item is null)
            {
                return(null);
            }

            var name = (!isSecondRevision && !string.IsNullOrWhiteSpace(item.Item.OldName)
                    ? item.Item.OldName
                    : item.Item.Name)
                       ?.ToPosixPath();
            var id = (isSecondRevision ? item.SecondRevision : item.FirstRevision)?.ObjectId;

            if (string.IsNullOrWhiteSpace(name) || id is null)
            {
                return(null);
            }

            if (id == ObjectId.WorkTreeId)
            {
                // A file system file
                return(name);
            }

            if (id == ObjectId.IndexId)
            {
                // Must be referenced by blob - no commit. File name presented in difftool will be blob or the other file
                return(item.Item.TreeGuid is not null
                    ? item.Item.TreeGuid.ToString()
                    : getFileBlobHash?.Invoke(name, id)?.ToString());
            }

            // commit:path
            return($"{id}:{name}");
        }
 public bool ShouldEnableSecondItemDiff(FileStatusItem item)
 => ShouldEnableSecondItemDiff(item, isSecondRevision: false) ||
 ShouldEnableSecondItemDiff(item, isSecondRevision: true);
 public bool ShouldEnableFirstItemDiff(FileStatusItem item, bool isSecondRevision)
 {
     // First item must be a git reference existing in the revision, i.e. other than work tree
     return(ShouldEnableSecondItemDiff(item, isSecondRevision: isSecondRevision) &&
            (isSecondRevision ? item.SecondRevision : item.FirstRevision)?.ObjectId != ObjectId.WorkTreeId);
 }
        // Executes GET requsts for all files
        private static ActionResult GetHandler(IFileHandler handler)
        {
            IFileStatus status = new FileStatus();
            using (FilesModel db = new FilesModel())
            {
                foreach (var row in db.Files)
                {
                    string url = handler.Context.Request.Url.OriginalString + "?fileName=" + row.Id.ToString();

                    IFileStatusItem file = new FileStatusItem()
                    {
                        ContentType = row.Type,
                        DeleteType = "DELETE",
                        FileName = row.Name,
                        FileSize = row.Size,
                        OriginalName = row.Original,
                        Progress = "100",
                        Success = true,
                        ThumbnailUrl = row.Preview,

                        // Set an identifier for GET and DELETE requests
                        DeleteUrl = url,
                        FileUrl = url
                    };

                    status.Files.Add(file);
                }
            }

            handler.FileStatus = status;

            // Create client plugin specific result and return an ActionResult
            IBackloadResult result = handler.Services.Core.CreatePluginResult();
            return ResultCreator.Create((IFileStatusResult)result);
        }