Skip to content

Commit

Permalink
Merge pull request #31 from santisq/30-add-exclude-parameter-to-compr…
Browse files Browse the repository at this point in the history
…ess-ziparchive

Adds `-Exclude` Parameter to `Compress-ZipArchive`
  • Loading branch information
santisq authored Aug 20, 2024
2 parents 0ffd22e + 5e582af commit 3ea5218
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 7 deletions.
41 changes: 38 additions & 3 deletions docs/en-US/Compress-ZipArchive.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ Get-ChildItem .\path -Recurse -Directory |
Compress-ZipArchive -Destination dest.zip -Update
```

### Example 8: Exclude files and folders from source

```powershell
Compress-ZipArchive .\path -Destination myPath.zip -Exclude *.xyz, *\test\*
```

This example shows how to compress all items in `path` excluding all files having a `.xyz` extension and excluding
a folder with name `test` and all its child items.

> [!TIP]
>
> The `-Exclude` parameter supports [wildcard patterns](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-7.4&viewFallbackFrom=powershell-7.3),
exclusion patterns are tested against the items `.FullName` property.

## PARAMETERS

### -Path
Expand All @@ -117,9 +131,9 @@ This parameter accepts wildcard characters. Wildcard characters allow you to add
> [!TIP]
> Using wildcards with a root directory affects the archive's contents:
>
> - To create an archive that includes the root directory, and all its files and subdirectories, specify the root directory in the Path without wildcards. For example: `-Path C:\Reference`
> - To create an archive that excludes the root directory, but zips all its files and subdirectories, use the asterisk (`*`) wildcard. For example: `-Path C:\Reference\*`
> - To create an archive that only zips the files in the root directory, use the star-dot-star (`*.*`) wildcard. Subdirectories of the root aren't included in the archive. For example: `-Path C:\Reference\*.*`
> - To create an archive that includes the root directory, and all its files and subdirectories, specify the root directory in the Path without wildcards. For example: `-Path C:\Reference`
> - To create an archive that excludes the root directory, but zips all its files and subdirectories, use the asterisk (`*`) wildcard. For example: `-Path C:\Reference\*`
> - To create an archive that only zips the files in the root directory, use the star-dot-star (`*.*`) wildcard. Subdirectories of the root aren't included in the archive. For example: `-Path C:\Reference\*.*`
```yaml
Type: String[]
Expand Down Expand Up @@ -187,6 +201,27 @@ Accept pipeline input: False
Accept wildcard characters: False
```

### -Exclude

Specifies an array of one or more string patterns to be matched as the cmdlet gets child items.
Any matching item is excluded from the created zip archive.
Wildcard characters are accepted.

> [!NOTE]
> Patterns are tested against the object's `.FullName` property.

```yaml
Type: String[]
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: True
```

### -Update

Updates the specified archive by replacing older file versions in the archive with newer file versions that have the same names. You can also use this parameter to add files to an existing archive.
Expand Down
57 changes: 53 additions & 4 deletions src/PSCompression/Commands/CompressZipArchiveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Management.Automation;
using PSCompression.Extensions;
using static PSCompression.Exceptions.ExceptionHelpers;
Expand All @@ -17,12 +18,14 @@ public sealed class CompressZipArchiveCommand : PSCmdlet, IDisposable

private bool _isLiteral;

private string[] _paths = Array.Empty<string>();
private string[] _paths = [];

private ZipArchive? _zip;

private FileStream? _destination;

private WildcardPattern[]? _excludePatterns;

private readonly Queue<DirectoryInfo> _queue = new();

[Parameter(
Expand Down Expand Up @@ -72,6 +75,11 @@ public string[] LiteralPath
[Parameter]
public SwitchParameter PassThru { get; set; }

[Parameter]
[SupportsWildcards]
[ValidateNotNullOrEmpty]
public string[]? Exclude { get; set; }

protected override void BeginProcessing()
{
if (!HasZipExtension(Destination))
Expand Down Expand Up @@ -100,6 +108,17 @@ protected override void BeginProcessing()
{
ThrowTerminatingError(StreamOpenError(Destination, e));
}

const WildcardOptions wpoptions = WildcardOptions.Compiled
| WildcardOptions.CultureInvariant
| WildcardOptions.IgnoreCase;

if (Exclude is not null)
{
_excludePatterns = Exclude
.Select(e => new WildcardPattern(e, wpoptions))
.ToArray();
}
}

protected override void ProcessRecord()
Expand All @@ -109,6 +128,11 @@ protected override void ProcessRecord()
_queue.Clear();
foreach (string path in _paths.NormalizePath(_isLiteral, this))
{
if (ShouldExclude(_excludePatterns, path))
{
continue;
}

if (!path.IsArchive())
{
Traverse(new DirectoryInfo(path), _zip);
Expand Down Expand Up @@ -159,6 +183,11 @@ private void Traverse(DirectoryInfo dir, ZipArchive zip)

foreach (FileSystemInfo item in enumerator)
{
if (ShouldExclude(_excludePatterns, item.FullName))
{
continue;
}

if (item is DirectoryInfo directory)
{
_queue.Enqueue(directory);
Expand All @@ -167,7 +196,7 @@ private void Traverse(DirectoryInfo dir, ZipArchive zip)

FileInfo file = (FileInfo)item;

if (ItemIsDestination(file, Destination))
if (ItemIsDestination(file.FullName, Destination))
{
continue;
}
Expand Down Expand Up @@ -265,8 +294,28 @@ private bool HasZipExtension(string path) =>
System.IO.Path.GetExtension(path)
.Equals(".zip", StringComparison.InvariantCultureIgnoreCase);

private bool ItemIsDestination(FileInfo source, string destination) =>
source.FullName.Equals(destination, StringComparison.InvariantCultureIgnoreCase);
private bool ItemIsDestination(string source, string destination) =>
source.Equals(destination, StringComparison.InvariantCultureIgnoreCase);

private static bool ShouldExclude(
WildcardPattern[]? patterns,
string path)
{
if (patterns is null)
{
return false;
}

foreach (WildcardPattern pattern in patterns)
{
if (pattern.IsMatch(path))
{
return true;
}
}

return false;
}

protected override void EndProcessing()
{
Expand Down
10 changes: 10 additions & 0 deletions tests/CompressZipArchive.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,14 @@ Describe 'Compress-ZipArchive' -Tag 'Compress-ZipArchive' {
Get-ChildItem skipitself -Recurse | ForEach-Object Name |
Should -Not -Contain $zipname
}

It 'Should skip items that match the exclusion patterns' {
Remove-Item "$extractpath.zip" -Force
Compress-ZipArchive $testpath $extractpath -Exclude *testfile00*, *testfolder05*
Expand-Archive "$extractpath.zip" $extractpath
Get-ChildItem $extractpath -Recurse | ForEach-Object {
$_.FullName | Should -Not -BeLike *testfile00*
$_.FullName | Should -Not -BeLike *testfolder05*
}
}
}

0 comments on commit 3ea5218

Please sign in to comment.