Skip to content
This repository has been archived by the owner on Nov 6, 2018. It is now read-only.

Commit

Permalink
teach Matcher to return Stems for matches
Browse files Browse the repository at this point in the history
  • Loading branch information
analogrelay committed Aug 27, 2015
1 parent 5357973 commit 044a23a
Show file tree
Hide file tree
Showing 26 changed files with 275 additions and 44 deletions.
37 changes: 37 additions & 0 deletions src/Microsoft.Framework.FileSystemGlobbing/FilePatternMatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using Microsoft.Framework.Internal;

namespace Microsoft.Framework.FileSystemGlobbing
{
public class FilePatternMatch : IEquatable<FilePatternMatch>
{
public string Path { get; }
public string Stem { get; }

public FilePatternMatch(string path, string stem)
{
Path = path;
Stem = stem;
}

public bool Equals(FilePatternMatch other)
{
return other != null &&
string.Equals(other.Path, Path, StringComparison.OrdinalIgnoreCase) &&
string.Equals(other.Stem, Stem, StringComparison.OrdinalIgnoreCase);
}

public override bool Equals(object obj)
{
return Equals(obj as FilePatternMatch);
}

public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Path)
.Add(Stem)
.CombinedHash;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Microsoft.Framework.FileSystemGlobbing.Internal
{
public interface IPathSegment
{
bool ProducesStem { get; }

bool Match(string value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface IPatternContext

bool Test(DirectoryInfoBase directory);

bool Test(FileInfoBase file);
PatternTestResult Test(FileInfoBase file);

void PushDirectory(DirectoryInfoBase directory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class MatcherContext
private readonly DirectoryInfoBase _root;
private readonly IList<IPatternContext> _includePatternContexts;
private readonly IList<IPatternContext> _excludePatternContexts;
private readonly IList<string> _files;
private readonly IList<FilePatternMatch> _files;

private readonly HashSet<string> _declaredLiteralFolderSegmentInString;
private readonly HashSet<LiteralPathSegment> _declaredLiteralFolderSegments = new HashSet<LiteralPathSegment>();
Expand All @@ -32,7 +32,7 @@ public MatcherContext(IEnumerable<IPattern> includePatterns,
StringComparison comparison)
{
_root = directoryInfo;
_files = new List<string>();
_files = new List<FilePatternMatch>();
_comparisonType = comparison;

_includePatternContexts = includePatterns.Select(pattern => pattern.CreatePatternContextForInclude()).ToList();
Expand Down Expand Up @@ -85,9 +85,12 @@ private void Match(DirectoryInfoBase directory, string parentRelativePath)
var fileInfo = entity as FileInfoBase;
if (fileInfo != null)
{
if (MatchPatternContexts(fileInfo, (pattern, file) => pattern.Test(file)))
var result = MatchPatternContexts(fileInfo, (pattern, file) => pattern.Test(file));
if (result.IsSuccessful)
{
_files.Add(CombinePath(parentRelativePath, fileInfo.Name));
_files.Add(new FilePatternMatch(
path: CombinePath(parentRelativePath, fileInfo.Name),
stem: result.Stem));
}

continue;
Expand Down Expand Up @@ -155,7 +158,7 @@ private void DeclareInclude(IPathSegment patternSegment, bool isLastSegment)
}
}

private string CombinePath(string left, string right)
internal static string CombinePath(string left, string right)
{
if (string.IsNullOrEmpty(left))
{
Expand All @@ -167,36 +170,43 @@ private string CombinePath(string left, string right)
}
}

// Used to adapt Test(DirectoryInfoBase) for the below overload
private bool MatchPatternContexts<TFileInfoBase>(TFileInfoBase fileinfo, Func<IPatternContext, TFileInfoBase, bool> test)
{
var found = false;
return MatchPatternContexts(fileinfo, (ctx, file) => test(ctx, file) ? PatternTestResult.Success(stem: string.Empty) : PatternTestResult.Failed).IsSuccessful;
}

private PatternTestResult MatchPatternContexts<TFileInfoBase>(TFileInfoBase fileinfo, Func<IPatternContext, TFileInfoBase, PatternTestResult> test)
{
var result = PatternTestResult.Failed;

// If the given file/directory matches any including pattern, continues to next step.
foreach (var context in _includePatternContexts)
{
if (test(context, fileinfo))
var localResult = test(context, fileinfo);
if (localResult.IsSuccessful)
{
found = true;
result = localResult;
break;
}
}

// If the given file/directory doesn't match any of the including pattern, returns false.
if (!found)
if (!result.IsSuccessful)
{
return false;
return PatternTestResult.Failed;
}

// If the given file/directory matches any excluding pattern, returns false.
foreach (var context in _excludePatternContexts)
{
if (test(context, fileinfo))
if (test(context, fileinfo).IsSuccessful)
{
return false;
return PatternTestResult.Failed;
}
}

return true;
return result;
}

private void PopDirectory()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;

namespace Microsoft.Framework.FileSystemGlobbing.Internal.PathSegments
{
public class CurrentPathSegment : IPathSegment
{
public bool ProducesStem { get { return false; } }

public bool Match(string value)
{
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class LiteralPathSegment : IPathSegment
{
private readonly StringComparison _comparisonType;

public bool ProducesStem { get { return false; } }

public LiteralPathSegment(string value, StringComparison comparisonType)
{
if (value == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class ParentPathSegment : IPathSegment
{
private static readonly string LiteralParent = "..";

public bool ProducesStem { get { return false; } }

public bool Match(string value)
{
return string.Equals(LiteralParent, value, StringComparison.Ordinal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Microsoft.Framework.FileSystemGlobbing.Internal.PathSegments
{
public class RecursiveWildcardSegment : IPathSegment
{
public bool ProducesStem { get { return true; } }

public bool Match(string value)
{
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public WildcardPathSegment(string beginsWith, List<string> contains, string ends
_comparisonType = comparisonType;
}

public bool ProducesStem { get { return true; } }

public string BeginsWith { get; }

public List<string> Contains { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public abstract class PatternContext<TFrame> : IPatternContext

public virtual void Declare(Action<IPathSegment, bool> declare) { }

public abstract bool Test(FileInfoBase file);
public abstract PatternTestResult Test(FileInfoBase file);

public abstract bool Test(DirectoryInfoBase directory);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.IO;
using Microsoft.Framework.FileSystemGlobbing.Abstractions;

namespace Microsoft.Framework.FileSystemGlobbing.Internal.PatternContexts
Expand Down Expand Up @@ -30,6 +31,14 @@ public override void PushDirectory(DirectoryInfoBase directory)
}
else
{
// Determine this frame's contribution to the stem (if any)
var segment = Pattern.Segments[Frame.SegmentIndex];
if (Frame.InStem || segment.ProducesStem)
{
Frame.InStem = true;
Frame.Stem = MatcherContext.CombinePath(Frame.Stem, directory.Name);
}

// directory matches segment, advance position in pattern
frame.SegmentIndex = frame.SegmentIndex + 1;
}
Expand All @@ -41,6 +50,8 @@ public struct FrameData
{
public bool IsNotApplicable;
public int SegmentIndex;
public bool InStem;
public string Stem;
}

protected ILinearPattern Pattern { get; }
Expand All @@ -59,5 +70,10 @@ protected bool TestMatchingSegment(string value)

return Pattern.Segments[Frame.SegmentIndex].Match(value);
}

protected string CalculateStem(FileInfoBase matchedFile)
{
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ public PatternContextLinearExclude(ILinearPattern pattern)
{
}

public override bool Test(FileInfoBase file)
public override PatternTestResult Test(FileInfoBase file)
{
if (IsStackEmpty())
{
throw new InvalidOperationException("Can't test file before enters any directory.");
}

if (Frame.IsNotApplicable)
if(!Frame.IsNotApplicable && IsLastSegment() && TestMatchingSegment(file.Name))
{
return false;
return PatternTestResult.Success(stem: string.Empty);
}

return IsLastSegment() && TestMatchingSegment(file.Name);
return PatternTestResult.Failed;
}

public override bool Test(DirectoryInfoBase directory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ public override void Declare(Action<IPathSegment, bool> onDeclare)
}
}

public override bool Test(FileInfoBase file)
public override PatternTestResult Test(FileInfoBase file)
{
if (IsStackEmpty())
{
throw new InvalidOperationException("Can't test file before enters any directory.");
}

if (Frame.IsNotApplicable)
if(!Frame.IsNotApplicable && IsLastSegment() && TestMatchingSegment(file.Name))
{
return false;
return PatternTestResult.Success(CalculateStem(file));
}

return IsLastSegment() && TestMatchingSegment(file.Name);
return PatternTestResult.Failed;
}

public override bool Test(DirectoryInfoBase directory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public sealed override void PushDirectory(DirectoryInfoBase directory)
frame.BacktrackAvailable += 1;
}

if(frame.InStem)
{
frame.Stem = MatcherContext.CombinePath(frame.Stem, directory.Name);
}

while (
frame.SegmentIndex == frame.SegmentGroup.Count &&
frame.SegmentGroupIndex != Pattern.Contains.Count)
Expand All @@ -72,6 +77,9 @@ public sealed override void PushDirectory(DirectoryInfoBase directory)
{
frame.SegmentGroup = Pattern.EndsWith;
}

// We now care about the stem
frame.InStem = true;
}

PushDataFrame(frame);
Expand All @@ -88,6 +96,10 @@ public struct FrameData
public int BacktrackAvailable;

public int SegmentIndex;

public bool InStem;

public string Stem;
}

protected IRaggedPattern Pattern { get; }
Expand Down Expand Up @@ -132,5 +144,10 @@ protected bool TestMatchingGroup(FileSystemInfoBase value)
}
return true;
}

protected string CalculateStem(FileInfoBase matchedFile)
{
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ public PatternContextRaggedExclude(IRaggedPattern pattern)
{
}

public override bool Test(FileInfoBase file)
public override PatternTestResult Test(FileInfoBase file)
{
if (IsStackEmpty())
{
throw new InvalidOperationException("Can't test file before enters any directory.");
}

if (Frame.IsNotApplicable)
if(!Frame.IsNotApplicable && IsEndingGroup() && TestMatchingGroup(file))
{
return false;
return PatternTestResult.Success(CalculateStem(file));
}

return IsEndingGroup() && TestMatchingGroup(file);
return PatternTestResult.Failed;
}

public override bool Test(DirectoryInfoBase directory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,18 @@ public override void Declare(Action<IPathSegment, bool> onDeclare)
}
}

public override bool Test(FileInfoBase file)
public override PatternTestResult Test(FileInfoBase file)
{
if (IsStackEmpty())
{
throw new InvalidOperationException("Can't test file before enters any directory.");
}

if (Frame.IsNotApplicable)
if(!Frame.IsNotApplicable && IsEndingGroup() && TestMatchingGroup(file))
{
return false;
return PatternTestResult.Success(CalculateStem(file));
}

return IsEndingGroup() && TestMatchingGroup(file);
return PatternTestResult.Failed;
}

public override bool Test(DirectoryInfoBase directory)
Expand Down
Loading

0 comments on commit 044a23a

Please sign in to comment.