2020-12-21 11:50:46 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Text ;
using System.Text.RegularExpressions ;
2022-10-03 17:01:13 -04:00
#pragma warning disable CA1045 // Do not pass types by reference
2020-12-21 23:07:37 -04:00
namespace EpicGames.Core
2020-12-21 11:50:46 -04:00
{
2022-06-22 13:23:01 -04:00
/// <summary>
/// Invalid file pattern exception
/// </summary>
2020-12-21 11:50:46 -04:00
public class FilePatternException : Exception
{
2022-06-22 13:23:01 -04:00
/// <summary>
/// Constructor
/// </summary>
2022-03-24 16:35:00 -04:00
public FilePatternException ( string message )
: base ( message )
2020-12-21 11:50:46 -04:00
{
}
2022-06-22 13:23:01 -04:00
/// <inheritdoc/>
2020-12-21 11:50:46 -04:00
public override string ToString ( )
{
return Message ;
}
2024-02-14 23:39:59 -05:00
}
/// <summary>
/// Exception thrown to indicate that a source file is not under the given base directory
/// </summary>
public class FilePatternSourceFileNotUnderBaseDirException : FilePatternException
{
/// <summary>
/// Constructor
/// </summary>
public FilePatternSourceFileNotUnderBaseDirException ( string message )
: base ( message )
2024-02-14 20:30:30 -05:00
{
2024-02-14 23:39:59 -05:00
}
}
/// <summary>
/// Exception thrown to indicate that a source file is missing
/// </summary>
public class FilePatternSourceFileMissingException : FilePatternException
{
/// <summary>
/// Constructor
/// </summary>
public FilePatternSourceFileMissingException ( string message )
: base ( message )
{
}
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Encapsulates a pattern containing the '?', '*', and '...' wildcards.
/// </summary>
public class FilePattern
{
/// <summary>
/// Base directory for all matched files
/// </summary>
2022-10-03 17:01:13 -04:00
public DirectoryReference BaseDirectory { get ; }
2020-12-21 11:50:46 -04:00
/// <summary>
/// List of tokens in the pattern. Every second token is a wildcard, other tokens are string fragments. Always has an odd number of elements. Path separators are normalized to the host platform format.
/// </summary>
2022-10-03 17:01:13 -04:00
public IReadOnlyList < string > Tokens { get ; }
2020-12-21 11:50:46 -04:00
/// <summary>
/// Constructs a file pattern which matches a single file
/// </summary>
2022-03-24 16:35:00 -04:00
/// <param name="file">Location of the file</param>
public FilePattern ( FileReference file )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
BaseDirectory = file . Directory ;
2022-10-03 17:01:13 -04:00
Tokens = new [ ] { file . GetFileName ( ) } ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Constructs a file pattern from the given string, resolving relative paths to the given directory.
/// </summary>
2022-03-24 16:35:00 -04:00
/// <param name="rootDirectory">If a relative path is specified by the pattern, the root directory used to turn it into an absolute path</param>
/// <param name="pattern">The pattern to match. If the pattern ends with a directory separator, an implicit '...' is appended.</param>
public FilePattern ( DirectoryReference rootDirectory , string pattern )
2020-12-21 11:50:46 -04:00
{
// Normalize the path separators
2022-03-24 16:35:00 -04:00
StringBuilder text = new StringBuilder ( pattern ) ;
2020-12-21 11:50:46 -04:00
if ( Path . DirectorySeparatorChar ! = '\\' )
{
2022-03-24 16:35:00 -04:00
text . Replace ( '\\' , Path . DirectorySeparatorChar ) ;
2020-12-21 11:50:46 -04:00
}
if ( Path . DirectorySeparatorChar ! = '/' )
{
2022-03-24 16:35:00 -04:00
text . Replace ( '/' , Path . DirectorySeparatorChar ) ;
2020-12-21 11:50:46 -04:00
}
// Find the base directory, stopping when we hit a wildcard. The source directory must end with a path specification.
2022-03-24 16:35:00 -04:00
int baseDirectoryLen = 0 ;
for ( int idx = 0 ; idx < text . Length ; idx + + )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( text [ idx ] = = Path . DirectorySeparatorChar )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
baseDirectoryLen = idx + 1 ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
else if ( text [ idx ] = = '?' | | text [ idx ] = = '*' | | ( idx + 2 < text . Length & & text [ idx ] = = '.' & & text [ idx + 1 ] = = '.' & & text [ idx + 2 ] = = '.' ) )
2020-12-21 11:50:46 -04:00
{
break ;
}
}
// Extract the base directory
2022-03-24 16:35:00 -04:00
BaseDirectory = DirectoryReference . Combine ( rootDirectory , text . ToString ( 0 , baseDirectoryLen ) ) ;
2020-12-21 11:50:46 -04:00
// Convert any directory wildcards ("...") into complete directory wildcards ("\\...\\"). We internally treat use "...\\" as the wildcard
// token so we can correctly match zero directories. Patterns such as "foo...bar" should require at least one directory separator, so
// should be converted to "foo*\\...\\*bar".
2022-03-24 16:35:00 -04:00
for ( int idx = baseDirectoryLen ; idx < text . Length ; idx + + )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( text [ idx ] = = '.' & & text [ idx + 1 ] = = '.' & & text [ idx + 2 ] = = '.' )
2020-12-21 11:50:46 -04:00
{
// Insert a directory separator before
2022-03-24 16:35:00 -04:00
if ( idx > baseDirectoryLen & & text [ idx - 1 ] ! = Path . DirectorySeparatorChar )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
text . Insert ( idx + + , '*' ) ;
text . Insert ( idx + + , Path . DirectorySeparatorChar ) ;
2020-12-21 11:50:46 -04:00
}
// Skip past the ellipsis
2022-03-24 16:35:00 -04:00
idx + = 3 ;
2020-12-21 11:50:46 -04:00
// Insert a directory separator after
2022-03-24 16:35:00 -04:00
if ( idx = = text . Length | | text [ idx ] ! = Path . DirectorySeparatorChar )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
text . Insert ( idx + + , Path . DirectorySeparatorChar ) ;
text . Insert ( idx + + , '*' ) ;
2020-12-21 11:50:46 -04:00
}
}
}
// Parse the tokens
2022-10-03 17:01:13 -04:00
List < string > tokens = new List < string > ( ) ;
2022-03-24 16:35:00 -04:00
int lastIdx = baseDirectoryLen ;
for ( int idx = baseDirectoryLen ; idx < text . Length ; idx + + )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( text [ idx ] = = '?' | | text [ idx ] = = '*' )
2020-12-21 11:50:46 -04:00
{
2022-10-03 17:01:13 -04:00
tokens . Add ( text . ToString ( lastIdx , idx - lastIdx ) ) ;
tokens . Add ( text . ToString ( idx , 1 ) ) ;
2022-03-24 16:35:00 -04:00
lastIdx = idx + 1 ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
else if ( idx - 3 > = baseDirectoryLen & & text [ idx ] = = Path . DirectorySeparatorChar & & text [ idx - 1 ] = = '.' & & text [ idx - 2 ] = = '.' & & text [ idx - 3 ] = = '.' )
2020-12-21 11:50:46 -04:00
{
2022-10-03 17:01:13 -04:00
tokens . Add ( text . ToString ( lastIdx , idx - 3 - lastIdx ) ) ;
tokens . Add ( text . ToString ( idx - 3 , 4 ) ) ;
2022-03-24 16:35:00 -04:00
lastIdx = idx + 1 ;
2020-12-21 11:50:46 -04:00
}
}
2022-10-03 17:01:13 -04:00
tokens . Add ( text . ToString ( lastIdx , text . Length - lastIdx ) ) ;
Tokens = tokens ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// A pattern without wildcards may match either a single file or directory based on context. This pattern resolves to the later as necessary, producing a new pattern.
/// </summary>
/// <returns>Pattern which matches a directory</returns>
public FilePattern AsDirectoryPattern ( )
{
if ( ContainsWildcards ( ) )
{
return this ;
}
else
{
2022-03-24 16:35:00 -04:00
StringBuilder pattern = new StringBuilder ( ) ;
foreach ( string token in Tokens )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
pattern . Append ( token ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
if ( pattern . Length > 0 )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
pattern . Append ( Path . DirectorySeparatorChar ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
pattern . Append ( "..." ) ;
2020-12-21 11:50:46 -04:00
2022-03-24 16:35:00 -04:00
return new FilePattern ( BaseDirectory , pattern . ToString ( ) ) ;
2020-12-21 11:50:46 -04:00
}
}
/// <summary>
/// For a pattern that does not contain wildcards, returns the single file location
/// </summary>
/// <returns>Location of the referenced file</returns>
public FileReference GetSingleFile ( )
{
if ( Tokens . Count = = 1 )
{
return FileReference . Combine ( BaseDirectory , Tokens [ 0 ] ) ;
}
else
{
throw new InvalidOperationException ( "File pattern does not reference a single file" ) ;
}
}
/// <summary>
/// Checks whether this pattern is explicitly a directory, ie. is terminated with a directory separator
/// </summary>
/// <returns>True if the pattern is a directory</returns>
public bool EndsWithDirectorySeparator ( )
{
2022-03-24 16:35:00 -04:00
string lastToken = Tokens [ ^ 1 ] ;
2023-08-14 09:27:38 -04:00
return lastToken . Length > 0 & & lastToken [ ^ 1 ] = = Path . DirectorySeparatorChar ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Determines whether the pattern contains wildcards
/// </summary>
/// <returns>True if the pattern contains wildcards, false otherwise.</returns>
public bool ContainsWildcards ( )
{
return Tokens . Count > 1 ;
}
/// <summary>
/// Tests whether a pattern is compatible with another pattern (that is, that the number and type of wildcards match)
/// </summary>
2022-03-24 16:35:00 -04:00
/// <param name="other">Pattern to compare against</param>
2020-12-21 11:50:46 -04:00
/// <returns>Whether the patterns are compatible.</returns>
2022-03-24 16:35:00 -04:00
public bool IsCompatibleWith ( FilePattern other )
2020-12-21 11:50:46 -04:00
{
// Check there are the same number of tokens in each pattern
2022-03-24 16:35:00 -04:00
if ( Tokens . Count ! = other . Tokens . Count )
2020-12-21 11:50:46 -04:00
{
return false ;
}
// Check all the wildcard tokens match
2022-03-24 16:35:00 -04:00
for ( int idx = 1 ; idx < Tokens . Count ; idx + = 2 )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( Tokens [ idx ] ! = other . Tokens [ idx ] )
2020-12-21 11:50:46 -04:00
{
return false ;
}
}
return true ;
}
/// <summary>
/// Converts this pattern to a C# regex format string, which matches paths relative to the base directory formatted with native directory separators
/// </summary>
/// <returns>The regex pattern</returns>
public string GetRegexPattern ( )
{
2022-03-24 16:35:00 -04:00
StringBuilder pattern = new StringBuilder ( "^" ) ;
pattern . Append ( Regex . Escape ( Tokens [ 0 ] ) ) ;
for ( int idx = 1 ; idx < Tokens . Count ; idx + = 2 )
2020-12-21 11:50:46 -04:00
{
// Append the wildcard expression
2022-03-24 16:35:00 -04:00
if ( Tokens [ idx ] = = "?" )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
pattern . Append ( "([^\\/])" ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
else if ( Tokens [ idx ] = = "*" )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
pattern . Append ( "([^\\/]*)" ) ;
2020-12-21 11:50:46 -04:00
}
else
{
2022-03-24 16:35:00 -04:00
pattern . AppendFormat ( "((?:.+{0})?)" , Regex . Escape ( Path . DirectorySeparatorChar . ToString ( ) ) ) ;
2020-12-21 11:50:46 -04:00
}
// Append the next sequence of characters to match
2022-03-24 16:35:00 -04:00
pattern . Append ( Regex . Escape ( Tokens [ idx + 1 ] ) ) ;
2020-12-21 11:50:46 -04:00
}
2022-10-03 17:01:13 -04:00
pattern . Append ( '$' ) ;
2022-03-24 16:35:00 -04:00
return pattern . ToString ( ) ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Creates a regex replacement pattern
/// </summary>
/// <returns>String representing the regex replacement pattern</returns>
public string GetRegexReplacementPattern ( )
{
2022-03-24 16:35:00 -04:00
StringBuilder pattern = new StringBuilder ( ) ;
for ( int idx = 0 ; ; idx + = 2 )
2020-12-21 11:50:46 -04:00
{
// Append the escaped replacement character
2022-10-03 17:01:13 -04:00
pattern . Append ( Tokens [ idx ] . Replace ( "$" , "$$" , StringComparison . Ordinal ) ) ;
2020-12-21 11:50:46 -04:00
// Check if we've reached the end of the string
2022-03-24 16:35:00 -04:00
if ( idx = = Tokens . Count - 1 )
2020-12-21 11:50:46 -04:00
{
break ;
}
// Insert the capture
2022-03-24 16:35:00 -04:00
pattern . AppendFormat ( "${0}" , ( idx / 2 ) + 1 ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
return pattern . ToString ( ) ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Creates a file mapping between a set of source patterns and a target pattern. All patterns should have a matching order and number of wildcards.
/// </summary>
2022-03-24 16:35:00 -04:00
/// <param name="files">Files to use for the mapping</param>
2022-06-22 13:23:01 -04:00
/// <param name="sourcePattern">List of source patterns</param>
2022-03-24 16:35:00 -04:00
/// <param name="targetPattern">Matching output pattern</param>
public static Dictionary < FileReference , FileReference > CreateMapping ( HashSet < FileReference > ? files , ref FilePattern sourcePattern , ref FilePattern targetPattern )
2020-12-21 11:50:46 -04:00
{
// If the source pattern ends in a directory separator, or a set of input files are specified and it doesn't contain wildcards, treat it as a full directory match
2022-03-24 16:35:00 -04:00
if ( sourcePattern . EndsWithDirectorySeparator ( ) )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
sourcePattern = new FilePattern ( sourcePattern . BaseDirectory , String . Join ( "" , sourcePattern . Tokens ) + "..." ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
else if ( files ! = null )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
sourcePattern = sourcePattern . AsDirectoryPattern ( ) ;
2020-12-21 11:50:46 -04:00
}
// If we have multiple potential source files, but no wildcards in the output pattern, assume it's a directory and append the pattern from the source.
2022-03-24 16:35:00 -04:00
if ( sourcePattern . ContainsWildcards ( ) & & ! targetPattern . ContainsWildcards ( ) )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
StringBuilder newPattern = new StringBuilder ( ) ;
foreach ( string token in targetPattern . Tokens )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
newPattern . Append ( token ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
if ( newPattern . Length > 0 & & newPattern [ ^ 1 ] ! = Path . DirectorySeparatorChar )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
newPattern . Append ( Path . DirectorySeparatorChar ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
foreach ( string token in sourcePattern . Tokens )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
newPattern . Append ( token ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
targetPattern = new FilePattern ( targetPattern . BaseDirectory , newPattern . ToString ( ) ) ;
2020-12-21 11:50:46 -04:00
}
// If the target pattern ends with a directory separator, treat it as a full directory match if it has wildcards, or a copy of the source pattern if not
2022-03-24 16:35:00 -04:00
if ( targetPattern . EndsWithDirectorySeparator ( ) )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
targetPattern = new FilePattern ( targetPattern . BaseDirectory , String . Join ( "" , targetPattern . Tokens ) + "..." ) ;
2020-12-21 11:50:46 -04:00
}
// Handle the case where source and target pattern are both individual files
2022-03-24 16:35:00 -04:00
Dictionary < FileReference , FileReference > targetFileToSourceFile = new Dictionary < FileReference , FileReference > ( ) ;
if ( sourcePattern . ContainsWildcards ( ) | | targetPattern . ContainsWildcards ( ) )
2020-12-21 11:50:46 -04:00
{
// Check the two patterns are compatible
2022-03-24 16:35:00 -04:00
if ( ! sourcePattern . IsCompatibleWith ( targetPattern ) )
2020-12-21 11:50:46 -04:00
{
2024-02-14 23:39:59 -05:00
throw new FilePatternException ( $"File patterns '{sourcePattern}' and '{targetPattern}' do not have matching wildcards" ) ;
2020-12-21 11:50:46 -04:00
}
// Create a filter to match the source files
2022-03-24 16:35:00 -04:00
FileFilter filter = new FileFilter ( FileFilterType . Exclude ) ;
filter . Include ( String . Join ( "" , sourcePattern . Tokens ) ) ;
2020-12-21 11:50:46 -04:00
// Apply it to the source directory
2022-03-24 16:35:00 -04:00
List < FileReference > sourceFiles ;
if ( files = = null )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
sourceFiles = filter . ApplyToDirectory ( sourcePattern . BaseDirectory , true ) ;
2020-12-21 11:50:46 -04:00
}
else
{
2022-03-24 16:35:00 -04:00
sourceFiles = CheckInputFiles ( files , sourcePattern . BaseDirectory ) ;
2020-12-21 11:50:46 -04:00
}
// Map them onto output files
2022-03-24 16:35:00 -04:00
FileReference [ ] targetFiles = new FileReference [ sourceFiles . Count ] ;
2020-12-21 11:50:46 -04:00
// Get the source and target regexes
2022-03-24 16:35:00 -04:00
string sourceRegex = sourcePattern . GetRegexPattern ( ) ;
string targetRegex = targetPattern . GetRegexReplacementPattern ( ) ;
for ( int idx = 0 ; idx < sourceFiles . Count ; idx + + )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
string sourceRelativePath = sourceFiles [ idx ] . MakeRelativeTo ( sourcePattern . BaseDirectory ) ;
string targetRelativePath = Regex . Replace ( sourceRelativePath , sourceRegex , targetRegex ) ;
targetFiles [ idx ] = FileReference . Combine ( targetPattern . BaseDirectory , targetRelativePath ) ;
2020-12-21 11:50:46 -04:00
}
// Add them to the output map
2022-03-24 16:35:00 -04:00
for ( int idx = 0 ; idx < targetFiles . Length ; idx + + )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
FileReference ? existingSourceFile ;
if ( targetFileToSourceFile . TryGetValue ( targetFiles [ idx ] , out existingSourceFile ) & & existingSourceFile ! = sourceFiles [ idx ] )
2020-12-21 11:50:46 -04:00
{
2024-02-14 23:39:59 -05:00
throw new FilePatternException ( $"Output file '{targetFiles[idx]}' is mapped from '{existingSourceFile}' and '{sourceFiles[idx]}'" ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
targetFileToSourceFile [ targetFiles [ idx ] ] = sourceFiles [ idx ] ;
2020-12-21 11:50:46 -04:00
}
}
else
{
// Just copy a single file
2022-03-24 16:35:00 -04:00
FileReference sourceFile = sourcePattern . GetSingleFile ( ) ;
if ( FileReference . Exists ( sourceFile ) )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
FileReference targetFile = targetPattern . GetSingleFile ( ) ;
targetFileToSourceFile [ targetFile ] = sourceFile ;
2020-12-21 11:50:46 -04:00
}
else
{
2024-02-14 23:39:59 -05:00
throw new FilePatternSourceFileMissingException ( $"Source file '{sourceFile}' does not exist" ) ;
2020-12-21 11:50:46 -04:00
}
}
// Check that no source file is also destination file
2022-03-24 16:35:00 -04:00
foreach ( FileReference sourceFile in targetFileToSourceFile . Values )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( targetFileToSourceFile . ContainsKey ( sourceFile ) )
2020-12-21 11:50:46 -04:00
{
2024-02-14 23:39:59 -05:00
throw new FilePatternException ( $"'{sourceFile}' is listed as a source and target file" ) ;
2020-12-21 11:50:46 -04:00
}
}
// Return the map
2022-03-24 16:35:00 -04:00
return targetFileToSourceFile ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Checks that the given input files all exist and are under the given base directory
/// </summary>
2022-03-24 16:35:00 -04:00
/// <param name="inputFiles">Input files to check</param>
/// <param name="baseDirectory">Base directory for files</param>
2020-12-21 11:50:46 -04:00
/// <returns>List of valid files</returns>
2022-03-24 16:35:00 -04:00
public static List < FileReference > CheckInputFiles ( IEnumerable < FileReference > inputFiles , DirectoryReference baseDirectory )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
List < FileReference > files = new List < FileReference > ( ) ;
foreach ( FileReference inputFile in inputFiles )
2020-12-21 11:50:46 -04:00
{
2022-03-24 16:35:00 -04:00
if ( ! inputFile . IsUnderDirectory ( baseDirectory ) )
2020-12-21 11:50:46 -04:00
{
2024-02-14 23:39:59 -05:00
throw new FilePatternSourceFileNotUnderBaseDirException ( $"Source file '{inputFile}' is not under '{baseDirectory}'" ) ;
2020-12-21 11:50:46 -04:00
}
2022-03-24 16:35:00 -04:00
else if ( ! FileReference . Exists ( inputFile ) )
2020-12-21 11:50:46 -04:00
{
2024-02-14 23:39:59 -05:00
throw new FilePatternSourceFileMissingException ( $"Source file '{inputFile}' does not exist" ) ;
2020-12-21 11:50:46 -04:00
}
else
{
2022-03-24 16:35:00 -04:00
files . Add ( inputFile ) ;
2020-12-21 11:50:46 -04:00
}
}
2022-03-24 16:35:00 -04:00
return files ;
2020-12-21 11:50:46 -04:00
}
/// <summary>
/// Formats the pattern as a string
/// </summary>
/// <returns>The original representation of this pattern</returns>
public override string ToString ( )
{
return BaseDirectory . ToString ( ) + Path . DirectorySeparatorChar + String . Join ( "" , Tokens ) ;
}
}
}