Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix *.* wildcard glob matching regression #6531

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions ref/Microsoft.Build/net/Microsoft.Build.cs
Expand Up @@ -1574,8 +1574,8 @@ public partial class GraphBuildOptions : System.IEquatable<Microsoft.Build.Graph
public virtual bool Equals(Microsoft.Build.Graph.GraphBuildOptions other) { throw null; }
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; }
public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; }
public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions left, Microsoft.Build.Graph.GraphBuildOptions right) { throw null; }
public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions left, Microsoft.Build.Graph.GraphBuildOptions right) { throw null; }
protected virtual bool PrintMembers(System.Text.StringBuilder builder) { throw null; }
public override string ToString() { throw null; }
public virtual Microsoft.Build.Graph.GraphBuildOptions <Clone>$() { throw null; }
Expand Down
4 changes: 2 additions & 2 deletions ref/Microsoft.Build/netstandard/Microsoft.Build.cs
Expand Up @@ -1568,8 +1568,8 @@ public partial class GraphBuildOptions : System.IEquatable<Microsoft.Build.Graph
public virtual bool Equals(Microsoft.Build.Graph.GraphBuildOptions other) { throw null; }
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; }
public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; }
public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions left, Microsoft.Build.Graph.GraphBuildOptions right) { throw null; }
public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions left, Microsoft.Build.Graph.GraphBuildOptions right) { throw null; }
protected virtual bool PrintMembers(System.Text.StringBuilder builder) { throw null; }
public override string ToString() { throw null; }
public virtual Microsoft.Build.Graph.GraphBuildOptions <Clone>$() { throw null; }
Expand Down
21 changes: 18 additions & 3 deletions src/Shared/FileMatcher.cs
Expand Up @@ -131,7 +131,7 @@ internal FileMatcher(IFileSystem fileSystem, GetFileSystemEntries getFileSystemE
"*",
directory,
false));
IEnumerable<string> filteredEntriesForPath = (pattern != null && pattern != "*" && pattern != "*.*")
IEnumerable<string> filteredEntriesForPath = (pattern != null && !IsAllFilesWildcard(pattern))
? allEntriesForPath.Where(o => IsMatch(Path.GetFileName(o), pattern))
: allEntriesForPath;
return stripProjectDirectory
Expand Down Expand Up @@ -886,7 +886,7 @@ struct RecursionState
// The wildcard path portion of the excluded search matches the include search
searchToExclude.RemainingWildcardDirectory == recursionState.RemainingWildcardDirectory &&
// The exclude search will match ALL filenames OR
(searchToExclude.SearchData.Filespec == "*" || searchToExclude.SearchData.Filespec == "*.*" ||
(IsAllFilesWildcard(searchToExclude.SearchData.Filespec) ||
// The exclude search filename pattern matches the include search's pattern
searchToExclude.SearchData.Filespec == recursionState.SearchData.Filespec))
{
Expand Down Expand Up @@ -1091,7 +1091,11 @@ struct RecursionState

private static bool MatchFileRecursionStep(RecursionState recursionState, string file)
{
if (recursionState.SearchData.Filespec != null)
if (IsAllFilesWildcard(recursionState.SearchData.Filespec))
{
return true;
}
else if (recursionState.SearchData.Filespec != null)
{
return IsMatch(Path.GetFileName(file), recursionState.SearchData.Filespec);
}
Expand Down Expand Up @@ -2564,6 +2568,17 @@ private static bool DirectoryEndsWithPattern(string directoryPath, string patter
return (index != -1 && IsMatch(directoryPath.Substring(index + 1), pattern));
}

/// <summary>
/// Returns true if <paramref name="pattern"/> is <code>*</code> or <code>*.*</code>.
/// </summary>
/// <param name="pattern">The filename pattern to check.</param>
private static bool IsAllFilesWildcard(string pattern) => pattern?.Length switch
{
1 => pattern[0] == '*',
3 => pattern[0] == '*' && pattern[1] == '.' && pattern[2] == '*',
_ => false
};

internal static bool IsRecursiveDirectoryMatch(string path) => path.TrimTrailingSlashes() == recursiveDirectoryMatch;
}
}
28 changes: 27 additions & 1 deletion src/Shared/UnitTests/FileMatcher_Tests.cs
Expand Up @@ -154,6 +154,7 @@ public class GetFilesComplexGlobbingMatchingInfo
@"src\bar.cs",
@"src\baz.cs",
@"src\foo\foo.cs",
@"src\foo\licence",
@"src\bar\bar.cs",
@"src\baz\baz.cs",
@"src\foo\inner\foo.cs",
Expand Down Expand Up @@ -368,7 +369,8 @@ public static IEnumerable<object[]> GetTestData()
ExpectedMatches = new[]
{
@"readme.txt",
@"licence"
@"licence",
@"src\foo\licence",
}
}
};
Expand Down Expand Up @@ -422,6 +424,30 @@ public static IEnumerable<object[]> GetTestData()
}
};

// Regression test for https://github.com/Microsoft/msbuild/issues/6502
yield return new object[]
{
new GetFilesComplexGlobbingMatchingInfo
{
Include = @"src\**",
Excludes = new[]
{
@"**\foo\**",
},
ExpectedMatches = new[]
{
@"src\foo.cs",
@"src\bar.cs",
@"src\baz.cs",
@"src\bar\bar.cs",
@"src\baz\baz.cs",
@"src\bar\inner\baz.cs",
@"src\bar\inner\baz\baz.cs",
},
ExpectNoMatches = NativeMethodsShared.IsLinux,
}
};

// Hits the early elimination of exclude file patterns that do not intersect with the include.
// The exclude is redundant and can be eliminated before starting the file system walk.
yield return new object[]
Expand Down