// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
namespace EpicGames.Perforce
{
///
/// Represents a change view from a clientspec or stream
///
public class PerforceChangeView
{
///
/// List of entries for this change view
///
public List Entries { get; } = new List();
///
/// Determines if a file revision is visible
///
/// Path to the depot file
/// Change number of the file
public bool IsVisible(string depotFile, int change)
{
bool visible = true;
foreach (PerforceChangeViewEntry entry in Entries)
{
if (entry.Matches(depotFile))
{
visible = change <= entry.Change;
}
}
return visible;
}
///
/// Parse a change view from a specification
///
/// Lines for the change view
/// Whether this will be evaluated in the context of a case-insensitive server
public static PerforceChangeView Parse(IEnumerable lines, bool ignoreCase)
{
PerforceChangeView changeView = new PerforceChangeView();
foreach (string line in lines)
{
if (!String.IsNullOrWhiteSpace(line))
{
// Skip over lines with unsupported formatting (generally @label instead of @changenumber)
try
{
changeView.Entries.Add(new PerforceChangeViewEntry(line, ignoreCase));
}
catch (FormatException)
{
// don't do anything
}
}
}
return changeView;
}
}
///
/// Entry for a change view
///
public class PerforceChangeViewEntry
{
///
/// Pattern to match
///
public string Path { get; }
///
/// Change to be imported at
///
public long Change { get; }
readonly Regex _pathRegex;
///
/// Constructor
///
public PerforceChangeViewEntry(string pattern, bool ignoreCase)
{
int atIdx = pattern.LastIndexOf('@');
Path = pattern.Substring(0, atIdx);
Change = Int64.Parse(pattern.AsSpan(atIdx + 1), NumberStyles.None);
string regexPattern = Regex.Escape(Path);
regexPattern = regexPattern.Replace(@"\?", ".", StringComparison.Ordinal);
regexPattern = regexPattern.Replace(@"\.\.\.", ".*", StringComparison.Ordinal);
_pathRegex = new Regex($"^{regexPattern}$", ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
}
///
/// Determine
///
///
///
public bool Matches(string depotPath) => _pathRegex.IsMatch(depotPath);
}
}