Skip to content

Commit

Permalink
Add the robust helper remove, close #123
Browse files Browse the repository at this point in the history
  • Loading branch information
nightroman committed Mar 23, 2018
1 parent 1abfb50 commit eeffcef
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 27 deletions.
12 changes: 6 additions & 6 deletions .build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ task Markdown {
exec { Convert-Markdown Release-Notes }
}

# Synopsis: Remove generated and temp files.
# Synopsis: Remove temporary items.
task Clean {
Get-Item z, Tests\z, Tests\z.*, README.htm, Release-Notes.htm, Invoke-Build.*.nupkg -ErrorAction 0 |
Remove-Item -Force -Recurse
remove z, *\z, *\z.*, README.htm, Release-Notes.htm, Invoke-Build.*.nupkg
}

# Synopsis: Build the PowerShell help file.
Expand All @@ -56,10 +55,11 @@ task Version {

# Synopsis: Make the module folder.
task Module Version, Markdown, Help, {
# mirror the module folder
Remove-Item [z] -Force -Recurse
remove z

# copy the module folder
$dir = "$BuildRoot\z\InvokeBuild"
exec {$null = robocopy.exe InvokeBuild $dir /mir} 1
Copy-Item InvokeBuild $dir -Recurse

# copy files
Copy-Item -Destination $dir `
Expand Down
11 changes: 11 additions & 0 deletions Invoke-Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,16 @@ function Invoke-BuildExec([Parameter(Mandatory=1)][scriptblock]$Command, [int[]]
}
}

#.ExternalHelp InvokeBuild-Help.xml
function Remove-BuildItem([Parameter(Mandatory=1)][string[]]$Path) {
if ($Path -match '^[.*/\\]*$') {*Die 'Not allowed paths.' 5}
foreach($_ in $Path) {
if (Get-Item $_ -Force -ErrorAction 0) {
Remove-Item $_ -Force -Recurse
}
}
}

#.ExternalHelp InvokeBuild-Help.xml
function Test-BuildAsset([Parameter(Position=0)][string[]]$Variable, [string[]]$Environment, [string[]]$Property) {
Remove-Variable Variable, Environment, Property
Expand Down Expand Up @@ -550,6 +560,7 @@ Set-Alias equals Assert-BuildEquals
Set-Alias error Get-BuildError
Set-Alias exec Invoke-BuildExec
Set-Alias property Get-BuildProperty
Set-Alias remove Remove-BuildItem
Set-Alias requires Test-BuildAsset
Set-Alias task Add-BuildTask
Set-Alias use Use-BuildAlias
Expand Down
37 changes: 37 additions & 0 deletions InvokeBuild-Help.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
exec (Invoke-BuildExec)
assert (Assert-Build)
equals (Assert-BuildEquals)
remove (Remove-BuildItem)
property (Get-BuildProperty)
requires (Test-BuildAsset)
use (Use-BuildAlias)
Expand Down Expand Up @@ -325,6 +326,7 @@
@{ text = 'exec (Invoke-BuildExec)' }
@{ text = 'assert (Assert-Build)' }
@{ text = 'equals (Assert-BuildEquals)' }
@{ text = 'remove (Remove-BuildItem)' }
@{ text = 'property (Get-BuildProperty)' }
@{ text = 'requires (Test-BuildAsset)' }
@{ text = 'use (Use-BuildAlias)' }
Expand Down Expand Up @@ -774,6 +776,41 @@
)
}

### Remove-BuildItem
@{
command = 'Remove-BuildItem'
synopsis = '(remove) Removes specified items.'

description = @'
Scripts use its alias 'remove'. This command removes existing items,
ignores missing items, and fails if it cannot remove existing items.
In other words, `remove X` is similar to
Remove-Item X -Force -Recurse -ErrorAction Ignore
but `remove` writes an error if existing X cannot be removed.
'@

parameters = @{
Path = @{
wildcard = $true
description = @'
Specifies the items to be removed. Wildcards are allowed.
The parameter is mostly the same as Path of Remove-Item.
For sanity, paths with only ., *, \, / are not allowed.
'@
}
}

examples = @(
@{code={
# Remove some temporary items

remove bin, obj, *.test.log
}}
)
}

### Test-BuildAsset
@{
command = 'Test-BuildAsset'
Expand Down
6 changes: 6 additions & 0 deletions Release-Notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@

# Invoke-Build Release Notes

## v5.3.0

Add the robust helper `remove`, the alternative to `Remove-Item`, see [#123](https://github.com/nightroman/Invoke-Build/issues/123)

Tools

- *New-VSCodeTask.ps1* 1.1.6 - Confirm removal of not generated file.

## v5.2.1
Expand Down
2 changes: 2 additions & 0 deletions Tests/.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ task TestFunctions {
'Get-BuildProperty'
'Get-BuildSynopsis'
'Invoke-BuildExec'
'Remove-BuildItem'
'Set-BuildData'
'Set-BuildHeader'
'Test-BuildAsset'
Expand Down Expand Up @@ -284,6 +285,7 @@ task ShowHelp {
'Get-BuildProperty'
'Get-BuildSynopsis'
'Invoke-BuildExec'
'Remove-BuildItem'
'Resolve-MSBuild'
'Test-BuildAsset'
'Use-BuildAlias'
Expand Down
2 changes: 1 addition & 1 deletion Tests/Acknowledged.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ task Dynamic-Switch-Issue {
assert ($r -like "*Missing task 'z.build.ps1'*")

Pop-Location
Remove-Item z -Force -Recurse
remove z
}

### Lost colors
Expand Down
4 changes: 2 additions & 2 deletions Tests/Custom.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Synopsis: Test "check", pass all, then run again.
task Check1 {
$file = '..\Tasks\Check\Check.build.ps1.Check.clixml'
Remove-Item $file -ErrorAction 0
remove $file

# fake to pass all
function Read-Host {}
Expand All @@ -28,7 +28,7 @@ task Check1 {
# Synopsis: Test "check", fail at task.2.2, then run again.
task Check2 {
$file = '..\Tasks\Check\Check.build.ps1.Check.clixml'
Remove-Item $file -ErrorAction 0
remove $file

# fake to fail at task.2.2
function Read-Host {
Expand Down
19 changes: 9 additions & 10 deletions Tests/Default.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
#>

task AmbigiousDefaultScript {
Get-Item [z] | Remove-Item -Force -Recurse
$null = mkdir z
Push-Location z
remove z
Push-Location (mkdir z)

1 > z.1.build.ps1
1 > z.2.build.ps1
Expand All @@ -16,11 +15,11 @@ task AmbigiousDefaultScript {
assert ("$r" -like "*Ambiguous default script in '*\z'.")

Pop-Location
Remove-Item z -Force -Recurse
remove z
}

task ParentHasManyCandidates {
Get-Item [z] | Remove-Item -Force -Recurse
remove z
$null = mkdir z\1

Push-Location z
Expand All @@ -35,11 +34,11 @@ task ParentHasManyCandidates {

assert ($tasks.Contains('AllTestScripts'))

Remove-Item z -Force -Recurse
remove z
}

task ParentHasOneCandidate {
Get-Item [z] | Remove-Item -Force -Recurse
remove z
$null = mkdir z\1\2

Set-Content z\test.build.ps1 'task SingleScript'
Expand All @@ -56,11 +55,11 @@ task ParentHasOneCandidate {

assert $tasks.Contains('SingleScript')

Remove-Item z -Force -Recurse
remove z
}

task InvokeBuildGetFile {
Get-Item [z] | Remove-Item -Force -Recurse
remove z
$null = mkdir z\1

# register the hook by the environment variable
Expand All @@ -81,7 +80,7 @@ task InvokeBuildGetFile {
# test: the script returned by the hook is invoked
assert $tasks.Contains('InvokeBuildGetFile')

Remove-Item z -Force -Recurse
remove z
}

task Summary {
Expand Down
15 changes: 14 additions & 1 deletion Tests/Dot-source-ib/Dot-test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,20 @@ Push-Location function:
assert (!(Test-Path Write-Warning))

# expected public functions
$OK = 'Add-BuildTask,Assert-Build,Assert-BuildEquals,Get-BuildError,Get-BuildFile,Get-BuildProperty,Get-BuildSynopsis,Invoke-BuildExec,Test-BuildAsset,Use-BuildAlias,Write-Build'
$OK = $(
'Add-BuildTask'
'Assert-Build'
'Assert-BuildEquals'
'Get-BuildError'
'Get-BuildFile'
'Get-BuildProperty'
'Get-BuildSynopsis'
'Invoke-BuildExec'
'Remove-BuildItem'
'Test-BuildAsset'
'Use-BuildAlias'
'Write-Build'
) -join ','
$KO = (Get-ChildItem *-Build* -Name | Sort-Object) -join ','
assert ($OK -ceq $KO) "Unexpected functions:
OK: [$OK]
Expand Down
4 changes: 2 additions & 2 deletions Tests/Fixed.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ task IncompleteErrorOnSafe {

# Synopsis: #5 Invoke-Build ** -Safe propagates -Safe.
task SafeTests {
Get-Item [z] | Remove-Item -Force -Recurse
remove z
$null = mkdir z

Set-Content z\1.test.ps1 {
Expand All @@ -49,7 +49,7 @@ task SafeTests {
assert ('oops-12' -eq $r.Tasks[1].Error)
assert ('oops-22' -eq $r.Tasks[3].Error)

Remove-Item z -Force -Recurse
remove z
}

<#
Expand Down
2 changes: 1 addition & 1 deletion Tests/Parallel.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ task OmittedBuildParameterFile {
equals $r[2].Name .

Pop-Location
Remove-Item z -Recurse
remove z
}

# Covers #27, [IB] was not found before loading IB.
Expand Down
84 changes: 84 additions & 0 deletions Tests/Remove.test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

<#
.Synopsis
Tests 'remove'.
.Example
Invoke-Build * Remove.test.ps1
#>

# Synopsis: Errors on invalid arguments.
task InvalidArgument {
($r = try {remove ''} catch {$_})
equals $r.FullyQualifiedErrorId 'ParameterArgumentValidationErrorEmptyStringNotAllowed,Remove-BuildItem'

($r = try {remove @()} catch {$_})
equals $r.FullyQualifiedErrorId 'ParameterArgumentValidationErrorEmptyArrayNotAllowed,Remove-BuildItem'

($r = try {remove .} catch {$_})
equals "$r" 'Not allowed paths.'

($r = try {remove *} catch {$_})
equals "$r" 'Not allowed paths.'

($r = try {remove '...***///\\\'} catch {$_})
equals "$r" 'Not allowed paths.'

($r = try {remove Remove.test.ps1, *} catch {$_})
assert (Test-Path Remove.test.ps1)
equals "$r" 'Not allowed paths.'
}

# Synopsis: Errors on locked items.
task ErrorLockedFile {
# create a locked file
$writer = [IO.File]::CreateText("$BuildRoot\z.txt")
try {
## terminating error
($r1 = try {remove z.txt} catch {$_})
equals $r1.FullyQualifiedErrorId 'RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand'

## non-terminating error
# this will be removed
Set-Content z.2.txt 42
assert (Test-Path z.2.txt)
# call with good and locked files
$r = remove z.2.txt, z.txt -ea 2 -ev r2 2>&1
$r | Out-String
# good is removed
assert (!(Test-Path z.2.txt))
# locked error, two ways of catching
equals $r.FullyQualifiedErrorId 'RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand'
equals $r2[0].FullyQualifiedErrorId 'RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand'
}
finally {
$writer.Close()
remove z.txt
}
}

# Synopsis: Work around Test-Path *\X when X is hidden
task HiddenInSubdirectory {
# new hidden item in a subdirectory
remove z
$item = mkdir z\hidden
$item.Attributes = $item.Attributes -bor [System.IO.FileAttributes]::Hidden

# OK, it exists
$r = Test-Path z\hidden
equals $r $true

# KO, Test-Path *\hidden fails to find it,
# hence the issue with using Test-Path
$r = Test-Path *\hidden
equals $r $false

# `remove` works around and removes
remove *\hidden

# it was removed
$r = Test-Path z\hidden
equals $r $false

remove z
}
8 changes: 4 additions & 4 deletions Tests/VSCode.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ task OmittedPaths {
equals $t.label .
equals $t.command 'Invoke-Build -Task .'

Remove-Item .vscode -Force -Recurse
remove .vscode
}

task FullPaths {
Expand All @@ -60,7 +60,7 @@ task FullPaths {
equals $t.command ("& '{0}' -Task OmittedPaths -File '{1}'" -f $InvokeBuild.Replace('\', '/'), $BuildFile.Replace('\', '/'))

Test-Json
Remove-Item .vscode -Force -Recurse
remove .vscode
}

task RelativePaths {
Expand All @@ -72,7 +72,7 @@ task RelativePaths {
equals $t.command "& '../Invoke-Build.ps1' -Task OmittedPaths -File './VSCode.test.ps1'"

Test-Json
Remove-Item .vscode -Force -Recurse
remove .vscode
}

task DiscoverEngine {
Expand All @@ -84,7 +84,7 @@ task DiscoverEngine {
equals $t.label .
equals $t.command "& './Invoke-Build.ps1' -Task ."

Remove-Item .vscode -Force -Recurse
remove .vscode
}

# Other tasks are not real tests
Expand Down

0 comments on commit eeffcef

Please sign in to comment.