patternshellMinor
Updating multiple svn repositories using powershell
Viewed 0 times
updatingpowershellrepositoriesusingsvnmultiple
Problem
I wrote a script to perform
Can this script be further simplified and written more idiomatically?
PS: I am using only
svn update on all the SVN repositories inside a folder. It would have been great if the folder containing all these repositories itself was a repository, but it was not setup like that, which is why I opted to write this script.$timestamp = get-date -f "yyyy-M-d-h-m-s"
$SvnLogPath="C:\out\svnlogs\"
if(test-path -path $SvnLogPath)
{
write-host "SVN Log path doesn't exist. So I am creating it . . ."
new-item -type directory $SvnLogPath | out-null
}
$logfile = "${SvnLogPath}svn_update_${timestamp}.log"
new-item -type file $logfile | out-null
$BaseDir="C:\TRUNK\"
$RepositoryList = "Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel"
# BUILDING FULL PATHS
$FullPaths = $RepositoryList | %{ $BaseDir+$_}
# ISSUING SVN UPDATE TO EACH DIR
$FullPaths | % {svn update $_ 2>&1 | ft -AutoSize -Wrap | Out-File -Append $logfile }
# OPEN LOG FILE AFTER THE COMPLETION
notepad $logfileCan this script be further simplified and written more idiomatically?
PS: I am using only
svn update without credentials as they are stored in the shell already.Solution
Reusable Commands
One of the most important ideas in PowerShell is the Get/Update/Set pattern. A clear delineation between resources (nouns) and commands (verbs) helps to write code that is useful not only for scripting, but also in the interactive shell.
We only need a couple of new commands. First we need to
Functions and Modules
Now you're convinced that we should create reusable commands with these great new names. What next? PowerShell v2 introduced the concept of a module, which is just a file that contains functions. (Of course, you could just create a new script for each command but it helps to keep things tidy by bundling all of the functions together in one file.)
What should our functions look like? Yes they will need to take some parameters. But more importantly, they should return objects to the pipeline, even if they aren't a "getter" function! This makes it easier to review what impact a function had.
Some actual code
Luckily for us, somebody else already found a way to find all the svn working copies underneath a directory. We can reuse that.
SvnTools.psm1
I took some liberties with the command
SvnTools.psm1 (continued)
Now we can reap the benefits from creating these commands. Here's your original script, rewritten to take advantage of our new module using just one line.
UpdateMyWorkingCopies.ps1
You could easily redirect the output to a file. If you don't, it will show up on screen looking something like this.
References
The Scripting Guy! blog on TechNet has a really excellent series about building your own PowerShell cmdlet that I recommend reading.
Coding Style
Bonus Points
For bonus points, install the module into one of the module path folders (
And if you want to get even more fancy, implement another command called
One of the most important ideas in PowerShell is the Get/Update/Set pattern. A clear delineation between resources (nouns) and commands (verbs) helps to write code that is useful not only for scripting, but also in the interactive shell.
We only need a couple of new commands. First we need to
Find the working copies under some directory, then Update each working copy. The list of approved verbs for PowerShell is a great resource for help with naming your commands. Let's use these names.- Find-SvnWorkingCopy (
Findlooks for an object in a container)
- Update-SvnWorkingCopy (
Updatebrings a resource up-to-date)
Functions and Modules
Now you're convinced that we should create reusable commands with these great new names. What next? PowerShell v2 introduced the concept of a module, which is just a file that contains functions. (Of course, you could just create a new script for each command but it helps to keep things tidy by bundling all of the functions together in one file.)
What should our functions look like? Yes they will need to take some parameters. But more importantly, they should return objects to the pipeline, even if they aren't a "getter" function! This makes it easier to review what impact a function had.
Some actual code
Luckily for us, somebody else already found a way to find all the svn working copies underneath a directory. We can reuse that.
SvnTools.psm1
function Find-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$BasePath
)
process
{
$prev = "^$"
Get-ChildItem -Recurse -Force -Include ".svn" -Path $BasePath |
Where-Object {
$_.PSIsContainer -and $_.Fullname.StartsWith($prev)-eq $false
} |
ForEach-Object {
$prev=$_.Fullname.TrimEnd(".svn")
$prev
}
}
}I took some liberties with the command
Update-SvnWorkingCopy. In addition to calling "svn update" like your original script, it also calls "svn info" and parses the results to find the current revision number and include that in the object returned to the pipeline.SvnTools.psm1 (continued)
function Update-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$WorkingCopy
)
process {
svn update $WorkingCopy > $null
[String[]] $result = svn info $WorkingCopy
[String] $revStr = $result -like "Revision:*"
[int] $revNumber = $revStr.Replace("Revision: ", "")
New-Object -TypeName PSObject -Prop @{
WorkingCopy=$WorkingCopy;
Revision=$revNumber;
} | Write-Output
}
}Now we can reap the benefits from creating these commands. Here's your original script, rewritten to take advantage of our new module using just one line.
UpdateMyWorkingCopies.ps1
Import-Module C:\path\to\module\SvnTools.psm1
Find-SvnWorkingCopy -BasePath "C:\TRUNK\" | Update-SvnWorkingCopyYou could easily redirect the output to a file. If you don't, it will show up on screen looking something like this.
WorkingCopy Revision
----------- --------
C:\TRUNK\Alpha 31
C:\TRUNK\Bravo 42
C:\TRUNK\Charlie 16References
The Scripting Guy! blog on TechNet has a really excellent series about building your own PowerShell cmdlet that I recommend reading.
Coding Style
- https://stackoverflow.com/a/2031927/190298
- https://stackoverflow.com/questions/5260125/whats-the-better-cleaner-way-to-ignore-output-in-powershell
- http://www.powershellcommunity.org/Wikis/BestPractices/tabid/79/topic/Naming/Default.aspx
Bonus Points
For bonus points, install the module into one of the module path folders (
$env:PSModulePath) so that you can import it from the shell more easily.And if you want to get even more fancy, implement another command called
Get-SvnWorkingCopy which parses all of the results from svn info. It should integrate nicely with the two commands we already created here.Code Snippets
function Find-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$BasePath
)
process
{
$prev = "^$"
Get-ChildItem -Recurse -Force -Include ".svn" -Path $BasePath |
Where-Object {
$_.PSIsContainer -and $_.Fullname.StartsWith($prev)-eq $false
} |
ForEach-Object {
$prev=$_.Fullname.TrimEnd(".svn")
$prev
}
}
}function Update-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$WorkingCopy
)
process {
svn update $WorkingCopy > $null
[String[]] $result = svn info $WorkingCopy
[String] $revStr = $result -like "Revision:*"
[int] $revNumber = $revStr.Replace("Revision: ", "")
New-Object -TypeName PSObject -Prop @{
WorkingCopy=$WorkingCopy;
Revision=$revNumber;
} | Write-Output
}
}Import-Module C:\path\to\module\SvnTools.psm1
Find-SvnWorkingCopy -BasePath "C:\TRUNK\" | Update-SvnWorkingCopyWorkingCopy Revision
----------- --------
C:\TRUNK\Alpha 31
C:\TRUNK\Bravo 42
C:\TRUNK\Charlie 16Context
StackExchange Code Review Q#23468, answer score: 8
Revisions (0)
No revisions yet.