I have a local nuget repository (Nuget Server). I need to upload packages from Nuget.Org to my local repository for offline building.
How can I list all packages missing for some solution? I need it to list all missing packages and thier depedecies (if it's missing too).
Is there a way to do it with nuget command line, other tools, powershell script (any other way)?
Found the solution. The powershell command Find-Package can list the package and it's depedencies. Next we can use the same command on each of the required packages to verify they exists in the target nuget reposiroy.
The following powershell script uses that command. It will enumerate the required packages for the specfied package (in nuget.org repository). And than check each package existence in the target repository. It will write to CSV files:
RequiredPackages.csv - The packages that are needed for the specified package
MissingPackages.csv - The missing packages in the target nuget repository
For example, set $inputPackage to "BenchmarkDotNet", replace $inputPackage with you own repository, and the script will write all the missing packages (including BenchmarkDotNet itself if it's missing) that Benchmark dot net uses and are missing in your repository.
$inputPackage = "<Package name>"
$inputPackage = "<target package source url>" #"local nuget repository url"
Write-Output "Enumerating needed packages"
$packages = Find-Package -Source https://api.nuget.org/v3/index.json -Name $inputPackage -IncludeDependencies
Write-Output "Writing needed packages to c:\temp\RequiredPackages.csv"
$packages | Export-Csv .\RequiredPackages.csv
#$packages = Import-Csv c:\temp\RequiredPackages.csv
Write-Output "Checking package existance in local nuget repository"
$missingPackages = #()
foreach($package in $packages)
{
try {
Find-Package -Source $targetNugetRepository -Name $package.Name -RequiredVersion $package.Version -ErrorAction Stop
}
catch {
$missingPackages += $package
}
}
$missingPackages | Export-Csv -Path .\MissingPackages.csv
Write-Output "Done"
The above sciprt can be used manually on the top level packages a solution needs (Or can be automated to read the projects files first).
Related
I know that the NuGet packages are there. I can list them on my Artifactory page. Why can't my nuget restore command see them?
I have a server at JFrog Artifactory. Let's say the URL is https://companyname.jfrog.io/artifactory.
I have a NuGet package repository at that location. The repository is called 'repo-name-local'.
My NuGet packages show up as they should at https://companyname.jfrog.io/ui/repos/tree/General/repo-name-local
... and they appear in the repository listing at https://companyname.jfrog.io/ui/repos/tree/General/repo-name-local
On that page, the "URL to file" is given as https://companyname.jfrog.io/artifactory/repo-name-local/.
I expect these three PowerShell commands to execute successfully:
# Start with a clean nuget.config
git checkout nuget.config
# Add package source, username, password
.\nuget.exe sources add -name "Artifactory" -source https://companyname.jfrog.io/artifactory/api/nuget/repo-name-local/ -username foo -password bar -configfile .\nuget.config
# Restore packages
.\nuget.exe restore -Source "https://companyname.jfrog.io/artifactory/api/nuget/repo-name-local/;https://www.nuget.org/api/v2" -ConfigFile .\nuget.config -Verbosity detailed .\Something\Something.sln
The first two commands execute successfully, but the third one gives this response:
WARNING: Unable to find version '31.3.0.1035' of package 'GemBox.Spreadsheet'.
C:\Users\rdepew\.nuget\packages\: Package 'GemBox.Spreadsheet.31.3.0.1035' is not found on source 'C:\Users\rdepew\.nuget\packages\'.
https://companyname.jfrog.io/artifactory/api/nuget/repo-name-local/: Package 'GemBox.Spreadsheet.31.3.0.1035' is not found on source 'https://companyname.jfrog.io/artifactory/api/nuget/repo-name-local/'.
https://www.nuget.org/api/v2: Package 'GemBox.Spreadsheet.31.3.0.1035' is not found on source 'https://www.nuget.org/api/v2'.
I thought that the modified URL was required, but maybe it wasn't. So I change the commands a bit:
# Start with a clean nuget.config
git checkout nuget.config
# Add package source, username, password
.\nuget.exe sources add -name "Artifactory" -source https://companyname.jfrog.io/artifactory/repo-name-local/ -username foo -password bar -configfile .\nuget.config
# Restore packages
.\nuget.exe restore -Source "https://companyname.jfrog.io/artifactory/repo-name-local/;https://www.nuget.org/api/v2" -ConfigFile .\nuget.config -Verbosity detailed .\Something\Something.sln
The response is slightly different, but still not successful:
WARNING: Unable to find version '31.3.0.1035' of package 'GemBox.Spreadsheet'.
C:\Users\rdepew\.nuget\packages\: Package 'GemBox.Spreadsheet.31.3.0.1035' is not found on source 'C:\Users\rdepew\.nuget\packages\'.
https://companyname.jfrog.io/artifactory/repo-name-local/: Failed to fetch results from V2 feed at 'https://companyname.jfrog.io/artifactory/repo-name-local/FindPackagesById()?id='GemBox.Spreadsheet'&semVerLevel=2.0.0' with following message : Response status code does not indicate success: 404 (Not Found).
Response status code does not indicate success: 404 (Not Found).
https://www.nuget.org/api/v2: Package 'GemBox.Spreadsheet.31.3.0.1035' is not found on source 'https://www.nuget.org/api/v2'.
Why are both nuget restore commands failing? Why can't they see the repository contents?
I hit to the similar issue, resolved by enabling force authentication for nuget repo.
Nuget Settings
I'm working on a nuget package that depends on the Unity and Unity.Mvc4 packages. My nuspec file has them listed as dependencies. Everything works, but when my package is installed the dependencies are installed first.
The Unity dependencies deploy files to the root of the project that my package has moved to a different location and customized, as such I don't want those files to exist in the root after my package is installed.
Is there any way to override dependency files in nuspec, or run a powershell script after install to clean them up?
You might add a Powershell script that move those files created by Unity to your actual project root.
For information about executing Powershell scripts during Nuget package installation, see the Nuget documentation. Note that these scripts must be placed within the tools folder of your Nuget package to be automatically executed.
Here's the code in my install.ps1 that did the trick if anyone wants it for reference.
# Runs every time a package is installed in a project
param($installPath, $toolsPath, $package, $project)
# $installPath is the path to the folder where the package is installed.
# $toolsPath is the path to the tools directory in the folder where the package is installed.
# $package is a reference to the package object.
# $project is a reference to the project the package was installed to.
#EnvDTE Project Reference
#https://msdn.microsoft.com/en-us/library/envdte.project.projectitems.aspx
function deleteProjectItem($fileName) {
$file = $null
foreach ($item in $project.ProjectItems) {
if ($item.Name.Equals($fileName, "InvariantCultureIgnoreCase")) {
$file = $item
break
}
}
if ($file -ne $null) {
Write-Host "Deleting: $($item.Name) ..." -NoNewline
$item.Delete()
Write-Host "Deleted!"
}
}
deleteProjectItem "BootStrapper.cs"
deleteProjectItem "job_scheduling_data_2_0.xsd"
deleteProjectItem "Unity.Mvc4.README.txt"
I'm trying to package and publish a library with nuget from a TFS post build script. It seems that TFS build doesn't use the standard project output paths, so it's making things complicated. All I want to do is build the project (which it does) and then pack and publish with nuget.
Here's my script. It runs just fine on my local machine.
param([string]$project, [string]$version)
if (-not $project)
{
Write-Error ("The project parameter is required.")
exit 1
}
if (-not $version)
{
$version = $Env:TF_BUILD_BUILDNUMBER
}
if (-not $version)
{
Write-Error ("Either the version parameter or the TF_BUILD_BUILDNUMBER environment variable is required.")
exit 1
}
$projectFile = "$project\$project.csproj"
$packageFile = "$project.$version.nupkg"
$nugetPath = ".nuget\NuGet.exe"
if ($Env:TF_BUILD_SOURCESDIRECTORY)
{
# relative paths won't work on the build server
$projectFile = "$Env:TF_BUILD_SOURCESDIRECTORY\$projectFile"
$packageFile = "$Env:TF_BUILD_SOURCESDIRECTORY\$packageFile"
$nugetPath = "$Env:TF_BUILD_SOURCESDIRECTORY\$nugetPath"
}
else
{
$nugetPath = ".\$nugetPath"
}
Write-Host ("packing $projectFile...")
& $nugetPath pack "$projectFile" -Version $version -Symbols -IncludeReferencedProjects
And here's the error I'm getting.
& : The term '.\.nuget\NuGet.exe' is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\a\src\project\.build\PublishPackage.ps1:85 char:3
+ & $nugetPath pack "$projectFile" -Version $version -Symbols -IncludeReferencedPr ...
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (.\.nuget\NuGet.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I simplified the script so the line number won't match, but you can see that it's the last line that's causing the error. I'm using Visual Studio Online with a hosted build controller.
Why don't you use the standard mechanism?
Right click on your solution and "Enable Nuget Package Restore"
This will create a folder that contains a NuGet.targets file
Open than file and set to true the Property BuildPackage
<!-- Property that enables building a package from a project -->
<BuildPackage Condition=" '$(BuildPackage)' == '' ">true</BuildPackage>
Edit each project in your solution you want to produce a nuget package from
Right click on the project -> "Unload Project"
Right click on the project again and "Edit [NameofYourProject]"
Set BuildPackage to true by adding the following to the first PropertyGroup
<BuildPackage>true</BuildPackage>
Save the file and Reload the project
Commit your changes queue a new build and you should see your package within the build outcome.
This will basically use the project file (for C# the .csproj) to create your package
If you need more control over your package creation you could include in you project a .nuspec file
Where you can specify more metadata attributes such as: dependencies, tags, title, owners, etc
or even you could use parameters like
<version>$version$</version>
to synchronize the nuget package version with the actual assembly version.
If you need to specify the OutDir on the nuget build command for the build server modify the NuGet.targets file BuildCommand definition as follow.
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform);OutDir=$(OutDir)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
When doing "install-package", nuget will get the latest version from the package source. If I want to constrain the selected version I need to explicitly set the version number. Is there a way to tell nuget to resolve the version from the local packages already installed in the solution?
Example:
package in solution packages folder:
Castle.Core.3.2.0
install-package castle.Core -projectname SomeProjectRequiringCastle
This will download the newest version of Castle (3.3.0), and add it to my packages folder. This is not what I want to do 99% of the time. In order to constrain nuget to select the version number already installed I have to remember the already installed version number:
install-package castle.Core -projectname SomeProjectRequiringCastle -version 3.2.0
My current workflow includes browsing to the packages folder to see whats already installed or opening a packages.config file from a project which already has a dependency on the requested assembly. Ideally I want something like this:
install-package castle.Core -localRepositoryVersion
Is there a way to achieve this behaviour? Or perhaps some nifty commands which can make my workflow around this a bit smoother? Note: The "manage" option under the nuget package manager (GUI) is to mouse-heavy and has already been rejected by my mouse-allergic fingers.
Edit
I wrapped Matts answer (credit to Matt, thanks) up in a function, here is a full solution for the lazy ones:
installLocal.psm1
<#
.Synopsis
Installs a package
#>
function install-local
{
[cmdletbinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[String] $Id,
[Parameter(Mandatory=$true, Position=1)]
[string]$ProjectName
)
$version = get-package | ? { $_.Id -eq $Id } | % { $_.Version }
if (-not $version) {
throw "A package with id $Id has not been installed in the solution"
} else {
write-host "Found version: $version of $Id installed in solution"
}
install-package -Id $Id -ProjectName $ProjectName -Version $version
}
export-modulemember -function install-local
Added this line to the powershell profile used by visual studio (which in my case was located at: C:\Data\WindowsPowerShell\NuGet_profile.ps1)
import-module <path to file>\installLocal.psm1
Then I can write one-liners from the package manager console:
PM> install-local moq -projectname LibWhichNeedsDeps
Found version: 4.0.10827 of moq installed in solution
'Moq 4.0.10827' already installed.
Adding 'Moq 4.0.10827' to LibWhichNeedsDeps.
Successfully added 'Moq 4.0.10827' to LibWhichNeedsDeps.
You can probably use the Get-Package command. This lists all the packages installed in the solution.
So you could something similar to:
$version = Get-Package | where-object { $_.Id -eq 'NUnit' } | % { $_.Version }
Install-Package NUnit -version $version
You can turn this into a function and add it to your profile. That would allow you to use a one line command instead of typing all of it in each time. You would want to add some error checking if there is no package that is already installed using that package id.
Another approach would be to just run Get-Package, copy the version you need from the output, then run the Install-Package command with the version number.
Firstly, I do not want to use Visual Studio at all when dealing with the certain .nupkg files.
I know there is a tool called NuGet Package Explorer and this can export nupkg files to a certain file location using a gui, but I'm looking to setup a MSBuild task to run and unpack about 50 .nupkg files, using the command line.
My question is, is there a tool you can use via the command line which will unpack .nupkg files to a specified file location?
NuPKG files are just zip files, so anything that can process a zip file should be able to process a nupkg file, i.e, 7zip.
You can also use the NuGet command line, by specifying a local host as part of an install. For example if your package is stored in the current directory
nuget install MyPackage -Source %cd% -OutputDirectory packages
will unpack it into the target directory.
Rename it to .zip, then extract it.
did the same thing like this:
clear
cd PACKAGE_DIRECTORY
function Expand-ZIPFile($file, $destination)
{
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace($file)
foreach($item in $zip.items())
{
$shell.Namespace($destination).copyhere($item)
}
}
Dir *.nupkg | rename-item -newname { $_.name -replace ".nupkg",".zip" }
Expand-ZIPFile "Package.1.0.0.zip" “DESTINATION_PATH”
With PowerShell 5.1 (PackageManagement module)
Install-Package -Name MyPackage -Source (Get-Location).Path -Destination C:\outputdirectory
This worked for me:
Rename-Item -Path A_Package.nupkg -NewName A_Package.zip
Expand-Archive -Path A_Package.zip -DestinationPath C:\Reference
I've expanded Zamarin.Essentials -version 1.6.1 with 7-zip and nuget package manager is not recognizing this package and I have source set to all.
I've tried just my global package source alone too.
Also I've noticed package manager downloads multiple versions to same folder, was wondering if it's ok to put a version folder in a package and copy the package end into it?