From 172e5fd1e6900e20b50bb5f331ac0d6006df5629 Mon Sep 17 00:00:00 2001 From: Scott Sumrall Date: Tue, 8 Aug 2023 13:53:15 -0400 Subject: [PATCH 1/5] Feature/i11099-skip-file-paths --- GitCommands/Git/Commands/GitCommandHelpers.cs | 6 +- .../FormCleanupRepository.Designer.cs | 246 ++++++++++++------ .../CommandsDialogs/FormCleanupRepository.cs | 147 ++++++++--- GitUI/Translation/English.xlf | 20 +- .../Git/Commands/GitCommandHelpersTest.cs | 23 +- contributors.txt | 1 + 6 files changed, 312 insertions(+), 131 deletions(-) diff --git a/GitCommands/Git/Commands/GitCommandHelpers.cs b/GitCommands/Git/Commands/GitCommandHelpers.cs index 478a056ce4d..c4b4164ba72 100644 --- a/GitCommands/Git/Commands/GitCommandHelpers.cs +++ b/GitCommands/Git/Commands/GitCommandHelpers.cs @@ -531,14 +531,16 @@ public static ArgumentString ApplyDiffPatchCmd(bool ignoreWhiteSpace, string pat /// Only show what would be deleted. /// Delete untracked directories too. /// Limit to specific paths. - public static ArgumentString CleanCmd(CleanMode mode, bool dryRun, bool directories, string? paths = null) + /// Exclude certain files. + public static ArgumentString CleanCmd(CleanMode mode, bool dryRun, bool directories, string? paths = null, string? excludes = null) { return new GitArgumentBuilder("clean") { mode, { directories, "-d" }, { dryRun, "--dry-run", "-f" }, - paths + paths, + { !string.IsNullOrEmpty(excludes), excludes } }; } diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.Designer.cs b/GitUI/CommandsDialogs/FormCleanupRepository.Designer.cs index f739170c349..385a993681a 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.Designer.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.Designer.cs @@ -29,7 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { Preview = new Button(); - AddPath = new Button(); + AddInclusivePath = new Button(); Cleanup = new Button(); _NO_TRANSLATE_Close = new Button(); groupBox1 = new GroupBox(); @@ -39,9 +39,13 @@ private void InitializeComponent() RemoveDirectories = new CheckBox(); PreviewOutput = new TextBox(); label1 = new Label(); - textBoxPaths = new TextBox(); - checkBoxPathFilter = new CheckBox(); - labelPathHint = new Label(); + textBoxIncludePaths = new TextBox(); + checkBoxIncludePathFilter = new CheckBox(); + textBoxExcludePaths = new TextBox(); + checkBoxExcludePathFilter = new CheckBox(); + AddExclusivePath = new Button(); + labelPathHintExclude = new Label(); + labelPathHintInclude = new Label(); CleanSubmodules = new CheckBox(); groupBox1.SuspendLayout(); SuspendLayout(); @@ -51,35 +55,38 @@ private void InitializeComponent() Preview.Anchor = AnchorStyles.Top | AnchorStyles.Right; Preview.Image = Properties.Images.Preview; Preview.ImageAlign = ContentAlignment.MiddleLeft; - Preview.Location = new Point(50, 300); + Preview.Location = new Point(60, 529); + Preview.Margin = new Padding(4); Preview.Name = "Preview"; - Preview.Size = new Size(120, 25); - Preview.TabIndex = 0; + Preview.Size = new Size(150, 31); + Preview.TabIndex = 10; Preview.Text = "Preview"; Preview.UseVisualStyleBackColor = true; Preview.Click += Preview_Click; // - // AddPath + // AddInclusivePath // - AddPath.Anchor = AnchorStyles.Top | AnchorStyles.Right; - AddPath.ImageAlign = ContentAlignment.MiddleLeft; - AddPath.Location = new Point(302, 164); - AddPath.Name = "AddPath"; - AddPath.Size = new Size(120, 25); - AddPath.TabIndex = 0; - AddPath.Text = "Add a path..."; - AddPath.UseVisualStyleBackColor = true; - AddPath.Click += AddPath_Click; + AddInclusivePath.Anchor = AnchorStyles.Top | AnchorStyles.Right; + AddInclusivePath.ImageAlign = ContentAlignment.MiddleLeft; + AddInclusivePath.Location = new Point(378, 203); + AddInclusivePath.Margin = new Padding(4); + AddInclusivePath.Name = "AddInclusivePath"; + AddInclusivePath.Size = new Size(150, 31); + AddInclusivePath.TabIndex = 3; + AddInclusivePath.Text = "Add a path..."; + AddInclusivePath.UseVisualStyleBackColor = true; + AddInclusivePath.Click += AddIncludePath_Click; // // Cleanup // Cleanup.Anchor = AnchorStyles.Top | AnchorStyles.Right; Cleanup.Image = Properties.Images.CleanupRepo; Cleanup.ImageAlign = ContentAlignment.MiddleLeft; - Cleanup.Location = new Point(176, 300); + Cleanup.Location = new Point(218, 529); + Cleanup.Margin = new Padding(4); Cleanup.Name = "Cleanup"; - Cleanup.Size = new Size(120, 25); - Cleanup.TabIndex = 1; + Cleanup.Size = new Size(150, 31); + Cleanup.TabIndex = 11; Cleanup.Text = "Cleanup"; Cleanup.UseVisualStyleBackColor = true; Cleanup.Click += Cleanup_Click; @@ -88,11 +95,12 @@ private void InitializeComponent() // _NO_TRANSLATE_Close.Anchor = AnchorStyles.Top | AnchorStyles.Right; _NO_TRANSLATE_Close.DialogResult = DialogResult.OK; - _NO_TRANSLATE_Close.Location = new Point(302, 300); + _NO_TRANSLATE_Close.Location = new Point(376, 529); + _NO_TRANSLATE_Close.Margin = new Padding(4); _NO_TRANSLATE_Close.Name = "_NO_TRANSLATE_Close"; - _NO_TRANSLATE_Close.Size = new Size(120, 25); - _NO_TRANSLATE_Close.TabIndex = 2; - _NO_TRANSLATE_Close.Text = TranslatedStrings.Close; + _NO_TRANSLATE_Close.Size = new Size(150, 31); + _NO_TRANSLATE_Close.TabIndex = 12; + _NO_TRANSLATE_Close.Text = "Close"; _NO_TRANSLATE_Close.UseVisualStyleBackColor = true; _NO_TRANSLATE_Close.Click += Close_Click; // @@ -102,19 +110,22 @@ private void InitializeComponent() groupBox1.Controls.Add(RemoveIgnored); groupBox1.Controls.Add(RemoveNonIgnored); groupBox1.Controls.Add(RemoveAll); - groupBox1.Location = new Point(12, 12); + groupBox1.Location = new Point(15, 15); + groupBox1.Margin = new Padding(4); groupBox1.Name = "groupBox1"; - groupBox1.Size = new Size(410, 100); - groupBox1.TabIndex = 3; + groupBox1.Padding = new Padding(4); + groupBox1.Size = new Size(512, 125); + groupBox1.TabIndex = 0; groupBox1.TabStop = false; groupBox1.Text = "Remove untracked files from working directory"; // // RemoveIgnored // RemoveIgnored.AutoSize = true; - RemoveIgnored.Location = new Point(7, 67); + RemoveIgnored.Location = new Point(9, 84); + RemoveIgnored.Margin = new Padding(4); RemoveIgnored.Name = "RemoveIgnored"; - RemoveIgnored.Size = new Size(197, 17); + RemoveIgnored.Size = new Size(272, 24); RemoveIgnored.TabIndex = 2; RemoveIgnored.Text = "Remove only ignored untracked files"; RemoveIgnored.UseVisualStyleBackColor = true; @@ -122,9 +133,10 @@ private void InitializeComponent() // RemoveNonIgnored // RemoveNonIgnored.AutoSize = true; - RemoveNonIgnored.Location = new Point(7, 43); + RemoveNonIgnored.Location = new Point(9, 54); + RemoveNonIgnored.Margin = new Padding(4); RemoveNonIgnored.Name = "RemoveNonIgnored"; - RemoveNonIgnored.Size = new Size(218, 17); + RemoveNonIgnored.Size = new Size(303, 24); RemoveNonIgnored.TabIndex = 1; RemoveNonIgnored.Text = "Remove only non-ignored untracked files"; RemoveNonIgnored.UseVisualStyleBackColor = true; @@ -133,9 +145,10 @@ private void InitializeComponent() // RemoveAll.AutoSize = true; RemoveAll.Checked = true; - RemoveAll.Location = new Point(7, 20); + RemoveAll.Location = new Point(9, 25); + RemoveAll.Margin = new Padding(4); RemoveAll.Name = "RemoveAll"; - RemoveAll.Size = new Size(150, 17); + RemoveAll.Size = new Size(204, 24); RemoveAll.TabIndex = 0; RemoveAll.TabStop = true; RemoveAll.Text = "Remove all untracked files"; @@ -146,84 +159,139 @@ private void InitializeComponent() RemoveDirectories.AutoSize = true; RemoveDirectories.Checked = true; RemoveDirectories.CheckState = CheckState.Checked; - RemoveDirectories.Location = new Point(19, 119); + RemoveDirectories.Location = new Point(24, 148); + RemoveDirectories.Margin = new Padding(4); RemoveDirectories.Name = "RemoveDirectories"; - RemoveDirectories.Size = new Size(168, 17); - RemoveDirectories.TabIndex = 4; + RemoveDirectories.Size = new Size(228, 24); + RemoveDirectories.TabIndex = 1; RemoveDirectories.Text = "Remove untracked directories"; RemoveDirectories.UseVisualStyleBackColor = true; // // PreviewOutput // PreviewOutput.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - PreviewOutput.Location = new Point(12, 353); + PreviewOutput.Location = new Point(17, 597); + PreviewOutput.Margin = new Padding(4); PreviewOutput.Multiline = true; PreviewOutput.Name = "PreviewOutput"; PreviewOutput.ScrollBars = ScrollBars.Both; - PreviewOutput.Size = new Size(410, 87); - PreviewOutput.TabIndex = 5; + PreviewOutput.Size = new Size(512, 117); + PreviewOutput.TabIndex = 14; PreviewOutput.WordWrap = false; // // label1 // label1.AutoSize = true; - label1.Location = new Point(9, 335); + label1.Location = new Point(17, 573); + label1.Margin = new Padding(4, 0, 4, 0); label1.Name = "label1"; - label1.Size = new Size(28, 13); - label1.TabIndex = 6; + label1.Size = new Size(37, 20); + label1.TabIndex = 13; label1.Text = "Log:"; // - // textBoxPaths - // - textBoxPaths.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - textBoxPaths.Location = new Point(48, 194); - textBoxPaths.Multiline = true; - textBoxPaths.Name = "textBoxPaths"; - textBoxPaths.ScrollBars = ScrollBars.Vertical; - textBoxPaths.Size = new Size(374, 63); - textBoxPaths.TabIndex = 1; - // - // checkBoxPathFilter - // - checkBoxPathFilter.AutoSize = true; - checkBoxPathFilter.Location = new Point(19, 169); - checkBoxPathFilter.Name = "checkBoxPathFilter"; - checkBoxPathFilter.Size = new Size(176, 17); - checkBoxPathFilter.TabIndex = 0; - checkBoxPathFilter.Text = "Affect the following path(s) only:"; - checkBoxPathFilter.UseVisualStyleBackColor = true; - checkBoxPathFilter.CheckedChanged += checkBoxPathFilter_CheckedChanged; - // - // labelPathHint - // - labelPathHint.AutoSize = true; - labelPathHint.Location = new Point(50, 261); - labelPathHint.Name = "labelPathHint"; - labelPathHint.Size = new Size(92, 13); - labelPathHint.TabIndex = 7; - labelPathHint.Text = "(one path per line)"; + // textBoxIncludePaths + // + textBoxIncludePaths.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + textBoxIncludePaths.Location = new Point(60, 240); + textBoxIncludePaths.Margin = new Padding(4); + textBoxIncludePaths.Multiline = true; + textBoxIncludePaths.Name = "textBoxIncludePaths"; + textBoxIncludePaths.ScrollBars = ScrollBars.Vertical; + textBoxIncludePaths.Size = new Size(466, 78); + textBoxIncludePaths.TabIndex = 4; + // + // checkBoxIncludePathFilter + // + checkBoxIncludePathFilter.AutoSize = true; + checkBoxIncludePathFilter.Location = new Point(24, 209); + checkBoxIncludePathFilter.Margin = new Padding(4); + checkBoxIncludePathFilter.Name = "checkBoxIncludePathFilter"; + checkBoxIncludePathFilter.Size = new Size(311, 24); + checkBoxIncludePathFilter.TabIndex = 2; + checkBoxIncludePathFilter.Text = "Affect the following directory path(s) only:"; + checkBoxIncludePathFilter.UseVisualStyleBackColor = true; + checkBoxIncludePathFilter.CheckedChanged += checkBoxPathFilter_CheckedChanged; + // + // textBoxExcludePaths + // + textBoxExcludePaths.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + textBoxExcludePaths.Location = new Point(60, 391); + textBoxExcludePaths.Margin = new Padding(4); + textBoxExcludePaths.Multiline = true; + textBoxExcludePaths.Name = "textBoxExcludePaths"; + textBoxExcludePaths.ScrollBars = ScrollBars.Vertical; + textBoxExcludePaths.Size = new Size(466, 78); + textBoxExcludePaths.TabIndex = 8; + // + // checkBoxExcludePathFilter + // + checkBoxExcludePathFilter.AutoSize = true; + checkBoxExcludePathFilter.Location = new Point(24, 360); + checkBoxExcludePathFilter.Margin = new Padding(4); + checkBoxExcludePathFilter.Name = "checkBoxExcludePathFilter"; + checkBoxExcludePathFilter.Size = new Size(252, 24); + checkBoxExcludePathFilter.TabIndex = 6; + checkBoxExcludePathFilter.Text = "Exclude the following file path(s):"; + checkBoxExcludePathFilter.UseVisualStyleBackColor = true; + checkBoxExcludePathFilter.CheckedChanged += checkBoxExcludePathFilter_CheckedChanged; + // + // AddExclusivePath + // + AddExclusivePath.Anchor = AnchorStyles.Top | AnchorStyles.Right; + AddExclusivePath.ImageAlign = ContentAlignment.MiddleLeft; + AddExclusivePath.Location = new Point(378, 354); + AddExclusivePath.Margin = new Padding(4); + AddExclusivePath.Name = "AddExclusivePath"; + AddExclusivePath.Size = new Size(150, 31); + AddExclusivePath.TabIndex = 7; + AddExclusivePath.Text = "Add a path..."; + AddExclusivePath.UseVisualStyleBackColor = true; + AddExclusivePath.Click += AddExcludePath_Click; + // + // labelPathHintExclude + // + labelPathHintExclude.AutoSize = true; + labelPathHintExclude.Location = new Point(62, 475); + labelPathHintExclude.Margin = new Padding(4, 0, 4, 0); + labelPathHintExclude.Name = "labelPathHintExclude"; + labelPathHintExclude.Size = new Size(132, 20); + labelPathHintExclude.TabIndex = 9; + labelPathHintExclude.Text = "(one path per line)"; + // + // labelPathHintInclude + // + labelPathHintInclude.AutoSize = true; + labelPathHintInclude.Location = new Point(62, 323); + labelPathHintInclude.Margin = new Padding(4, 0, 4, 0); + labelPathHintInclude.Name = "labelPathHintInclude"; + labelPathHintInclude.Size = new Size(132, 20); + labelPathHintInclude.TabIndex = 5; + labelPathHintInclude.Text = "(one path per line)"; // // CleanSubmodules // CleanSubmodules.AutoSize = true; - CleanSubmodules.Location = new Point(19, 144); + CleanSubmodules.Location = new Point(24, 178); CleanSubmodules.Name = "CleanSubmodules"; - CleanSubmodules.Size = new Size(183, 19); + CleanSubmodules.Size = new Size(225, 24); CleanSubmodules.TabIndex = 8; CleanSubmodules.Text = "Clean submodules recursively"; CleanSubmodules.UseVisualStyleBackColor = true; // // FormCleanupRepository // - AcceptButton = AddPath; - AutoScaleDimensions = new SizeF(96F, 96F); + AcceptButton = AddInclusivePath; + AutoScaleDimensions = new SizeF(120F, 120F); AutoScaleMode = AutoScaleMode.Dpi; CancelButton = _NO_TRANSLATE_Close; - ClientSize = new Size(434, 462); - Controls.Add(CleanSubmodules); - Controls.Add(labelPathHint); - Controls.Add(textBoxPaths); - Controls.Add(checkBoxPathFilter); + ClientSize = new Size(542, 727); + Controls.Add(labelPathHintInclude); + Controls.Add(labelPathHintExclude); + Controls.Add(textBoxExcludePaths); + Controls.Add(checkBoxExcludePathFilter); + Controls.Add(AddExclusivePath); + Controls.Add(textBoxIncludePaths); + Controls.Add(checkBoxIncludePathFilter); Controls.Add(label1); Controls.Add(PreviewOutput); Controls.Add(RemoveDirectories); @@ -231,10 +299,12 @@ private void InitializeComponent() Controls.Add(_NO_TRANSLATE_Close); Controls.Add(Cleanup); Controls.Add(Preview); - Controls.Add(AddPath); + Controls.Add(AddInclusivePath); + Controls.Add(CleanSubmodules); + Margin = new Padding(4); MaximizeBox = false; MinimizeBox = false; - MinimumSize = new Size(450, 500); + MinimumSize = new Size(558, 738); Name = "FormCleanupRepository"; StartPosition = FormStartPosition.CenterParent; Text = "Clean working directory"; @@ -247,7 +317,7 @@ private void InitializeComponent() #endregion private Button Preview; - private Button AddPath; + private Button AddInclusivePath; private Button Cleanup; private Button _NO_TRANSLATE_Close; private GroupBox groupBox1; @@ -257,9 +327,13 @@ private void InitializeComponent() private CheckBox RemoveDirectories; private TextBox PreviewOutput; private Label label1; - private TextBox textBoxPaths; - private CheckBox checkBoxPathFilter; - private Label labelPathHint; + private TextBox textBoxIncludePaths; + private CheckBox checkBoxIncludePathFilter; + private TextBox textBoxExcludePaths; + private CheckBox checkBoxExcludePathFilter; + private Button AddExclusivePath; + private Label labelPathHintExclude; + private Label labelPathHintInclude; private CheckBox CleanSubmodules; } } diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.cs b/GitUI/CommandsDialogs/FormCleanupRepository.cs index aebe5b5a1d8..f7dc8da46b2 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.cs @@ -24,34 +24,45 @@ public FormCleanupRepository(GitUICommands commands) InitializeComponent(); InitializeComplete(); PreviewOutput.ReadOnly = true; + checkBoxPathFilter_CheckedChanged(this, EventArgs.Empty); + checkBoxExcludePathFilter_CheckedChanged(this, EventArgs.Empty); } public void SetPathArgument(string? path) { if (string.IsNullOrEmpty(path)) { - checkBoxPathFilter.Checked = false; - textBoxPaths.Text = ""; + checkBoxExcludePathFilter.Checked = false; + textBoxExcludePaths.Text = ""; + + checkBoxIncludePathFilter.Checked = false; + textBoxIncludePaths.Text = ""; } else { - checkBoxPathFilter.Checked = true; - textBoxPaths.Text = path; + checkBoxExcludePathFilter.Checked = true; + textBoxExcludePaths.Text = path; + + checkBoxIncludePathFilter.Checked = true; + textBoxIncludePaths.Text = path; } } private void Preview_Click(object sender, EventArgs e) { - string pathArgument = GetPathArgumentFromGui(); + string includePathArgument = GetInclusivePathArgumentFromGui(); + string excludePathArguments = GetExclusivePathArgumentFromGui(); CleanMode mode = GetCleanMode(); - var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: true, directories: RemoveDirectories.Checked, paths: pathArgument); + var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: false, directories: RemoveDirectories.Checked, + paths: includePathArgument, excludes: excludePathArguments); + string cmdOutput = FormProcess.ReadDialog(this, arguments: cleanUpCmd, Module.WorkingDir, input: null, useDialogSettings: true); PreviewOutput.Text = EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); if (CleanSubmodules.Checked) { - var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: true, directories: RemoveDirectories.Checked, paths: pathArgument); + var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: true, directories: RemoveDirectories.Checked, paths: includePathArgument); cmdOutput = FormProcess.ReadDialog(this, arguments: cleanSubmodulesCmd, Module.WorkingDir, input: null, useDialogSettings: true); PreviewOutput.Text += EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); } @@ -61,16 +72,18 @@ private void Cleanup_Click(object sender, EventArgs e) { if (MessageBox.Show(this, _reallyCleanupQuestion.Text, _reallyCleanupQuestionCaption.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - string pathArgument = GetPathArgumentFromGui(); + string includePathArgument = GetInclusivePathArgumentFromGui(); + string excludePathArguments = GetExclusivePathArgumentFromGui(); CleanMode mode = GetCleanMode(); - var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: false, directories: RemoveDirectories.Checked, paths: pathArgument); + var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: false, directories: RemoveDirectories.Checked, + paths: includePathArgument, excludes: excludePathArguments); string cmdOutput = FormProcess.ReadDialog(this, arguments: cleanUpCmd, Module.WorkingDir, input: null, useDialogSettings: true); PreviewOutput.Text = EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); if (CleanSubmodules.Checked) { - var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: false, directories: RemoveDirectories.Checked, paths: pathArgument); + var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: false, directories: RemoveDirectories.Checked, paths: includePathArgument); cmdOutput = FormProcess.ReadDialog(this, arguments: cleanSubmodulesCmd, Module.WorkingDir, input: null, useDialogSettings: true); PreviewOutput.Text += EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); } @@ -97,9 +110,9 @@ private CleanMode GetCleanMode() throw new NotSupportedException($"Unknown value for {nameof(CleanMode)}."); } - private string? GetPathArgumentFromGui() + private string? GetInclusivePathArgumentFromGui() { - if (!checkBoxPathFilter.Checked) + if (!checkBoxIncludePathFilter.Checked) { return null; } @@ -107,7 +120,22 @@ private CleanMode GetCleanMode() // 1. get all lines from text box which are not empty // 2. wrap lines with "" // 3. join together with space as separator - return string.Join(" ", textBoxPaths.Lines.Where(a => !string.IsNullOrEmpty(a)).Select(a => string.Format("\"{0}\"", a))); + return string.Join(" ", textBoxIncludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => string.Format("\"{0}\"", p))); + } + + private string? GetExclusivePathArgumentFromGui() + { + if (!checkBoxExcludePathFilter.Checked) + { + return null; + } + + // 1. get all lines from text box which are not empty + // 2. Prepend lines with '--exclude=' + // 3. Replace whitespace with '?' and convert to POSIX path + // 3. join together with space as separator + + return string.Join(" ", textBoxExcludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => string.Format("--exclude={0}", p.Replace(" ", "?")).ToPosixPath())); } private void Close_Click(object sender, EventArgs e) @@ -117,14 +145,42 @@ private void Close_Click(object sender, EventArgs e) private void checkBoxPathFilter_CheckedChanged(object sender, EventArgs e) { - bool filterByPath = checkBoxPathFilter.Checked; - textBoxPaths.Enabled = filterByPath; - labelPathHint.Visible = filterByPath; + bool filterByPath = checkBoxIncludePathFilter.Checked; + textBoxIncludePaths.Enabled = filterByPath; + labelPathHintInclude.Visible = filterByPath; + } + + private void checkBoxExcludePathFilter_CheckedChanged(object sender, EventArgs e) + { + bool filterByPath = checkBoxExcludePathFilter.Checked; + textBoxExcludePaths.Enabled = filterByPath; + labelPathHintExclude.Visible = filterByPath; + } + + private void AddIncludePath_Click(object sender, EventArgs e) + { + string path = RequestUserFolderPath(); + + if (path is not null) + { + textBoxIncludePaths.Text += path; + } + } + + private void AddExcludePath_Click(object sender, EventArgs e) + { + string path = RequestUserFilePath(); + + if (path is not null) + { + path = path.Replace(Module.WorkingDir, ""); + textBoxExcludePaths.Text += path; + } } - private void AddPath_Click(object sender, EventArgs e) + private string? RequestUserFolderPath() { - FolderBrowserDialog dialog = new() + using FolderBrowserDialog dialog = new() { SelectedPath = Module.WorkingDir, }; @@ -132,20 +188,51 @@ private void AddPath_Click(object sender, EventArgs e) var result = dialog.ShowDialog(this); string subFoldersToClean; - if (result == DialogResult.OK - && (subFoldersToClean = dialog.SelectedPath).StartsWith(Module.WorkingDir) - && Directory.Exists(subFoldersToClean) - && !subFoldersToClean.Equals(Module.WorkingDirGitDir.TrimEnd(Path.DirectorySeparatorChar))) - { - checkBoxPathFilter.Checked = true; - textBoxPaths.Enabled = true; - if (textBoxPaths.Text.Length != 0) - { - textBoxPaths.Text += Environment.NewLine; - } + if (result != DialogResult.OK + || !(subFoldersToClean = dialog.SelectedPath).StartsWith(Module.WorkingDir) + || !Directory.Exists(subFoldersToClean) + || subFoldersToClean.Equals(Module.WorkingDirGitDir.TrimEnd(Path.DirectorySeparatorChar))) + { + return null; + } - textBoxPaths.Text += string.Join(Environment.NewLine, subFoldersToClean); + checkBoxIncludePathFilter.Checked = true; + textBoxIncludePaths.Enabled = true; + if (textBoxIncludePaths.Text.Length != 0) + { + textBoxIncludePaths.Text += Environment.NewLine; } + + string userPath = string.Join(Environment.NewLine, subFoldersToClean); + return userPath; + } + + private string? RequestUserFilePath() + { + using OpenFileDialog openFileDialog = new(); + + openFileDialog.InitialDirectory = Module.WorkingDir; + openFileDialog.RestoreDirectory = true; + + var result = openFileDialog.ShowDialog(this); + + string fileToExclude; + if (result != DialogResult.OK + || !(fileToExclude = openFileDialog.FileName).StartsWith(Module.WorkingDir)) + { + return null; + } + + checkBoxExcludePathFilter.Checked = true; + textBoxExcludePaths.Enabled = true; + + if (textBoxExcludePaths.Text.Length != 0) + { + textBoxExcludePaths.Text += Environment.NewLine; + } + + string userPath = string.Join(Environment.NewLine, fileToExclude); + return userPath; } } } diff --git a/GitUI/Translation/English.xlf b/GitUI/Translation/English.xlf index 7600e9b9bbf..6f4326f272e 100644 --- a/GitUI/Translation/English.xlf +++ b/GitUI/Translation/English.xlf @@ -3240,7 +3240,11 @@ revision: Clean working directory - + + Add a path... + + + Add a path... @@ -3280,8 +3284,12 @@ revision: Cleanup - - Affect the following path(s) only: + + Exclude the following file path(s): + + + + Affect the following directory path(s) only: @@ -3292,7 +3300,11 @@ revision: Log: - + + (one path per line) + + + (one path per line) diff --git a/UnitTests/GitCommands.Tests/Git/Commands/GitCommandHelpersTest.cs b/UnitTests/GitCommands.Tests/Git/Commands/GitCommandHelpersTest.cs index b6780069ef8..564cfda4c4c 100644 --- a/UnitTests/GitCommands.Tests/Git/Commands/GitCommandHelpersTest.cs +++ b/UnitTests/GitCommands.Tests/Git/Commands/GitCommandHelpersTest.cs @@ -499,15 +499,20 @@ public void RebaseCmd() () => GitCommandHelpers.RebaseCmd("branch", false, false, false, false, false, false, from: "from", onto: null)); } - [TestCase(CleanMode.OnlyNonIgnored, true, false, null, "clean --dry-run")] - [TestCase(CleanMode.OnlyNonIgnored, false, false, null, "clean -f")] - [TestCase(CleanMode.OnlyNonIgnored, false, true, null, "clean -d -f")] - [TestCase(CleanMode.OnlyNonIgnored, false, false, "paths", "clean -f paths")] - [TestCase(CleanMode.OnlyIgnored, false, false, null, "clean -X -f")] - [TestCase(CleanMode.All, false, false, null, "clean -x -f")] - public void CleanCmd(CleanMode mode, bool dryRun, bool directories, string paths, string expected) - { - Assert.AreEqual(expected, GitCommandHelpers.CleanCmd(mode, dryRun, directories, paths).Arguments); + [TestCase(CleanMode.OnlyNonIgnored, true, false, null, null, "clean --dry-run")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, null, null, "clean -f")] + [TestCase(CleanMode.OnlyNonIgnored, false, true, null, null, "clean -d -f")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, "\"path1\"", null, "clean -f \"path1\"")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, "\"path1\"", "--exclude=excludes", "clean -f \"path1\" --exclude=excludes")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, null, "excludes", "clean -f excludes")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, "\"path1\" \"path2\"", null, "clean -f \"path1\" \"path2\"")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, "\"path1\" \"path2\"", "--exclude=exclude1 --exclude=exclude2", "clean -f \"path1\" \"path2\" --exclude=exclude1 --exclude=exclude2")] + [TestCase(CleanMode.OnlyNonIgnored, false, false, null, "--exclude=exclude1 --exclude=exclude2", "clean -f --exclude=exclude1 --exclude=exclude2")] + [TestCase(CleanMode.OnlyIgnored, false, false, null, null, "clean -X -f")] + [TestCase(CleanMode.All, false, false, null, null, "clean -x -f")] + public void CleanCmd(CleanMode mode, bool dryRun, bool directories, string paths, string excludes, string expected) + { + Assert.AreEqual(expected, GitCommandHelpers.CleanCmd(mode, dryRun, directories, paths, excludes).Arguments); } [TestCase(CleanMode.OnlyNonIgnored, true, false, null, "clean --dry-run")] diff --git a/contributors.txt b/contributors.txt index 4aa7c5ef0df..8814cdfece5 100644 --- a/contributors.txt +++ b/contributors.txt @@ -196,4 +196,5 @@ YYYY/MM/DD, github id, Full name, email 2023/05/31, SimonCropp, Simon Cropp, simon.cropp@gmail.com 2023/06/09, beiifeng, YiFei Wang, beiifeng@hotmail.com 2023/07/05, NatRavenhill, Nat Ravenhill, natalie.ravenhill(at)gmail.com +2023/07/13, Scott Sumrall, ssumrall, snsumrall(at)gmail.com 2023/08/01, IlijaQ, Ilija Kujovic, ilijaqnet{at]gmail.com From b475a3fe8a8dceb48ac51290604550bc5ec3616d Mon Sep 17 00:00:00 2001 From: Gerhard Olsson Date: Sat, 12 Aug 2023 23:33:21 +0200 Subject: [PATCH 2/5] fixup! mstv review comment --- GitUI/CommandsDialogs/FormCleanupRepository.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.cs b/GitUI/CommandsDialogs/FormCleanupRepository.cs index f7dc8da46b2..733946a47e2 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.cs @@ -133,8 +133,7 @@ private CleanMode GetCleanMode() // 1. get all lines from text box which are not empty // 2. Prepend lines with '--exclude=' // 3. Replace whitespace with '?' and convert to POSIX path - // 3. join together with space as separator - + // 4. join together with space as separator return string.Join(" ", textBoxExcludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => string.Format("--exclude={0}", p.Replace(" ", "?")).ToPosixPath())); } From 5379a4ee12f75748a21987857fada75de5427125 Mon Sep 17 00:00:00 2001 From: Gerhard Olsson Date: Sat, 12 Aug 2023 23:39:51 +0200 Subject: [PATCH 3/5] fixup! bad merge --- GitUI/CommandsDialogs/FormCleanupRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.cs b/GitUI/CommandsDialogs/FormCleanupRepository.cs index 733946a47e2..d020fe2ea42 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.cs @@ -54,7 +54,7 @@ private void Preview_Click(object sender, EventArgs e) string includePathArgument = GetInclusivePathArgumentFromGui(); string excludePathArguments = GetExclusivePathArgumentFromGui(); CleanMode mode = GetCleanMode(); - var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: false, directories: RemoveDirectories.Checked, + var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: true, directories: RemoveDirectories.Checked, paths: includePathArgument, excludes: excludePathArguments); string cmdOutput = FormProcess.ReadDialog(this, arguments: cleanUpCmd, Module.WorkingDir, input: null, useDialogSettings: true); From 5bfe577d660ca79e69c982ff2b7148efb1472446 Mon Sep 17 00:00:00 2001 From: Gerhard Olsson Date: Sat, 12 Aug 2023 23:34:42 +0200 Subject: [PATCH 4/5] fixup! review comment to to use string interpolating --- GitUI/CommandsDialogs/FormCleanupRepository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.cs b/GitUI/CommandsDialogs/FormCleanupRepository.cs index d020fe2ea42..cdc08164eaf 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.cs @@ -120,7 +120,7 @@ private CleanMode GetCleanMode() // 1. get all lines from text box which are not empty // 2. wrap lines with "" // 3. join together with space as separator - return string.Join(" ", textBoxIncludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => string.Format("\"{0}\"", p))); + return string.Join(" ", textBoxIncludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => $"\"{p}\"")); } private string? GetExclusivePathArgumentFromGui() @@ -134,7 +134,7 @@ private CleanMode GetCleanMode() // 2. Prepend lines with '--exclude=' // 3. Replace whitespace with '?' and convert to POSIX path // 4. join together with space as separator - return string.Join(" ", textBoxExcludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => string.Format("--exclude={0}", p.Replace(" ", "?")).ToPosixPath())); + return string.Join(" ", textBoxExcludePaths.Lines.Where(p => !string.IsNullOrEmpty(p)).Select(p => $"--exclude={p.Replace(" ", "?")}".ToPosixPath())); } private void Close_Click(object sender, EventArgs e) From faa935e41b266aef56c6dc6ef6737cec49e45713 Mon Sep 17 00:00:00 2001 From: Gerhard Olsson Date: Sat, 12 Aug 2023 23:12:43 +0200 Subject: [PATCH 5/5] fixup! Use common code for cleanup --- .../CommandsDialogs/FormCleanupRepository.cs | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/GitUI/CommandsDialogs/FormCleanupRepository.cs b/GitUI/CommandsDialogs/FormCleanupRepository.cs index cdc08164eaf..749d0186dd7 100644 --- a/GitUI/CommandsDialogs/FormCleanupRepository.cs +++ b/GitUI/CommandsDialogs/FormCleanupRepository.cs @@ -1,6 +1,7 @@ using GitCommands; using GitCommands.Git.Commands; using GitCommands.Utils; +using GitExtUtils; using GitUI.HelperDialogs; using ResourceManager; @@ -49,12 +50,12 @@ public void SetPathArgument(string? path) } } - private void Preview_Click(object sender, EventArgs e) + private void CleanUp(bool dryRun) { string includePathArgument = GetInclusivePathArgumentFromGui(); string excludePathArguments = GetExclusivePathArgumentFromGui(); CleanMode mode = GetCleanMode(); - var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: true, directories: RemoveDirectories.Checked, + ArgumentString cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun, directories: RemoveDirectories.Checked, paths: includePathArgument, excludes: excludePathArguments); string cmdOutput = FormProcess.ReadDialog(this, arguments: cleanUpCmd, Module.WorkingDir, input: null, useDialogSettings: true); @@ -62,31 +63,22 @@ private void Preview_Click(object sender, EventArgs e) if (CleanSubmodules.Checked) { - var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: true, directories: RemoveDirectories.Checked, paths: includePathArgument); + ArgumentString cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun, directories: RemoveDirectories.Checked, paths: includePathArgument); cmdOutput = FormProcess.ReadDialog(this, arguments: cleanSubmodulesCmd, Module.WorkingDir, input: null, useDialogSettings: true); PreviewOutput.Text += EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); } } + private void Preview_Click(object sender, EventArgs e) + { + CleanUp(dryRun: true); + } + private void Cleanup_Click(object sender, EventArgs e) { if (MessageBox.Show(this, _reallyCleanupQuestion.Text, _reallyCleanupQuestionCaption.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - string includePathArgument = GetInclusivePathArgumentFromGui(); - string excludePathArguments = GetExclusivePathArgumentFromGui(); - CleanMode mode = GetCleanMode(); - var cleanUpCmd = GitCommandHelpers.CleanCmd(mode, dryRun: false, directories: RemoveDirectories.Checked, - paths: includePathArgument, excludes: excludePathArguments); - - string cmdOutput = FormProcess.ReadDialog(this, arguments: cleanUpCmd, Module.WorkingDir, input: null, useDialogSettings: true); - PreviewOutput.Text = EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); - - if (CleanSubmodules.Checked) - { - var cleanSubmodulesCmd = GitCommandHelpers.CleanSubmodules(mode, dryRun: false, directories: RemoveDirectories.Checked, paths: includePathArgument); - cmdOutput = FormProcess.ReadDialog(this, arguments: cleanSubmodulesCmd, Module.WorkingDir, input: null, useDialogSettings: true); - PreviewOutput.Text += EnvUtils.ReplaceLinuxNewLinesDependingOnPlatform(cmdOutput); - } + CleanUp(dryRun: false); } }