How can I write Nuspec for MEF Plugin File - mef

I want to write nuspec for MEF plugin.
I can copy xxx.dll to content directory, like below.
<files>
<file src="Alhambra\bin\Release\Plugins\Alhambra.Plugin.SqlServer.dll" target="content\Plugins\Alhambra.Plugin.SqlServer.dll" />
<file src="Alhambra\bin\Release\Alhambra.dll" target="lib\Alhambra.dll" />
</files>
but I can't set file property in user project to copy output directory.
Thanks for any suggestions or code snippets.

My approach would be to add the plugin to the project as a separate file. For that you need an install script (see NuGet docs for this).
My solution for this is the following script:
param($installPath, $toolsPath, $package, $project)
Function add_file($file)
{
$do_add = 1
foreach($item in $project.DTE.ActiveSolutionProjects[0].ProjectItems)
{
if ($item -eq $file)
{ $do_add = 0 }
}
if ($do_add -eq 1)
{
$added = $project.DTE.ItemOperations.AddExistingItem($file)
$added.Properties.Item("CopyToOutputDirectory").Value = 2
$added.Properties.Item("BuildAction").Value = 0
}
}
add_file(<file1>)
add_file(<file2>)
Of course, when the user uninstalls the package, you need to clean up:
param($installPath, $toolsPath, $package, $project)
Function remove_file($file)
{
foreach($item in $project.DTE.ActiveSolutionProjects[0].ProjectItems)
{
if ($item.Name -eq $file)
{
$item.Delete()
}
}
}
remove_file(<file1>)
remove_file(<file2>)

Related

How do I update all NuGet packages at once with the dotnet CLI?

I'm trying to update all NuGet packages for a solution in VS Code (using Mac). Is there a way to achieve that in VS code or for a specific project.json file? At the moment I'm going one by one but I would have thought there is either an extension or a feature that does that for you?
For update all packages in all projects Nuget Package Manager GUI extension can do it with one click.
How it works
Open your project workspace in VSCode
Open the Command Palette (Ctrl+Shift+P)
Select > Nuget Package Manager GUI
Click Load Package Versions
Click Update All Packages
Based on Jon Canning's powershell solution. I fixed a small bug where only the first dependency was being updated and not all the dependencies for the project file.
$regex = 'PackageReference Include="([^"]*)" Version="([^"]*)"'
ForEach ($file in get-childitem . -recurse | where {$_.extension -like "*proj"})
{
$packages = Get-Content $file.FullName |
select-string -pattern $regex -AllMatches |
ForEach-Object {$_.Matches} |
ForEach-Object {$_.Groups[1].Value.ToString()}|
sort -Unique
ForEach ($package in $packages)
{
write-host "Update $file package :$package" -foreground 'magenta'
$fullName = $file.FullName
iex "dotnet add $fullName package $package"
}
}
Here's a shell script and a powershell script that will do this
#!/bin/bash
regex='PackageReference Include="([^"]*)" Version="([^"]*)"'
find . -name "*.*proj" | while read proj
do
while read line
do
if [[ $line =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
if [[ $version != *-* ]]
then
dotnet add $proj package $name
fi
fi
done < $proj
done
$regex = [regex] 'PackageReference Include="([^"]*)" Version="([^"]*)"'
ForEach ($file in get-childitem . -recurse | where {$_.extension -like "*proj"})
{
$proj = $file.fullname
$content = Get-Content $proj
$match = $regex.Match($content)
if ($match.Success) {
$name = $match.Groups[1].Value
$version = $match.Groups[2].Value
if ($version -notin "-") {
iex "dotnet add $proj package $name"
}
}
}
Should also mention Paket as a fantastic alternative package manager that supports update:
https://fsprojects.github.io/Paket/index.html
dotnet tool install paket --tool-path .paket
Also have a look at dotnet outdated:
https://github.com/dotnet-outdated/dotnet-outdated
UPDATE 2023/01
The current way to do this from the command line seems to be this:
https://github.com/dotnet-outdated/dotnet-outdated
OLD
This seems to work https://nukeeper.com/
dotnet tool install nukeeper --global
nukeeper update <SLN/PROJ>
UPDATE
The default settings on nukeeper seem slightly odd to me as running nukeeper update will only update a single package, and only if it is a major version that is more than 3 days old.
To update to the latest non-prerelease version of everything run:
nukeeper update -a 0 -m 1000
And for prerelease:
nukeeper update -a 0 -m 1000 --useprerelease Always
The -m 1000 flag is a synonym for everything, assuming that you have less than 1000 packages in your solution / project.
I wrote this powershell script to keep packages up to date on Githup.
To update all packages of the solution I use first dotnet sln list.
The for each project I get the list of outdated package with dotnet list package --outdated, it give the latest version of each outdated packages.
And for each packages I update the project with dotnet add package {package name} --version {new version}.
Full code:
# Update one project packages
function UpdatePackages {
param (
$project
)
$return = $false
# Get outdated packages
$packageLineList = dotnet list $project package --outdated
foreach($line in $packageLineList) {
Write-Host $line
$match = $line -match '>\s(\S*)\s*\S*\s*\S*\s*(\S*)'
if (!$match) {
# the line doesn't contain a package information, continue
continue
}
# update an outdated package
$added = dotnet add $project package $Matches.1 --version $Matches.2
if ($LASTEXITCODE -ne 0) {
# error while updating the package
Write-Error "dotnet add $project package $Matches.1 --version $Matches.2 exit with code $LASTEXITCODE"
Write-Host $added
break
}
$return = $true
}
return $return
}
# Restore dependencies
dotnet restore
# Get all project list in the solution
$projectList = dotnet sln list
$updated = $false
foreach($path in $projectList) {
if ($path -eq "Project(s)" -or $path -eq "----------") {
# The line doesn't contain a path, continue
continue
}
# Update project dependencies
$projectUpdated = UpdatePackages -project $path
if ($LASTEXITCODE -ne 0) {
#The update fail, exit
exit $LASTEXITCODE
}
$updated = $updated -or $projectUpdated
}
if (!$updated) {
# No packages to update found, exit
Write-Host "nothing to update"
exit 0
}
For CLI -
as already mentioned in comments there exist a package to perform updates
https://github.com/dotnet-outdated/dotnet-outdated
From UI -
In case some one is still looking for answer, with vs 2019 this has been pretty easy :)
Right Click on solution and choose "Manage nuget package for solution".
It should open a window like below -
On selection of package, right side we can see the project and we can update the packages :)
Based on Jon Caning answer, I've written this small bash script to add in .bashrc (or just change a bit to keep it in its bash file)
function read_solution() {
echo "Parsing solution $1"
while IFS='' read -r line || [[ -n "$line" ]]; do
if [[ $line =~ \"([^\"]*.csproj)\" ]]; then
project="${BASH_REMATCH[1]}"
read_project "$(echo "$project"|tr '\\' '/')"
fi
done < "$1"
}
function read_project() {
echo "Parsing project $1"
package_regex='PackageReference Include="([^"]*)" Version="([^"]*)"'
while IFS='' read -r line || [[ -n "$line" ]]; do
if [[ $line =~ $package_regex ]]; then
name="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
if [[ $version != *-* ]]; then
dotnet add "$1" package "$name"
fi
fi
done < $1
}
function dotnet_update_packages() {
has_read=0
if [[ $1 =~ \.sln$ ]]; then
read_solution "$1"
return 0
elif [[ $1 =~ \.csproj$ ]]; then
read_project "$1"
return 0
elif [[ $1 != "" ]]; then
echo "Invalid file $1"
return 1
fi
for solution in ./*.sln; do
if [ ! -f ${solution} ]; then
continue
fi
read_solution "${solution}"
has_read=1
done
if [[ $has_read -eq 1 ]]; then
return 0
fi
for project in ./*.csproj; do
if [ ! -f ${project} ]; then
continue
fi
read_project "${project}"
done
}
export -f dotnet_update_packages
To use it, either run it without parameter in a folder with a solution, it would first look for all solution files in the current folder and run for all csproj files referenced in those (it might need to be changed if you work with something else than c#).
If no solution is found, it looks for all csproj files in the current directory and run for those.
You can also pass a .sln or .csproj file as argument:
dotnet_update_packages mysolution.sln
dotnet_update_packages myproject.csproj
I'm not a bash expert so I'm sure it can be improved
Nukeeper seems to be an excellent tool for the job. We're even using it in nightly builds to keep the internal libraries up-to-date. After installing the tool, in the solution folder use a command like:
nukeeper update --age 0 --maxpackageupdates 1000 --change Major --useprerelease Never
I created a cake build task to do the same. See below:
Task("Nuget-Update")
.Does(() =>
{
var files = GetFiles("./**/*.csproj");
foreach(var file in files)
{
var content = System.IO.File.ReadAllText(file.FullPath);
var matches = System.Text.RegularExpressions.Regex.Matches(content, #"PackageReference Include=""([^""]*)"" Version=""([^""]*)""");
Information($"Updating {matches.Count} reference(s) from {file.GetFilename()}");
foreach (System.Text.RegularExpressions.Match match in matches) {
var packageName = match.Groups[1].Value;
Information($" Updating package {packageName}");
var exitCode = StartProcess("cmd.exe",
new ProcessSettings {
Arguments = new ProcessArgumentBuilder()
.Append("/C")
.Append("dotnet")
.Append("add")
.Append(file.FullPath)
.Append("package")
.Append(packageName)
}
);
}
}
});
If you're using Visual Studio, it can be done quite easily.
Step 1
Right click the solution and click 'Manage NuGet Packages for Solution':
Step 2
Go to Updates tab, check Select all packages and hit Update button:

Get the latest checkin files from a tfs folder using powershell

Hi i am actually new to powershell. I am trying to do ETL database deployment, so i need all the files with in the tfs folder after a given time. I established the connection with the tfs but i am able to download the files but if a file has two check-ins i am getting the file with the previous checkin and not the latest
My code:
$TfsUrl = "http://tfs2013-xxx02.ad.xxx.com:8080/tfs/abcd-xxx243"
# Load TFS assemblies for connecting to the TFS server
Add-Type -Path "E:\Microsoft Visual Studio 14.0\Common7\IDE\TestAgent\Microsoft.TeamFoundation.Client.dll"
Add-Type -Path "E:\Microsoft Visual Studio 14.0\Common7\IDE\TestAgent\Microsoft.TeamFoundation.Common.dll"
Add-Type -Path "E:\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\4qvjm2or.ipa\Microsoft.TeamFoundation.Lab.Client.dll"
Add-Type -Path "E:\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\4qvjm2or.ipa\Microsoft.TeamFoundation.Lab.Common.dll"
Add-Type -Path "E:\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\4qvjm2or.ipa\Microsoft.TeamFoundation.VersionControl.Client.dll"
#Get TFS Instance
$Tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($TfsUrl)
# use the account credentials of the process running the script
try
{
$Tfs.EnsureAuthenticated()
Write-Output "TFS Connection is successful"
}
catch
{
Write-Output "Error trying to connect to tfs server. Check your tfs permissions and path: $_ "
Exit(1)
}
#Write-Message $LogFileName "THIS IS INSIDE Connect-ToTFS"
#Write-Message $LogFileName "TFS IS $Tfs"
$DeploymentFilePath= "$/xxxx/FutureReleases/Database/ReportingETLs"
$TFSInstance = $Tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$LatestVersion = [Microsoft.TeamFoundation.VersionControl.Client.VersionSpec]::Latest
$RecursionType = [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::Full
$DateFrom = "D2016-10-08T01:59"
# Get the From and To date-time in version format to be passed to TFS API
$VersionFrom = $null
$VersionFrom = [Microsoft.TeamFoundation.VersionControl.Client.VersionSpec]::ParseSingleSpec($DateFrom, "")
$FileHistory = #($TFSInstance.QueryHistory($DeploymentFilePath,$LatestVersion,0,$RecursionType,$null,$null,$null,[int32]::MaxValue, $true ,$true, $true))
#Write-Output "Filehistory is: $FileHistory"
#$ChangeSetCount = $FileHistory.Count
#Write-Output "ChangeSetCount is: $ChangeSetCount"
$TFSGetFullPath = "E:\temp\"
$chArray = #()
$checkin =""
foreach ($history in $FileHistory)
{
foreach ($change in $history.Changes)
{
foreach ($item in $change.item)
{
if($item.CheckinDate -gt $VersionFrom.Date)
{
$chArray += $history.ChangesetId
}
}
}
}
Write-Output "ChangesetArray is: $chArray"
foreach ($ch in $chArray)
{
foreach ($lastdeployedHistory in $FileHistory)
{
if($lastdeployedHistory.ChangesetId -eq $ch)
{
foreach ($workitem in $lastdeployedHistory.Changes)
{
$workitem.Item.DownloadFile([IO.Path]::GetFullPath($TFSGetFullPath) + $workitem.Item.ServerItem.Split('/')[$workitem.Item.ServerItem.Split('/').Length - 1]);
}
}
}
}
This is caused by the object order in $chArray. The changeset in $chArray is ordered from new to old. When you download the file, it is downloading the new file first and then download the older file.
For example, there are two changesets for one file: 111 and 112, with the code Write-Output "ChangesetArray is: $chArray" in your script, you should see the output like: ChangesetArray is: 112 111. When it downloads the file, the file with 112 version is downloaded first and then 111 version which overwrite the latest version.
You can sort the array in $chArray to fix this issue:
Write-Output "ChangesetArray is: $chArray"
$sortcsarray = $chArray | Sort-Object
Write-Output "ChangesetArray is: $sortcsarray"
foreach ($ch in $sortcsarray)

How to get latest version of specific project in TFS using Powershell.

I've look through many posts but still don't get it. I need a powershell script to download latest version of a specific project.
Let's say I just want to download the latest copies of files from ProjectA branch dfe. I saw some PS script that deletes the old files and download all the files again but that takes too long. script that would overwrite existing files would be much better. I tried update-tfsworkspace, it downloads everything but I don't want to download everything.
server: http://servername:8080/tfs/DefaultCollection
DefaultCollection
ProjectA
-Folder1
- branch dfe
-Folder2
- branch abc
ProjectB
-Folder1
- branch
- branch
First you need a good workspace mapping. You can create one manually, or from an xml file as below. Also, the functionality you are after to overwrite is [Microsoft.TeamFoundation.VersionControl.Client.GetOptions]::Overwrite
function Get-ProjectXml {
[CmdletBinding()]
Param(
[string] $tfs13Url,
[string] $workspaceName ,
[string] $workspaceDescription,
[string] $fileName,
[bool] $autoDeleteCreate)
try
{
#Connect to TFS:
$tfs13 = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($tfs13url)
$vcs13 = $tfs13.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$workspaces=$vcs13.QueryWorkspaces($workspaceName, $vcs13.AuthenticatedUser, [Environment]::MachineName);
if($autoDeleteCreate ){
#Delete if Workspace exists, as this is an automated process...
if ($workspaces.count -gt 0)
{
$vcs13.DeleteWorkspace($workspaceName, $vcs13.AuthenticatedUser);
}
$workspace = $tfs10.VCS.CreateWorkspace($workspaceName, $vcs13.AuthenticatedUser, $workspaceDescription);
}
else
{
$workspace=$workspaces[0]
}
#Get XML File
[xml]$xmlMappings= New-Object System.Xml.XmlDocument
$xmlMappings.Load($fileName)
$rootLocalItem=$xmlMappings.Root.LocalItem
#Iterate through each collection
foreach($collection in $xmlMappings.Collection){
write-host "Mapping project $($collection.Name)"
#Iterate through each project
foreach($project in $collection.Project){
write-host "Mapping project $($project.Name)"
foreach($mapping in $project.Mapping){
$workspace.Map($mapping.ServerItem, $mapping.LocalItem);
}
}
}
$resultTime= Measure-Command {
$result=$workspace.Get([Microsoft.TeamFoundation.VersionControl.Client.VersionSpec]::Latest,[Microsoft.TeamFoundation.VersionControl.Client.GetOptions]::Overwrite)
}
$resultAlerts=$result.NumConflicts+ $result.NumFailures+ $result.NumWarnings
if ($resultAlerts -eq 0) {
Write-host "Get Operation completed without any errors. $($result.NumUpdated) files are updated on workspace: $($workspace.name)" }
else {
Write-Host "Get Operation completed with errors. Please check errors: $($result.GetFailures)"}
$resultTime.ToString()
}
catch
{
return $_.exception
}
}
[string] $tfs13Url="http://tfs:8080/tfs/defaultcollection",
[string] $workspaceName = "AutomatedWorkspace",
[string] $workspaceDescription = "AutomatedWorkspace",
[string] $fileName="D:\projects\ProjectMapping.xml",
[bool] $autoDeleteCreate =$true
Get-ProjectXml $tfs13Url $workspaceName $workspaceDescription $fileName $autoDeleteCreate
Assuming your xml is like:
<?xml version="1.0"?>
<Collection Name="DefaultCollection">
<Root>
<ServerItem>$/</ServerItem>
<LocalItem>d:\Src</LocalItem>
</Root>
<Project name="ProjectA">
<Mapping>
<ServerItem>$/ProjectA/Folder1/BranchDEF</ServerItem>
<LocalItem>d:\Src\ProjectA\Folder1\BranchDEF\</LocalItem>
</Mapping>
<Mapping>
<ServerItem>$/ProjectA/Folder2\BranchABC</ServerItem>
<LocalItem>d:\Src\ProjectA\Folder2\BranchABC</LocalItem>
</Mapping>
</Project>
<Project Name="ProjectB">
<Mapping>
<ServerItem>$/ProjectB/Folder5\BranchXYZ</ServerItem>
<LocalItem>d:\Src\ProjectB\Folder5\BranchXYZ</LocalItem>
</Mapping>
</Project>
</Collection>

Update project property with a powershell script

I want to create a nuget package which will run a Powershell script on restore in a C# project. The script will change the values of the project properties on the project e.g.:
Set value of
<AssemblyVersion>1.0.0.0</AssemblyVersion>
to
<AssemblyVersion>$(ReleaseApplicationVersion)</AssemblyVersion>
and some other properties.
Thanks in advance!
UPDATE-------------------------------------------
This is what I have
param([string]$projectName = $(throw 'csproj file is required'))
$proj = Resolve-Path $projectName
$propAssemblyName = $proj.Properties.Item("AssemblyName")
$propAssemblyName.Value = '$(ReleasedAssemblyName)'
But I obviously dont know how to make this work as I get bunch of issues. Thanks
function Set-Version {
Write-Header "Updating version in .csproj files"
try {
Push-Location ".\csprojLocation"
$versionProjFile = Resolve-Path "*.csproj"
$xml = [xml](Get-Content $versionProjFile)
$xml.Project.PropertyGroup.AssemblyVersion = ${version}
$xml.Save($versionPropsFile)
}
finally {
Pop-Location
}
}
Set-Version

NuGet Uninstall.ps1 - remove a project reference

So in my Install.ps1 I can add a reference like this:
param($installPath, $toolsPath, $package, $project)
$project.Object.References.Add("YourDLL")
How do you remove a project reference in PowerShell?
Here's what we use for Machine.Specifications:
param($installPath, $toolsPath, $package, $project)
$project.Object.References | Where-Object { $_.Name -eq 'Machine.Specifications.TDNetRunner' } | ForEach-Object { $_.Remove() }
There are some casting issues to do this in powershell.
this is the c# to remove a reference.
DTE dte = (DTE)dteObject;
var targetProject = (VSProject)dte.GetProject(target).Object;
var refToRemove = targetProject.References.Cast<Reference>().Where(assembly => assembly.Name.EndsWith(library, System.StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
if (refToRemove != null)
{
refToRemove.Remove();
}
If you want to use the Solution Factory nuget package you can use the powershell command that solution factory adds.
Remove-LibraryReference projectName system.web
Here is a link the the solution factory source http://solutionfactory.codeplex.com/SourceControl/network/Forks/erichexter/PowershellRewrite
Update: new url for solution factory:
https://github.com/erichexter/SolutionFactory