目錄html
Jenkins持續集成學習-Windows環境進行.Net開發1
Jenkins持續集成學習-Windows環境進行.Net開發2
Jenkins持續集成學習-Windows環境進行.Net開發3
Jenkins持續集成學習-Windows環境進行.Net開發4
Jenkins持續集成學習-搭建jenkins問題彙總
Jenkins持續部署-Windows環境持續部署探究1
Jenkins持續部署-自動生成版本號
Jenkins持續部署-建立差量更新包shell
上一篇文章介紹關於版本號的自動生成邏輯,本篇文章主要介紹經過腳本跟版本號建立程序的差量包。json
本章主要是經過jenkins持續集成以後經過powershell生成差量更新包與全量更新包,而後將他們上傳到FTP上。windows
當jenkins編譯完成以後,咱們須要處理如下事項。api
上一章介紹了.net
環境下如何自動生成版本號的邏輯,這裏再也不介紹。有興趣的能夠看《Jenkins持續部署-自動生成版本號
》數組
$version =(Get-ChildItem $executeFile).VersionInfo.FileVersion
$executeFile
爲可執行的exe文件。經過Get-ChildItem 獲取到該文件。經過VersionInfo.FileVersion
或VersionInfo.ProductVersion
獲取到文件的文件版本號。服務器
不知道爲何和文件右鍵屬性看到的兩個版本號有點區別右擊屬性的文件版本號和產品版本可能不同,可是經過代碼獲取到的都是同樣的函數
爲了可以生成程序差量更新包,減小程序更新時的更新包大小,須要能夠經過比較當前版本和上一個版本的各個文件的版本號信息。經過將該文件保存成一份文件清單。再比較時直接經過該文件清單進行比對,可以很方便的生成從差量的文件清單。同時文件清單可以清晰的列出每一個須要更新的文件和文件版本號,給人看會比較直觀。學習
主要是咱們本身須要用該文件,也能夠不用該文件,直接獲取全部文件,對比他們的文件名和版本號是否一致也能夠。ui
$programFiles = Get-ChildItem *.dll,*.exe $updateListFileName = "FileUpdateList.txt" Create-FileUpdateList -files $programFiles -fileName $updateListFileName function Create-FileUpdateList(){ param([System.IO.FileInfo[]]$files,[string]$fileName) ## 刪除原始的清單文件 if(Test-Path $fileName) { Write-Host "Remove Old UpdateList File" Remove-Item $fileName } $array=New-Object System.Collections.ArrayList foreach($file in $files) { ## 獲取每一個文件版本號 $fileVersion =(Get-ChildItem $file).VersionInfo.ProductVersion $fileInfo="" | Select-Object -Property FileName,Version $fileInfo.FileName = $file.Name $fileInfo.Version = $fileVersion ## 追加到文件 $null = $array.Add($fileInfo) Write-Host "Update File:"$file.Name ",Version:" $fileVersion } $json = ConvertTo-Json $array.ToArray() $json >> $fileName }
Get-ChildItem *.dll,*.exe
獲取當前目錄全部的dll和exe文件FileUpdateList.txt
,若已經存在更新清單文件,則刪除舊的從新生成。New-Object
建立一個.Net的集合,用於存放每一個文件的文件信息。$fileInfo="" | Select-Object -Property FileName,Version
定義了一個自定義對象類型,包含了文件名和版本號2個屬性。因爲我須要在powershell2.0
的環境上執行腳本,powershell2.0
沒有Json讀寫的api,這裏使用的是別人寫的一個腳本生成json格式的字符串。
function ConvertTo-Json { param( $InputObject ) if( $InputObject -is [string]){ "`"{0}`"" -f $InputObject } elseif( $InputObject -is [bool]) { $InputObject.ToString().ToLower() } elseif( $null -eq $InputObject){ "null" } elseif( $InputObject -is [pscustomobject]) { $result = "$space{`r`n" $properties = $InputObject | Get-Member -MemberType NoteProperty | ForEach-Object { "`"{0}`": {1}" -f $_.Name, (ConvertTo-Json $InputObject.($_.Name)) } $result += $properties -join ",`r`n" $result += "$space`r`n}" $result } elseif( $InputObject -is [hashtable]) { $result = "{`r`n" $properties = $InputObject.Keys | ForEach-Object { "`"{0}`": {1}" -f $_, (ConvertTo-Json $InputObject[$_]) } $result += $properties -join ",`r`n" $result += "`r`n}" $result } elseif( $InputObject -is [array]) { $result = "[`r`n" $items = @() for ($i=0;$i -lt $InputObject.length;$i++) { $items += ConvertTo-Json $InputObject[$i] } $result += $items -join ",`r`n" $result += "`r`n]" $result } else{ $InputObject.ToString() } }
將全部文件進行壓縮,壓縮文件名爲版本號。
function New-ZipFile() { param(## The name of the zip archive to create [object[]]$files, $zipName = $(throw "Specify a zip file name"), ## Switch to delete the zip archive if it already exists. [Switch] $Force) ## Check if the file exists already. If it does, check ## for -Force - generate an error if not specified. if(Test-Path $zipName) { if($Force) { Write-Host "Remove File:" $zipName Remove-Item $zipName } else { throw "Item with specified name $zipName already exists." } } ## Add the DLL that helps with file compression Add-Type -Assembly System try { #打開或建立文件流 $compressedFileStream = [System.IO.File]::Open($zipName,[System.IO.FileMode]::OpenOrCreate) #建立壓縮文件流 $compressionStream = New-Object ICSharpCode.SharpZipLib.Zip.ZipOutputStream($compressedFileStream) ## Go through each file in the input, adding it to the Zip file ## specified foreach($file in $files) { ## Skip the current file if it is the zip file itself if($file.FullName -eq $zipName) { continue } ## Skip directories if($file.PSIsContainer) { continue } #讀取每一個文件進行壓縮 try { #打開文件 $originalFileStream = [System.IO.File]::Open($file.FullName,[System.IO.FileMode]::Open) $entry = New-Object ICSharpCode.SharpZipLib.Zip.ZipEntry($file.Name) $compressionStream.PutNextEntry($entry); $bytes = New-Object Byte[] $originalFileStream.Length #讀取文件流 $null = $originalFileStream.Read($bytes,0,$bytes.Length) #寫入到壓縮流 $compressionStream.Write($bytes,0,$bytes.Length) } finally { $originalFileStream.Dispose() } } } catch{ $Error Remove-Item $Path } finally { ## Close the file $compressionStream.Dispose() $compressedFileStream.Dispose() $compressionStream = $null $compressedFileStream = $null } }
powershell2.0
沒有內部的壓縮解壓方法。這裏使用.net的ICSharpCode.SharpZipLib.dll
進行壓縮。powershell
中能夠經過New-Object Byte[]
建立.net的字節數組
,若構造函數須要傳參則直接將參數寫到後面便可。該腳本不支持帶文件夾的壓縮。
因爲我定義的都是4位版本號,前三位是需求號,最後一位是修訂號。所以我直接經過前三位獲取上個版本的壓縮包文件便可,若沒有,則無需建立差量更新包。
function Get-LastPackage($currentVersion,$majorVersion) { #默認上個版本號就是當前版本號 $lastFileName = $null $lastMajorVersion = $null $lastVersion = $null #讀取上一個版本的壓縮文件 # 獲取全部文件夾,程序目錄下的目錄都是版本號目錄 $allFile = Get-ChildItem | Where-Object{ $_.Name -match '(\d*\.\d*\.\d*.\d*)\.zip' } if($null -eq $allFile) { Write-Host "No Last Package" return } ## 獲取上一個版本號最新的修改 $allFile = $allFile | Where-Object {$_.Name -lt $majorVersion} | Sort-Object -descending ## 判斷是否有比當前版本小的 if($null -eq $allFile) { ## 沒有歷史的大版本號,則全量更新,和當前版本的主版本號同樣 Write-Host "No Last Package" return } #有多個文件如2.25.0,2.24.1,則獲取到的是數組 elseif($allFile -is [array]) { ##存在歷史更新,則獲取上一個版本的更新目錄 $lastFileName = $allFile[0] } #只有一個目錄,首個版本打包時則獲取到的是DirectoryInfo else { $lastFileName = $allFile } ## 獲取最新的版本 $lastVersion =[System.IO.Path]::GetFileNameWithoutExtension($lastFileName) $lastMajorVersion = [System.IO.Path]::GetFileNameWithoutExtension($lastVersion) #返回文件名 主版本號 版本號 $lastFileName $lastVersion $lastMajorVersion }
四位數字版本.zip
的文件。我只須要根據兩個文件清單進行文件名和版本號的對比,若是同一個文件的版本號同樣,則該文件無需更新。
$lastUnpackDir = UnZip $lastZipFullName $lastVersion $currentUpdateObject = Read-Json $currentUpdateListFile $lastUpdateObject = Read-Json $lastUpdateListFile $array = New-Object System.Collections.ArrayList #比較兩個清單文件 foreach($currentFile in $currentUpdateObject) { if($currentFile -eq "FileUpdateList.txt") { #跳過清單文件 continue } ##遍歷json數組數組對象自己也會遍歷,且值爲空 if($null -eq $currentFile.FileName) { #跳過清單文件 continue } #當前清單每一個文件去上個版本查找 $lastFile = $lastUpdateObject | Where-Object {$_.FileName -eq $currentFile.FileName} | Select-Object -First 1 #找到文件,判斷版本號 if($lastFile.Version -eq $currentFile.Version) { #版本號同樣則不須要更新 $sameFile = Join-Path $currentUnpackDir $lastFile.FileName $null = $array.Add($sameFile) continue } }
有了重複文件的列表,接下來就能夠將重複文件都刪除。最後剩下差量更新的文件
if($array.Count -eq $currentUpdateObject.Length - 1) { #全部都同樣,不須要更新 Write-Host "No Modified File" return $false } else { #存在不同的包,則更新全部 foreach($sameFile in $array) { Write-Host "Remove Not Modified File " $sameFile Remove-Item $sameFile #同時刪除pdb文件 $pdbFile = [System.IO.Path]::GetFileNameWithoutExtension($sameFile)+".pdb" if(Test-Path $pdbFile) { Remove-Item $pdbFile } } #從新獲取解壓的目錄 $diffFiles = Get-ChildItem *.dll,*.exe #建立新的清單文件 Create-FileUpdateList -files $diffFiles -fileName $currentUpdateListFile #從新壓縮全部文件 $files = Get-ChildItem *.dll,*.pdb,*.exe,"FileUpdateList.txt" Write-Host "Need Update File " $files $diffZipFullName = [System.IO.Path]::GetFileNameWithoutExtension($currentZipFullName)+"_diff.zip" New-ZipFile -files $files -Path $diffZipFullName -Force true } #移除上個版本的解壓出的壓縮文件夾 Write-Host "Remove Last Update Package dir" $lastUnpackDir Get-ChildItem $lastUnpackDir | Remove-Item -Recurse Remove-Item $lastUnpackDir -Recurse $return $true
false
表示沒有生成差量更新文件。就不用建立差量更新文件了。不然則刪除全部的文件和對應的符號文件。true
表示生成了差量更新文件。全量和差量文件生成完畢後就能夠將文件上傳到指定的服務器了。我將服務器的配置信息保存到了ServerInfo.Json
文件中,這樣想添加其餘服務器只要修改一下這個配置文件便可。讀取配置的服務器,ServerInfo.Json
包含了服務器的一些信息,包括地址,用戶名,及一些路徑配置。
$config = Read-Json "ServerInfo.json" foreach($itemConfig in $config) { Remote-CreateDic -userName $itemConfig.UserName -password $itemConfig.Password -address $itemConfig.Address -jobName $ftpFileName -programeDir $itemConfig.ProgramDir -ErrorAction Stop #目標 ftp://host:port/xxx/xxx.zip $destination = "ftp://"+$itemConfig.FTP.Host+":"+$itemConfig.FTP.Port+"/"+$ftpFileName # FTP上傳壓縮包 FTP-UpdateFile -file $zipFullName -destination $destination -userName $itemConfig.FTP.UserName -password $itemConfig.FTP.Password -ErrorAction Stop if($hasDiffFile ){ $ftpFileName = Join-Path $ENV:JOB_NAME ($version+"_diff.zip") FTP-UpdateFile -file $zipFullName -destination $destination -userName $itemConfig.FTP.UserName -password $itemConfig.FTP.Password -ErrorAction Stop } }
Remote-CreateDic
執行遠程建立文件夾的命令。FTP-UpdateFile
將全量更新包和差量更新包都上傳到指定的服務器上。在上傳到FTP上時,如有必要則須要先在FTP上建立指定的文件夾,避免上傳文件夾的時候因爲沒有文件夾致使上傳失敗。
因爲須要遠程調用,所以須要傳遞用戶,密碼和服務器地址。同時還要包含jenkins當前的job名稱以及遠程服務器程序上傳路徑。上傳的路徑約定爲FTP地址/Job名稱/版本號.zip
function Remote-CreateDic() { param([string] $userName=$(throw "Parameter missing: -userName"), [string] $password=$(throw "Parameter missing: -password"), [string] $address=$(throw "Parameter missing: -address"), [string] $jobName=$(throw "Parameter missing: -jobName"), [string] $programeDir=$(throw "Parameter missing: -programeDir")) #非域用戶須要添加\,不然遠程調用有問題 if(!$userName.StartsWith('\')) { $userName="\"+$userName } $secpwd = convertto-securestring $password -asplaintext -force $cred = new-object System.Management.Automation.PSCredential -argumentlist $userName,$secpwd #程序存放目錄和當前的jenkins job目錄合併後是服務器鎖在的FTP程序存放目錄 $zipFile= [System.IO.Path]::Combine($programeDir,$jobName) #備份程序 invoke-command -computername $address -Credential $cred -command { param([string]$file) #獲取文件夾路徑 $dir = [System.IO.Path]::GetDirectoryName($file) if(Test-Path $dir){ Write-Host "Dic exists :" $dir #文件夾存在 if(Test-Path $file) { #壓縮文件已存在.不容許,版本號沒變。必須改變 throw $file + "exists,retry after change version" } } else { # 判斷文件夾是否存在 # 沒有文件夾則建立,不然首次FTP上傳沒有文件夾時則會上傳失敗 #防止輸出 $null = New-Item -Path $dir -Type Directory } } -ArgumentList $zipFile -ErrorAction Stop }
FTP上傳能夠調用.Net的WebClient上傳文件的方法處理。
function FTP-UpdateFile() { param([String]$file=$(throw "Parameter missing: -name file"), [String]$destination=$(throw "Parameter missing: -name destination"), [String]$userName=$(throw "Parameter missing: -name userName"), [String]$password=$(throw "Parameter missing: -name destination")) $pwd=ConvertTo-SecureString $password -AsPlainText -Force; #111111爲密碼 $cred=New-Object System.Management.Automation.PSCredential($userName,$pwd); #建立自動認證對象 $wc = New-Object System.Net.WebClient try { $wc.Credentials = $cred Write-Host "upload to ftp. " $file "->" $destination $wc.UploadFile($destination, $file) Write-Host "upload success " } finally { $wc.Dispose() Write-Host "close ftp. " } }
本文對Windows下的持續部署包建立和上傳的邏輯繼續了說明,主要經過自動生成的版本號繼續判斷與比較哪些庫包須要更新。最終將庫包經過FTP上傳到各個服務器上。最後就能夠調用各個服務器的遠程腳本進行服務的卸載與更新了。
本文地址:http://www.javashuo.com/article/p-uangfmlj-kx.html 做者博客:傑哥很忙 歡迎轉載,請在明顯位置給出出處及連接