Проблема
Я пишу сценарий развертывания с использованием powershell.Использование команды Copy-Item
не дает одинакового результата между запусками, даже с одинаковыми данными.(Это не кажется идемпотентом)
См. Результаты ниже для примера того, что я имею в виду.Я понимаю, что могу удалить файлы в C:\products
перед копированием «новой» версии в, но мне более любопытно, является ли это ожидаемым поведением в Powershell или нет.(И я предполагаю, что это так)
Я бы лучше выучил «правильный» способ использования Copy-Item
вместо того, чтобы взламывать мое отсутствие знаний.
Я пытался использоватьпуть target\*
вместо target
, но он взорвал мою папку lib
в корне showcase
, чего я не ожидал даже с флагом -Recurse
.
C:\products
- showcase
- showcase.jar
- logback.jar
- foo.jar
- junit.jar
- etc, etc
IЯ также немного запутался с документацией здесь (в частности, примеры 7,10 и 11), поскольку 7 использует флаг -Recurse
, а 11 - нет.Между тем пример 10 говорит следующее:
Если папка сценариев содержит файлы в подпапках, эти подпапки будут скопированы с целыми деревьями файлов.
, но никогда не будет указывать флаг рекурсиилибо.
Результаты
Перед развертыванием
C:\products
- backup
Первоначальное развертывание
C:\products
- showcase
- showcase.jar
- lib
- <dependencies for showcase.jar>
- backup
<empty>
# Expected, as there wasn't a prior deployment yet.
Второе развертывание
C:\products
- showcase
- showcase.jar
- lib
- <dependencies for showcase.jar>
- target
- showcase.jar
- lib
- <dependencies for inner showcase.jar>
- backup
- showcase
- showcase.jar
- lib
- <dependencies for "old" showcase.jar>
# Expected, the old version was backed up
Сценарий развертывания и как он называется
./deploy.ps1 -hostname foobar (it's a remote server)
deploy.ps1
param( [String]$hostname, [switch]$debug )
$folder_to_copy = "target"
$init_file = "./init.ps1"
function Backup-Binary ( [String]$source, [String]$name, [String]$dest ) {
$FullyQualifiedSourcePath = "$source\$name"
if (Test-Path $FullyQualifiedSourcePath) {
Write-Host "Backing up $FullyQualifiedSourcePath to the destination $dest"
Copy-Item -Recurse -Force -Path $FullyQualifiedSourcePath -Destination $dest -ErrorAction Stop
} else {
Write-Output "Directory $FullyQualifiedSourcePath didn't exist. May be an initial deployment. Continuing with deployment."
}
}
function Verify-Env ([String]$env_var) {
$check = [Environment]::GetEnvironmentVariable($env_var)
if ($check -eq $null) {
Write-Error "$env_var environment variable doesn't exist. Exiting program."
exit 1
}
}
function Deploy-Local {
# Checks that the given string exists as an Environment variable
Verify-Env "DEPLOY_DRIVE"
Verify-Env "CI_PROJECT_NAME"
# C:\products or D:\products *most* of the time.
$root = "$env:DEPLOY_DRIVE\products"
$destination = "$root\$env:CI_PROJECT_NAME"
$backup_loc = "$root\backup"
# Removes prior binaries
Backup-Binary -source $root -name $env:CI_PROJECT_NAME -dest $backup_loc
# Copy binary locally since we're deploying to local machine.
Copy-Item -Recurse -Force -Path $folder_to_copy -Destination $destination -ErrorAction Stop
# Run the init script the developer has written
Invoke-Expression "$init_file" -ErrorAction Stop
}
function Deploy-Remote {
$session = New-PSSession -ComputerName $hostname
$DEPLOY_DRIVE = Invoke-Command -Session $session -ScriptBlock {
[Environment]::GetEnvironmentVariable("DEPLOY_DRIVE")
} -ErrorAction Stop
$root = "$DEPLOY_DRIVE\products"
$destination = "$root\$env:CI_PROJECT_NAME"
$backup_loc = "$root\backup"
Write-Host "$root = root $destination = destination $backup_loc = backup_location"
Invoke-Command -Session $session -ScriptBlock ${function:Backup-Binary} -ArgumentList $root,$env:CI_PROJECT_NAME,$backup_loc -ErrorAction Stop
Copy-Item -Recurse -Force -ToSession $session -Path $folder_to_copy -Destination $destination -ErrorAction Stop
Invoke-Command -Session $session -FilePath $init_file -ErrorAction Stop
Remove-PSSession $session -ErrorAction Stop
}
if ( $hostname.ToLower() -eq $env:COMPUTERNAME.ToLower() ) {
Deploy-Local
} else {
Deploy-Remote
}