@@ -17,20 +17,29 @@ internal class PathHelper
1717
1818 private const string FileSystemProviderName = "FileSystem" ;
1919
20+ internal bool Flatten { get ; set ; }
21+
22+ internal string ? Filter { get ; set ; }
23+
24+ internal WildcardPattern ? _wildCardPattern ;
25+
2026 internal PathHelper ( PSCmdlet cmdlet )
2127 {
2228 _cmdlet = cmdlet ;
2329 }
2430
2531 internal List < ArchiveAddition > GetArchiveAdditions ( HashSet < string > fullyQualifiedPaths )
2632 {
33+ if ( Filter is not null ) {
34+ _wildCardPattern = new WildcardPattern ( Filter ) ;
35+ }
2736 List < ArchiveAddition > archiveAdditions = new List < ArchiveAddition > ( fullyQualifiedPaths . Count ) ;
2837 foreach ( var path in fullyQualifiedPaths )
2938 {
3039 // Assume each path is valid, fully qualified, and existing
3140 Debug . Assert ( Path . Exists ( path ) ) ;
3241 Debug . Assert ( Path . IsPathFullyQualified ( path ) ) ;
33- AddAdditionForFullyQualifiedPath ( path , archiveAdditions ) ;
42+ AddAdditionForFullyQualifiedPath ( path , archiveAdditions , entryName : null , parentMatchesFilter : false ) ;
3443 }
3544 return archiveAdditions ;
3645 }
@@ -41,7 +50,7 @@ internal List<ArchiveAddition> GetArchiveAdditions(HashSet<string> fullyQualifie
4150 /// <param name="path">The fully qualified path</param>
4251 /// <param name="additions">The list where to add the ArchiveAddition object for the path</param>
4352 /// <param name="shouldPreservePathStructure">If true, relative path structure will be preserved. If false, relative path structure will NOT be preserved.</param>
44- private void AddAdditionForFullyQualifiedPath ( string path , List < ArchiveAddition > additions )
53+ private void AddAdditionForFullyQualifiedPath ( string path , List < ArchiveAddition > additions , string ? entryName , bool parentMatchesFilter )
4554 {
4655 Debug . Assert ( Path . Exists ( path ) ) ;
4756 FileSystemInfo fileSystemInfo ;
@@ -61,15 +70,38 @@ private void AddAdditionForFullyQualifiedPath(string path, List<ArchiveAddition>
6170 fileSystemInfo = new FileInfo ( path ) ;
6271 }
6372
64- // Get the entry name of the file or directory in the archive
65- // The cmdlet will preserve the directory structure as long as the path is relative to the working directory
66- var entryName = GetEntryName ( fileSystemInfo , out bool doesPreservePathStructure ) ;
67- additions . Add ( new ArchiveAddition ( entryName : entryName , fileSystemInfo : fileSystemInfo ) ) ;
73+ bool doesMatchFilter = true ;
74+ if ( ! parentMatchesFilter && _wildCardPattern is not null ) {
75+ doesMatchFilter = _wildCardPattern . IsMatch ( fileSystemInfo . Name ) ;
76+ }
77+
78+ // if entryName, then set it as the entry name of the file or directory in the archive
79+ // The entry name will preserve the directory structure as long as the path is relative to the working directory
80+ if ( entryName is null ) {
81+ entryName = GetEntryName ( fileSystemInfo , out bool doesPreservePathStructure ) ;
82+ }
83+
84+
85+ // Number of elements in additions before adding this item and its descendents if it is a directory
86+ int initialAdditions = additions . Count ;
6887
6988 // Recurse through the child items and add them to additions
70- if ( fileSystemInfo . Attributes . HasFlag ( FileAttributes . Directory ) && fileSystemInfo is DirectoryInfo directoryInfo ) {
71- AddDescendentEntries ( directoryInfo : directoryInfo , additions : additions , shouldPreservePathStructure : doesPreservePathStructure ) ;
89+ if ( fileSystemInfo . Attributes . HasFlag ( FileAttributes . Directory ) && fileSystemInfo is DirectoryInfo directoryInfo )
90+ {
91+ AddDescendentEntries ( directoryInfo , additions , doesMatchFilter ) ;
7292 }
93+
94+ // Number of elements in additions after adding this item's descendents (if directory)
95+ int finalAdditions = additions . Count ;
96+
97+ // If the item being added is a file, finalAdditions - initialAdditions = 0
98+ // If the item being added is a directory and does not have any descendent files that match the filter, finalAdditions - initialAdditions = 0
99+ // If the item being added is a directory and has descendent files that match the filter, finalAdditions > initialAdditions
100+
101+ if ( doesMatchFilter || ( ! doesMatchFilter && finalAdditions - initialAdditions > 0 ) ) {
102+ additions . Add ( new ArchiveAddition ( entryName : entryName , fileSystemInfo : fileSystemInfo ) ) ;
103+ }
104+
73105 }
74106
75107 /// <summary>
@@ -78,28 +110,41 @@ private void AddAdditionForFullyQualifiedPath(string path, List<ArchiveAddition>
78110 /// <param name="path">A fully qualifed path referring to a directory</param>
79111 /// <param name="additions">Where the ArchiveAddtion object for each child item of the directory will be added</param>
80112 /// <param name="shouldPreservePathStructure">See above</param>
81- private void AddDescendentEntries ( System . IO . DirectoryInfo directoryInfo , List < ArchiveAddition > additions , bool shouldPreservePathStructure )
113+ private void AddDescendentEntries ( System . IO . DirectoryInfo directoryInfo , List < ArchiveAddition > additions , bool parentMatchesFilter )
82114 {
83115 try
84116 {
85117 // pathPrefix is used to construct the entry names of the descendents of the directory
86118 var pathPrefix = GetPrefixForPath ( directoryInfo : directoryInfo ) ;
87- foreach ( var childFileSystemInfo in directoryInfo . EnumerateFileSystemInfos ( "*" , SearchOption . AllDirectories ) )
119+ // If the parent directory matches the filter, then we don't have to check if each individual descendent of the directory
120+ // matches the filter.
121+ // This reduces the total number of method calls
122+ SearchOption searchOption = parentMatchesFilter ? SearchOption . AllDirectories : SearchOption . TopDirectoryOnly ;
123+ foreach ( var childFileSystemInfo in directoryInfo . EnumerateFileSystemInfos ( "*" , searchOption ) )
88124 {
89125 string entryName ;
90- // If the cmdlet should preserve the path structure, then use the relative path
91- if ( shouldPreservePathStructure )
126+ if ( Flatten )
92127 {
93- entryName = GetEntryName ( childFileSystemInfo , out bool doesPreservePathStructure ) ;
94- Debug . Assert ( doesPreservePathStructure ) ;
128+ entryName = childFileSystemInfo . Name ;
129+ } else
130+ {
131+ entryName = GetEntryNameUsingPrefix ( path : childFileSystemInfo . FullName , prefix : pathPrefix ) ;
95132 }
96- // Otherwise, get the entry name using the prefix
133+
134+
135+ // Add an entry for each descendent of the directory
136+ if ( parentMatchesFilter )
137+ {
138+ // If the parent directory matches the filter, all its contents are included in the archive
139+ // Just add the entry for each child without needing to check whether the child matches the filter
140+ additions . Add ( new ArchiveAddition ( entryName : entryName , fileSystemInfo : childFileSystemInfo ) ) ;
141+ }
97142 else
98143 {
99- entryName = GetEntryNameUsingPrefix ( path : childFileSystemInfo . FullName , prefix : pathPrefix ) ;
144+ // If the parent directory does not match the filter, we want to call this function
145+ // because this function will check if the name of the child matches the filter and if so, will add it
146+ AddAdditionForFullyQualifiedPath ( childFileSystemInfo . FullName , additions , entryName , parentMatchesFilter : false ) ;
100147 }
101- // Add an entry for each descendent of the directory
102- additions . Add ( new ArchiveAddition ( entryName : entryName , fileSystemInfo : childFileSystemInfo ) ) ;
103148 }
104149 }
105150 // Write a non-terminating error if a securityException occurs
@@ -122,7 +167,7 @@ private string GetEntryName(FileSystemInfo fileSystemInfo, out bool doesPreserve
122167 string entryName ;
123168 doesPreservePathStructure = false ;
124169 // If the path is relative to the current working directory, return the relative path as name
125- if ( TryGetPathRelativeToCurrentWorkingDirectory ( path : fileSystemInfo . FullName , out var relativePath ) )
170+ if ( ! Flatten && TryGetPathRelativeToCurrentWorkingDirectory ( path : fileSystemInfo . FullName , out var relativePath ) )
126171 {
127172 Debug . Assert ( relativePath is not null ) ;
128173 doesPreservePathStructure = true ;
0 commit comments