@@ -17,20 +17,29 @@ internal class PathHelper
17
17
18
18
private const string FileSystemProviderName = "FileSystem" ;
19
19
20
+ internal bool Flatten { get ; set ; }
21
+
22
+ internal string ? Filter { get ; set ; }
23
+
24
+ internal WildcardPattern ? _wildCardPattern ;
25
+
20
26
internal PathHelper ( PSCmdlet cmdlet )
21
27
{
22
28
_cmdlet = cmdlet ;
23
29
}
24
30
25
31
internal List < ArchiveAddition > GetArchiveAdditions ( HashSet < string > fullyQualifiedPaths )
26
32
{
33
+ if ( Filter is not null ) {
34
+ _wildCardPattern = new WildcardPattern ( Filter ) ;
35
+ }
27
36
List < ArchiveAddition > archiveAdditions = new List < ArchiveAddition > ( fullyQualifiedPaths . Count ) ;
28
37
foreach ( var path in fullyQualifiedPaths )
29
38
{
30
39
// Assume each path is valid, fully qualified, and existing
31
40
Debug . Assert ( Path . Exists ( path ) ) ;
32
41
Debug . Assert ( Path . IsPathFullyQualified ( path ) ) ;
33
- AddAdditionForFullyQualifiedPath ( path , archiveAdditions ) ;
42
+ AddAdditionForFullyQualifiedPath ( path , archiveAdditions , entryName : null , parentMatchesFilter : false ) ;
34
43
}
35
44
return archiveAdditions ;
36
45
}
@@ -41,7 +50,7 @@ internal List<ArchiveAddition> GetArchiveAdditions(HashSet<string> fullyQualifie
41
50
/// <param name="path">The fully qualified path</param>
42
51
/// <param name="additions">The list where to add the ArchiveAddition object for the path</param>
43
52
/// <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 )
45
54
{
46
55
Debug . Assert ( Path . Exists ( path ) ) ;
47
56
FileSystemInfo fileSystemInfo ;
@@ -61,15 +70,38 @@ private void AddAdditionForFullyQualifiedPath(string path, List<ArchiveAddition>
61
70
fileSystemInfo = new FileInfo ( path ) ;
62
71
}
63
72
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 ;
68
87
69
88
// 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 ) ;
72
92
}
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
+
73
105
}
74
106
75
107
/// <summary>
@@ -78,28 +110,41 @@ private void AddAdditionForFullyQualifiedPath(string path, List<ArchiveAddition>
78
110
/// <param name="path">A fully qualifed path referring to a directory</param>
79
111
/// <param name="additions">Where the ArchiveAddtion object for each child item of the directory will be added</param>
80
112
/// <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 )
82
114
{
83
115
try
84
116
{
85
117
// pathPrefix is used to construct the entry names of the descendents of the directory
86
118
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 ) )
88
124
{
89
125
string entryName ;
90
- // If the cmdlet should preserve the path structure, then use the relative path
91
- if ( shouldPreservePathStructure )
126
+ if ( Flatten )
92
127
{
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 ) ;
95
132
}
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
+ }
97
142
else
98
143
{
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 ) ;
100
147
}
101
- // Add an entry for each descendent of the directory
102
- additions . Add ( new ArchiveAddition ( entryName : entryName , fileSystemInfo : childFileSystemInfo ) ) ;
103
148
}
104
149
}
105
150
// Write a non-terminating error if a securityException occurs
@@ -122,7 +167,7 @@ private string GetEntryName(FileSystemInfo fileSystemInfo, out bool doesPreserve
122
167
string entryName ;
123
168
doesPreservePathStructure = false ;
124
169
// 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 ) )
126
171
{
127
172
Debug . Assert ( relativePath is not null ) ;
128
173
doesPreservePathStructure = true ;
0 commit comments